add cart identify feature

This commit is contained in:
Li 2024-02-24 21:16:04 +13:00
parent bc8cf7ec36
commit 1d00a1f96f
12 changed files with 431 additions and 11 deletions

View File

@ -62,6 +62,49 @@
// exfatfs does each 0x20000 reading internally - Princess of Sleeping
static uint8_t DEVICE_DUMP_BUFFER[0x20000]__attribute__((aligned(0x40)));
char* mmc_vendor_id_to_manufacturer(uint8_t vendorId) {
char* vendor = "Unknown";
switch(vendorId) {
case 0x00:
vendor = "Sandisk";
break;
case 0x02:
vendor = "Kingston or SanDisk";
break;
case 0x03:
case 0x11:
vendor = "Toshiba";
break;
case 0x13:
vendor = "Micron";
break;
case 0x15:
vendor = "Samsung or SanDisk or LG";
break;
case 0x37:
vendor = "KingMax";
break;
case 0x44:
vendor = "ATP";
break;
case 0x45:
vendor = "SanDisk Corporation";
break;
case 0x2c:
case 0x70:
vendor = "Kingston";
break;
case 0x90:
vendor = "Hynix";
break;
case 0xfe:
vendor = "Micron";
break;
}
return vendor;
}
uint8_t device_exist(char* block_device) {
int dfd = OpenDevice(block_device, SCE_O_RDONLY);

View File

@ -5,6 +5,7 @@
#define BLOCK_DEVICE_GRW0 "sdstor0:gcd-lp-ign-gamerw"
#define BLOCK_DEVICE_GRO0 "sdstor0:gcd-lp-ign-gamero"
char* mmc_vendor_id_to_manufacturer(uint8_t vendorId);
uint64_t device_size(char* block_device);
int dump_device_network(char* ip_address, unsigned short port, char* block_device, char* output_path, GcKEYS* keys, void (*progress_callback)(char*, char*, uint64_t, uint64_t));
int dump_device(char* block_device, char* output_path, GcKEYS* keys, void (*progress_callback)(char*, char*, uint64_t, uint64_t));

View File

@ -16,6 +16,9 @@ void GetDeviceSize(int device_handle, uint64_t* device_size);
int FormatDevice(char* device);
int GetCardId(int deviceIndex, void* cardId);
int GetCardCsd(int deviceIndex, void* cardCsd);
typedef struct SceSblSmCommGcData {
int always1;
int command;

View File

@ -12,3 +12,17 @@
#define PRINT_BUFFER(buffer) /**/
#endif
#define TO_HEX(in, insz, out, outsz) \
{ \
unsigned char * pin = in; \
const char * hex = "0123456789ABCDEF"; \
char * pout = out; \
for(; pin < in+insz; pout +=2, pin++){ \
pout[0] = hex[(*pin>>4) & 0xF]; \
pout[1] = hex[ *pin & 0xF]; \
if (pout + 2 - out > outsz){ \
break; \
} \
} \
pout[-1] = 0; \
}

View File

@ -319,6 +319,8 @@ void handle_menu_select_option() {
break;
case RESET_GRW0:
break;
case GET_GC_INFO:
break;
default:
break;
};
@ -331,6 +333,8 @@ void handle_menu_select_option() {
handle_wipe_option(selected);
if(selected == WRITE_MEDIAID || selected == WRITE_GRW0)
handle_select_input_device(selected);
if(selected == GET_GC_INFO)
do_device_info();
}
int main() {

View File

@ -113,9 +113,6 @@ void term_menus() {
free_texture(insertgc_tex);
}
void draw_wipe_progress(char* device, char* unused, uint64_t progress, uint64_t total) {
RESTORE_MENU("Formatting", "Writing", device, device);
}
@ -150,6 +147,8 @@ int draw_gc_options(int* selected, int* window, char* title, uint8_t has_grw0, u
ADDOPT(has_grw0, "Restore Writable Section (.IMG)");
ADDOPT(has_grw0, "Format Writable Section");
ADDOPT(1, "Get GC Information");
end_draw();
RETURNOPT();
@ -291,12 +290,60 @@ void draw_confirmation_message(char* title, char* msg) {
draw_title(title);
draw_text_center(200, msg);
draw_text_center(250, "Press any button to continue ...");
end_draw();
}
void draw_device_info(char* cardId, char* cardCsd, uint8_t vendorId) {
start_draw();
draw_background();
draw_title("GC Information");
char msg[0x100];
snprintf(msg, sizeof(msg), "CID: %s", cardId);
draw_text_center(200, msg);
snprintf(msg, sizeof(msg), "CSD: %s", cardCsd);
draw_text_center(220, msg);
snprintf(msg, sizeof(msg), "Vendor: %s (0x%02X)", mmc_vendor_id_to_manufacturer(vendorId), vendorId);
draw_text_center(240, msg);
draw_text_center(280, "Press any button to continue ...");
end_draw();
}
void do_device_info() {
char cardId[0xF];
char cardCsd[0xF];
// cmd56 parms
uint16_t cardKeyId = 0x1;
char cardRandom[0x10];
char cardIdHex[0x100];
char cardCsdHex[0x100];
char cardRandomHex[0x100];
int cidRes = GetCardId(1, cardId);
int csdRes = GetCardCsd(1, cardCsd);
if(cidRes >= 0 && csdRes >= 0){
TO_HEX(cardId, sizeof(cardId), cardIdHex, sizeof(cardIdHex));
TO_HEX(cardCsd, sizeof(cardCsd), cardCsdHex, sizeof(cardCsdHex));
uint8_t vendorId = cardId[0xF];
draw_device_info(cardIdHex, cardCsdHex, vendorId);
}
get_key();
}
int do_network_options(char* ip_address, unsigned short port) {
PROCESS_MENU(draw_network_settings, ip_address, port);
return selected;

View File

@ -12,6 +12,7 @@ void do_confirm_message(char* title, char* msg);
int do_network_options(char* ip_address, unsigned short port);
void do_ime();
int do_error(int error);
void do_device_info();
void init_menus();
void term_menus();
@ -24,8 +25,8 @@ enum insert_menu_options {
RESET_MEDIAID,
DUMP_GRW0,
WRITE_GRW0,
RESET_GRW0
RESET_GRW0,
GET_GC_INFO
};
enum select_network_options {

View File

@ -27,6 +27,7 @@ add_executable(${PROJECT_NAME}
otg.c
format.c
cmd56.c
gc.c
)
target_link_libraries(${PROJECT_NAME}
@ -43,6 +44,7 @@ target_link_libraries(${PROJECT_NAME}
SceSysmemForDriver_stub
SceDebugForDriver_stub
ScePowerForDriver_stub
SceSdifForDriver_stub
SceSysconForDriver_stub
SceSblGcAuthMgrGcAuthForDriver_stub
SceSblGcAuthMgrDrmBBForDriver_stub

28
kern/gc.c Normal file
View File

@ -0,0 +1,28 @@
#include <vitasdkkern.h>
#include <stdint.h>
#include <stdio.h>
#include "gc.h"
int GetCardId(int deviceIndex, void* cardId) {
sd_context_part_mmc* k_deviceInfo = ksceSdifGetSdContextPartValidateMmc(deviceIndex);
if(k_deviceInfo == NULL) return -1;
char k_cardId[sizeof(k_deviceInfo->ctxb.CID)];
memcpy(k_cardId, k_deviceInfo->ctxb.CID, sizeof(k_deviceInfo->ctxb.CID));
ksceKernelMemcpyKernelToUser(cardId, (const void*)k_cardId, sizeof(k_cardId));
return 0;
}
int GetCardCsd(int deviceIndex, void* cardCsd) {
sd_context_part_mmc* k_deviceInfo = ksceSdifGetSdContextPartValidateMmc(deviceIndex);
if(k_deviceInfo == NULL) return -1;
char k_cardCsd[sizeof(k_deviceInfo->ctxb.CSD)];
memcpy(k_cardCsd, k_deviceInfo->ctxb.CSD, sizeof(k_deviceInfo->ctxb.CSD));
ksceKernelMemcpyKernelToUser(cardCsd, (const void*)k_cardCsd, sizeof(k_cardCsd));
return 0;
}

275
kern/gc.h Normal file
View File

@ -0,0 +1,275 @@
#ifndef GC_H
#define GC_H 1
// shamelessly stolen from the henkaku wiki.
typedef struct sd_context_part_base {
struct sd_context_global* gctx_ptr;
uint32_t unk_4;
uint32_t def_sector_size_mmc; // looks like default sector size - used in mmc read/write commands for resp_block_size_24
uint32_t def_sector_size_sd; // looks like default sector size - used in sd read/write commands for resp_block_size_24
uint8_t unk_10; // can be padding
uint8_t CID[15]; // this is CID data but in reverse
uint8_t unk_20; // can be padding
uint8_t CSD[15]; // this is CSD data but in reverse
} sd_context_part_base;
typedef enum SceSdifDevice {
SCE_SDIF_DEVICE_EMMC = 0,
SCE_SDIF_DEVICE_GC = 1,
SCE_SDIF_DEVICE_SDIO = 2,
SCE_SDIF_DEVICE_USD = 3,
} SceSdifDevice;
typedef enum SceSdifDeviceType {
SCE_SDIF_DEVICE_TYPE_INVALID = 0,
SCE_SDIF_DEVICE_TYPE_MMC = 1,
SCE_SDIF_DEVICE_TYPE_SD = 2,
SCE_SDIF_DEVICE_TYPE_SDIO = 3,
} SceSdifDeviceType;
typedef struct cmd_info {
uint32_t state_flags;
uint32_t command;
uint32_t argument;
void* buffer;
uint16_t resp_block_size;
uint16_t resp_n_blocks;
union {
struct {
char data[0x10];
} db;
struct {
uint32_t dw0;
uint32_t dw1;
uint32_t dw2;
uint32_t dw3;
} dw;
} response;
uint32_t error_code;
} cmd_info;
typedef struct host_info {
void** host_registers;
uint32_t unk_4;
uint32_t base_clock; // = 48000000 dec
uint32_t bus_width; // = 1 / 4 / 8 (bits)
uint32_t clock_frequency; // = base_clock >> (SDCLK Frequency Select)
uint8_t timeout_control_register;
uint8_t specification_version_number; // = 1 / 2 / 3
uint8_t vendor_version_number;
uint8_t unk_17;
uint32_t unk_18;
uint32_t unk_1C;
uint32_t unk_20;
uint32_t unk_24;
} host_info;
typedef struct device_info {
uint32_t dev_type_idx; // (1,2,3)
uint32_t unk_4;
uint16_t unk_8;
} device_info;
typedef struct sdif_context_general { //size is 0x40
SceUID suspend_callback_id;
uint32_t max_array_index; // typically 3
uint32_t unk_8;
uint32_t unk_C;
uint32_t unk_10;
uint32_t unk_14;
uint32_t unk_18;
uint32_t unk_1C;
uint32_t unk_20;
uint32_t unk_24;
uint32_t unk_28;
uint32_t unk_2C;
uint32_t unk_30;
uint32_t unk_34;
uint32_t unk_38;
uint32_t unk_3C;
} sdif_context_general;
typedef struct cmd_input { // size is 0x240
uint32_t size; // 0x240
// bit 10 (shift left 0x15) - request invalidate flag - invalidate vaddr_1C0 and vaddr_200
// this flag is used for CMD56 and CMD17
// bit 20 (shift left 0xB) - request mem_188 free - free memblock with uid mem_188
// bit 20 or bit 9 cancels invalidation (both must be clear)
uint32_t state_flags; // interrupt handler completion flag
uint32_t command;
uint32_t argument;
// stores normal response without command index and crc-7
// can also store CID or CSD. crr-7 will be cleared
// storage order is reversed
union {
struct {
char data[0x10];
} db;
struct {
uint32_t dw0;
uint32_t dw1;
uint32_t dw2;
uint32_t dw3;
} dw;
} response;
void* buffer; // cmd data buffer ptr - dest for vaddr_1C0
uint16_t resp_block_size_24; // block size of response. typically 0x200 which is default sector size
uint16_t resp_n_blocks_26; // number of blocks in response. typically number of sectors to read/write
uint32_t error_code; // error code from interrupt handler (confirmed)
uint32_t unk_2C;
uint8_t data0[0x30];
struct cmd_input* next_cmd;
uint32_t unk_64; // some flag. must be 3 for invalidation to happen
uint32_t array_index;
int(*set_event_flag_callback)(void* ctx);
SceUID evid; // event id SceSdif0, SceSdif1, SceSdif2 (SceSdif3 ?)
struct cmd_input* secondary_cmd; // (when multiple commands are sent)
struct sd_context_global* gctx_ptr;
uint32_t unk_7C;
char vaddr_80[0x80]; // 3 - mapped to paddr_184 (invalidate 0x80)
void* vaddr_100;
uint8_t data_104[0x7C];
uint32_t unk_180;
void* paddr_184; // 3 - phys address of vaddr_80
SceUID mem_188; // SceSdif memblock
uint32_t unk_18C;
uint32_t unk_190;
uint32_t unk_194;
void* base_198; // dest base for vaddr_200 (also ptr for invalidate)
// data at base contains CMD17 data
// data at base also contains fragments of CMD56 response
// data at offset is unknown (zeroes)
uint32_t offset_19C; //dest offset for vaddr_200 (also size for invalidate)
uint32_t size_1A0; // size of vaddr_1C0 - only valid if request invalidate flag is set
uint32_t size_1A4; // size of vaddr_200 - only valid if request invalidate flag is set
void* paddr_1A8; // 1 - phys address of vaddr_1C0
void* paddr_1AC; // 2 - phys address of vaddr_200
SceInt64 wide_time1; // 0x1B0
SceInt64 wide_time2; // 0x1B8 - relevant for commands that need to wait for data on DAT lines
char vaddr_1C0[0x40]; // 1 - mapped to paddr_1A8 (invalidate 0x40)
// - only valid if request invalidate flag is set
// - contains fragments of CMD56 request/response
// - does not contain CMD17 data
char vaddr_200[0x40]; // 2 - mapped to paddr_1AC (invalidate 0x40)
// - only valid if request invalidate flag is set
// - contains unknown data (zeroes)
} cmd_input;
typedef struct sd_context_data { // size is 0xC0
struct cmd_input* cmd_ptr;
struct cmd_input* cmd_ptr_next;
uint32_t unk_8;
uint32_t unk_C;
uint32_t dev_type_idx; // (1, 2, 3)
sd_context_part_base* ctx; // pointer to custom context (sd_context_part_mmc*, sd_context_part_sd*, sd_context_part_wlanbt*)
uint32_t voltages; // MMC_VDD_165_195, MMC_VDD_32_33, etc. Values seen: SDIF0 and SDIF2: 0x80, SDIF1 and SDIF3: 0x300000
uint32_t unk_1C;
uint32_t array_idx; // (0,1,2)
uint8_t unk_24;
uint8_t unk_25;
uint8_t unk_26;
uint8_t unk_27;
cmd_input* cmd_28;
cmd_input* cmd_2C;
void** host_registers; // membase of SceSdif (0,1,2) memblock of size 0x1000
uint32_t unk_34;
uint8_t unk_38;
uint8_t slow_mode; // relevant only for 2 read and 2 write functions
uint8_t unk_3A;
uint8_t unk_3B;
SceUID host_registers_uid; // UID of SceSdif (0,1,2) memblock of size 0x1000
SceUID evid; // event id SceSdif0, SceSdif1, SceSdif2 (SceSdif3 ?)
void* sdif_fast_mutex; //size is 0x40 - SceSdif0, SceSdif1, SceSdif2 (SceSdif3 ?)
//it looks like this chunk is separate structure since offset 0x2480 is used too often
//offset 0x2484
SceUID uid_10000; // UID of SceSdif (0,1,2) memblock of size 0x10000
void* membase_10000; // membase of SceSdif (0,1,2) memblock of size 0x10000
uint32_t unk_8C;
uint32_t unk_90;
int lockable_int;
uint32_t unk_98;
uint32_t unk_9C;
uint32_t unk_A0;
uint32_t unk_A4;
uint32_t unk_A8;
uint32_t unk_AC;
uint32_t unk_B0;
uint32_t unk_B4;
uint32_t unk_B8;
uint32_t unk_BC;
} sd_context_data;
typedef struct sd_context_part_mmc { // size is 0x398
sd_context_part_base ctxb;
uint8_t EXT_CSD[0x200]; // 0x30
uint8_t data_230[0x160];
void* unk_390;
uint32_t unk_394;
} sd_context_part_mmc;
typedef struct sd_context_part_sd { // size is 0xC0
sd_context_part_base ctxb;
uint8_t data[0x90];
} sd_context_part_sd;
typedef struct sd_context_part_wlanbt { // size is 0x398
struct sd_context_global* gctx_ptr;
uint8_t data[0x394];
} sd_context_part_wlanbt;
typedef struct sd_context_global { // size is 0x24C0
struct cmd_input commands[16];
struct sd_context_data ctx_data;
} sd_context_global;
typedef struct bulk_transfer {
uint32_t unk0;
uint32_t unk1;
uint32_t count;
uint32_t unk2;
uint32_t type; // 1: register access, 2: memory access
uint32_t unk3;
void * (*get_next)(void *); // callback to get next buffer
uint32_t unk4;
} bulk_transfer;
#endif

View File

@ -23,4 +23,6 @@ f00dbridge:
- WriteDevice
- CloseDevice
- GetDeviceSize
- FormatDevice
- FormatDevice
- GetCardCsd
- GetCardId

View File

@ -7,6 +7,7 @@ SceUID sceSysconSetOtgPowerLevelHook = -1;
static tai_hook_ref_t sceSysconSetOtgPowerLevelHookRef;
static int return_1() {
return 1;
}
@ -31,7 +32,7 @@ int load_umass() {
if(ksceKernelSearchModuleByName("SceUsbMass") < 0) {
tai_hook_ref_t ksceSysrootIsSafeModeHookRef;
tai_hook_ref_t ksceSblAimgrIsDolceHookRef;
// temporarily patch isSafeMode and isDolce
SceUID ksceSysrootIsSafeModeHook = taiHookFunctionExportForKernel(KERNEL_PID,
&ksceSysrootIsSafeModeHookRef,
@ -54,11 +55,10 @@ int load_umass() {
PRINT_STR("ksceSblAimgrIsDolceHook 0x%04X\n", ksceSblAimgrIsDolceHook);
PRINT_STR("ksceSblAimgrIsDolceHookRef 0x%04X\n", ksceSblAimgrIsDolceHookRef);
// start from here, technically the module is actually in os0 bootimage
// but cannot start after system already started, unfortunately.
// load from the bootimage
SceUID umass_modid = ksceKernelLoadStartModule("ux0:VitaShell/module/umass.skprx", 0, NULL, 0, NULL, NULL);
PRINT_STR("Load umass.skprx 0x%04X\n", umass_modid);
// release hooks
if(ksceSysrootIsSafeModeHook > 0) taiHookReleaseForKernel(ksceSysrootIsSafeModeHook, ksceSysrootIsSafeModeHookRef);
if(ksceSblAimgrIsDolceHook > 0) taiHookReleaseForKernel(ksceSblAimgrIsDolceHook, ksceSblAimgrIsDolceHookRef);