maybe Storage device interface
SceSdif is a kernel module that is primary responsible for communicating with SD devices. This includes onboard eMMC, game card MMC, wi-fi/bluetooth SDIO devices.
To communicate with particular device SceSdif module uses device index (sd_ctx_index)
Device Index |
Type |
Description
|
0 |
MMC |
onboard eMMC
|
1 |
MMC |
game card
|
2 |
SDIO |
wi-fi/bluetooth
|
There is one more index value that closely correlates with device index.
This is speculated to be device type index. It is initialized by internal subroutine that does preinitialization (cmd0, cmd8, cmd5_sdio, cmd55, acmd41).
Value is typically stored in sd_context_data structure in field dev_type_idx.
Device Type Index |
Description
|
0 |
unknown (invalid ?)
|
1 |
MMC
|
2 |
SD
|
3 |
SDIO
|
Device type index will be validated when sd_context_part* will be aquired through these functions:
Module
Version |
World |
Privilege
|
1.69-3.65 |
Non-secure |
Kernel
|
Libraries
Known NIDs
Version |
Name |
World |
Visibility |
NID
|
1.69-3.65 |
SceSdifForDriver |
Non-secure |
Kernel |
0x96D306FA
|
Data segment layout
Address |
Size |
Description
|
0x0000 |
0x40 |
sdif_context_general
|
0x0040 |
0x24C0 |
sd_context_global (eMMC)
|
0x2500 |
0x24C0 |
sd_context_global (game card)
|
0x49C0 |
0x24C0 |
sd_context_global (wlan/bt)
|
0x6E80 |
0x398 |
sd_context_part_mmc (eMMC)
|
0x7218 |
0x398 |
sd_context_part_mmc (game card)
|
0x75B0 |
0xC0 |
sd_context_part_sd (unknown) used in initialize_sd_device (c1271539)
|
0x7670 |
0xC0 |
sd_context_part_sd (game card) used in initialize_sd_device (c1271539)
|
0x7730 |
0xC0 |
sd_context_part_sd (unknown) used in initialize_sd_device (c1271539)
|
0x77F0 |
0xD38 |
custom context used in aabaa0f0
|
0x8528 |
0xD38 |
custom context used in aabaa0f0
|
0x9260 |
0x398 |
sd_context_part_wlanbt (wlan/bt)
|
0x95F8 |
0x888 |
unknown
|
0x9E80 |
0x118 |
some wlan/bt data
|
Allocated blocks
During initialization step Sdif driver allocates couple of memory blocks.
This happens when 'module_start' function is called, inside 'init' function.
There are 2 blocks per device context. Each block is named as SceSdif<N> where N is array index.
First block is of size 0x1000 - SceUID and void* are stored in sd_context_data per device context.
Second block is of size 0x10000 - SceUID and void* are stored in sd_context_data per device context.
First block is DMA copied to / from corresponding SceSdif<N> physical address.
First block looks like to have layout that corresponds to standard SD/MMC host that is described in "Physical Layer Simplified Specification"
SceSdifForDriver
Types
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
{
sd_mmc_registers* host_registers;
uint32_t unk_4;
uint32_t base_clock;
uint32_t bus_width;
uint32_t clock_frequency;
uint8_t timeout_control_register;
uint8_t specification_version_number;
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;
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;
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;
uint32_t state_flags;
uint32_t command;
uint32_t argument;
union
{
struct
{
char data[0x10];
} db;
struct
{
uint32_t dw0;
uint32_t dw1;
uint32_t dw2;
uint32_t dw3;
} dw;
}response;
void* buffer;
uint16_t resp_block_size_24;
uint16_t resp_n_blocks_26;
uint32_t error_code;
uint32_t unk_2C;
uint8_t data0[0x30];
struct cmd_input* next_cmd;
uint32_t unk_64;
uint32_t array_index;
int(*set_event_flag_callback)(void* ctx);
SceUID evid;
struct cmd_input* secondary_cmd;
struct sd_context_global* gctx_ptr;
uint32_t unk_7C;
char vaddr_80[0x80];
void* vaddr_100;
uint8_t data_104[0x7C];
uint32_t unk_180;
void* paddr_184;
SceUID mem_188;
uint32_t unk_18C;
uint32_t unk_190;
uint32_t unk_194;
void* base_198;
uint32_t offset_19C;
uint32_t size_1A0;
uint32_t size_1A4;
void* paddr_1A8;
void* paddr_1AC;
SceInt64 wide_time1;
SceInt64 wide_time2;
char vaddr_1C0[0x40];
char vaddr_200[0x40];
} cmd_input;
typedef struct sd_mmc_registers
{
}sd_mmc_registers;
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;
sd_context_part_base* ctx;
uint32_t unk_18;
uint32_t unk_1C;
uint32_t array_idx;
uint8_t unk_24;
uint8_t unk_25;
uint8_t unk_26;
uint8_t unk_27;
cmd_input* cmd_28;
cmd_input* cmd_2C;
sd_mmc_registers* host_registers;
uint32_t unk_34;
uint8_t unk_38;
uint8_t slow_mode;
uint8_t unk_3A;
uint8_t unk_3B;
SceUID host_registers_uid;
SceUID evid;
fast_mutex sdif_fast_mutex;
SceUID uid_10000;
void* membase_10000;
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_base
{
struct sd_context_global* gctx_ptr;
uint32_t unk_4;
uint32_t def_sector_size_mmc;
uint32_t def_sector_size_sd;
uint8_t unk_10;
uint8_t CID[15];
uint8_t unk_20;
uint8_t CSD[15];
}sd_context_part_base;
typedef struct sd_context_part_mmc // size is 0x398
{
sd_context_part_base ctxb;
uint8_t EXT_CSD[0x200];
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;
uint32_t unk3;
void * (*get_next)(void *);
uint32_t unk4;
}
init
Version |
NID
|
3.60 |
0x0eb0ef86
|
int init();
deinit
Version |
NID
|
3.60 |
0xe5e5f42e
|
int deinit();
return_error
Version |
NID
|
3.60 |
0x235ad556
|
int return_error();
sceSdifEnableSlowCardModeForDriver
Version |
NID
|
0.990-3.60 |
0xF37CF8E5
|
sets slow_mode flag in sd_context_data for game card device
also tries to set flag for device with index 3 but it does not actually exist
int sceSdifEnableSlowCardModeForDriver();
get_card_insert_state1
Version |
NID
|
3.60 |
0x36a2b01b
|
int get_card_insert_state1(int sd_ctx_index);
get_card_insert_state2
Version |
NID
|
3.60 |
0xfd9e5cfa
|
int get_card_insert_state2(int sd_ctx_index);
gc_cmd56_response
Version |
NID
|
3.60 |
0x134e06c4
|
int gc_cmd56_response(sd_context_part* ctx, char* buffer, int length);
gc_cmd56_request
Version |
NID
|
3.60 |
0xb0996641
|
int gc_cmd56_request(sd_context_part* ctx, char* buffer, int length);
get_sd_context_global
Version |
NID
|
3.60 |
0xdc8f52f8
|
sd_context_global* get_sd_context_global(int sd_ctx_index);
get_sd_context_part_validate_mmc
Version |
NID
|
3.60 |
0x6a71987f
|
sd_context_part* get_sd_context_part_validate_mmc(int sd_ctx_index);
get_sd_context_part_validate_sd
Version |
NID
|
3.60 |
0xb9ea5b1e
|
sd_context_part* get_sd_context_part_validate_sd(int sd_ctx_index);
get_sd_context_part_validate_sdio
Version |
NID
|
3.60 |
0x6a8235fc
|
sd_context_part* get_sd_context_part_validate_sdio(int sd_ctx_index);
initialize_mmc_device
Version |
NID
|
3.60 |
0x22c82e79
|
this function only initializes devices with sd_ctx_index 0 and 1 and returns 0x80320013 on any other sd_ctx_index
it is confirmed that this function sends sequence of commands that correspond to MMC initialization protocol
int initialize_mmc_device(int sd_ctx_index, sd_context_part** result);
wlan_bt_cmd52_sdio
Version |
NID
|
3.60 |
0x3428884d
|
Called in initialization sequence.
int wlan_bt_acquiredev(wlan_context* wlan_ctx);
wlan_bt_cmd52_sdio
Version |
NID
|
3.60 |
0xe80293ef
|
Called in failures. Assumed to be release of sdio device.
int wlan_bt_release(wlan_context* wlan_ctx);
sceSdioRead
Version |
NID
|
3.60 |
0xD0F78D9B
|
Reads from wlan sdio device.
Type variable seems to define which access to use. 1 is for register access, 2 is for data access.
int sceSdioRead(wlan_context* wlan_ctx, int reg, int count, void* dst, int type);
sceSdioWriteForDriver
Version |
NID
|
3.60 |
0x3C4CDC8B
|
Writes from wlan sdio device.
Type variable seems to define which access to use. 1 is for register access, 2 is for data access.
int sceSdioWriteForDriver(wlan_context* wlan_ctx, int reg, int count, void *src, int type);
wlan_bt_cmd52_sdio
Version |
NID
|
3.60 |
0x733bc373
|
int wlan_bt_cmd52_sdio(wlan_context* wlan_ctx, int num);
wlan_bt_cmd52_sdio
Version |
NID
|
3.60 |
0xdece963b
|
int wlan_bt_cmd52_sdio(sd_context_part* ctx, int num0, int num1, void* unk2);
wlan_bt_cmd52_sdio
Version |
NID
|
3.60 |
0x5d65e66b
|
int wlan_bt_cmd52_sdio(sd_context_part* ctx, int num0, int num1, void* unk2);
wlan_bt_cmd52_sdio
Version |
NID
|
3.60 |
0xbc45c83d
|
int wlan_bt_cmd52_sdio(sd_context_part* ctx, int num);
wlan_bt_initialize_custom_context2
Version |
NID
|
3.60 |
0xaabaa0f0
|
this function can send these commands: cmd3, cmd52_sdio, cmd0, cmd5_sdio, cmd55, acmd41, cmd7, cmd8
this function uses array of 2 custom contexts.
this function can either set device type index to 3 and use custom context for initialization.
or it can use preinitialization (cmd0, cmd8, cmd5_sdio, cmd55, acmd41) and then check that device type index is 3.
if device type index is not 3 then 0x80320017 error is returned.
int wlan_bt_initialize_custom_context2(int sd_ctx_index, sd_context_part** ctx);
wlan_bt
Version |
NID
|
3.60 |
0x855c95e1
|
]
This function is used in aggregated frame transmit when more than one packet is being transmitted over wlan.
int wlan_bt_bulk_transfer(wlan_context* wlan_ctx, bulk_transfer* b, void* unk1);
wlan_bt
Version |
NID
|
3.60 |
0x0c66e36f
|
Get wlan_context for sdio device. Vidpid is array with Marvell Vid and wlan/bt pid.
For wlan: vidpid = [0x02df, 0x911a]
For bt: vidpid = [0x2df, 0x9119]
int wlan_bt_get_wlan_context(sd_context_part* ctx, int vidpid[2]);
sceSdifGoStandbyStateForDriver
Version |
NID
|
0.990-3.60 |
0xAB0222F2
|
Temp name was wlan_bt_cmd7.
int wlan_bt_cmd7(sd_context_part* ctx);
wlan_bt_cmd52_sdio
Version |
NID
|
3.60 |
0x55baeb2d
|
int wlan_bt_cmd52_sdio(wlan_context* wlan_ctx);
wlan_bt_cmd52_sdio
Version |
NID
|
3.60 |
0xfe6f3e7b
|
int wlan_bt_cmd52_sdio(wlan_context* wlan_ctx);
wlan_bt_cmd52_sdio
Version |
NID
|
3.60 |
0xf1a24edd
|
int wlan_bt_cmd52_sdio(wlan_context* wlan_ctx);
wlan_bt_cmd52_sdio
Version |
NID
|
3.60 |
0x1847b18c
|
int wlan_bt_cmd52_sdio(wlan_context* wlan_ctx);
wlan_bt_cmd52_sdio
Version |
NID
|
3.60 |
0xd3c1e2b6
|
int wlan_bt_cmd52_sdio(wlan_context* wlan_ctx, int unk0, int unk1, int unk2);
wlan_bt_cmd52_sdio
Version |
NID
|
3.60 |
0x5bac6e70
|
int wlan_bt_cmd52_sdio(wlan_context* wlan_ctx, int unk0, int unk1, int unk2);
wlan_bt_cmd52_sdio
Version |
NID
|
3.60 |
0x01e8eb6c
|
int wlan_bt_cmd52_sdio(sd_context_part* ctx, char* output, int destLength_100);
wlan_bt_cmd52_sdio
Version |
NID
|
3.60 |
0x763f1075
|
int wlan_bt_cmd52_sdio(sd_context_part* ctx);
wlan_bt_initialize_custom_context1
Version |
NID
|
3.60 |
0x53962379
|
this function is just a wrapper for wlan_bt_initialize_custom_context2 (aabaa0f0)
int wlan_bt_initialize_custom_context1(int sd_ctx_index);
wlan_bt_cmd0
Version |
NID
|
3.60 |
0x3b6ab29e
|
int wlan_bt_cmd0(wlan_context* wlan_ctx, void* unk0, int* result);
wlan_bt_cmd0_cmd52_sdio
Version |
NID
|
3.60 |
0x180e7395
|
int wlan_bt_cmd0_cmd52_sdio(wlan_context* wlan_ctx, char* output, int destLength_100);
wlan_bt
Version |
NID
|
3.60 |
0x0f157f49
|
int wlan_bt(wlan_context* wlan_ctx);
wlan_bt
Version |
NID
|
3.60 |
0x849e3216
|
int wlan_bt(wlan_context* wlan_ctx);
wlan_bt
Version |
NID
|
3.60 |
0xb05eff68
|
int wlan_bt(wlan_context *wlan_ctx, int unk0);
sceMmcReadSectorForDriver
Version |
NID
|
0.990-3.60 |
0x6F8D529B
|
int sceMmcReadSectorForDriver(sd_context_part* ctx, int sector, char* buffer, int nSectors);
sdstor_read_sector_sd
Version |
NID
|
3.60 |
0xb9593652
|
int sdstor_read_sector_sd(sd_context_part* ctx, int sector, char* buffer, int nSectors);
sceMmcWriteSectorForDriver
Version |
NID
|
0.990-3.60 |
0x175543D2
|
int sceMmcWriteSectorForDriver(sd_context_part* ctx, int sector, char* buffer, int nSectors);
sceSdWriteSectorForDriver
Version |
NID
|
0.990-3.60 |
0xE0781171
|
int sceSdWriteSectorForDriver(sd_context_part* ctx, int sector, char* buffer, int nSectors);
sdstor_get_cid
Version |
NID
|
3.60 |
0x23a4ef01
|
int sdstor_get_cid(sd_context_part* ctx, char* cid);
sdstor_cmd0_cmd13
Version |
NID
|
3.60 |
0x6cc8e28d
|
int sdstor_cmd0_cmd13(int sd_ctx_index);
sdstor_cmd32_cmd33_cmd38_sdio
Version |
NID
|
3.60 |
0x35ba9df8
|
int sdstor_cmd32_cmd33_cmd38_sdio(int sd_ctx_index, int unk0);
initialize_sd_device
Version |
NID
|
3.60 |
0xc1271539
|
it is confirmed that this function sends sequence of commands that correspond to SD initialization protocol
these commands include: cmd0, cmd8, cmd5_sdio, cmd2, cmd3, cmd6, cmd9, cmd7, cmd16
some paired commands: (cmd55, acmd41), (cmd55, acmd42), (cmd55, acmd13), (cmd55, acmd51)
there are couple of special points:
- it does not check sd_ctx_index argument.
- it uses array of 3 custom contexts instead of sd_context_part structures.
- it checks device type index after preinitialization (cmd0, cmd8, cmd5_sdio, cmd55, acmd41)
- it only initializes device with device type index 2. otherwise 0x80320017 error is returned.
int initialize_sd_device(int sd_ctx_index, int* result);
sdstor_cmd6_cmd30
Version |
NID
|
3.60 |
0x995748ea
|
int sdstor_cmd6_cmd30(sd_context_part *input, int unk0, int unk1, void *unk2);
sdstor
Version |
NID
|
3.60 |
0xe091ba2e
|
int sdstor(sd_context_part* unk, int unk0, int unk1, int* unk2);
sceMmcWriteSector2ForDriver
Version |
NID
|
0.990-3.60 |
0x60642F49
|
int sceMmcWriteSector2ForDriver(sd_context_part *ctx, int unk0, int unk1);
sceSdWriteSector2ForDriver
Version |
NID
|
0.990-3.60 |
0x0203ECDC
|
int sceSdWriteSector2ForDriver(sd_context_part *ctx, int unk0, int unk1);
sceSdifDisableSlowCardMode
Version |
NID
|
3.60 |
0x29A71E7F
|
resets slow_mode flag in sd_context_data for game card device
also tries to reset flag for device with index 3 but it does not actually exist
int sceSdifDisableSlowCardMode(void);
sdif_cmd0_cmd13
Version |
NID
|
3.60 |
0x53518827
|
int sdif_cmd0_cmd13(sd_context_global *ctx, int *result);
reset_to_low_speed_mode
Version |
NID
|
3.60 |
0x475d8e45
|
this function sends CMD0 reset command to the card
then enables (Internal Clock Enable) bit
then waits till clock is table (Internal Clock Stable)
then enables (SD Clock Enable) bit for sdio device
then resets (High Speed Enable) bit
then resets (Data Transfer Width) bit
then resets (Extended Data Transfer Width) bit
int reset_to_low_speed_mode(int sd_ctx_index);
get_host_info
Version |
NID
|
3.60 |
0x3df7e207
|
int get_host_info(int sd_ctx_index, host_info *info);
get_device_info
Version |
NID
|
3.60 |
0x76d2b87b
|
int get_device_info(int sd_ctx_index, device_info* result);
sdif_cmd_exec
Version |
NID
|
3.60 |
0xb83f7518
|
int sdif_cmd_exec(int sd_ctx_index, cmd_info* info);
set_default_sector_size_mmc
Version |
NID
|
3.60 |
0xb32776c7
|
this function internally also executes CMD16 which sets BLOCKLEN
int set_default_sector_size_mmc(sd_context_part* ctx, int default_sector_size);
sdif_cmd0_cmd16
Version |
NID
|
3.60 |
0xaf702fe7
|
int sdif_cmd0_cmd16(sd_context_part* ctx, int num_200);