Editing Hypervisor Reverse Engineering
Jump to navigation
Jump to search
The edit can be undone. Please check the comparison below to verify that this is what you want to do, and then publish the changes below to finish undoing the edit.
Latest revision | Your text | ||
Line 1: | Line 1: | ||
[[Category:Software]] | |||
---- | ---- | ||
= Difference between Debug Firmware HV and Retail HV = | = Difference between Debug Firmware HV and Retail HV = | ||
There is no difference between debug firmware lv1.self and retail firmware lv1.self | There is no difference between debug firmware lv1.self and retail firmware lv1.self | ||
The differences reside on the repository nodes loaded because of policies/flags. | The differences reside on the repository nodes loaded because of policies/flags. | ||
= HSPRG = | = HSPRG = | ||
Line 19: | Line 16: | ||
LPAR = Logical Partition | LPAR = Logical Partition | ||
lpar1 starts at 0x<unknown>, and | lpar1 starts at 0x<unknown>, and its belived to be the memory space where lv1 stores its variables, flags and other data. | ||
lpar2 starts at 0x80000000000 and it's | lpar2 starts at 0x80000000000 and it's belived to be the memory space where lv2 stores its variables, flags and other data. | ||
<br> | <br> | ||
Line 109: | Line 106: | ||
== HV call == | == HV call == | ||
{| class="wikitable FCK__ShowTableBorders" | |||
|- | |||
! Id | |||
! Name | |||
! Description | |||
|- | |||
| 8 | |||
| lv1_undocumented_function_8 | |||
| Retruns current uptime of HV | |||
|- | |||
| 62 | |||
| lv1_undocumented_function_62 | |||
| SPE (isolation, it updates a SLB entry, writes to SLB_Index, SLB_VSID, SLB_ESID and SLB_Invalidate_Entry registers) | |||
|- | |||
| 89 | |||
| lv1_undocumented_function_89 | |||
| SPE (writes to MFC_TLB_Invalidate_Entry register) | |||
|- | |||
| 99 | |||
| lv1_authenticate_program_segment | |||
| SPE (isolation, syscall 0x10043, syscall 0x10042, syscall 0x1004A) | |||
|- | |||
| 102 | |||
| lv1_undocumented_function_102 | |||
| Returns current TB ticks | |||
|- | |||
| 137 | |||
| lv1_undocumented_function_137 | |||
| SPE | |||
|- | |||
| 138 | |||
| lv1_undocumented_function_138 | |||
| SPE | |||
|- | |||
| 167 | |||
| lv1_undocumented_function_167 | |||
| SPE (isolation, reads from SPU_Out_Intr_Mbox and MFC_CNTL registers) | |||
|- | |||
| 168 | |||
| lv1_undocumented_function_168 | |||
| SPE (isolation, writes to MFC_CNTL register) | |||
|- | |||
| 195 | |||
| lv1_undocumented_function_195 | |||
| WLAN Gelic device | |||
|- | |||
| 196 | |||
| lv1_undocumented_function_196 | |||
| WLAN Gelic device | |||
|- | |||
| 200 | |||
| lv1_undocumented_function_200 | |||
| SPE (isolation) | |||
|- | |||
| 201 | |||
| lv1_undocumented_function_201 | |||
| SPE (isolation) | |||
|- | |||
| 209 | |||
| lv1_undocumented_function_209 | |||
| SPE (isolation) | |||
|- | |||
| 250 | |||
| lv1_undocumented_function_250 | |||
| Storage device | |||
|- | |||
| 251 | |||
| lv1_undocumented_function_251 | |||
| Storage device | |||
|- | |||
| 252 | |||
| lv1_undocumented_function_252 | |||
| Storage device | |||
|- | |||
| 253 | |||
| lv1_undocumented_function_253 | |||
| Storage device | |||
|} | |||
=== Initializing HV Call Table === | === Initializing HV Call Table === | ||
Line 166: | Line 241: | ||
lv1_get_repository_node_value - 0x002DD260 (3.15) | lv1_get_repository_node_value - 0x002DD260 (3.15) | ||
lv1_undocumented_function_231 - 0x0030B560 (3.15) | lv1_undocumented_function_231 - 0x0030B560 (3.15) | ||
= System call = | = System call = | ||
Line 180: | Line 255: | ||
There are 2 system call tables in HV. The first one stores system calls 0 - 36. The second one stores system calls 0x10000 - 0x100FF. | There are 2 system call tables in HV. The first one stores system calls 0 - 36. The second one stores system calls 0x10000 - 0x100FF. | ||
== | == System call table 0 - 36 == | ||
0x0035FAE8 (3.15) | 0x0035FAE8 (3.15) | ||
Line 187: | Line 262: | ||
=== System call numbers === | === System call numbers === | ||
0x1 - | 0x1 - getpid(void) | ||
0x2 - | 0x2 - getppid(void) | ||
0x3 - | 0x3 - fork(void) | ||
0x4 - | 0x4 - exit | ||
0x5 - | 0x5 - exec(filename) | ||
0x6 - | 0x6 - wait(status) | ||
0x7 - | 0x7 - open(filename) | ||
0x8 - | 0x8 - close(fd) | ||
0x9 - | 0x9 - read | ||
0xA - | 0xA - write | ||
0xB - | 0xB - seek | ||
0xC - unlink( | 0xC - unlink(filename) | ||
0xD - | 0xD - signal | ||
0xE - | 0xE - kill(pid, signal type) | ||
0xF - | 0xF - brk | ||
0x10 - | 0x10 - socket(af, type, protocol) (supports only address family 0x1F, type 0x0 and protocol 0x0) | ||
0x11 - | 0x11 - bind | ||
0x12 - | 0x12 - listen(fd, backlog) | ||
0x13 - | 0x13 - accept | ||
0x14 - | 0x14 - connect | ||
0x15 - | 0x15 - ? | ||
0x16 - | 0x16 - pause(void) | ||
0x17 - | 0x17 - sleep(seconds) | ||
0x18 - | 0x18 - mmap(addr, size, prot, flags, fd, offset) | ||
0x19 - | 0x19 - munmap | ||
0x1A - | 0x1A - some fs func for directories, perhaps readdir | ||
0x1B - | 0x1B - ? | ||
0x1C - map_pages | 0x1C - map_pages (used for alloc) | ||
0x1D - unmap_pages | 0x1D - unmap_pages (used for free) | ||
0x1E - | 0x1E - select | ||
0x1F - getcwd | 0x1F - getcwd | ||
0x20 - | 0x20 - ? | ||
0x21 - | 0x21 - alarm | ||
0x22 - | 0x22 - ioctl | ||
0x23 - | 0x23 - _map_pages | ||
0x24 - | 0x24 - _unmap_pages | ||
== | == System call table 0x10000 - 0x100FF == | ||
0x0035DE78 (3.15) | 0x0035DE78 (3.15) | ||
Line 269: | Line 343: | ||
=== System call numbers === | === System call numbers === | ||
0x10000 - | 0x10000 - allocate_memory_region(LPAR id, size, log2 of page size, ?, ?) | ||
0x10001 - lpar_query_address_region_info | |||
0x10002 - lpar_memory_addr_to_phys_addr(LPAR id, LPAR address, physical addr) | |||
0x10005 - construct_logical_pu | 0x10005 - construct_logical_pu | ||
0x10007 - activate_logical_pu(LPAR id, PPE id) | 0x10007 - activate_logical_pu(LPAR id, PPE id) | ||
0x10009 - construct_logical_partition(0, LPAR id, outlet) | 0x10009 - construct_logical_partition(0, LPAR id, outlet) | ||
0x1000E - release_memory_region(LPAR id, memory region address) | 0x1000E - release_memory_region(LPAR id, memory region address) | ||
0x1001A - construct_event_receive_port | 0x1001A - construct_event_receive_port | ||
0x10024 - shutdown_logical_partition(LPAR id, shutdown command) | 0x10024 - shutdown_logical_partition(LPAR id, shutdown command) | ||
Line 320: | Line 364: | ||
0x10026 - get_logical_partition_info | 0x10026 - get_logical_partition_info | ||
0x1002C - construct_scheduling_table | 0x1002C - construct_scheduling_table | ||
Line 335: | Line 369: | ||
0x1002D - set_scheduling_slot | 0x1002D - set_scheduling_slot | ||
0x10032 - accesses system console | |||
0x10032 - | |||
0x10036 - accesses system console | |||
0x10040 - construct_spe_type_1(SPE id, shaddow_addr) | 0x10040 - construct_spe_type_1(SPE id, shaddow_addr) | ||
0x10041 - destruct_spe(SPE id) | 0x10041 - destruct_spe(SPE id) | ||
0x10042 - decrypt_lv2_self(spe id, LPAR auth id, SELF file image ptr, LPAR memory address) | 0x10042 - decrypt_lv2_self(spe id, LPAR auth id, SELF file image ptr, LPAR memory address) | ||
Line 363: | Line 383: | ||
0x10044 - disable_spe_execution | 0x10044 - disable_spe_execution | ||
0x10045 - | 0x10045 - set_spe_interrupt_mask | ||
0x10046 - read_spe_problem_state_register(spe id, register offset, value) | 0x10046 - read_spe_problem_state_register(spe id, register offset, value) | ||
0x10047 - write_spe_problem_state_register(spe id, register offset, value) | 0x10047 - write_spe_problem_state_register(spe id, register offset, value) | ||
0x1004B - disable_spe_loading | 0x1004B - disable_spe_loading | ||
0x10053 - pmi_set_guest_os_mode | |||
0x10081 - accesses system console | |||
0x10084 - construct_virtual_uart(LPAR id, VUART id, VUART data buffer size) | |||
0x10085 - destruct_virtual_uart(LPAR id, VUART id) | |||
0x10085 - destruct_virtual_uart(LPAR id, VUART id) | |||
0x10088 - RSX_syscall_10088(LPAR id) | 0x10088 - RSX_syscall_10088(LPAR id) | ||
Line 415: | Line 413: | ||
0x100C2 - modify_repository_node_value(LPAR id) | 0x100C2 - modify_repository_node_value(LPAR id) | ||
0x100C3 - | 0x100C3 - remove_repository_node_value(LPAR id) | ||
= Process = | = Process = | ||
Line 423: | Line 421: | ||
HV supports only 32 processes simultaneously. The number of processes currently running in HV is stored at address 0x0035EA54 (3.15) and 0x00357E3C (2.60). | HV supports only 32 processes simultaneously. The number of processes currently running in HV is stored at address 0x0035EA54 (3.15) and 0x00357E3C (2.60). | ||
The process table is an array of 32 process table entries. | The process table is an array of 32 process table entries. | ||
0x0035F8D0 (3.55) | 0x0035F8D0 (3.55) | ||
Line 570: | Line 562: | ||
*0x000A9870 (PID 6) | *0x000A9870 (PID 6) | ||
*0x00084B80 (PID 9) | *0x00084B80 (PID 9) | ||
= PThread = | = PThread = | ||
Line 671: | Line 653: | ||
== Member variables == | == Member variables == | ||
offset | offset 0x8 - pointer to previous AddressProtectionDomain object | ||
offset | offset 0x10 - pointer to next AddressProtectionDomain object | ||
offset | offset 0x18 - poiinter to pointer to SLB entries | ||
offset | offset 0x20 - pointer to AddressSpace object that owns this object | ||
offset | offset 0x34 - pointer to previous ProtectionPage | ||
offset | offset 0x3C - pointer to next ProtectionPage | ||
offset | offset 0x48 - Mutex object | ||
= ProtectionPage = | = ProtectionPage = | ||
Line 840: | Line 822: | ||
=== vtable === | === vtable === | ||
0x003569F8 (3.15) | 0x003569F8 (3.15) | ||
== IOIF device file objects == | == IOIF device file objects == | ||
Line 976: | Line 958: | ||
== Repository nodes from HV 3.15 == | == Repository nodes from HV 3.15 == | ||
[ | [[Dump of all repository nodes from HV 3.15]] | ||
== Repository nodes from HV 3.41 dump made from GameOS == | == Repository nodes from HV 3.41 dump made from GameOS == | ||
[ | [[Dump of all repository nodes from HV 3.41 dump made from GameOS]] | ||
= Buses = | = Buses = | ||
Line 1,026: | Line 1,008: | ||
=== vtable === | === vtable === | ||
0x000x352308 (3.15) | |||
=== Member variables === | === Member variables === | ||
Line 1,061: | Line 1,043: | ||
interrupt index = 8 | interrupt index = 8 | ||
=== MMIO regions === | === MMIO regions === | ||
Line 1,641: | Line 1,604: | ||
|- | |- | ||
| 41 | | 41 | ||
| EBUS (Flash | | EBUS (Flash StartShip) | ||
| 0x002814EC (3.15) | | 0x002814EC (3.15) | ||
|- | |- | ||
Line 1,705: | Line 1,668: | ||
*Before a storage region is accessed, HV checks access rights of the caller. | *Before a storage region is accessed, HV checks access rights of the caller. | ||
*Repository node '''ss.laid''' ( | *Repository node '''ss.laid''' (LPAR authentication id) is evaluated for this purpose. | ||
*If LPAR has a repository node '''ios.ata.region0.access''' (value doesn't matter) then the access rights check never fails. After System Manager sets ATA keys it removes this repository node from LPAR 1. If we add this repository node again or patch System Manager so it's not removed then we will be able to access all storage regions of all storage devices. | *If LPAR has a repository node '''ios.ata.region0.access''' (value doesn't matter) then the access rights check never fails. After System Manager sets ATA keys it removes this repository node from LPAR 1. If we add this repository node again or patch System Manager so it's not removed then we will be able to access all storage regions of all storage devices. | ||
*'''ALL storage accesses from LPAR 1 are allowed''' | *'''ALL storage accesses from LPAR 1 are allowed''' | ||
Line 1,758: | Line 1,721: | ||
*The storage subsystem is a storage device itself. | *The storage subsystem is a storage device itself. | ||
*It's a | *It's a psuedo device used to notify a LPAR when storage devices become e.g. ready. | ||
*Linux implements a loop and reads from this device and process notifications (adds new devices dynamically). | *Linux implements a loop and reads from this device and process notifications (adds new devices dynamically). | ||
Line 1,836: | Line 1,799: | ||
*The commands can be used with HV call '''lv1_storage_send_device_command'''. | *The commands can be used with HV call '''lv1_storage_send_device_command'''. | ||
*However, before a command is executed HV does bit manipulation with it and checks it against the value of repository node '''ss.laid''' or also called ''' | *However, before a command is executed HV does bit manipulation with it and checks it against the value of repository node '''ss.laid''' or also called '''LPAR authentication ID'''. If this test fails then the command is NOT executed. | ||
{| class="wikitable FCK__ShowTableBorders" | {| class="wikitable FCK__ShowTableBorders" | ||
Line 2,089: | Line 2,052: | ||
*The commands can be used with HV call '''lv1_storage_send_device_command'''. | *The commands can be used with HV call '''lv1_storage_send_device_command'''. | ||
*However, before a command is executed HV does bit manipulation with it and checks it against the value of repository node '''ss.laid''' or also called ''' | *However, before a command is executed HV does bit manipulation with it and checks it against the value of repository node '''ss.laid''' or also called '''LPAR authentication ID'''. If this test fails then the command is NOT executed. | ||
{| class="wikitable FCK__ShowTableBorders" | {| class="wikitable FCK__ShowTableBorders" | ||
Line 2,689: | Line 2,652: | ||
*The commands can be used with HV call '''lv1_storage_send_device_command'''. | *The commands can be used with HV call '''lv1_storage_send_device_command'''. | ||
*However, before a command is executed HV does bit manipulation with it and checks it against the value of repository node '''ss.laid''' or also called ''' | *However, before a command is executed HV does bit manipulation with it and checks it against the value of repository node '''ss.laid''' or also called '''LPAR authentication ID'''. If this test fails then the command is NOT executed. | ||
{| class="wikitable FCK__ShowTableBorders" | {| class="wikitable FCK__ShowTableBorders" | ||
Line 2,730: | Line 2,693: | ||
|- | |- | ||
| 0x32 | | 0x32 | ||
| ATA | | ATA Stanby Immediate | ||
|- | |- | ||
| 0x33 | | 0x33 | ||
Line 2,742: | Line 2,705: | ||
block size = 512 | block size = 512 | ||
*It's a | *It's a psuedo device. | ||
*'''This storage device redirects all requests to the region 1 of HDD storage device !!!''' | *'''This storage device redirects all requests to the region 1 of HDD storage device !!!''' | ||
Line 3,475: | Line 3,438: | ||
! Address of Data in HV Dump | ! Address of Data in HV Dump | ||
! Size of Data | ! Size of Data | ||
|- | |- | ||
| 0 | | 0 | ||
| | | - | ||
| 0x0C150000 | | 0x0C150000 | ||
| 0x1E5CC | | 0x1E5CC | ||
|- | |- | ||
| 1 | | 1 | ||
Line 3,487: | Line 3,448: | ||
| 0x00011000 | | 0x00011000 | ||
| 0xE8D0 | | 0xE8D0 | ||
|- | |- | ||
| 2 | | 2 | ||
Line 3,493: | Line 3,453: | ||
| 0x00020000 | | 0x00020000 | ||
| 0x16DA0 | | 0x16DA0 | ||
|- | |- | ||
| 3 | | 3 | ||
Line 3,499: | Line 3,458: | ||
| 0x00055000 | | 0x00055000 | ||
| 0x12E44 | | 0x12E44 | ||
|- | |- | ||
| 4 | | 4 | ||
Line 3,505: | Line 3,463: | ||
| 0x00037000 | | 0x00037000 | ||
| 0x1DAE4 | | 0x1DAE4 | ||
|- | |- | ||
| 5 | | 5 | ||
Line 3,511: | Line 3,468: | ||
| 0x00068000 | | 0x00068000 | ||
| 0x860 | | 0x860 | ||
|- | |- | ||
| 6 | | 6 | ||
| | | - | ||
| 0x00069010 | | 0x00069010 | ||
| 0x8 | | 0x8 | ||
|- | |- | ||
| 7 | | 7 | ||
| | | - | ||
| 0x00069020 | | 0x00069020 | ||
| 0x50 | | 0x50 | ||
|- | |- | ||
| 8 | | 8 | ||
| | | - | ||
| 0x00069070 | | 0x00069070 | ||
| 0x8 | | 0x8 | ||
|} | |} | ||
Line 3,593: | Line 3,546: | ||
=== appldr === | === appldr === | ||
*'''appldr''' is used for decryption of SELFs | *'''appldr''' is used for decryption of SELFs | ||
*HV call '''lv1_authenticate_program_segment''' loads '''appldr''' | *HV call '''lv1_authenticate_program_segment''' loads '''appldr''' | ||
Line 3,602: | Line 3,555: | ||
==== Loading appldr ==== | ==== Loading appldr ==== | ||
*64 bit memory address of ''' | *64 bit memory address of '''isoldr''' is written into 32 bit SPU register '''SPU_In_Mbox''' | ||
*'''metldr''' is loaded | *'''metldr''' is loaded | ||
Line 3,941: | Line 3,894: | ||
*Each entry is a pointer to a function responsible for processing SID packets. | *Each entry is a pointer to a function responsible for processing SID packets. | ||
= | = A/V Manager = | ||
* | *A/V Manager is running in Process 9 of HV. | ||
* It communicates with Guest OS through '''/proc/partitions/0/vuart/0 file'''. | *It communicates with Guest OS through '''/proc/partitions/0/vuart/0 file'''. | ||
* GameOS accesses | *GameOS accesses A/V Manager through '''syscalls 367 - 370'''. | ||
* PS2 Soft EMU accesses | *PS2 Soft EMU accesses A/V Manager also. | ||
= System Manager (SM) = | = System Manager (SM) = | ||
Line 3,989: | Line 3,919: | ||
offset 0x90 - LPAR image path | offset 0x90 - LPAR image path | ||
offset 0x1C0 - LPAR ability (8 bytes) | offset 0x1C0 - LPAR ability (8 bytes) | ||
=== Types of System Manager === | === Types of System Manager === | ||
Line 4,449: | Line 4,379: | ||
| 0xA | | 0xA | ||
| 0x1B6 | | 0x1B6 | ||
| Makes a | | Makes a double beep | ||
|- | |- | ||
| 0x29 | | 0x29 | ||
Line 4,461: | Line 4,391: | ||
| Makes a continuous beep | | Makes a continuous beep | ||
|} | |} | ||
=== Active System Managers in HV dump 3.15 === | === Active System Managers in HV dump 3.15 === | ||
Line 4,637: | Line 4,566: | ||
| 0x23 | | 0x23 | ||
| 0x2001 - 0x2017 | | 0x2001 - 0x2017 | ||
| Virtual TRM Manager | |||
|- | |- | ||
| 0x3000 | | 0x3000 | ||
| 0x24 | | 0x24 | ||
| 0x3001 - 0x3003 | | 0x3001 - 0x3003 | ||
| Secure RTC | |||
|- | |- | ||
| 0x5000 | | 0x5000 | ||
| 0x23 | | 0x23 | ||
| 0x5001 - 0x500A | | 0x5001 - 0x500A | ||
| Storage Manager | |||
|- | |- | ||
| 0x6000 | | 0x6000 | ||
| 0x23 | | 0x23 | ||
| 0x6001 - 0x6011 | | 0x6001 - 0x6011 | ||
| Update Manager | |||
|- | |- | ||
| 0x9000 | | 0x9000 | ||
| 0x24 | | 0x24 | ||
| 0x9001 - 0x9016 | | 0x9001 - 0x9016 | ||
| SC Manager | |||
|- | |- | ||
| 0x10000 | | 0x10000 | ||
| 0x23 | | 0x23 | ||
| | | - | ||
| | | - | ||
|- | |- | ||
| 0x11000 | | 0x11000 | ||
| 0x25 | | 0x25 | ||
| 0x11001 - 0x11002 | | 0x11001 - 0x11002 | ||
| SPM (Security Policy Manager) | |||
|- | |- | ||
| 0x14000 | | 0x14000 | ||
| 0x25 | | 0x25 | ||
| 0x14004 - 0x14005 | | 0x14004 - 0x14005 | ||
| SLL (Secure LPAR Loader) | |||
|- | |- | ||
| 0x15000 | | 0x15000 | ||
| 0x24 | | 0x24 | ||
| 0x15001, 0x15003, 0x15009 | | 0x15001, 0x15003, 0x15009 | ||
| SPL (Secure Profile Loader) | |||
|- | |- | ||
| 0x17000 | | 0x17000 | ||
| 0x24 | | 0x24 | ||
| 0x17001 - 0x17017 | | 0x17001 - 0x17017 | ||
| Indi Info Manager | |||
|- | |- | ||
| 0x18000 | | 0x18000 | ||
| 0x25 | | 0x25 | ||
| 0x18001, 0x18002, 0x18004 | | 0x18001, 0x18002, 0x18004 | ||
| Dispatcher Manager | |||
|- | |- | ||
| 0x19000 | | 0x19000 | ||
| 0x24 | | 0x24 | ||
| 0x19002 - 0x19005 | | 0x19002 - 0x19005 | ||
| AIM | |||
|- | |- | ||
| 0x24000 | | 0x24000 | ||
| 0x23 | | 0x23 | ||
| 0x24001 - 0x24002 | | 0x24001 - 0x24002 | ||
| USB Dongle Authenticator | |||
|- | |- | ||
| 0x25000 | | 0x25000 | ||
| 0x23 | | 0x23 | ||
| 0x25001 - 0x25002 | | 0x25001 - 0x25002 | ||
| User Token Manager | |||
|} | |} | ||
Line 4,740: | Line 4,659: | ||
uint32_t retval; | uint32_t retval; | ||
uint8_t res[4]; | uint8_t res[4]; | ||
uint64_t laid; /* LPAR | uint64_t laid; /* LPAR authority id */ | ||
uint64_t paid; /* Program | uint64_t paid; /* Program authority id */ | ||
} | } | ||
</pre> | </pre> | ||
Line 4,772: | Line 4,691: | ||
*The size of the body depends on a used service. | *The size of the body depends on a used service. | ||
= | == 0x2000 - Virtual TRM Manager == | ||
{| class="wikitable FCK__ShowTableBorders" | |||
|- | |||
! Packet ID | |||
! Description | |||
|- | |||
| 0x2001 | |||
| Init | |||
|- | |||
| 0x2002 | |||
| Status | |||
|- | |||
| 0x2003 | |||
| Store | |||
|- | |||
| 0x2004 | |||
| Store | |||
|- | |||
| 0x2005 | |||
| Retrieve | |||
|- | |||
| 0x2006 | |||
| Free | |||
|- | |||
| 0x200A | |||
| Encrypt | |||
|- | |||
| 0x200B | |||
| Decrypt | |||
|- | |||
| 0x200C | |||
| Encrypt With Portability | |||
|- | |||
| 0x200D | |||
| Decrypt With Portability | |||
|- | |||
| 0x200E | |||
| Decrypt Master | |||
|- | |||
| 0x2012 | |||
| Backup Flash | |||
|- | |||
| 0x2013 | |||
| Restore Flash | |||
|- | |||
| 0x2014 | |||
| Backup SRK SRH | |||
|- | |||
| 0x2015 | |||
| Restore SRK SRH | |||
|- | |||
| 0x2016 | |||
| Flash Address Size | |||
|- | |||
| 0x2017 | |||
| Force Restart | |||
|} | |||
=== 0x200E - Decrypt Master === | |||
*This service is e.g. used in Process 6 by '''USB Dongle Authenticator''' to decrypt '''USB Dongle Master Key''' | |||
*GameOS uses this service e.g. in syscall '''SYS_SS_AD_SIGN''' | |||
*'''syscall 862''' uses Virtual TRM Manager services. | |||
== 0x3000 - Secure RTC == | |||
= | {| class="wikitable FCK__ShowTableBorders" | ||
|- | |||
! Packet ID | |||
! Description | |||
|- | |||
| 0x3001 | |||
| Set RTC | |||
|- | |||
| 0x3002 | |||
| Get Time | |||
|- | |||
| 0x3003 | |||
| Set Time | |||
|} | |||
*Secure RTC reads LAIDs and PAIDs that are allowed to access Secure RTC service from '''DEFAULT.SPP''' segment '''SCE_CELLOS_SS_SECURE_RTC'''. | |||
=== 0x3001 - Set RTC === | |||
*This service uses '''SC Manager Set RTC (0x9008)''' service. | |||
=== 0x3002 - Get Time === | |||
*This service uses '''SC Manager Get Time (0x9009)''' service. | |||
=== 0x3003 - Set Time === | |||
*This service uses '''SC Manager Set Time (0x900A)''' service. | |||
== 0x5000 - Storage Manager == | |||
{| class="wikitable FCK__ShowTableBorders" | |||
|- | |||
! Packet ID | |||
! Description | |||
|- | |||
| 0x5001 | |||
| Set Encdec Key | |||
|- | |||
| 0x5002 | |||
| Set/Delete ATA (Encdec) Key | |||
|- | |||
| 0x5003 | |||
| Get Random Number | |||
|- | |||
| 0x5004 | |||
| Authenticate BD Drive | |||
|- | |||
| 0x5005 | |||
| Authenticate PS2 Disc | |||
|- | |||
| 0x5006 | |||
| Get Secure Firmware Version | |||
|- | |||
| 0x5007 | |||
| HW disc auth emu | |||
|- | |||
| 0x5008 | |||
| HW mc | |||
|- | |||
| 0x5009 | |||
| HW me auth header | |||
|- | |||
| 0x500A | |||
| HW me dec block | |||
|} | |||
* | *Storage Manager service is used e.g. by '''syscall 864''' and '''syscall SYS_SS_MEDIA_ID''' | ||
*GameOS's VSH uses '''syscall 864''' | |||
*Storage Manager executes SPU module '''sb_iso_spu_module.self''' | |||
*Storage Manager communicates with devices '''/dev/encdec0''' and '''/dev/rbd0''' from LPAR 1 | |||
*2nd value from repository node '''bus1.id''' is used by Storage Manager | |||
*Storage Manager communicates with '''sb_iso_spu_module.self''' through a shared DMA memory buffer and SPU MBox | |||
*'''EID4''' data is passed to '''sb_iso_spu_module.self''' module. | |||
==== | ==== SB Isolation DMA Buffer Header ==== | ||
<pre>struct sb_iso_header | |||
{ | |||
u32 seqno; | |||
u32 mbmsg; | |||
u32 cmd; | |||
u32 cmd_size; | |||
u8 cmd_data[0]; | |||
} | |||
</pre> | |||
*seqno has values 0x03 to 0x08. It is incremented when sending and receiving data from the spu. | |||
=== 0x5001 - Set Encdec Key === | |||
* This service allows you to set ENCDEC keys with index '''0xC - 0xF''' | |||
* '''By patching HV process 6 it would be possible to set default ENCDEC key (used for HDD encryption) to a value different from the default one !!! It means we could encrypt our HDDs with a key we want !!!''' | |||
* The service accepts 2 parameters: a key (max 24 bytes) and a key length (in bits) | |||
* Valid key length values: '''0x40''', '''0x80''' and '''0xC0''' | |||
* The service returns the ENCDEC key index used for the key | |||
* '''ENCDEC supports upto 16 keys !!!''' | |||
* Storage Manager in HV process 6 has a bit mask of size 2 bytes which indicates which keys are used currently. | |||
Per default, keys with index 0x0 - 0xB are not free. But we could patch it also. | |||
=== 0x5002 - Set/Delete ATA (Encdec) Key === | |||
* | *Sets/Deletes ATA (Encdec) Key | ||
* | *The service has only one parameter of size 8 bytes: '''0x100 - Set ATA Key''' and '''0x110 - Delete ATA Key'''. | ||
* | *This service is used e.g. by '''System Manager''' in HV Process 9 during LPAR booting. | ||
* | *SPM doesn't allow GameOS to use this service. | ||
*3 possible key lengths: 0x40, 0x80 and 0xC0 | |||
*This service communicates with '''/dev/encdec0''' device. | |||
*The service uses ENCDEC device commands '''EdecKgen1 (0x81)''', '''EdecKgen2 (0x82)''', '''EdecKset (0x83)''' and '''EdecKgenFlash (0x84)'''. | |||
*This service communicates also with '''/dev/rbd0''' device. | |||
*I guess that the ATA key is stored encrypted in '''EID4''' data. | |||
*This service is used by LPAR Manager in HV Process 9 during LPAR 2 loading. | |||
* I tested this service on Linux with '''ps3dm-utils''' and after deleting ATA key the sectors on VFLASH or HDD were NOT decrypted by HV | |||
* After setting ATA key again, the sectors were encrypted/decrypted by HV again | |||
* '''Deleting an ENCDEC key is nothing more than setting key with all bytes set to 0x0 !!!''' | |||
* On old PS3s which didn't use HDD for VFLASH, HV uses 2 ENCDEC keys, one for HDD (key index 1) and one for VFLASH (key index 0). On new PS3s which use HDD for VFLASH, only one ENCDEC key is used (key index 1). | |||
==== Service Parameter Table ==== | |||
{| class="wikitable FCK__ShowTableBorders" | |||
|- | |||
! Service Parameter | |||
! Description | |||
|- | |||
| 0xC - 0xF | |||
| Delete Encdec Key | |||
|- | |||
| 0x10* | |||
| Set ATA Key (index 1) | |||
|- | |||
| 0x11* | |||
| Delete ATA Key (index 1) | |||
|} | |||
=== | === 0x5003 - Get Random Number === | ||
* | *I have got access to Get Random Number service through DM and tested it with PSGroove | ||
* | *The service returns 192-bit random numbers | ||
* | *It has no input parameters except those in SS packet header | ||
* | *Storage Manager communicates with device '''/dev/encdec0'''. | ||
* | *This service is used e.g. by USB Dongle Authenticator to generate the body of a challenge or by GameOS to generate hardware random numbers. | ||
== | === 0x5004 - Authenticate BD Drive === | ||
*Used by LPAR Manager in HV Process 9 during LPAR 2 loading and unloading. | |||
*Used by SLL Load GOS service (0x14004) in HV Process 3 during PS2EMU loading and by SLL Unload GOS service (0x14005) during PS2EMU unloading. | |||
*The service expects one additional parameter. | |||
*The service is used during loading of LPAR 2 to authenticate BD drive and during unloading LPAR 2 to reset BD drive. | |||
*The service uses isolated SPU module '''sv_iso_spu_module.self''' for BD drive authentication. | |||
*The service communicates with LPAR 1 device '''/dev/rbd0''' through ATAPI interface. | |||
=== | ==== Service Parameter Table ==== | ||
{| class="wikitable FCK__ShowTableBorders" | |||
|- | |||
! Service Parameter | |||
! Description | |||
|- | |||
| 0x02 | |||
| Used by SLL service 0x14004 during PS2EMU loading | |||
|- | |||
| 0x1E | |||
| Used by SLL service 0x14005 during PS2EMU unloading | |||
|- | |||
| 0x29 | |||
| Reset BD Drive | |||
|- | |||
| 0x46 | |||
| Authenticate BD Drive | |||
|} | |||
=== | === 0x5005 - PS2 Disc Authenticate === | ||
=== 0x5006 - Get Version === | |||
* By default not accessible from GameOS. But it can be enabled by patching Dispatcher Manager. | |||
=== 0x5007 - Control BD Drive === | |||
*Used by GameOS to authenticate discs and for BD emulation. | |||
==== Service Parameter Table ==== | |||
{| class="wikitable FCK__ShowTableBorders" | {| class="wikitable FCK__ShowTableBorders" | ||
|- | |- | ||
! | ! Service Parameter | ||
! | ! Description | ||
|- | |||
| 0x41 | |||
| - | |||
|- | |- | ||
| | | 0x46 | ||
| | | - | ||
| | |- | ||
| | | 0x51 | ||
| | | - | ||
|- | |- | ||
| | | 0x52 | ||
| | | - | ||
|- | |- | ||
| | | 0x53 | ||
| | | - | ||
|- | |- | ||
| | | 0xA3 | ||
| | | BD emu | ||
|- | |- | ||
| | | 0xA5 | ||
| | | BD emu | ||
|- | |- | ||
| | | 0xA7 | ||
| | | BD emu | ||
|- | |- | ||
| | | 0xAA | ||
| | | BD emu | ||
|} | |} | ||
== 0x6000 - Update Manager == | |||
= | {| class="wikitable FCK__ShowTableBorders" | ||
|- | |||
! Packet ID | |||
! Description | |||
|- | |||
| 0x6001 | |||
| Update Package Tophalf | |||
|- | |||
| 0x6002 | |||
| Inspect Package Tophalf | |||
|- | |||
| 0x6003 | |||
| Get Package Info | |||
|- | |||
| 0x6004 | |||
| Get Fix Instruction | |||
|- | |||
| 0x6005 | |||
| Extract Package Tophalf | |||
|- | |||
| 0x6006 | |||
| Get Extract Package | |||
|- | |||
| 0x6009 | |||
| Get Token Seed | |||
|- | |||
| 0x600A | |||
| Set Token | |||
|- | |- | ||
| 0x600B | |||
| Read EPROM | |||
|- | |- | ||
| | | 0x600C | ||
| | | Write EPROM | ||
|- | |- | ||
| | | 0x6010 | ||
| | | Check Integrity | ||
|- | |- | ||
| | | 0x6011 | ||
| | | Get Applicable Version | ||
|} | |} | ||
== | *Update Manager service is accessed by GameOS '''syscall 863''' | ||
=== 0x6001 - Update Package Tophalf === | |||
*The result of the request can be checked by reading the value of repository node '''ss.update.request.<Request ID>''' periodically | |||
=== 0x6002 - Inspect Package Tophalf === | |||
*I have got access to this service through DM and tested it with PSGroove | |||
*This service can tell you if a package can be installed or not, the service just checks a package but does not install it | |||
*'''Packages can be updated without GameOS !!! I'm using only HV calls and communicate directly with Dispatcher Manager and Update Manager''' | |||
*I just sent a whole SCE package to GameOS through network, created a LPAR memory region and stored the file there | |||
*It expects a SCE package that can be easily extracted from '''PUP file''' | |||
*The data of SCE package can be passed either in SS packet itself or through LPAR memory of requester | |||
*When the data of SCE package is too large for SS packet (SS packets are sent through DM, GameOS and DM communicate through VUART that has only 0x800 bytes buffer) then the data of SCE package has to be passed through GameOS LPAR memory. The requester sends a vector of LPAR memory addresses where the data of SCE package is stored and Update Manager maps it into the address space of Process 6 | |||
*E.g. '''Revoke List''' packages can be sent in SS packets because they are small (about 0x200 bytes). All other packages are too big to sent them in SS packets | |||
*The service is actually split into 2 halfs: '''Top-Half''' and '''Bottom-Half''' | |||
*The '''Top-Half''' is executed synchronously with service request and it sends a reply to the requester | |||
*In the reply sent by '''Top-Half''' a '''Request ID''' (8 bytes) is returned to the requester | |||
*'''Request ID''' is calculated by using '''SHA-1''' | |||
*After the '''Top-Half''' is done, a reply is sent to the requester but the service just checked some input parameter upto now and the passed SCE package was not really checked yet | |||
*The '''Bottom-Half''' is called asynchronously to the request, it does the real job, it checks the passed SCE package. | |||
*The result of the request can be checked by reading the value of repository node '''ss.inspect.request.<Request ID>''' periodically | |||
*I successfully tested this service with '''RL_FOR_PROGRAM.img''' from '''3.50 PUP file''' and the service returned '''Success''', so theoretically i could install this package on my PS3. But of course i want to downgrade and NOT to upgrade. | |||
==== Inspect Package Tophalf Return Values ==== | |||
= | {| class="wikitable FCK__ShowTableBorders" | ||
|- | |||
! Error Code | |||
! Description | |||
|- | |||
| 0x00000000 | |||
| Success | |||
|- | |||
| 0x00000013 | |||
| Same Version/Older Version | |||
|- | |||
| 0x00000014 | |||
| - | |||
|} | |||
=== 0x6003 - Get Package Info === | |||
*I have got access to this service through DM and tested it with PSGroove | |||
*The service expects one additional parameter: package type (valid values are 1-9) | |||
*The service returns the version (8 bytes) of a package type installed | |||
Here | Here are the versions of packages installed on my PS3: | ||
{| class="wikitable FCK__ShowTableBorders" | {| class="wikitable FCK__ShowTableBorders" | ||
|- | |- | ||
! | ! Package Type | ||
! | ! Returned Version | ||
! | ! Description | ||
! | ! Package Name in PUP File | ||
|- | |||
| 1 | |||
| 0x0003004100000000 | |||
| Core OS Package | |||
| CORE_OS_PACKAGE.pkg | |||
|- | |- | ||
| 2 | | 2 | ||
| 0x0003004100000000 | |||
| Revoke List Package for Program | |||
| RL_FOR_PROGRAM.img | |||
|- | |||
| 3 | | 3 | ||
| | | 0x0002003000000000 | ||
| | | Revoke List Package for Package | ||
| | | RL_FOR_PACKAGE.img | ||
| | |- | ||
| 4 | |||
| 0xDEADBEAFFACEBABE | |||
| - | |||
| - | |||
|- | |||
| 5 | |||
| 0xDEADBEAFFACEBABE | |||
| - | |||
| - | |||
|- | |||
| 6 | |||
| 0x0003004000000000 | |||
| BD Firmware Package | |||
| BDIT_FIRMWARE_PACKAGE.pkg, BDPT_FIRMWARE_PACKAGE_*.pkg | |||
|- | |||
| 7 | |||
| Invalid Parameter | |||
| Bluetooth Firmware, dev_flash tarballs | |||
| BLUETOOTH_FIRMWARE.pkg, dev_flash, dev_flash3 | |||
|- | |- | ||
| | | 8 | ||
| | | Invalid Parameter | ||
| | | - | ||
| | | - | ||
|- | |- | ||
| | | 9 | ||
| | | Invalid Parameter | ||
| | | SC Firmware Package | ||
| | | SYS_CON_FIRMWARE_*.pkg | ||
|} | |} | ||
=== | ==== Decrypting and Extracting Packages with spu_pkg_rvk_verifier.self ==== | ||
*I have managed to decrypt and extract '''Revoke List Packages 3.41 and 3.50''' by using SPE HV calls and '''spu_pkg_rvk_verifier.self''' | |||
*Important: Parameters to SPU module shuold be aligned, i used cache line alignment, don't know exactly alignment requerements. Or else some very strange things could happen. E.g SYSCON firmware was only partially decrypted when i used no cache line alignment. | |||
*I have also managed to decrypt and extract '''Core OS Packages 1.10, 1.18 Debug, 2.40, 2.80, 3.15, 3.41 and 3.50''' by using SPE HV calls and '''spu_pkg_rvk_verifier.self''' but it's compressed with '''zlib'''.Update Manager in Process 6 from 3.15 uses '''zlib 1.2.3 inflate''' to decompress it after it was decrypted and then it stores the data to flash memory. | |||
*I decompressed the decrypted Core OS Packages with zlib. | |||
*I am able now to decrypt and decompress all Core OS Packages | |||
*'''The decrypted and decompressed package CORE_OS_PACKAGE.pkg looks exactly like it's stored on flash.''' | |||
*I also decrypted BD Firmwares '''BDIT_FIRMWARE_PACKAGE.pkg''' and '''BDPT_FIRMWARE_PACKAGE.pkg''' successfully. The firmware is not compressed. | |||
*I also decrypted Bluetooth Firmware '''BLUETOOTH_FIRMWARE.pkg''' successfully. The firmware is encrypted and compressed. | |||
*I also managed to decrypt System Controller Firmware '''SYS_CON_FIRMWARE_01050101.pkg''' from 3.41. | |||
*Core OS Package 3.50 contains a new isolated SPU module that is not contained in older versions. The SPU module is '''manu_info_spu_module.self'''. | |||
*Here links to PS3 Firmwares: [http://forums.penhacks.net/Thread-ALL-PS3-Firmware-to-date] and [http://www.ps3-hacks.com/category/3] | |||
===== RL_FOR_PROGRAM.img 3.41 ===== | |||
<pre>Offset 0 1 2 3 4 5 6 7 8 9 A B C D E F | |||
=== | 00000200 00 00 00 04 00 00 00 01 00 03 00 41 00 00 00 00 ...........A.... | ||
00000210 00 00 00 06 00 00 00 00 00 00 00 00 00 00 00 00 ................ | |||
00000220 00 00 00 03 00 00 00 01 00 03 00 41 00 00 00 00 ...........A.... | |||
00000230 00 00 00 00 00 00 00 02 FF FF FF FF FF FF FF FF ........ÿÿÿÿÿÿÿÿ | |||
00000240 00 00 00 04 00 00 00 01 00 03 00 41 00 00 00 00 ...........A.... | |||
00000250 10 70 00 05 FF 00 00 01 FF FF FF FF FF FF FF FF .p..ÿ...ÿÿÿÿÿÿÿÿ | |||
00000260 00 00 00 04 00 00 00 01 00 03 00 41 00 00 00 00 ...........A.... | |||
00000270 10 70 00 05 FE 00 00 01 FF FF FF FF FF FF FF FF .p..þ...ÿÿÿÿÿÿÿÿ | |||
00000280 00 00 00 04 00 00 00 01 00 03 00 41 00 00 00 00 ...........A.... | |||
00000290 10 70 00 05 FD 00 00 01 FF FF FF FF FF FF FF FF .p..ý...ÿÿÿÿÿÿÿÿ | |||
000002A0 00 00 00 04 00 00 00 01 00 03 00 41 00 00 00 00 ...........A.... | |||
000002B0 10 70 00 05 FC 00 00 01 FF FF FF FF FF FF FF FF .p..ü...ÿÿÿÿÿÿÿÿ | |||
000002C0 00 00 00 04 00 00 00 03 00 01 00 00 00 00 00 00 ................ | |||
000002D0 10 70 00 04 00 00 00 01 FF FF FF FF FF FF FF FF .p......ÿÿÿÿÿÿÿÿ | |||
</pre> | |||
===== RL_FOR_PROGRAM.img 3.50 ===== | |||
<pre>Offset 0 1 2 3 4 5 6 7 8 9 A B C D E F | |||
Here is | 00000200 00 00 00 04 00 00 00 01 00 03 00 50 00 00 00 00 ...........P.... | ||
<pre> | 00000210 00 00 00 06 00 00 00 00 00 00 00 00 00 00 00 00 ................ | ||
00000220 00 00 00 03 00 00 00 01 00 03 00 50 00 00 00 00 ...........P.... | |||
00000230 00 00 00 00 00 00 00 02 FF FF FF FF FF FF FF FF ........ÿÿÿÿÿÿÿÿ | |||
00000240 00 00 00 04 00 00 00 01 00 03 00 50 00 00 00 00 ...........P.... | |||
00000250 10 70 00 05 FF 00 00 01 FF FF FF FF FF FF FF FF .p..ÿ...ÿÿÿÿÿÿÿÿ | |||
00000260 00 00 00 04 00 00 00 01 00 03 00 50 00 00 00 00 ...........P.... | |||
00000270 10 70 00 05 FE 00 00 01 FF FF FF FF FF FF FF FF .p..þ...ÿÿÿÿÿÿÿÿ | |||
00000280 00 00 00 04 00 00 00 01 00 03 00 50 00 00 00 00 ...........P.... | |||
00000290 10 70 00 05 FD 00 00 01 FF FF FF FF FF FF FF FF .p..ý...ÿÿÿÿÿÿÿÿ | |||
000002A0 00 00 00 04 00 00 00 01 00 03 00 50 00 00 00 00 ...........P.... | |||
000002B0 10 70 00 05 FC 00 00 01 FF FF FF FF FF FF FF FF .p..ü...ÿÿÿÿÿÿÿÿ | |||
000002C0 00 00 00 04 00 00 00 03 00 01 00 00 00 00 00 00 ................ | |||
000002D0 10 70 00 04 00 00 00 01 FF FF FF FF FF FF FF FF .p......ÿÿÿÿÿÿÿÿ | |||
</pre> | |||
===== RL_FOR_PACKAGE.img 3.41 ===== | |||
<pre>Offset 0 1 2 3 4 5 6 7 8 9 A B C D E F | |||
00000200 00 00 00 03 00 00 00 02 00 01 00 00 00 00 00 00 ................ | |||
00000210 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 ................ | |||
00000220 00 00 00 01 00 00 00 00 00 00 00 01 00 00 00 02 ................ | |||
00000230 00 00 00 08 00 05 00 00 00 00 00 00 00 00 00 00 ................ | |||
</pre> | |||
===== RL_FOR_PACKAGE.img 3.50 ===== | |||
<pre>Offset 0 1 2 3 4 5 6 7 8 9 A B C D E F | |||
00000200 00 00 00 03 00 00 00 02 00 01 00 00 00 00 00 00 ................ | |||
00000210 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 ................ | |||
00000220 00 00 00 01 00 00 00 00 00 00 00 01 00 00 00 02 ................ | |||
00000230 00 00 00 08 00 05 00 00 00 00 00 00 00 00 00 00 ................ | |||
</pre> | |||
===== CORE_OS_PACKAGE.pkg 3.15 ===== | |||
Here is a piece of data from decrypted and decompressed package. | |||
<pre>Offset 0 1 2 3 4 5 6 7 8 9 A B C D E F | |||
00000000 00 00 00 01 00 00 00 17 00 00 00 00 00 6F FF E0 .............oÿà | |||
00000010 00 00 00 00 00 00 04 60 00 00 00 00 00 04 00 00 .......`........ | |||
00000020 63 72 65 73 65 72 76 65 64 5F 30 00 00 00 00 00 creserved_0..... | |||
00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ | |||
00000040 00 00 00 00 00 04 04 60 00 00 00 00 00 00 00 08 .......`........ | |||
00000050 73 64 6B 5F 76 65 72 73 69 6F 6E 00 00 00 00 00 sdk_version..... | |||
00000060 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ | |||
00000070 00 00 00 00 00 04 04 80 00 00 00 00 00 01 E5 CC .......€......åÌ | |||
00000080 6C 76 31 6C 64 72 00 00 00 00 00 00 00 00 00 00 lv1ldr.......... | |||
00000090 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ | |||
000000A0 00 00 00 00 00 05 EA 80 00 00 00 00 00 01 6D A0 ......ê€......m | |||
000000B0 6C 76 32 6C 64 72 00 00 00 00 00 00 00 00 00 00 lv2ldr.......... | |||
000000C0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ | |||
000000D0 00 00 00 00 00 07 58 80 00 00 00 00 00 01 2E 44 ......X€.......D | |||
000000E0 69 73 6F 6C 64 72 00 00 00 00 00 00 00 00 00 00 isoldr.......... | |||
000000F0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ | |||
00000100 00 00 00 00 00 08 87 00 00 00 00 00 00 01 DA E4 ......‡.......Úä | |||
00000110 61 70 70 6C 64 72 00 00 00 00 00 00 00 00 00 00 appldr.......... | |||
00000120 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ | |||
00000130 00 00 00 00 00 0A 61 E4 00 00 00 00 00 00 FA CC ......aä......úÌ | |||
00000140 73 70 75 5F 70 6B 67 5F 72 76 6B 5F 76 65 72 69 spu_pkg_rvk_veri | |||
00000150 66 69 65 72 2E 73 65 6C 66 00 00 00 00 00 00 00 fier.self....... | |||
00000160 00 00 00 00 00 0B 5C B0 00 00 00 00 00 00 5C 94 ......\°......\” | |||
00000170 73 70 75 5F 74 6F 6B 65 6E 5F 70 72 6F 63 65 73 spu_token_proces | |||
00000180 73 6F 72 2E 73 65 6C 66 00 00 00 00 00 00 00 00 sor.self........ | |||
00000190 00 00 00 00 00 0B B9 44 00 00 00 00 00 00 65 D0 ......¹D......eÐ | |||
000001A0 73 70 75 5F 75 74 6F 6B 65 6E 5F 70 72 6F 63 65 spu_utoken_proce | |||
000001B0 73 73 6F 72 2E 73 65 6C 66 00 00 00 00 00 00 00 ssor.self....... | |||
000001C0 00 00 00 00 00 0C 1F 14 00 00 00 00 00 01 53 2C ..............S, | |||
000001D0 73 63 5F 69 73 6F 2E 73 65 6C 66 00 00 00 00 00 sc_iso.self..... | |||
000001E0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ | |||
000001F0 00 00 00 00 00 0D 72 40 00 00 00 00 00 00 44 98 [email protected]˜ | |||
00000200 61 69 6D 5F 73 70 75 5F 6D 6F 64 75 6C 65 2E 73 aim_spu_module.s | |||
00000210 65 6C 66 00 00 00 00 00 00 00 00 00 00 00 00 00 elf............. | |||
00000220 00 00 00 00 00 0D B6 D8 00 00 00 00 00 00 D7 F0 ......¶Ø......×ð | |||
00000230 73 70 70 5F 76 65 72 69 66 69 65 72 2E 73 65 6C spp_verifier.sel | |||
00000240 66 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 f............... | |||
00000250 00 00 00 00 00 0E 8E C8 00 00 00 00 00 00 80 8C ......ŽÈ......€Œ | |||
00000260 6D 63 5F 69 73 6F 5F 73 70 75 5F 6D 6F 64 75 6C mc_iso_spu_modul | |||
00000270 65 2E 73 65 6C 66 00 00 00 00 00 00 00 00 00 00 e.self.......... | |||
00000280 00 00 00 00 00 0F 0F 54 00 00 00 00 00 00 88 B8 .......T......ˆ¸ | |||
00000290 6D 65 5F 69 73 6F 5F 73 70 75 5F 6D 6F 64 75 6C me_iso_spu_modul | |||
000002A0 65 2E 73 65 6C 66 00 00 00 00 00 00 00 00 00 00 e.self.......... | |||
000002B0 00 00 00 00 00 0F 98 0C 00 00 00 00 00 00 C0 78 ......˜.......Àx | |||
000002C0 73 76 5F 69 73 6F 5F 73 70 75 5F 6D 6F 64 75 6C sv_iso_spu_modul | |||
000002D0 65 2E 73 65 6C 66 00 00 00 00 00 00 00 00 00 00 e.self.......... | |||
000002E0 00 00 00 00 00 10 58 84 00 00 00 00 00 00 5D B0 ......X„......]° | |||
000002F0 73 62 5F 69 73 6F 5F 73 70 75 5F 6D 6F 64 75 6C sb_iso_spu_modul | |||
00000300 65 2E 73 65 6C 66 00 00 00 00 00 00 00 00 00 00 e.self.......... | |||
00000310 00 00 00 00 00 10 B6 34 00 00 00 00 00 00 22 A0 ......¶4......" | |||
00000320 64 65 66 61 75 6C 74 2E 73 70 70 00 00 00 00 00 default.spp..... | |||
00000330 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ | |||
00000340 00 00 00 00 00 10 D9 00 00 00 00 00 00 12 B1 70 ......Ù.......±p | |||
00000350 6C 76 31 2E 73 65 6C 66 00 00 00 00 00 00 00 00 lv1.self........ | |||
00000360 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ | |||
00000370 00 00 00 00 00 23 8A 80 00 00 00 00 00 03 E8 28 .....#Š€......è( | |||
00000380 6C 76 30 00 00 00 00 00 00 00 00 00 00 00 00 00 lv0............. | |||
00000390 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ | |||
000003A0 00 00 00 00 00 27 72 A8 00 00 00 00 00 16 EE B8 .....'r¨......î¸ | |||
000003B0 6C 76 32 5F 6B 65 72 6E 65 6C 2E 73 65 6C 66 00 lv2_kernel.self. | |||
000003C0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ | |||
000003D0 00 00 00 00 00 3E 61 60 00 00 00 00 00 07 0F 94 .....>a`.......” | |||
000003E0 65 75 72 75 73 5F 66 77 2E 62 69 6E 00 00 00 00 eurus_fw.bin.... | |||
000003F0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ | |||
00000400 00 00 00 00 00 45 70 F4 00 00 00 00 00 07 FC 48 .....Epô......üH | |||
00000410 65 6D 65 72 5F 69 6E 69 74 2E 73 65 6C 66 00 00 emer_init.self.. | |||
00000420 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ | |||
00000430 00 00 00 00 00 4D 6D 3C 00 00 00 00 00 06 16 00 .....Mm<........ | |||
00000440 68 64 64 5F 63 6F 70 79 2E 73 65 6C 66 00 00 00 hdd_copy.self... | |||
00000450 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ | |||
00040460 33 31 35 2E 30 30 30 0A 00 00 00 00 00 00 00 00 315.000......... | |||
00040470 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ | |||
</pre> | |||
===== BDIT_FIRMWARE_PACKAGE.pkg 3.50 ===== | |||
Here is a piece of data from decrypted package. | |||
<pre>Offset 0 1 2 3 4 5 6 7 8 9 A B C D E F | |||
00000300 43 6F 70 79 72 69 67 68 74 28 43 29 20 32 30 30 Copyright(C) 200 | |||
00000310 35 2D 32 30 30 36 2C 20 53 6F 6E 79 20 43 6F 6D 5-2006, Sony Com | |||
00000320 70 75 74 65 72 20 45 6E 74 65 72 74 61 69 6E 6D puter Entertainm | |||
00000330 65 6E 74 20 49 6E 63 2E 1A 00 00 00 00 00 00 00 ent Inc......... | |||
00000340 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ | |||
00000350 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ | |||
00000360 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ | |||
00000370 41 96 18 D3 2D 8F 0F 68 11 4D A7 09 E4 1F A7 6F A–.Ó-.h.M§.ä.§o | |||
00000380 EF 29 48 A0 E9 F2 A8 F0 CC 4B F3 4D E0 4A B0 17 ï)H éò¨ðÌKóMàJ°. | |||
00000390 C2 DA 07 5F 96 B3 C8 8D E1 06 2E 3A 1D A7 FD 20 ÂÚ._–³Èá..:.§ý | |||
</pre> | |||
===== BDPT_FIRMWARE_PACKAGE_301R.pkg 3.50 ===== | |||
Here is a piece of data from decrypted package. | |||
<pre>Offset 0 1 2 3 4 5 6 7 8 9 A B C D E F | |||
00000300 43 6F 70 79 72 69 67 68 74 28 43 29 20 32 30 30 Copyright(C) 200 | |||
00000310 35 2D 32 30 30 39 2C 20 53 6F 6E 79 20 43 6F 6D 5-2009, Sony Com | |||
00000320 70 75 74 65 72 20 45 6E 74 65 72 74 61 69 6E 6D puter Entertainm | |||
00000330 65 6E 74 20 49 6E 63 2E 1A 00 00 00 00 00 00 00 ent Inc......... | |||
00000340 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ | |||
00000350 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ | |||
00000360 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ | |||
00000370 80 18 D2 E4 22 AA 2B D7 85 47 F4 40 53 9A 04 0C €.Òä"ª+×…Gô@Sš.. | |||
00000380 D0 B8 A5 04 20 51 9E 90 09 4F 2E 78 BA 32 C0 EA и¥. Qž.O.xº2Àê | |||
00000390 E9 61 96 ED D8 2A 70 C0 59 68 4E B2 47 25 9C 97 éa–íØ*pÀYhN²G%œ— | |||
</pre> | |||
===== BLUETOOTH_FIRMWARE.pkg 3.41 ===== | |||
<pre>Offset 0 1 2 3 4 5 6 7 8 9 A B C D E F | |||
00000000 52 43 32 39 5F 66 69 72 6D 77 61 72 65 5F 66 6F RC29_firmware_fo | |||
00000010 6F 74 65 72 2E 64 66 75 00 00 00 00 00 00 00 00 oter.dfu........ | |||
00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ | |||
00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ | |||
00000040 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ | |||
00000050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ | |||
00000060 00 00 00 00 30 30 30 30 36 34 34 00 30 30 30 30 ....0000644.0000 | |||
00000070 30 30 30 00 30 30 30 30 30 30 30 00 30 30 30 30 000.0000000.0000 | |||
00000080 31 35 36 36 33 30 30 00 31 31 30 36 34 33 34 36 1566300.11064346 | |||
00000090 33 30 36 00 30 31 35 34 36 33 00 20 30 00 00 00 306.015463. 0... | |||
000000A0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ | |||
000000B0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ | |||
000000C0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ | |||
000000D0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ | |||
000000E0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ | |||
000000F0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ | |||
00000100 00 75 73 74 61 72 20 20 00 72 6F 6F 74 00 00 00 .ustar .root... | |||
00000110 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ | |||
00000120 00 00 00 00 00 00 00 00 00 72 6F 6F 74 00 00 00 .........root... | |||
00000130 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ | |||
00000140 00 00 00 00 00 00 00 00 00 30 30 30 30 30 30 30 .........0000000 | |||
00000150 00 30 30 30 30 30 30 30 00 00 00 00 00 00 00 00 .0000000........ | |||
000A5950 84 1B 00 C0 94 04 00 00 74 06 00 00 45 75 72 75 „..À”...t...Euru | |||
000A5960 73 5F 50 72 69 6D 61 72 79 5F 50 68 79 00 00 00 s_Primary_Phy... | |||
000A5970 4D 61 72 76 65 6C 6C 5F 41 50 00 00 94 BB 01 C0 Marvell_AP..”».À | |||
000B7CC0 00 00 00 00 01 10 60 23 4D 61 72 76 65 6C 6C 20 ......`#Marvell | |||
000B7CD0 46 69 72 6D 77 61 72 65 20 53 44 4B 20 56 65 72 Firmware SDK Ver | |||
000B7CE0 73 69 6F 6E 20 32 2E 33 2E 30 54 74 5D 04 02 2B sion 2.3.0Tt]..+ | |||
000B7CF0 0F 14 E1 36 04 32 0A 1A FD 08 32 1A 1A C1 08 02 ..á6.2..ý.2..Á.. | |||
000F42B0 44 6F 53 68 61 72 65 64 4B 65 79 53 65 71 31 3A DoSharedKeySeq1: | |||
000F42C0 20 45 6E 74 65 72 65 64 20 2D 2D 2D 20 72 73 70 Entered --- rsp | |||
000F42D0 4D 61 63 20 3D 20 25 30 32 78 3A 25 30 32 78 3A Mac = %02x:%02x: | |||
000F42E0 25 30 32 78 3A 25 30 32 78 3A 25 30 32 78 3A 25 %02x:%02x:%02x:% | |||
000F42F0 30 32 78 0A 00 00 00 00 6D 6C 6D 65 41 75 74 68 02x.....mlmeAuth | |||
000F4300 44 6F 53 68 61 72 65 64 4B 65 79 53 65 71 31 3A DoSharedKeySeq1: | |||
000F4310 20 56 61 6C 69 64 61 74 69 6F 6E 20 66 61 69 6C Validation fail | |||
000F4320 65 64 20 2D 2D 2D 20 72 73 70 4D 61 63 20 3D 20 ed --- rspMac = | |||
000F4330 25 30 32 78 3A 25 30 32 78 3A 25 30 32 78 0A 00 %02x:%02x:%02x.. | |||
000F4340 6D 6C 6D 65 41 75 74 68 44 6F 53 68 61 72 65 64 mlmeAuthDoShared | |||
000F4350 4B 65 79 53 65 71 33 3A 20 76 61 6C 69 64 61 74 KeySeq3: validat | |||
000F4360 69 6F 6E 20 66 61 69 6C 65 64 21 20 2D 2D 2D 20 ion failed! --- | |||
000F4370 72 73 70 4D 61 63 20 3D 20 25 30 32 78 3A 25 30 rspMac = %02x:%0 | |||
000F4380 32 78 3A 25 30 32 78 0A 00 65 65 70 72 6F 6D 00 2x:%02x..eeprom. | |||
000F4390 62 74 5F 68 63 69 00 62 74 5F 75 61 72 74 00 75 bt_hci.bt_uart.u | |||
000F43A0 73 62 30 00 75 73 62 31 00 4F 53 41 00 77 6C 61 sb0.usb1.OSA.wla | |||
000F43B0 F3 B8 E9 70 01 00 00 00 1C 6B 03 00 00 02 00 00 ó¸ép.....k...... | |||
</pre> | </pre> | ||
== | ===== SYS_CON_FIRMWARE_01050101.pkg 3.41 ===== | ||
<pre>Offset 0 1 2 3 4 5 6 7 8 9 A B C D E F | |||
00000300 1B 2D 70 0F AB 5E B3 99 68 20 FE 3D E1 80 6A 1D .-p.«^³™h þ=á€j. | |||
00000310 B8 FD 37 CF CD 45 85 AB 51 F7 05 E3 EA 32 A5 EA ¸ý7ÏÍE…«Q÷.ãê2¥ê | |||
00000320 67 45 F9 48 00 00 00 00 00 10 00 00 C0 0F 00 00 gEùH........À... | |||
00000330 8B 04 07 F9 9B A2 90 3A 75 89 F1 42 12 59 DA 0D ‹..ù›¢:u‰ñB.YÚ. | |||
00000340 21 7C A2 C3 5A E4 78 00 10 8D 4B F7 A2 73 9C 63 !|¢ÃZäx..K÷¢sœc | |||
00000350 5D 8D 5D 49 16 C7 6F 2C AD 33 FE 1F D3 6C A1 CA ]]I.Ço,3þ.Ól¡Ê | |||
00000360 BA AD 2B FE 8F 33 71 D7 C5 E6 5C FF BF 77 6C 80 º+þ3q×Åæ\ÿ¿wl€ | |||
00000370 F2 BE 11 BB 3C 52 52 DC A9 68 E5 24 AD 4F F3 48 ò¾.»<RRÜ©hå$OóH | |||
</pre> | |||
=== 0x6005 - Extract Package Tophalf === | |||
*The result of the request can be checked by reading the value of repository node '''ss.extract.request.<Request ID>''' periodically | |||
=== 0x600B - Read EEPROM === | |||
= | *I have got read access to EEPROM of Update Manager through DM and tested it with PSGroove | ||
*I read PRODUCT_MODE from it successfully, PRODUCT_MODE = 0x000000FF | |||
*The service expects one additional parameter: offset (4 bytes) | |||
*The service accepts only some predefined offsets | |||
*The service returns the specified offset and the value at this offset | |||
=== | ==== EEPROM Offset Table ==== | ||
Here is the | Here is the table of EEPROM offsets that can be accessed through Update Manager (3.15): | ||
{| class="wikitable FCK__ShowTableBorders" | {| class="wikitable FCK__ShowTableBorders" | ||
|- | |- | ||
! | ! Offset | ||
! Size | ! Size | ||
! | ! Description | ||
|- | |||
| 0x48C06 | |||
| 1 | |||
| FSELF Control Flag | |||
|- | |||
| 0x48C07 | |||
| 1 | |||
| Product Mode (UM allows to read this offset, it can be also written but only when already in product mode) | |||
|- | |||
| 0x48C0A | |||
| 1 | |||
| QA Flag | |||
|- | |||
| 0x48C13 | |||
| 1 | |||
| Device Type | |||
|- | |- | ||
| | | 0x48C30 | ||
| 1 | | 1 | ||
| | | SPE number Usally 0x06, can be set to 0x07 to enable the 8 SPE | ||
|- | |- | ||
| | | 0x48C42 | ||
| | | 1 | ||
| | | HDD Copy Mode | ||
|- | |- | ||
| | | 0x48C50 | ||
| | | 0x10 | ||
| | | Debug Support Flag | ||
|- | |- | ||
| | | 0x48C60 | ||
| | | 1 | ||
| | | Update Status | ||
|- | |- | ||
| | | 0x48C61 | ||
| | | 1 | ||
| | | Recover Mode Flag | ||
|- | |- | ||
| | | 0x48D3E | ||
| | | 0x50 | ||
| | | QA Token (UM doesn't allow access to this offset but SC Manager can read/write it) | ||
|} | |} | ||
== | === 0x600C - Write EEPROM === | ||
*Writting to EEPROM of Update Manager is also possible through DM | |||
*Tested this service successfully with QA flag | |||
=== 0x6010 - Check Integrity === | |||
*This service checks integrity of important files stored on '''/dev/rflash1''', e.g. '''lv0''' or '''lv1''' | |||
*The service is used e.g. by System Manager | |||
*When '''product mode''' is NOT '''0xFF''' then check is skipped !!! | |||
=== 0x6011 - Get Applicable Version === | |||
*I have got access to this service through DM and PSGroove and tested it | |||
*The service expects one additional unknown parameter of size 4 bytes, it has to be 0x00000001 or else the service fails | |||
Here is the return value: | |||
<pre>00 00 00 01 00 00 00 00 00 03 00 20 00 00 00 00 00 00 00 00 00 00 00 01 | |||
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 | |||
</pre> | |||
=== BD Firmware Update === | |||
*Update Manager in HV Process 6 updates BD firmware through '''ATAPI Interface''' of '''/dev/rbd0''' device. | |||
*BD firmware is sent to BD drive by using '''ATAPI Write Buffer (0x3B)''' command with '''Mode 0x07 (Download microcode with offsets and save)''' and '''Buffer ID 0x00'''. | |||
*The current BD drive firmware version and hash is also stored by and retrieved from SYSCON by using '''SC Manager Get/Set Region Data (0x9006/0x9007)''' service. After successfull BD firmware update, Update Manager sends the new firmware version and hash to SYSCON. | |||
*BD firmware package is decrypted, SCE header size + 0x80 bytes are skipped and data beginning with copyright message is sent to BD drive. | |||
*BD firmware is sent packet wise, one packet is at most 0x8000 bytes. | |||
*After each sent packet, Update Manager checks the result by using '''ATAPI Request Sense (0x3)''' command. | |||
*Theoretically, BD firmware update can be done also from GameOS by using ATAPI interface of the BD drive. | |||
=== | ==== Detecting BD Drive Type, Generation and Revision ==== | ||
*To detect BD drive type, Update Manager uses '''ATAPI Inquiry''' command. | |||
*To detect BD drive generation, Update Manager uses '''ATAPI Mode Sense 10''' command. | |||
=== | ===== BD Drive Type Table ===== | ||
Here is the | Here is the BD Drive Type Table extracted from HV Process 6 (3.15): | ||
{| class="wikitable FCK__ShowTableBorders" | {| class="wikitable FCK__ShowTableBorders" | ||
|- | |- | ||
! | ! Index | ||
! | ! Vendor Identification String | ||
! | ! Drive Type | ||
|- | |||
| 0 | |||
| <pre>"SONY EmerFlashROM"</pre> | |||
| 0x2100000000000001 | |||
|- | |- | ||
| 1 | | 1 | ||
| | | <pre>"SONY PS-EMBOOT 300R"</pre> | ||
| 0x2100000000000001 | |||
| | |||
|- | |- | ||
| 2 | | 2 | ||
| | | <pre>"SONY BDRW AQUAM(BDIT)"</pre> | ||
| | | 0x1100000000000001 | ||
|- | |- | ||
| 3 | | 3 | ||
| | | <pre>"SONY PS-SYSTEM 300R"</pre> | ||
| 0x1100000000000001 | |||
| | |||
|- | |- | ||
| 4 | | 4 | ||
| | | <pre>"SONY PS-SYSTEM V300"</pre> | ||
| 0x1100000000000001 | |||
| | |||
|- | |- | ||
| 5 | | 5 | ||
| | | <pre>"SCEI EMER-FLASH-8"</pre> | ||
| | | 0x2200000000000002 | ||
| - | |- | ||
| | | 6 | ||
| | | <pre>"SONY PS-EMBOOT 301R"</pre> | ||
| 0x2200000000000002 | |||
|- | |||
| 7 | |||
| <pre>"SONY PS-SYSTEM 301R"</pre> | |||
| 0x1200000000000002 | |||
|- | |||
| 8 | |||
| <pre>"SONY PS-EMBOOT 302R"</pre> | |||
| 0x2200000000000003 | |||
|- | |||
| 9 | |||
| <pre>"SONY PS-SYSTEM 302R"</pre> | |||
| 0x1200000000000003 | |||
|- | |||
| 10 | |||
| <pre>"SONY PS-EMBOOT 303R"</pre> | |||
| 0x2200000000000004 | |||
|- | |||
| 11 | |||
| <pre>"SONY PS-SYSTEM 303R"</pre> | |||
| 0x1200000000000004 | |||
|- | |||
| 12 | |||
| <pre>"SONY PS-EMBOOT 304R"</pre> | |||
| 0x2200000000000005 | |||
|- | |||
| 13 | |||
| <pre>"SONY PS-SYSTEM 304R"</pre> | |||
| 0x1200000000000005 | |||
|- | |||
| 14 | |||
| <pre>"SONY PS-EMBOOT 306R"</pre> | |||
| 0x2200000000000007 | |||
|- | |- | ||
| | | 15 | ||
| <pre>"SONY PS-SYSTEM 306R"</pre> | |||
| 0x1200000000000007 | |||
| - | |||
| | |||
|} | |} | ||
== | ==== Methods (HV Process 6) ==== | ||
update_manager_update_bd_firmware - 0x800064BC (3.15) | |||
bd_updater_prepare_drive - 0x80011A88 (3.15) | |||
bd_updater_send_firmware - 0x80011544 (3.15) | |||
bd_updater_disable_reqsense - 0x80010410 (3.15) | |||
bd_updater_enable_reqsense - 0x800104D8 (3.15) | |||
send_atp_command - 0x80023B10 (3.15) | |||
== | == 0x9000 - SC Manager == | ||
*SC Manager cannot be accessed directly by using DM unfortunately (DM discards all requests) but it's used by other services that are accessable through DM | |||
*E.g. Update Manager services "Read EEPROM" and "Write EEPROM" send requests to SC Manager services "Read EEPROM" and "Write EEPROM" | |||
*SC Manager runs '''sc_iso.self''' | |||
* With full HV rights you could patch Dispatcher Manager and enable access to SC Manager from GameOS. | |||
{| class="wikitable FCK__ShowTableBorders" | {| class="wikitable FCK__ShowTableBorders" | ||
|- | |- | ||
! | ! Packet ID | ||
! | ! Description | ||
|- | |||
| 0x9001 | |||
| Get SRH | |||
|- | |- | ||
| | | 0x9002 | ||
| | | Set SRH | ||
|- | |- | ||
| | | 0x9003 | ||
| | | Encrypt | ||
| | |- | ||
| | | 0x9004 | ||
| | | Decrypt | ||
| | |- | ||
| | | 0x9005 | ||
| | | Init For VTRM | ||
|- | |||
| 0x9006 | |||
| Get Region Data | |||
|- | |||
| 0x9007 | |||
| Set Region Data | |||
|- | |||
| 0x9008 | |||
| Set RTC | |||
|- | |||
| 0x9009 | |||
| Get Time | |||
|- | |||
| 0x900A | |||
| Set Time | |||
|- | |||
| 0x900B | |||
| Read EPROM | |||
|- | |||
| 0x900C | |||
| Write EPROM | |||
|- | |||
| 0x900D | |||
| Init For Updater | |||
|- | |||
| 0x900E | |||
| Get SC Status | |||
|- | |||
| 0x9011 | |||
| SC Binary Patch | |||
|- | |||
| 0x9012 | |||
| SC RTC Factory | |||
|- | |||
| 0x9013 | |||
| Correct RTC Factory | |||
|- | |||
| 0x9014 | |||
| Set SC Status | |||
|- | |- | ||
| | | 0x9015 | ||
| | | Backup Root Info | ||
|- | |- | ||
| | | 0x9016 | ||
| | | Restore Root Info | ||
|} | |} | ||
== | === 0x9001 - SC Get SRH === | ||
<pre> | |||
struct ss_sc_mgr_get_srh | |||
{ | |||
u8 field0[20]; | |||
u8 res1[4]; | |||
u8 field18[20]; | |||
u8 res2[4]; | |||
}; | |||
</pre> | |||
=== 0x9003 - SC Encrypt === | |||
*There are 5 different types/kinds of encryption: 1 - 5. | |||
<pre> | |||
struct ss_sc_mgr_encrypt | |||
{ | |||
u32 type; /* 1 - 5 */ | |||
u8 res[4]; | |||
u8 field8[16]; | |||
u8 field18[16]; | |||
u64 field28; | |||
}; | |||
</pre> | |||
=== | === 0x9004 - SC Decrypt === | ||
*There are 5 different types/kinds of decryption: 1 - 5. | |||
*'''Virtual TRM Decrypt Master (0x200E)''' service uses e.g. decryption type 4. | |||
=== | === 0x9006 - SC Get Region Data === | ||
*This service expects an ID. The valid range of ID is 0 - 15. | |||
*E.g. Update Manager uses this service to retrieve hash and version of some SELFs and firmwares, e.g. '''lv0''' and '''lv1'''. | |||
{| class="wikitable FCK__ShowTableBorders" | <pre> | ||
|- | struct ss_sc_mgr_get_region_data | ||
! | { | ||
! | u64 id; | ||
u64 data_size; /* max 0x30 bytes */ | |||
u8 data[0]; | |||
}; | |||
</pre> | |||
==== Update Package Type - ID Mapping Table ==== | |||
{| class="wikitable FCK__ShowTableBorders" | |||
|- | |||
! Update Package Type | |||
! ID | |||
|- | |||
| 1 | |||
| 0 | |||
|- | |- | ||
| | | 2 | ||
| 2 | | 2 | ||
|- | |- | ||
| | | 3 | ||
| | | 4 | ||
|- | |- | ||
| | | 4 | ||
| | | 6 | ||
|- | |- | ||
| | | 5 | ||
| | | 7 | ||
|- | |- | ||
| | | 6 | ||
| | | 8 | ||
|} | |} | ||
== | === 0x9007 - SC Set Region Data === | ||
This | *This service expects an ID. The valid range of ID is 0 - 15. | ||
''' | *E.g. Update Manager uses this service to store hash and version of some SELFs and firmwares, e.g. '''lv0''' and '''lv1'''. | ||
* | <pre> | ||
struct ss_sc_mgr_set_region_data | |||
{ | |||
u64 id; | |||
u64 data_size; /* max 0x30 bytes */ | |||
u8 data[0]; | |||
}; | |||
</pre> | |||
=== | === 0x900B - SC Read EPROM === | ||
* There are 2 ways to access SC EPROM: '''NVS Service''' and '''Device Access Service'''. | |||
* '''NVS Service''' uses '''Block ID''' and '''Block Offset'''. | |||
* Not all EPROM offsets can be accessed through SC Manager. | |||
<pre> | |||
struct ss_sc_mgr_read_eprom | |||
{ | |||
u32 offset; | |||
u8 res1[4]; | |||
u32 nread; /* max 0x100 bytes */ | |||
u8 res2[4]; | |||
u64 buf_size; | |||
u8 buf[0]; | |||
/* here follows buf */ | |||
}; | |||
</pre> | |||
==== EPROM Offset - Block ID and Block Offset Mapping Table (NVS Service) ==== | |||
= | {| class="wikitable FCK__ShowTableBorders" | ||
|- | |||
! EPROM Offset | |||
! Block ID | |||
! Block Offset | |||
|- | |||
| 0x48000 - 0x480FF | |||
| 0x00 | |||
| 0x48000 - 0x480FF | |||
|- | |||
| 0x48800 - 0x488FF | |||
| 0x01 | |||
| 0x48800 - 0x488FF | |||
|- | |||
| 0x48C00 - 0x48CFF | |||
| 0x02 | |||
| 0x48C00 - 0x48CFF | |||
|- | |||
| 0x48D00 - 0x48DFF | |||
| 0x03 | |||
| 0x48D00 - 0x48DFF | |||
|- | |||
| 0x2F00 - 0x2FFF | |||
| 0x10 | |||
| 0x2F00 - 0x2FFF | |||
|- | |||
| 0x3000 - 0x30FF | |||
| 0x20 | |||
| 0x3000 - 0x30FF | |||
|- | |||
| All other offsets | |||
| Invalid | |||
| Invalid | |||
|} | |||
=== 0x900C - SC Write EPROM === | |||
<pre> | |||
struct ss_sc_mgr_write_eprom | |||
{ | |||
u32 offset; | |||
u8 res1[4]; | |||
* | u32 nwrite; | ||
* | u8 res2[4]; | ||
u64 buf_size; | |||
u8 buf[0]; | |||
/* here follows buf */ | |||
}; | |||
</pre> | |||
== | === 0x900E - SC Get Status === | ||
Here is what the service returned on my fat PS3: | |||
<pre> | |||
0x00 0x00 0x00 0x03 0x00 0x00 0x00 0x00 0xC0 0x00 0x00 0xFF 0x00 0x00 0x00 0x00 | |||
</pre> | |||
So, '''version''' is '''0x00000003''' and '''mode''' is '''0xC00000FF'''. | |||
<pre> | |||
struct ss_sc_mgr_get_sc_status | |||
{ | |||
u32 version; | |||
u8 res1[4]; | |||
u32 mode; | |||
u8 res2[4]; | |||
}; | |||
</pre> | |||
=== 0x9011 - SC Binary Patch === | |||
*This service is used by Update Manager to send a new SC firmware version to SYSCON. | |||
== | ==== SC Isolation DMA Buffer Header ==== | ||
<pre>struct sc_iso_header | |||
{ | |||
u32 seqno; | |||
u32 mbmsg; | |||
u32 cmd; | |||
u32 cmd_size; | |||
u8 cmd_data[0]; | |||
}; | |||
</pre> | |||
== 0x11000 - SPM (Security Policy Manager) == | |||
*Packet ID is mapped to '''SS id''' | |||
*SS id value range is 0x0 - 0x84 | |||
{| class="wikitable FCK__ShowTableBorders" | |||
|- | |||
! Packet ID | |||
! Description | |||
|- | |||
| 0x11001 | |||
| Request | |||
|- | |||
| 0x11002 | |||
| Load Additional Policy | |||
|} | |||
== | == 0x14000 - SLL (Secure LPAR Loader) == | ||
*SLL opens '''lv2_kernel.self''', parses ELF header and determines the size of initial memory region for GameOS LPAR | |||
*SLL creates a memory region for GameOS LPAR by using '''syscall 0x10000'''. | |||
*SLL opens '''/proc/partitions/<LPAR id>/mem''' file and maps it with mmap syscall into it's address space. | |||
*Then it authenticates, decrypts and copies the SELF file of GameOS to LPAR's memory region by using '''SPE syscalls 0x10040 and 0x10042'''. | |||
*Linux is not loaded by SLL, it's loaded in Process 9 by Linux System Manager | |||
*GameOS file image '''lv2_kernel.self''' is stored on '''/dev/rflash1''' | |||
{| class="wikitable FCK__ShowTableBorders" | |||
|- | |||
! Packet ID | |||
! Description | |||
|- | |||
| 0x14004 | |||
| Load GOS | |||
|- | |||
| 0x14005 | |||
| Unload GOS | |||
|} | |||
== | == 0x15000 - SPL (Secure Profile Loader) == | ||
* | *DEFAULT.SPP file is stored on '''/dev/rflash1''' | ||
= | {| class="wikitable FCK__ShowTableBorders" | ||
|- | |||
! Packet ID | |||
! Description | |||
|- | |||
| 0x15001 | |||
| Get LPAR Parameter Size/Get LPAR Parameter | |||
|- | |||
| 0x15003 | |||
| Get Contents Size/Get Contents | |||
|- | |||
| 0x15009 | |||
| Get Component | |||
|} | |||
=== SPP File === | |||
* | *The file is encrypted but can be read by using 0x15003 service of SPL | ||
*1 | *SPL reads SPP file, parses SPP header and checks some fields | ||
* | *SPP file is verified and decrypted by SPU module '''spp_verifier.self''' that cab be executed with HV SPE calls | ||
*Even old default.spp from PS3 Firmware 1.10 can be decrypted with spp_verifier.self from PS3 Firmware 3.41 | |||
*Header format version should be '''5''' or else the header check fails | |||
*If (SPP header size % 256 != 0) then header check fails | |||
*'''Finally i was able to decrypt profile file from 3.41 but by using SPE HV calls only !!! And Linux Manager is still there !!!''' | |||
*The decrypted file is a binary file | |||
Here are the contents of [[:DEFAULT.SPP]] from 3.41. | |||
Here are the contents of [[:DEFAULT.SPP 1.18 Debug]] from 1.18 Debug Firmware. | |||
==== SPP Header ==== | |||
offset 0x2 - header format version (2 bytes) | |||
offset 0x4 - header size (4 bytes) | |||
offset 0x18 - number of segments (4 bytes) | |||
= | ==== Segments ==== | ||
* | *Segments follow after the header | ||
*SPP file contains several segments. | |||
* | |||
Here is the list of profile segments from 3.41: | |||
{| class="wikitable FCK__ShowTableBorders" | |||
|- | |||
! Name | |||
! auth id/authority id | |||
|- | |||
|*SCE_CELLOS_PME | |||
|0x1070000001000001 | |||
|- | |||
|*PS3_LPAR | |||
|0x1070000002000001 | |||
|- | |||
|*PS2_LPAR | |||
|0x1020000003000001 | |||
|- | |||
|*PS2_GX_LPAR | |||
|0x1020000003000001 | |||
|- | |||
|*PS2_SW_LPAR | |||
|0x1020000003000001 | |||
|- | |||
|*LINUX_LPAR | |||
|0x1080000004000001 | |||
|- | |||
|*SCE_CELLOS_SYSTEM_MGR | |||
|0x107000001D000001 | |||
|- | |||
|*SCE_CELLOS_SYSTEM_MGR_LINUX | |||
|0x107000001D000001 | |||
|- | |||
|*SCE_CELLOS_SYSTEM_MGR_PS2 | |||
|0x107000001D000001 | |||
|- | |||
|*SCE_CELLOS_SYSTEM_MGR_PS2_SW | |||
|0x107000001D000001 | |||
|- | |||
|*SCE_CELLOS_SYSTEM_MGR_PS2_GX | |||
|0x107000001D000001 | |||
|- | |||
|*SCE_CELLOS_SS_SECURE_RTC | |||
|0x1070000033000001 | |||
|- | |||
|*SCE_CELLOS_SS_INDI_INFO_EID | |||
| | |||
|- | |||
|*SCE_CELLOS_SS_INIT_LV1_ACL | |||
|0x1070000017000001 | |||
|} | |||
== 0x15003 - Get Contents Size/Get Contents == | |||
*This service provides the contents of a segment specified by a service requester | |||
*I have got access to this service through DM but couldn't get through access policy yet, the service returns error code 0x00000005 that means '''Access Violation''' | |||
*But i still could test with this service which segment names are valid | |||
*I need valid '''laid''' and '''paid''' to get through it | |||
== 0x17000 - Indi Info Manager == | |||
{| class="wikitable FCK__ShowTableBorders" | |||
|- | |||
! Packet ID | |||
! Description | |||
|- | |||
| 0x17001 | |||
| Read EID Data Size By Index/Read metldr Size | |||
|- | |||
| 0x17002 | |||
| Read EID Data By Index/Read metldr | |||
|- | |||
| 0x17004 | |||
| Read System Data | |||
|- | |||
| 0x17007 | |||
| Read System Data From EEPROM | |||
|- | |||
| 0x17013 | |||
| Read eEID Size | |||
|- | |||
| 0x17014 | |||
| Write eEID/Write metldr | |||
|- | |||
| 0x17015 | |||
| Read cISD Size | |||
|- | |||
| 0x17016 | |||
| Read cISD | |||
|- | |||
| 0x17017 | |||
| Write cISD | |||
|} | |||
*Indi Info Manager is accessed e.g. in '''syscall 868''' on GameOS | |||
=== 0x17001 - Read EID Data Size By Index === | |||
*I have got access to this service through DM and tested it | |||
*This service is used e.g. by Update Manager, User Token Manager or Storage Manager | |||
*The service expects 2 additional parameters, each parameter is 8 bytes | |||
*I tested it with values: 0x0, 0x4 and 0x1000 for the 1st parameter. I extracted this values from HV Processes which use this service | |||
*The 2nd parameter is not used in a request but in a response. It contains EID size. | |||
{| class="wikitable FCK__ShowTableBorders" | |||
|- | |||
! Index | |||
! Size Of Data | |||
! Description | |||
|- | |||
| 0 | |||
| 0x860 | |||
| Used e.g. by Update Manager to decrypt update packages | |||
|- | |||
| 4 | |||
| 0x30 | |||
| Used e.g. by Storage Manager | |||
|- | |||
| 0x1000 | |||
| 0xe960 | |||
| metldr | |||
|} | |||
== | === 0x17002 - Read EID Data By Index === | ||
* | *I have got access to this service through DM and tested it | ||
*''' | *This service is used e.g. by Update Manager, User Token Manager or Storage Manager | ||
*The service expects 2 additional parameters, each parameter is 8 bytes | |||
*The 1st parameter is same as the 1st parameter of service '''Read EID Data Size By Index''' | |||
*The 2nd parameter is '''EID Data Size''' that is returned by the service '''Read EID Data Size By Index''' | |||
*The returned data is some binary data. | |||
*The data returned by the service with 1st parameter set to 0x0 or 0x4 is from file '''eEID''' stored on FLASH storage device region 0. | |||
*The data returned by the service with 1st parameter set to 0x1000 contains string '''metldr'''. | |||
*E.g. EID0 data is passed by Update Manager to SPU module '''spu_token_processor.self''' when Update Manager loads and executes it with syscall '''0x10043'''. | |||
*E.g. EID4 data is passed by Storage Manager to SPU module '''sb_iso_spu_module.self'''. | |||
=== | === 0x17004 - Read System Data === | ||
*Reads data from '''cISD''' or '''cCSD''' files stored on '''/dev/rflash1'''. | |||
*E.g. Gelic MAC address is stored in file '''cISD'''. | |||
=== | === 0x17007 - Read System Data From EEPROM === | ||
* | *Reads data from SC EEPROM | ||
* | *An index is passed to the service. The index is mapped to a specific SC EEPROM offset. | ||
= | Here is the list of possible EEPROM offsets from HV 3.15: | ||
{| class="wikitable FCK__ShowTableBorders" | |||
|- | |||
! Index | |||
! SC EEPROM Offset | |||
! Size Of Data | |||
|- | |||
| 0 | |||
| 0x48D20 | |||
| 6 | |||
|- | |||
| 1 | |||
| 0x48D28 | |||
| 6 | |||
|- | |||
| 2 | |||
| 0x48D30 | |||
| 6 | |||
|- | |||
| 3 | |||
| 0x48D38 | |||
| 6 | |||
|- | |||
| 4 | |||
| 0x48D00 | |||
| 4 | |||
|- | |||
| 5 | |||
| 0x48D04 | |||
| 4 | |||
|- | |||
| 6 | |||
| 0x48D08 | |||
| 4 | |||
|} | |||
=== 0x17014 - Write eEID/Write metldr === | |||
*'''Holy crap, it writes passed data to the region of FLASH memory where eEID or metldr data is stored !!!''' | |||
*'''And GameOS is allowed to use this service !!!''' | |||
*'''Do not experiment with this service if you don't know what it does or else your PS3 will not work anymore !!!''' | |||
=== 0x17015 - Read cISD Size === | |||
*Returns size of data '''cISD''' that is stored on '''FLASH storage device region 0''' | |||
=== 0x17016 - Read cISD === | |||
*Returns data '''cISD''' that is stored on '''FLASH storage device region 0''' | |||
=== 0x17017 - Write cISD === | |||
*'''Writes passed data to the region of FLASH memory where cISD data is stored !!!''' | |||
== | == 0x18000 - DM (Dispatcher Manager) == | ||
*Dispatcher Manager runs in Process 3. | |||
*When SLL (Secure LPAR Loader) creates GamesOS LPAR and loads it, it also creates a VUART with port number '''10''' owned by GameOS using a service provided by Dispatcher Manager (0x18001 - Construct Service Port). | |||
*Dispatcher Manager communicates with GameOS through this VUART. It opens the file '''/proc/partitions/<LPAR id>/vuart/10'''. When the file '''/proc/partitions/<LPAR id>/vuart/10''' is opened by Dispatcher Manager, the Hypervisor creates a peer VUART which is connected to the GameOS's VUART 10. | |||
*After that Dispatcher Manager reads requests from this VUART sent by GameOS and dispatches these requests to services (functions) provided by Hypervisor Processes through sockets. '''Through VUART and Dispatcher Manager, the GameOS LPAR has access to all services provided by Hypervisor Processes.''' | |||
*However, the services provided by Hypervisor Processes are protected by Security Policy Manager (SPM). Before Dispatcher Manager routes the requests from GameOS to these services, it consults SPM (by using 0x11001 service of SPM) and checks if the GameOS has access rights to the requested service. If not then the request is not routed. | |||
*DM overwrites the LAID sent in SS packet header with the LAID of the LPAR that sent the request. So, no matter what LAID you send in SS packet header, it will be always overwritten with the correct one by DM. That is the reason why e.g. USB Dongle Master Key cannot be decrypted by GameOS without patching DM. But with HV access rights, DM can be easily patched and access to SYSCON can be gained. | |||
*Linux LPAR doesn't have a VUART communication link to Dispatcher Manager. | |||
*I tested VUART 10 on GameOS with PSGroove and it's there. | |||
*On GamesOS, '''_ss_multiplexer''' accesses DM (VUART 10) | |||
{| class="wikitable FCK__ShowTableBorders" | {| class="wikitable FCK__ShowTableBorders" | ||
|- | |- | ||
! | ! Packet ID | ||
! | ! Description | ||
|- | |- | ||
| | | 0x18001 | ||
| | | Construct Service Port | ||
|- | |- | ||
| | | 0x18002 | ||
| | | Destruct Service Port | ||
|} | |} | ||
== | === Dispatcher Manager Messages === | ||
==== Dispatcher Manager Header ==== | |||
=== | *Payload follows after header | ||
*Payload is a SS packet | |||
<pre>struct dispmgr_header | |||
{ | |||
uint32_t request_id; | |||
uint32_t function_id; | |||
uint32_t request_size; /* payload size of request */ | |||
uint32_t response_size; /* payload size of response */ | |||
} | |||
</pre> | |||
=== Packet ID - SS ID Mapping === | |||
*Before DM routes a received request to a service provider (HV Process) it consults SPM | |||
*DM sends a request to SPM | |||
*Request contains SS ID and Subject ID (laid and paid) | |||
*DM obtains SS ID by mapping Packet ID | |||
Here is the mapping table i extracted from HV Process 3 where SPM and DM run: | |||
{| class="wikitable FCK__ShowTableBorders" | {| class="wikitable FCK__ShowTableBorders" | ||
|- | |- | ||
! | ! Packet ID | ||
! | ! SS ID | ||
|- | |||
| 0x2001 | |||
| 0x34 | |||
|- | |||
| 0x2002 | |||
| 0x35 | |||
|- | |||
| 0x2003 | |||
| 0x36 | |||
|- | |||
| 0x2004 | |||
| 0x37 | |||
|- | |||
| 0x2005 | |||
| 0x38 | |||
|- | |||
| 0x2006 | |||
| 0x39 | |||
|- | |||
| 0x200A | |||
| 0x3D | |||
|- | |||
| 0x200B | |||
| 0x3E | |||
|- | |||
| 0x200C | |||
| 0x3F | |||
|- | |||
| 0x200D | |||
| 0x40 | |||
|- | |||
| 0x200E | |||
| 0x41 | |||
|- | |||
| 0x2012 | |||
| 0x7B | |||
|- | |- | ||
| | | 0x2013 | ||
| | | 0x7C | ||
|- | |- | ||
| | | 0x2014 | ||
| | | 0x7E | ||
|- | |- | ||
| | | 0x2015 | ||
| | | 0x7F | ||
|- | |- | ||
| | | 0x2016 | ||
| | | 0x7D | ||
|- | |- | ||
| | | 0x2017 | ||
| | | 0x80 | ||
|} | |} | ||
== | == 0x19000 - AIM == | ||
*Executes isolated SPU module '''aim_spu_module.self''' | |||
*'''EID0 data''' is passed to '''aim_spu_module.self''' | |||
{| class="wikitable FCK__ShowTableBorders" | {| class="wikitable FCK__ShowTableBorders" | ||
|- | |- | ||
! | ! Packet ID | ||
! Description | ! Description | ||
|- | |- | ||
| | | 0x19002 | ||
| | | Get Device Type | ||
|- | |- | ||
| | | 0x19003 | ||
| | | Get Device ID | ||
|- | |- | ||
| | | 0x19004 | ||
| | | Get PS Code | ||
|- | |- | ||
| | | 0x19005 | ||
| | | Get Open PS ID | ||
| - | |} | ||
=== 0x19002 - Get Device Type === | |||
| | On my fat PS3 with HV 3.41 it returns: | ||
<pre> | |||
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x85 | |||
</pre> | |||
<pre> | |||
struct ss_aim_get_device_type | |||
{ | |||
u8 field0[16]; | |||
}; | |||
</pre> | |||
=== 0x19003 - Get Device ID === | |||
<pre> | |||
struct ss_aim_get_device_id | |||
{ | |||
u8 field0[16]; | |||
}; | |||
</pre> | |||
=== 0x19004 - Get PS Code === | |||
<pre> | |||
struct ss_aim_get_ps_code | |||
{ | |||
u8 field0[8]; | |||
}; | |||
</pre> | |||
=== 0x19005 - Get Open PS ID === | |||
<pre> | |||
struct ss_aim_get_open_ps_id | |||
{ | |||
u8 field0[16]; | |||
}; | |||
</pre> | |||
== 0x24000 - USB Dongle Authenticator == | |||
{| class="wikitable FCK__ShowTableBorders" | |||
|- | |- | ||
! Packet ID | |||
! Description | |||
|- | |- | ||
| | | 0x24001 | ||
| | | Generate Challenge | ||
|- | |- | ||
| | | 0x24002 | ||
| | | Verify Response | ||
| | |} | ||
=== 0x24001 - Generate Challenge === | |||
*I have got access to this service through DM and tested it | |||
*The service expects no input parameters except those in SS packet header | |||
*It uses 0x5003 service (Generate Random Number) to generate random numbers that are used in challenge body | |||
*The length of a challnge body is always 23 bytes, first 3 bytes are always the same: '''0x2E 0x02 0x01''' | |||
| | |||
Here are hexdumps of some challenge bodies i let 0x24001 service generate: | |||
<pre>2E 02 01 72 3A 0A 76 BB 81 CB 29 BC E7 B5 D6 62 7C 0E EE 23 18 A9 1D | |||
</pre><pre>2E 02 01 F0 DA 78 D4 1D CB D7 C9 C7 F0 32 F4 2E 92 39 BD 3F 32 93 AA | |||
</pre><pre>2E 02 01 3B B2 9D FD A8 83 AF 9A C0 E9 13 BB AE D5 6C 8C 45 2E DE 13 | |||
</pre> | |||
=== 0x24002 - Verify Response === | |||
*I have got access to this service and tested it with PSGroove | |||
*The response body is 25 bytes large | |||
*The first 3 bytes have to be '''0x2E 0x02 0x02''' or else the check fails | |||
*The 16 bit at offset 3 is a dongle ID | |||
*The dongle ID is checked if it's revoked or not | |||
*When the verification succeedes then '''product mode''' is set to '''1''' | |||
*The service calculates '''USB Dongle Key''' from '''USB Dongle ID''' and '''USB Dongle Master Key''' by using '''HMAC SHA-1''' | |||
*The service uses '''HMAC SHA-1''' to calculate the correct response body from the challenge body and '''USB Dongle Key''' | |||
*After that the service compares the calculated response body with the given one that was sent to the service | |||
*It seems that '''laid''' and '''paid''' from SS packet header are used in decryption process | |||
==== USB Dongle Master Key ==== | |||
*USB Dongle Master Key is stored encrypted in Process 6 | |||
*The encrypted key is 64 bytes large | |||
*The decrypted key is 20 bytes large | |||
*The USB Dongle Master Key is decrypted first time the service 0x24002 is used | |||
*The USB Dongle Master Key is decrypted by using the service '''0x200E (Decrypt Master)''' of '''Vitual TRM Manager''' | |||
*The decrypted USB Dongle Master Key is stored in Process 6 in clear text (after first usage of this service) | |||
*When decryption of USB Dongle Master Key fails then a dummy key is used | |||
*Unfortunately, in the HV dump 3.15 the USB Dongle Master Key was not decrypted at the moment of dumping | |||
*The first 12 bytes of decrypted USB Dongle Master Key is a magic value: '''_USB_DONGLE_'''. After these 12 bytes follows the real USB Dongle Master Key of size 20 bytes. So, if after decryption of USB Dongle Master Key, you see this magic value then the decryption was successfull. | |||
Here is the encrypted USB Dongle Master Key from HV 3.15: | |||
<pre>0x22 0xD5 0xD1 0x8C 0xFF 0xE2 0x4F 0xAC 0xEC 0x72 0xA2 0x42 0xA7 0x18 0x98 0x10 | |||
0x25 0x33 0xE0 0x96 0xF2 0xC1 0x91 0x0D 0x15 0x23 0xD3 0x07 0x74 0xE7 0x2B 0x72 | |||
0xDF 0xA6 0xDD 0xE9 0x68 0x8B 0x76 0x2A 0x6A 0x87 0x51 0x7F 0x85 0x39 0x0B 0xD4 | |||
0x20 0x3F 0x46 0x89 0x04 0x82 0xB7 0x30 0x84 0x89 0x4B 0xCC 0x9D 0xB1 0x24 0x7C | |||
</pre> | |||
This is the '''decrypted''' dongle master key: | |||
<pre> | |||
0x46 0xDC 0xEA 0xD3 0x17 0xFE 0x45 0xD8 0x09 0x23 | |||
0xEB 0x97 0xE4 0x95 0x64 0x10 0xD4 0xCD 0xB2 0xC2 | |||
</pre> | |||
This is the '''decrypted''' dongle key for dongle ID 0xAAAA which works up to 3.55: | |||
<pre> | |||
0x04 0x4E 0x61 0x1B 0xA6 0xA6 0xE3 0x9A 0x98 0xCF | |||
0x35 0x81 0x2C 0x80 0x68 0xC7 0xFC 0x5F 0x7A 0xE8 | |||
</pre> | |||
Here is the USB Dongle Master Dummy Key from HV 3.15: | |||
<pre>0xD1 0xFC 0x57 0x55 0xBF 0x20 0xFA 0xB2 0xD4 0xA5 0x4A 0x0A 0x0C 0x5D 0x52 0x8E | |||
0xDF 0x66 0xCD 0x74 | |||
</pre> | |||
==== USB Dongle ID Revoke List ==== | |||
*Process 6 contains a revoke list for USB Dongle IDs | |||
*The revoke list is 0x2000 bytes large. It's a bitmap. | |||
*Each bit represents a USB Dongle ID. If bit is 0 then USB Dongle ID is revoked. | |||
The following USB Dongle IDs are revoked in HV 3.15: | |||
<pre>0, 2, 13, 32, 34, 176, 241 | |||
</pre> | |||
== 0x25000 - User Token Manager == | |||
{| class="wikitable FCK__ShowTableBorders" | |||
|- | |- | ||
! Packet ID | |||
! Description | |||
|- | |- | ||
| | | 0x25001 | ||
| | | Encrypt User Token | ||
|- | |- | ||
| | | 0x25002 | ||
| | | Decrypt User Token | ||
| | |} | ||
=== User Token === | |||
*Before User Token Manager encrypts a received user token it checks it's format. | |||
*User Tokens are processed by '''spu_utoken_processor.self''' | |||
*Before User Token is processed, User Token Manager reads IDPS by sending SS requests to Indi Info Manager (packet ids 0x17001 and 0x17002). Indi Info Manager runs in HV Process 5. | |||
==== User Token Format ==== | |||
<pre>stuct user_token_attr | |||
{ | |||
uint32_t type; /* 0x00000001, value != 0x00000001 means attribute list ends here */ | |||
uint32_t size; /* 8 + sizeof(data) */ | |||
/* data follows here, size of data may be 0 */ | |||
} | |||
struct user_token | |||
{ | |||
uint32_t magic; /* 0x73757400 = "sut\0" */ | |||
uint32_t format_version; /* 0x00000001 */ | |||
uint64_t size; | |||
uint8_t idps[16]; | |||
uint64_t expire_date; | |||
uint64_t capability; | |||
union | |||
{ | |||
stuct user_token_attr attrs[0]; | |||
uint8_t dummy[3072]; | |||
} attrs; | |||
/* 0xC30 */ | |||
uint8_t digest[20]; | |||
} | |||
</pre> | |||
= LPAR Memory Management = | |||
== Memory Region class == | |||
This class is the base class for different memory region types. | |||
=== vtable === | |||
0x003578B0 (3.15) | |||
=== Member variables === | |||
offset 0x40 - pointer to LPAR object that owns this memory region | |||
offset 0x48 - type of memory region (8 bytes) | |||
offset 0x50 - LPAR start address of memory region | |||
offset 0x58 - size of memory region (8 bytes) | |||
offset 0x60 - flags (8 bytes) | |||
offset 0xA0 - log2 of page size | |||
=== Generating New LPAR Memory Region Addresses === | |||
generate_new_lpar_mem_region_address(?, memory region size, log2(page size), ?, ?) - 002C82E8 (3.15) | |||
generate_new_lpar_mem_region_address - 002C6570 (3.41) | |||
*The function returns a new LPAR memory region address. | |||
*This method is used e.g. in all HV calls which create any kind of memory regions, e.g. '''lv1_allocate_memory''', '''lv1_map_htab''', '''lv1_undocumented_function_114''', '''lv1_construct_logical_spe''', '''lv1_map_device_mmio_region''' or '''syscall 0x10040'''. | |||
==== Encoding LPAR Memory Region Start Addresses and Sizes ==== | |||
*Size of LPAR memory region is encoded in the LPAR memory region start address. | |||
*That is why e.g. the LPAR Memory Region Start Addresses of LPAR Memory Region of size 4096 byte begin with '''0x300000000000''', '''0x300000000000 >> 42 = 0xC = log2(4096)'''. | |||
*Each LPAR has a counter (8 bytes) which is incremented by 1 every time a new LPAR Memory Region is created. | |||
*Before incrementing, the counter is shifted left by '''log2(LPAR Memory Region Size)''' and ored with '''log2(LPAR Memory Region Size) << 42'''. | |||
LPAR Memory Region Start Address >> 42 = log2(LPAR Memory Region Size) | |||
LPAR Memory Region Start Address = (log2(LPAR Memory Region Size) << 42) | | |||
(counter << log2(LPAR Memory Region Size)) | |||
| | |||
=== LPAR | ===== LPAR Memory Region Address Counter ===== | ||
*LPAR Memory Region Address Counter is stored at address: '''0x38(LPAR ptr) + 0x9E8''' | |||
*LPAR1's Memory Region Address Counter is at address '''0x00677A48''' in HV dump 3.15 | |||
*LPAR2's Memory Region Address Counter is at address '''0x007632D8''' in HV dump 3.15 | |||
*LPAR1's Memory Region Address Counter is at address '''0x00677A48''' in HV dump 3.41 | |||
*LPAR2's Memory Region Address Counter is at address '''0x00161E68''' in HV dump 3.41 | |||
== Physical Memory Region class == | |||
This type of memory region is created e.g. in '''lv1_allocate_memory''' HV call or in '''syscall 0x10000'''. | |||
=== vtable === | |||
0x00357D08 (3.15) | |||
=== Member variables === | |||
offset 0xB0 - pointer to object that stores a list of addresses of physical pages owned by this memory region | |||
offset 0xB8 - pointer to LPAR object that owns this memory region | |||
offset 0xC0 - reference counter (8 bytes) | |||
=== Objects === | |||
Here is the | Here is the list of physical memory region objects i found in HV 3.15. | ||
{| class="wikitable FCK__ShowTableBorders" | {| class="wikitable FCK__ShowTableBorders" | ||
|- | |- | ||
! Address in HV dump | |||
! Address | ! LPAR id | ||
! | ! LPAR Start Address | ||
! Size | |||
! Flags | |||
! log2(Page Size) | |||
! Physical Page Addresses | |||
|- | |- | ||
| | | 0x006B5510 | ||
| | | 1 | ||
| | | 0x300000001000 | ||
| 0x1000 | |||
| 0x0 | |||
| 0xC | |||
| 0x672000 | |||
|- | |||
| 0x006B5E50 | |||
| 1 | |||
| 0x440000040000 | |||
| 0x20000 | |||
| 0x0 | |||
| 0x11 | |||
| 0x6C0000 | |||
|- | |||
| 0x006B6980 | |||
| 1 | |||
| 0x440000060000 | |||
| 0x20000 | |||
| 0x0 | |||
| 0x11 | |||
| 0x6E0000 | |||
|- | |- | ||
| 0x006B7F00 | |||
| 1 | | 1 | ||
| | | 0x400000040000 | ||
| | | 0x10000 | ||
| 0x0 | |||
| 0x10 | |||
| 0x100000 | |||
|- | |- | ||
| 0x003A80F0 | |||
| 2 | | 2 | ||
| | | 0x6C0058000000 | ||
| | | 0x7000000 | ||
| 0x4 | |||
| 0x18 | |||
| 0x1000000 - 0x7000000 | |||
|- | |- | ||
| | | 0x003BE800 | ||
| | | 2 | ||
| | | 0x300000047000 | ||
| 0x1000 | |||
| 0x0 | |||
| 0xC | |||
| 0x1FA000 | |||
|- | |- | ||
| | | 0x006BDAA0 | ||
| | | 2 | ||
| | | 0x0 | ||
| 0x8000000 | |||
| 0x8 | |||
| 0x1B (single huge page) | |||
| 0x8000000 | |||
|} | |} | ||
So, Linux kernel should be located at physical address 0x8000000 and Linux syscall handler at 0x8000C00. Too bad that the HV dump is not large enough. | |||
=== GameOS Physical Memory Regions === | |||
*GameOS allocates nearly all physical memory of PS3 for itself !!! That is why new HV calls '''lv1_allocate_memory''' with large memory region sizes will fail. | |||
*So when someone wants a large piece of physical memory, he can borrow it from GameOS's LPAR memory region that starts at '''0x700020000000'''. It can be used for example to send update packages to Update Manager which are very large. | |||
Here is the list of physical memory regions of GameOS i found in HV 3.41: | |||
{| class="wikitable FCK__ShowTableBorders" | |||
|- | |||
! Start Address | |||
! Size | |||
! Access Right | |||
! Max Page Size | |||
! Flags | |||
! Real Addresses | |||
|- | |||
| 0x0 | |||
| 0x1000000 | |||
| 0x3 | |||
| 0x18 | |||
| 0x8 | |||
| 0x1000000 - 0x1FFF000 | |||
|- | |||
| 0x500000300000 | |||
| 0xA0000 | |||
| 0x3 | |||
| 0x10 | |||
| 0x8 | |||
| 0x380000 - 0x38F000, 0x3B0000 - 0x3BF000, 0x1E0000 - 0x1FF000, 0x3C0000 - 0x3FF000, 0xFF00000 - 0xFF1F000 | |||
|- | |||
| 0x700020000000 | |||
| 0xE900000 (huge memory region) | |||
| 0x3 | |||
| 0x14 | |||
| 0x0 | |||
| 0x400000 - 0x5FF000, 0x800000 - 0xFFF000, 0x2000000 - 0xFEFF000 | |||
|} | |||
== HTAB Memory Region class == | |||
This memory region is created when a HTAB is mapped into LPAR's address space. It's created in '''lv1_map_htab''' HV call. | |||
== | === vtable === | ||
0x00357C98 (3.15) | |||
== | === Member variables === | ||
offset 0xB0 - pointer to VAS object that owns the HTAB | |||
=== | === Objects === | ||
Here is the list of HTAB memory region objects i found in HV 3.15. | |||
{| class="wikitable FCK__ShowTableBorders" | |||
|- | |||
! Address in HV dump | |||
! LPAR id | |||
! VAS id | |||
! LPAR Start Address | |||
! Size | |||
! Flags | |||
! log2(Page Size) | |||
|- | |||
} | | 0x001FE0F0 | ||
| 2 | |||
| 3 | |||
| 0x500000C00000 | |||
| 0x100000 | |||
| 0xC000000000000000 | |||
| 0x14 | |||
|- | |||
| 0x003BD850 | |||
| 2 | |||
| 3 | |||
| 0x500004300000 | |||
| 0x100000 | |||
| 0xC000000000000000 | |||
| 0x14 | |||
|- | |||
| 0x003BDEA0 | |||
| 2 | |||
| 3 | |||
| 0x500004500000 | |||
| 0x100000 | |||
| 0xC000000000000000 | |||
| 0x14 | |||
|} | |||
=== | === GameOS HTAB === | ||
*HTAB of GameOS is already mapped into address space of GameOS so that is why HV call '''lv1_map_htab''' will fail until you unmap it with '''lv1_unmap_htab''' | |||
*Effective address of GameOS HTAB is '''0x800000000F000000''' | |||
*Virtual address of GameOS HTAB is '''0xF000000''' | |||
*Size of GameOS HTAB is '''0x40000''' | |||
*GameOS HTAB supports large pages of size '''64K''' and '''1M''' | |||
*GameOS HTAB can be easily dumped by reading 0x40000 bytes at EA 0x800000000F000000 | |||
=== GameOS SLB === | |||
Here is the dump of SLB entries from GameOS 3.41: | |||
<pre>0x8000000008000000 0x0000000000000500 | |||
0x8000000208000000 0x0000000000020500 | |||
0x8000000300000000 0x0000000000030510 | |||
0x0000000000000000 0x0000000000000000 | |||
0x0000000080000000 0x0000000000038C00 | |||
0x00000000A0000000 0x000000000003AC00 | |||
0x00000000C0000000 0x000000000003CC00 | |||
0x0000000000000000 0x0000000000000000 | |||
0x0000000000000000 0x0000000000000000 | |||
0x0000000000000000 0x0000000000000000 | |||
0x0000000000000000 0x0000000000000000 | |||
0x0000000000000000 0x0000000000000000 | |||
0x0000000000000000 0x0000000000000000 | |||
0x0000000000000000 0x0000000000000000 | |||
0x0000000000000000 0x0000000000000000 | |||
0x0000000000000000 0x0000000000000000 | |||
0x0000000000000000 0x0000000000000000 | |||
0x0000000000000000 0x0000000000000000 | |||
0x0000000000000000 0x0000000000000000 | |||
</pre> | 0x0000000000000000 0x0000000000000000 | ||
0x0000000000000000 0x0000000000000000 | |||
0x0000000000000000 0x0000000000000000 | |||
0x0000000000000000 0x0000000000000000 | |||
0x0000000000000000 0x0000000000000000 | |||
0x0000000000000000 0x0000000000000000 | |||
0x0000000000000000 0x0000000000000000 | |||
0x0000000000000000 0x0000000000000000 | |||
0x0000000000000000 0x0000000000000000 | |||
0x0000000000000000 0x0000000000000000 | |||
0x0000000000000000 0x0000000000000000 | |||
0x0000000000000000 0x0000000000000000 | |||
0x0000000000000000 0x0000000000000000 | |||
0x8000000010057960 0x8000000000313E78 | |||
0x8000000010057940 0x0000000000000000 | |||
0x800000000001B698 0x0000000000000000 | |||
0x8000000010057930 0x8000000000490708 | |||
0x80000000002B6C68 0x80000000003DE928 | |||
0x8000000010057EC0 0x80000000003DE920 | |||
0x0000000000000000 0x8000000000309810 | |||
0x80000000004B3000 0x0000000000000000 | |||
0x8000000010057CC0 0x0000000000000000 | |||
0x80000000004AF000 0x80000000004E1F00 | |||
0x80000000100579C8 0x80000000100579C0 | |||
0x80000000100579E0 0x2400002200000000 | |||
0x80000000004CF5B0 0x8000000200012000 | |||
0x80000000100579F8 0x80000000100579F0 | |||
0x8000000010057A10 0x80000000004A3A00 | |||
0x80000000004CF5B0 0x80000000004C8D00 | |||
0x800000000001BF6C 0x80000000004CD400 | |||
0x800000000001B698 0x80000000004C8100 | |||
0x80000000100579D0 0x80000000004B48C0 | |||
0x0000000000001C08 0x0000000000000000 | |||
0x8000000010057A78 0x8000000010057A70 | |||
0x8000000010057A90 0x0000000000000000 | |||
0x80000000004CF90C 0x0000000000000000 | |||
0x0000000000000000 0x8000000010057A80 | |||
0x8000000010057A90 0x8000000000309810 | |||
0x80000000004CF62C 0x0000000000000000 | |||
0x8000000010057CC0 0x0000000000000000 | |||
0x80000000004AF000 0x80000000004B48C0 | |||
0x00004000001C0000 0x0000000000000001 | |||
0x00000000D0000000 0x0000A8E3EE7D10DA | |||
0x0000000000000000 0x0000000000000000 | |||
0x80000000004D8088 0x80000000004D9000 | |||
</pre> | |||
== SPE MMIO Memory Region class == | |||
This type of memory region represents MMIO memory region of a SPE. It's created e.g. in '''lv1_construct_logical_spe''' or in '''syscall 0x10040'''. | |||
=== | === vtable === | ||
0x003583F8 (3.15) | |||
=== Member variables === | |||
=== | === Objects === | ||
Here is the list of SPE memory region objects i found in HV 3.15. | |||
= | {| class="wikitable FCK__ShowTableBorders" | ||
|- | |||
! Address in HV dump | |||
! LPAR id | |||
! SPE | |||
! LPAR Start Address | |||
! Size | |||
! Physical Address | |||
! Flags | |||
! log2(Page Size) | |||
|- | |||
| 0x003ABC20 | |||
| 2 | |||
| 1 | |||
| 0x4C0000880000 | |||
| 0x80000 | |||
| 0x20000080000 | |||
| 0xA000000000000000 | |||
| 0xC | |||
|- | |||
| 0x003AAD70 | |||
| 2 | |||
| 2 | |||
| 0x4C0000980000 | |||
| 0x80000 | |||
| 0x20000100000 | |||
| 0xA000000000000000 | |||
| 0xC | |||
|- | |||
| 0x003A8880 | |||
| 2 | |||
| 3 | |||
| 0x4C0000780000 | |||
| 0x80000 | |||
| 0x20000180000 | |||
| 0xA000000000000000 | |||
| 0xC | |||
|- | |||
| 0x003B4F70 | |||
| 2 | |||
| 4 | |||
| 0x4C0000A80000 | |||
| 0x80000 | |||
| 0x20000200000 | |||
| 0xA000000000000000 | |||
| 0xC | |||
|- | |||
| 0x003AB700 | |||
| 2 | |||
| 5 | |||
| 0x4C0000680000 | |||
| 0x80000 | |||
| 0x20000280000 | |||
| 0xA000000000000000 | |||
| 0xC | |||
|- | |||
| 0x003B5BE0 | |||
| 2 | |||
| 6 | |||
| 0x4C0000B80000 | |||
| 0x80000 | |||
| 0x20000300000 | |||
| 0xA000000000000000 | |||
| 0xC | |||
|} | |||
== SPE Shadow Registers Memory Region class == | |||
This type of memory region represents shadow registers memory region of a SPE. It's created e.g. in '''lv1_construct_logical_spe''' or in '''syscall 0x10040'''. | |||
=== vtable === | |||
0x00358448 (3.15) | |||
=== Objects === | |||
Here is the list of SPE Shadow Registers memory region objects i found in HV 3.15. | |||
{| class="wikitable FCK__ShowTableBorders" | |||
|- | |||
! Address in HV dump | |||
! LPAR id | |||
! SPE | |||
! LPAR Start Address | |||
! Size | |||
! Physical Address | |||
! Flags | |||
! log2(Page Size) | |||
|- | |||
| 0x003ABDA0 | |||
| 2 | |||
| 1 | |||
| 0x300000012000 | |||
| 0x1000 | |||
| - | |||
| 0xA000000000000000 | |||
| 0xC | |||
|- | |||
| 0x003B4290 | |||
| 2 | |||
| 2 | |||
| 0x300000014000 | |||
| 0x1000 | |||
| - | |||
| 0xA000000000000000 | |||
| 0xC | |||
|- | |||
| 0x003A8A00 | |||
| 2 | |||
| 3 | |||
| 0x300000010000 | |||
| 0x1000 | |||
| - | |||
| 0xA000000000000000 | |||
| 0xC | |||
|- | |||
| 0x003B50F0 | |||
| 2 | |||
| 4 | |||
| 0x300000016000 | |||
| 0x1000 | |||
| - | |||
| 0xA000000000000000 | |||
| 0xC | |||
|- | |||
| 0x001FFC90 | |||
| 2 | |||
| 5 | |||
| 0x30000000E000 | |||
| 0x1000 | |||
| - | |||
| 0xA000000000000000 | |||
| 0xC | |||
|- | |||
| 0x003AE5B0 | |||
| 2 | |||
| 6 | |||
| 0x300000018000 | |||
| 0x1000 | |||
| - | |||
| 0xA000000000000000 | |||
| 0xC | |||
|} | |||
== Device MMIO Memory Region class == | |||
This type of memory region is created when a device MMIO region is mapped into LPAR address space, e.g. in '''lv1_map_device_mmio_region'''. | |||
=== vtable === | |||
0x00352468 (3.15) | |||
=== Member variables === | |||
offset 0xA8 - physical address where the device MMIO region is mapped to | |||
=== Objects === | |||
Here is the list of Device MMIO memory region objects i found in HV 3.15. | |||
{| class="wikitable FCK__ShowTableBorders" | |||
|- | |||
! Address in HV dump | |||
! LPAR id | |||
! LPAR Start Address | |||
! Size | |||
! Flags | |||
! log2(Page Size) | |||
! Physical Address | |||
! Device | |||
|- | |||
| 0x001FDF00 | |||
| 2 | |||
| 0x4000001D0000 | |||
| 0x10000 | |||
| 0x8000000000000000 | |||
| 0xC | |||
| 0x24003010000 | |||
| USB controller | |||
|- | |||
| 0x003B3850 | |||
| 2 | |||
| 0x400000200000 | |||
| 0x10000 | |||
| 0x8000000000000000 | |||
| 0xC | |||
| 0x24003020000 | |||
| USB controller | |||
|- | |||
| 0x003B6E50 | |||
| 2 | |||
| 0x4000001E0000 | |||
| 0x10000 | |||
| 0x8000000000000000 | |||
| 0xC | |||
| 0x24003810000 | |||
| USB controller | |||
|- | |||
| 0x003B9950 | |||
| 2 | |||
| 0x4000001F0000 | |||
| 0x10000 | |||
| 0x8000000000000000 | |||
| 0xC | |||
| 0x24003820000 | |||
| USB controller | |||
|} | |||
== GPU Device Memory Region class == | |||
This type of memory region is created e.g. in '''lv1_gpu_open''', '''lv1_gpu_device_map''' and '''lv1_undocumented_function_114'''. | |||
=== vtable === | |||
0x00357C48 (3.15) | |||
=== Member variables === | |||
offset 0xA8 - physical address | |||
=== Objects === | |||
Here is the list of Device GPU memory region objects i found in HV 3.15. | |||
{| class="wikitable FCK__ShowTableBorders" | |||
|- | |||
! Address in HV dump | |||
! LPAR id | |||
! LPAR Start Address | |||
! Size | |||
! Flags | |||
! log2(Page Size) | |||
! Physical Address | |||
|- | |||
| 0x003AF380 | |||
| 2 | |||
| 0x700190000000 | |||
| 0xFE00000 | |||
| 0x8000000000000000 | |||
| 0x14 | |||
| 0x28080000000 | |||
|- | |||
| 0x003AF500 | |||
| 2 | |||
| 0x4000001A0000 | |||
| 0xC000 | |||
| 0x8000000000000000 | |||
| 0xC | |||
| 0x3C0000 | |||
|- | |||
| 0x003AF680 | |||
| 2 | |||
| 0x4800006C0000 | |||
| 0x40000 | |||
| 0x8000000000000000 | |||
| 0xC | |||
| 0x2808FE00000 | |||
|- | |||
| 0x003AFC30 | |||
| 2 | |||
| 0x440000380000 | |||
| 0x20000 | |||
| 0x8000000000000000 | |||
| 0xC | |||
| 0x28000C00000 | |||
|- | |||
| 0x003BB420 | |||
| 2 | |||
| 0x3C0000108000 | |||
| 0x8000 | |||
| 0x8000000000000000 | |||
| 0xC | |||
| 0x28000080100 | |||
|} | |||
== Direct Map Memory Region class == | |||
This type of memory region is created in HV call '''lv1_undocumented_function_114'''. | |||
'''lv1_undocumented_function_114''' allows you to map any memory address into LPAR's memory address. | |||
* The HV call '''lv1_undocumented_function_115''' destroys a memory region of this type. | |||
* HV allows GameOS to create objects of this type of size 0 only !!! But it can be exploited with a dangling HTAB entry. | |||
=== vtable === | |||
0x00357C48 (3.15) | |||
= | === Member variables === | ||
offset 0xA8 - physical address | |||
=== Exploiting HV with memory glitching and HV call lv1_undocumented_function_114 === | |||
Here is a short description of the method i used to exploit HV from GameOS 3.15 and 3.41. | |||
* First i used the Geohot's method to create a dangling HTAB entry. | |||
* Making memory glitch work on GameOS was the largest of my obstacles but i solved it and i'm able to create a dangling HTAB entry from GameOS within 1-3 minutes. | |||
* Then i created many '''Direct Map Memory Region''' objects of size 0 with HV call '''lv1_undocumented_function_114''' and checked if they are within the page to which the dangling HTAB entry points to. | |||
* When i found one such '''Direct Map Memory Region''' object i patched the size of this object to 0x1000. Then i pointed this memory region object to the code of HV call '''lv1_undocumented_function_114''' and patched 4 bytes in this HV call which allows me to create any '''Direct Map Memory Region''' objects without any restrictions. | |||
* Function '''LPAR_construct_direct_mapping_mem_region''' which is used by HV call '''lv1_undocumented_function_114''' has a parameter (register %r9) and when this parameter is not 0 then HV will allow you to create any '''Direct Map Memory Region''' objects without restrictions, but unfortunately the HV call '''lv1_undocumented_function_114''' passes 0 in this parameter, so i just patched it. | |||
* Then i mapped whole HV memory range with the patched HV call '''lv1_undocumented_function_114''' into the address space of GameOS. | |||
* And now you have read/write access to the whole HV. | |||
* $ONY could fix this exploit by disallowing creating of '''Direct Map Memory Region''' objects of size 0, but i know tons of other HV C++ classes which will allow me to exploit the HV in a similar way, so it wouldn't bring $ONY anything :-) And they have to change member variable offsets in those objects to make sure that i cannot patch them easily :-) | |||
== Methods == | |||
LPAR_get_memory_region_by_start_address - 0x002C7C40 (3.15) | |||
LPAR_get_memory_region_by_address - 0x002C7DA8 (3.15) | |||
LPAR_mem_addr_to_phys_addr(LPAR id, LPAR address, phys_addr) - 0x002FB8F0 (3.15) | |||
LPAR_construct_direct_mapping_mem_region - 0x002D4D04 (3.15) | |||
= | = Network Devices = | ||
== | == Ethernet Gelic Device == | ||
device id = 0 | |||
MAC Address: 00:1F:A7:C6:2A:C5 | |||
== | device memory base address = 0x24003004000 (size = 0x1000) | ||
== WLAN Gelic Device == | |||
= | device id = 0 | ||
MAC Address: 02:1F:A7:C6:2A:C5 (locally administered) | |||
=== Net Manager === | |||
*Net Manager runs in Process 9 | |||
*It sends commands to '''/dev/sc1''' to reset WLAN Gelic device | |||
*It opens '''/dev/net0''', sets MAC address and writes device firmware '''eurus_fw.bin''' to WLAN device by using '''ioctl''' syscall | |||
=== /dev/net0 === | |||
The device supports 3 ioctl commands: | |||
*0 - 0x002AC10C (3.15) | |||
*1 - 0x002AC250 (3.15) | |||
*2 - EURUS_STAT 0x002AC320 (3.15) | |||
=== Methods === | |||
net_control_cmd_GELIC_LV1_POST_WLAN_CMD - 0x0024A55C (3.15) | |||
net_control_wlan_cmd_GELIC_EURUS_CMD_ASSOC - 0x00246C78 (3.15) | |||
net_control_wlan_cmd_GELIC_EURUS_CMD_START_SCAN - 0x00248A14 (3.15) | |||
net_control_wlan_cmd_GELIC_EURUS_CMD_SET_WEP_CFG - 0x00249F24 (3.15) | |||
net_control_wlan_cmd_GELIC_EURUS_CMD_SET_WPA_CFG - 0x002497B8 (3.15) | |||
= Event Notification = | |||
*Event Notfication is used e.g. to notify a LPAR about some event, e.g. device interrupt or notify a LPAR about destruction of another LPAR. | |||
*For example Process 9 is notified through Event Notification when LPAR 2 is destructed. | |||
*During LPAR construction, Process 9 creates an Outlet object with '''syscall 0x1001A''' and then passes the outlet ID to the '''syscall 0x10009''' that constructs the LINUX LPAR. In this way Process 9 is notified when LINUX LPAR is destructed. | |||
== Outlet class == | |||
This is the base Outlet class. There are different types of Outlet and they derive from this base class. | |||
=== vtable === | |||
0x00357DC0 (3.15) | |||
=== | === Member variables === | ||
offset 0x30 - type (8 bytes) | |||
offset 0x38 - pointer to LPAR that owns this Outlet object | |||
offset | offset 0x48 - outlet id (8 bytes) | ||
offset | offset 0x90 - VIRQ assigned to this Outlet object (4 bytes) | ||
== Event Receive Port class == | |||
*This type of Outlet is created e.g. in '''lv1_construct_event_receive_port''' and in '''syscall 0x1001A'''. | |||
*HV calls '''lv1_connect_irq_plug''' and '''lv1_connect_irq_plug_ext''' assigns a VIRQ to Event Receive Port object. | |||
=== vtable === | |||
0x00357E88 | |||
== VUART Outlet == | |||
*HV supports only one VUART Outlet per LPAR | |||
*'''lv1_configure_virtual_uart_irq''' constructs a VUART Outlet object and passes the address of LPAR's VUART IRQ Bitmap to HV | |||
=== vtable === | |||
0x00357DC0 | |||
=== | === VUART IRQ Bitmap === | ||
* | *At address 0x38(LPAR ptr) + 0x158 is the VUART IRQ Bitmap owned by HV for LPAR (4 * 8 bytes = 256 bits) | ||
* | *At address 0x38(LPAR ptr) + 0x150 is stored the physical address of LPAR's VUART IRQ Bitmap that was passed to '''lv1_configure_virtual_uart_irq''' | ||
* | *When a VUART interrupt is generated by HV then first the VUART IRQ Bitmap owned by HV is updated and then this bitmap is copied to LPAR's VUART IRQ Bitmap, so VUART IRQ Bitmap is stored twice, once in HV and once in LPAR, just like IRQ State Bitmap. | ||
* | *VUART IRQ Bitmap is not allowed to cross page boundary of LPAR memory region where it is stored. HV checks it and makes sure that it doesn't happen. | ||
*'''GameOS 3.41''' VUART IRQ bitmap is at address '''0x80000000003556E8''' and of size '''32 bytes (256 bits, each bit corresponds to a VUART port)'''. | |||
*'''GameOS 3.15''' VUART IRQ bitmap is at address '''0x8000000000354768'''. | |||
= | = Logical PPE = | ||
* | *Logical PPE is used for interrupt management of LPAR. | ||
* | *A Logical PPE object is created in '''syscall 0x10005'''. It' used e.g. in Process 9 during LPAR construction. | ||
*'''syscall 0x10007''' activates a Logical PPE object | |||
*0x67F0(HSPRG0) - pointer to currently active Logical PPE object (in HV dump it points to Linux PPE object naturally because the dump was made on Linux, so Linux LPAR was active at that time) | |||
*E.g. '''lv1_get_logical_ppe_id''', '''lv1_start_ppe_periodic_tracer''' and '''lv1_set_ppe_periodic_tracer_frequency''' grab the currently active Logical PPE object | |||
== vtable == | |||
0x00357DF0 (3.15) | |||
== Member variables == | |||
offset | offset 0x90 - pointer to an object that contains VIRQ-Outlet mapping table for thread 0 | ||
offset 0x98 - pointer to an object that contains VIRQ-Outlet mapping table for thread 1 | |||
== Objects == | |||
Here is the list of Logical PPE objects i found in HV 3.15. | |||
= | {| class="wikitable FCK__ShowTableBorders" | ||
|- | |||
! Address in HV dump | |||
! LPAR id | |||
! PPE id | |||
|- | |||
| 0x0069C7F0 | |||
| 1 | |||
| 1 | |||
|- | |||
| 0x007A8900 | |||
| 2 | |||
| 1 | |||
|} | |||
== Virtual IRQ - Outlet Mapping == | |||
*HV maintains 2 tables per PPE that map a VIRQ to an Outlet object. | |||
*The table has 256 entries and is indexed by VIRQ. | |||
*Each entry is a pointer to Outlet object. | |||
*Each Logical PPE object has 2 tables, one for each thread of Cell CPU. | |||
=== LPAR 1 PPE 1 Thread 0 === | |||
0x0069C990 (3.15) - address of VIRQ-Outlet table for '''LPAR 1 PPE 1 Thread 0''' (not empty) | |||
{| class="wikitable FCK__ShowTableBorders" | |||
|- | |||
! VIRQ | |||
! Address of Outlet object in HV dump | |||
! Description | |||
|- | |||
| 58 | |||
| 0x00090D10 | |||
| - | |||
|- | |||
| 59 | |||
| 0x006BAC50 | |||
| - | |||
|- | |||
| 60 | |||
| 0x006B3ED0 | |||
| FLASH storage device / Storage device notification for LPAR 1 | |||
|- | |||
| 61 | |||
| 0x00697E70 | |||
| VUART interrupts | |||
|- | |||
| 62 | |||
| 0x001C8F20 | |||
| - | |||
|} | |||
=== LPAR 1 PPE 1 Thread 1 === | |||
0x0069D9B0 (3.15) - address of VIRQ-Outlet table for '''LPAR 1 PPE 1 Thread 1''' (empty) | |||
=== | === LPAR 2 PPE 1 Thread 0 === | ||
0x000A06B0 (3.15) - address of VIRQ-Outlet table for '''LPAR 2 PPE 1 Thread 0''' (not empty) | |||
{| class="wikitable FCK__ShowTableBorders" | |||
|- | |||
! VIRQ | |||
! Address of Outlet object in HV dump | |||
! Description | |||
|- | |||
| 20 | |||
| 0x003AA210 | |||
| - | |||
|- | |||
| 21 | |||
| 0x003AFEC0 | |||
| - | |||
|- | |||
| 22 | |||
| 0x001FC010 | |||
| - | |||
|- | |||
| 23 | |||
| 0x003A8E50 | |||
| - | |||
|- | |||
| 24 | |||
| 0x001FFED0 | |||
| SPE 0 Class 0 Interrupt | |||
|- | |||
| 25 | |||
| 0x003AE160 | |||
| SPE 0 Class 1 Interrupt | |||
|- | |||
| 26 | |||
| 0x003AE350 | |||
| SPE 0 Class 2 Interrupt | |||
|- | |||
| 27 | |||
| 0x003AB100 | |||
| SPE 1 Class 0 Interrupt | |||
|- | |||
| 28 | |||
| 0x003AB2F0 | |||
| SPE 1 Class 1 Interrupt | |||
|- | |||
| 29 | |||
| 0x003AB4E0 | |||
| SPE 1 Class 2 Interrupt | |||
|- | |||
| 30 | |||
| 0x003AA6A0 | |||
| SPE 2 Class 0 Interrupt | |||
|- | |||
| 31 | |||
| 0x003AA890 | |||
| SPE 2 Class 1 Interrupt | |||
|- | |||
| 32 | |||
| 0x003AAA80 | |||
| SPE 2 Class 2 Interrupt | |||
|- | |||
| 33 | |||
| 0x003B44A0 | |||
| SPE 3 Class 0 Interrupt | |||
|- | |||
| 34 | |||
| 0x003B4690 | |||
| SPE 3 Class 1 Interrupt | |||
|- | |||
| 35 | |||
| 0x003B4AD0 | |||
| SPE 3 Class 2 Interrupt | |||
|- | |||
| 36 | |||
| 0x003B5300 | |||
| SPE 4 Class 0 Interrupt | |||
|- | |||
| 37 | |||
| 0x003B54F0 | |||
| SPE 4 Class 1 Interrupt | |||
|- | |||
| 38 | |||
| 0x003B56E0 | |||
| SPE 4 Class 2 Interrupt | |||
|- | |||
| 39 | |||
| 0x003AE7C0 | |||
| SPE 5 Class 0 Interrupt | |||
|- | |||
| 40 | |||
| 0x003AE9B0 | |||
| SPE 5 Class 1 Interrupt | |||
|- | |||
| 41 | |||
| 0x003AEBA0 | |||
| SPE 5 Class 2 Interrupt | |||
|- | |||
| 42 | |||
| 0x003B2040 | |||
| Storage device notification for LPAR 2 | |||
|- | |||
| 43 | |||
| 0x003AEE30 | |||
| VUART interrupts | |||
|- | |||
| 44 | |||
| 0x001FEAA0 | |||
| - | |||
|- | |||
| 45 | |||
| 0x001FEED0 | |||
| HDD storage device | |||
|- | |||
| 46 | |||
| 0x003B5E20 | |||
| - | |||
|- | |||
| 47 | |||
| 0x003B7040 | |||
| - | |||
|- | |||
| 48 | |||
| 0x003B9B40 | |||
| - | |||
|- | |||
| 49 | |||
| 0x003B3A40 | |||
| - | |||
|- | |||
| 50 | |||
| 0x003BACA0 | |||
| Gelic device | |||
|- | |||
| 51 | |||
| 0x003BAE10 | |||
| UNKNOWN storage device | |||
|- | |||
| 52 | |||
| 0x003B8350 | |||
| - | |||
|} | |||
=== | === LPAR 2 PPE 1 Thread 1 === | ||
0x007A89E0 (3.15) - address of VIRQ-Outlet table for '''LPAR 2 PPE 1 Thread 1''' (not empty) | |||
= | {| class="wikitable FCK__ShowTableBorders" | ||
|- | |||
! VIRQ | |||
! Address of Outlet object in HV dump | |||
! Description | |||
|- | |||
| 16 | |||
| 0x003B2480 | |||
| - | |||
|- | |||
| 17 | |||
| 0x003B2590 | |||
| - | |||
|- | |||
| 18 | |||
| 0x003B26A0 | |||
| - | |||
|- | |||
| 19 | |||
| 0x003B27B0 | |||
| - | |||
|} | |||
== IRQ State Bitmap == | |||
offset | *There is one IRQ State Bitmap (256 bits = 32 bytes) per thread of Logical PPE | ||
*'''HSPRG0 value is per thread''', so there are 2 HSPRG0 values in HV dump !!! | |||
*The IRQ State Bitmap of a thread is stored at -0x68E0(HSPRG0) | |||
*When an Event or Interrupt happens then the bitmap at 0x68E0(HSPRG0) is updated | |||
*The physical address of '''LPAR's IRQ State Bitmap''' of thread is stored at offset -0x68C0(HSPRG0) | |||
*The address of LPAR's IRQ State Bitmap is passed to Hypervisor through HV call '''lv1_configure_irq_state_bitmap''' | |||
*'''lv1_detect_pending_interrupts''' returns value of current IRQ State Bitmap. | |||
*The IRQ State Bitmap is updated if an Outlet object is assigned to VIRQ and when Outlet generates an event | |||
*After IRQ State Bitmap update, it's copied to LPAR's IRQ State Bitmap and a hardware interrupt is generated so that LPAR can read it's IRQ State Bitmap and handle interrupts. | |||
*So, IRQ State Bitmap is stored twice, once in HV and once in LPAR, just like VUART IRQ Bitmap. | |||
*'''GameOS''' IRQ state bitmap is stored at address '''SPRG0 + 0x1C0 and of size 64 bytes (256 bits state + 256 bits mask) per thread of Cell CPU'''. So there are 2 IRQ state bitmaps. | |||
0x8941FC0 - physical address of LPAR's IRQ State Bitmap for Thread 0 of LINUX LPAR | |||
0x8948FC0 - physical address of LPAR's IRQ State Bitmap for Thread 1 of LINUX LPAR | |||
= System Controller (SC or SYSCON) = | |||
Crossreference: [http://wiki.gitbrew.org/index.php/PS3:HvReverseEngineering#SYSCON gitbrew.org::SYSCON] <br /> | |||
*Data received from SC is sent to a VUART | |||
*'''lv1_get_rtc''' and '''syscall 0x10036''' communicate with '''SC VUART 4'''. | |||
=== | === VUART Table === | ||
* | *Address of SC VUART Table - 0x00610410 (3.15). | ||
* | *There are 5 VUARTs for SC in HV 3.15 | ||
Here is the SC VUART table from HV 3.15: | |||
{| class="wikitable FCK__ShowTableBorders" | |||
|- | |||
! Index | |||
! Address of VUART object in HV dump | |||
! Description | |||
|- | |||
| 0 | |||
| 0x0060FD20 | |||
| This VUART is connected with the '''VUART 0 (/dev/sc0)''' of LPAR 1 | |||
|- | |||
| 1 | |||
| 0x0060FE20 | |||
| This VUART is connected with the '''VUART 1 (/dev/sc1)''' of LPAR 1 | |||
|- | |||
| 2 | |||
| 0x0060FF20 | |||
| This VUART is not connected to some peer VUART but i guess that it should be connected to '''VUART 2 (/dev/sc2)''' of LPAR1 | |||
|- | |||
| 3 | |||
| 0x006124E0 | |||
| This VUART is connected with the '''VUART 3 (/dev/sc3)''' of LPAR 1 | |||
|- | |||
| 4 | |||
| 0x00612DF0 | |||
| '''lv1_get_rtc''' and '''syscall 0x10036''' communicate with this VUART. | |||
|} | |||
== | == Interrupt Handling == | ||
spider_sc_interrupt_handler - 0x0020A68C (3.15) | |||
== Methods == | |||
sc_vuart_4_get_peer_vuart - 0x002ED384 (3.15) | |||
sc_send - 0x0020A908 (3.15) | |||
sc_receive - 0x0020A354 (3.15) | |||
sc_vuart_rx_trigger_callback - 0x002ED470 (3.15) | |||
== lv1_get_rtc == | |||
''' | *'''lv1_get_rtc''' communicates with SC VUART 4. | ||
''' | *20 bytes are written to the peer VUART of SC VUART 4. | ||
*After a request is sent to SC VUART 4, '''lv1_get_rtc''' busy waits until SC VUART 4 receive data buffer is not empty. | |||
*When SC VUART 4 receive data buffer is not empty, '''lv1_get_rtc''' reads 24 bytes from the VUART. | |||
== SYSCON Protocol == | |||
* I was able to enable SYSCON Manager debug messages in HV Process 5 | |||
* Messages sent to SYSCON are at least '''0x10''' bytes of size. SC VUARTs check it before sending the messages to SYSCON. | |||
* The header size of the SYSCON messages is '''0x10''' bytes. | |||
=== Packet Header === | |||
offset | * Packet header is of size '''0x10''' bytes. | ||
* At offset '''0x6''' of SYSCON packet is the header checksum which is of size '''2''' bytes. | |||
* '''The header checkum is just a sum of first 6 header bytes and 0x8000 constant''' | |||
* The '''2nd byte''' in every SYSCON message has to be '''1''' or else the function '''sc_send''' fails. | |||
* The '''word''' at offset '''0x8''' is the '''SC VUART index'''. | |||
* The '''half-words''' at offset '''0xC''' and '''0xE''' have to be equal or the function '''sc_send''' fails. | |||
<pre> | |||
struct sc_hdr | |||
* | { | ||
* | uint8_t field0; | ||
uint8_t field1; /* always 1 */ | |||
uint8_t field2[4]; | |||
uint16_t cksum; /* header checksum */ | |||
uint32_t index; /* syscon index (0 - /dev/sc0, 1 - /dev/sc1, 2 - /dev/sc2, 3 - /dev/sc3) */ | |||
uint16_t size1; /* body size */ | |||
uint16_t size2; /* body size */ | |||
}; | |||
</pre> | |||
==== | ==== Calculating Packet Header Checksum ==== | ||
<pre> | |||
/* calculating SC packet header checksum */ | |||
* | |||
* | |||
/* | |||
* sc_hdr_cksum | |||
*/ | |||
uint16_t sc_hdr_cksum(struct sc_hdr *sc_hdr) | |||
{ | |||
uint8_t *ptr; | |||
uint32_t sum; | |||
ptr = (uint8_t *) sc_hdr; | |||
sum = 0; | |||
for (i = 0; i < 6; i++) | |||
sum += *ptr++; | |||
= | sum += 0x8000; | ||
return sum & 0xffff; | |||
} | |||
struct sc_hdr sc_hdr; | |||
memset(&sc_hdr, 0, sizeof(sc_hdr)); | |||
sc_hdr.cksum = sc_hdr_cksum(sc_hdr); | |||
/* fill sc header here */ | |||
sc_hdr.cksum = sc_hdr_cksum(sc_hdr); | |||
</pre> | |||
=== Packet Body === | |||
* Packet body follows packet header | |||
* Packet body size is stored at offset '''0xC''' and '''0xE''' in packet header and is of size 2 bytes | |||
=== Reading SYSCON EPROM (NVS Service) === | |||
Here is a command which is sent to SYSCON to read 1 byte of EPROM at offset 0x48C07 (Product Mode): | |||
0x14 <span style="background:#00FF00">0x01</span> 0x00 0x00 0x00 0x00 <span style="background:#FF0000">0x80 0x15</span> <span style="background:#FFFF00">0x00 0x00 0x00 0x00</span> <span style="background:#00FFFF">0x00 0x04</span> <span style="background:#00FFFF">0x00 0x04</span> 0x20 0x02 0x07 0x01 | |||
And here is the response to the above request: | |||
0x14 <span style="background:#00FF00">0x01</span> 0x00 0x00 0x00 0x00 <span style="background:#FF0000">0x80 0x15</span> <span style="background:#FFFF00">0x00 0x00 0x00 0x03</span> <span style="background:#00FFFF">0x00 0x05</span> <span style="background:#00FFFF">0x00 0x05</span> 0x00 0x02 0x07 0x01 0xff | |||
=== | === PCI Bus Power === | ||
* Used by | * '''Used by PS2EMU System Manager in HV process 9 when PS2 EMU is booted''' | ||
==== PCI Bus Power On ==== | |||
'''Request to SC1:''' | |||
0x10 0x01 0x00 0x00 0x00 0x00 0x80 0x11 0x00 0x00 0x00 0x00 0x00 0x02 0x00 0x02 0x31 0x01 | |||
==== | ==== PCI Bus Power Off ==== | ||
'''Request to SC1:''' | |||
0x10 0x01 0x00 0x00 0x00 0x00 0x80 0x11 0x00 0x00 0x00 0x00 0x00 0x02 0x00 0x02 0x31 0x00 | |||
=== Ring Buzzer === | |||
'''Request:''' | |||
0x16 0x01 0x00 0x00 0x00 0x00 0x80 0x17 0x00 0x00 0x00 0x00 0x00 0x08 0x00 0x08 0x20 0x00 0x00 0x00 0x00 0x00 0x00 0x00 | |||
= Gelic Device = | |||
Crossreference: [http://wiki.gitbrew.org/index.php/PS3:HvReverseEngineering#Gelic_Device gitbrew.org::Gelic Device] <br /> | |||
== | ==sys.hw.config== | ||
* | * Value of the loader parameter "sys.hw.config" controls if Gelic WLAN is enabled or not. | ||
* | * Value of the loader parameter "sys.hw.config" is stored in the repository node "sys.hw.config" too. | ||
* If bit '''0x40000''' is set then LV1 allows using Gelic WLAN interface from LV2. | |||
* Value on my PS3 slim '''0x4e00ffff0a03bc3c''' with Gelic WLAN interface disabled. As you can see, the Gelic WLAN interface is disabled and LV1 doesn't allow using of LV1 calls 196 and 195. It returns LV1_CONDITION_NOT_SATISFIED. | |||
* GameOS checks bit '''0x40000''' of the repository node "sys.hw.config" during network initialization and if it's set then LV2 initializes Gelic WLAN interface. | |||
* Check your "sys.hw.config" repository node and if bit '''0x40000''' is set then you are a lucky owner of a PS3 model with the old WLAN interface. | |||
* '''On newer PS3 models, GameOS uses USB interface to communicate with WLAN.''' | |||
* On PS3 models, where bit '''0x40000''' is NOT set in "sys.hw.config" repository node, the new USB interface is used. | |||
''Note:[http://www.ps3devwiki.com/index.php?title=Wifi old vs. new]: Old == CECHA up to CECHK, New == CECHL and later'' | |||
== | == Control Interface == | ||
HV calls 195 and 196 are used by GameOS to send commands to Gelic device directly. | |||
=== lv1_undocumented_function_196 === | |||
==== | ==== Parameters ==== | ||
r3 - LPAR address of data buffer | |||
r4 - size of data buffer | |||
r5 - must be 0 | |||
=== | === lv1_undocumented_function_195 === | ||
==== Parameters ==== | |||
r3 - command (16 bit value) | |||
r4 - command data size | |||
r5 - must be 0 | |||
=== Data Buffer === | |||
* Data Buffer passed to HV call 196 is divided into 2 parts. | |||
* The first 0x800 bytes are for sending and receiving command data | |||
* The remaining 0x800 bytes are for event notification. | |||
=== Command Data Buffer === | |||
* Every command data sent to Gelic device contains header of size '''0xC''' | |||
* After the header follows the command data | |||
* After the Gelic device processed the command, it notifies LV2 kernel about command completion by sending an interrupt | |||
==== Header ==== | |||
* Size is '''0xc'''. | |||
* Byte order is little-endian. | |||
* Header data in a request command buffer is always all 0s. | |||
0x0 - command = request command + 1 (2 bytes) | |||
0x4 - result, 1 - success ??? (2 bytes) | |||
0x6 - body size (2 bytes) | |||
=== | === Event Data Buffer === | ||
* | * The Gelic device notifies LV2 kernel by sending an interrupt when new events are available | ||
* | * Event Data Buffer has 8 bytes header | ||
* The remaining bytes are divided into event slots | |||
* Each event slot is of size 64 bytes | |||
* Events are in little-endian format | |||
==== | ==== Header ==== | ||
offset 0x0 - GET index (4 bytes) | |||
offset 0x4 - PUT index (4 bytes) | |||
* | * GET index is updated by Gelic driver. The Gelic driver reads events beginning with the event slot at index GET. | ||
* | * PUT index is the index of event entry where next Gelic event will be stored by the Gelic device. | ||
* If GET index is equal to PUT index then there are no Gelic events. | |||
=== | === GameOS === | ||
* | * LV2 syscall 726 sends Gelic device command and blocks until a response from the Gelic device arrives | ||
* | * LV2 kernel uses this LV1 interface to send commands to Gelic device internally too, probably for wireless controllers and Wake On WLAN. | ||
* The system call 726 is used heavily by VSH. | |||
==== | ==== Parameters ==== | ||
r3 - command (16 bits) | |||
r4 - effective address of command data buffer | |||
r5 - size of command data buffer | |||
=== | === Commands === | ||
====Unknown (0x1)==== | |||
* Used by VSH. | |||
* Command buffer size is '''0x10''' | |||
====Unknown (0x5)==== | |||
* Used by VSH. | |||
====Unknown (0xf)==== | |||
* Used by VSH. | |||
==== | ====Set AP Channel (0x11)==== | ||
* Used by | * Used by VSH. | ||
* Command buffer size is ''' | * Command buffer size is '''0xd''' | ||
* Valid channels: '''0 - 13'''. '''0''' means that the channel is selected '''automatically'''. | |||
====Set | ====Set AP WEP Configuration (0x5b)==== | ||
* Used by | * Used by VSH. | ||
* | * Sets WEP security type (none, wep64, wep128) and WEP key. | ||
====Unknown (0x61)==== | |||
* Used by VSH. | |||
* Command buffer size is '''0xd''' | |||
====Unknown (0x65)==== | |||
* Used by VSH. | |||
====Get Firmware Version (0x99)==== | |||
* Used by VSH. | |||
Here is the response on my PS3 Slim: | |||
<pre> | |||
00000000: 4a 55 50 49 54 45 52 2d 54 57 4f 2d 46 57 2d 32 |JUPITER-TWO-FW-2| | |||
00000010: 30 2e 30 2e 31 32 2e 70 30 28 4a 61 6e 20 31 39 |0.0.12.p0(Jan 19| | |||
00000020: 20 32 30 31 30 20 32 31 3a 32 30 3a 35 33 29 00 | 2010 21:20:53).| | |||
00000030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |.............. | | |||
</pre> | |||
====Set AP Operating Mode (0xb9)==== | |||
* Used by VSH. | |||
* Command buffer size is '''0x10''' | |||
* Sets operating mode (mixed, 11b or 11g). | |||
====Unknown (0xc5)==== | |||
* Used by VSH. | |||
====Unknown (0xc9)==== | |||
* Used by VSH. | |||
====Unknown (0xcf)==== | |||
* Used by VSH. | |||
* Command buffer size is '''0x10''' | |||
==== | ====Unknown (0xd3)==== | ||
* Used by | * Used by VSH. | ||
* Command buffer is | * Command buffer size is '''0x4c''' | ||
==== | ====Unknown (0xd5)==== | ||
* Used by | * Used by VSH. | ||
* Command buffer size is ''' | * Command buffer size is '''0xd''' | ||
==== | ====Unknown (0x127)==== | ||
* Used by | * Used by VSH. | ||
====Unknown (0x12b)==== | |||
* Used by VSH. | |||
====Unknown (0x17d)==== | |||
* Used by VSH. | |||
* Command buffer size is '''0x2D''' | |||
==== | ====Unknown (0x1bf)==== | ||
* Used by VSH. | * Used by VSH. | ||
* | * Command buffer size is '''0x11''' | ||
====Unknown ( | ====Unknown (0x1d9)==== | ||
* Used by VSH. | * Used by VSH. | ||
* | * Command buffer size is '''0x10''' | ||
==== | ====Unknown (0x1dd)==== | ||
* Used by VSH. | * Used by VSH. | ||
* | * Command buffer size is '''0xd''' | ||
==== | ====Unknown (0x1ed)==== | ||
* Used by VSH. | * Used by VSH. | ||
==== | ====Associate (0x1001)==== | ||
* Used by VSH. | * Used by VSH. | ||
* | * Used by LV1 on FAT models. | ||
* | * Command buffer size is '''0xd''' | ||
* | * Data passed to Gelic device is all 0s | ||
=== | ====Get Common Configuration (0x1003)==== | ||
* Used by VSH. | |||
* Used by LV1 on FAT models. | |||
* Command buffer size is '''0x18''' | |||
* Data passed to Gelic device is all 0s | |||
====Set Common Configuration (0x1005)==== | |||
* Used by VSH. | |||
* Used by LV1 on FAT models. | |||
* Command buffer size is '''0x18''' | |||
====Get WEP Configuration (0x1013)==== | |||
* Used by VSH. | |||
* Used by LV1 on FAT models. | |||
* Command buffer size is '''0x50''' | |||
* Data passed to Gelic device is all 0s | |||
====Set WEP Configuration (0x1015)==== | |||
* Used by VSH. | |||
* Used by LV1 on FAT models. | |||
* Command buffer size is '''0x50''' | |||
====Get WPA Configuration (0x1017)==== | |||
* Used by VSH. | |||
* Used by LV1 on FAT models. | |||
* Command buffer size is '''0x5b''' | |||
* Data passed to Gelic device is all 0s | |||
====Set WPA Configuration (0x1019)==== | |||
* Used by VSH. | |||
* Used by LV1 on FAT models. | |||
* Command buffer size is '''0x5b''' | |||
====Unknown (0x1025)==== | |||
* Used by VSH. | |||
====Unknown (0x1031)==== | |||
* Used by VSH. | |||
* Command buffer size is '''0xe''' | |||
====Get Scan Results (0x1033)==== | |||
* Used by VSH. | |||
* Used by LV1 on FAT models. | |||
* Command buffer size is '''0x5b0''' | |||
* Data passed to Gelic device is all 0s | |||
=====Scan Results Format===== | |||
offset 0x0 - number of results (1 byte) | |||
== | ====Start Scan (0x1035)==== | ||
* | * Used by VSH. | ||
* ''' | * Used by LV1 on FAT models. | ||
* Command buffer size depends on size of channel list and ESSID string length | |||
* Data passed to Gelic device contains channel list and ESSID string | |||
* First '''0x16''' bytes in command data buffer are all 0s, then follows the channel list and after that ESSID | |||
=== | ====Diassociate (0x1037)==== | ||
* | * Used by VSH. | ||
* Used by LV1 on FAT models. | |||
* Command buffer size is '''0xd''' | |||
* | * Data passed to Gelic device is all 0s | ||
* | |||
* | |||
====Get RSSI Configuration (0x103d)==== | |||
* Used by VSH. | |||
* Used by LV1 on FAT models. | |||
* Command buffer size is '''0x17''' | |||
====Set MAC Address (0x1041)==== | |||
* Used by VSH. | |||
* Used by LV1 too. | |||
* Command buffer size is '''0x12''' | |||
====Unknown (0x104d)==== | |||
* Used by VSH. | |||
====Unknown (0x1051)==== | |||
* Used by VSH. | |||
====Unknown (0x1053)==== | |||
* Used by VSH. | |||
====Unknown (0x1059)==== | |||
* Used by VSH. | |||
====Unknown (0x1101)==== | |||
* Used by VSH. | |||
* Not a Gelic device command, handled by LV2 kernel. | |||
* LV2 uses LV1 call '''lv1_net_control(0x8000000000000002)''' | |||
====Unknown (0x1133)==== | |||
* Used by VSH. | |||
====Unknown (0x1139)==== | |||
* Used by LV2 internally. | |||
====Unknown (0x113b)==== | |||
* Used by LV2 internally. | |||
====Unknown (0x113d)==== | |||
* Used by LV2 internally. | |||
====Unknown (0x113f)==== | |||
* Used by LV2 internally. | |||
====Unknown (0x1141)==== | |||
* Used by LV2 internally. | |||
====Unknown (0x1143)==== | |||
* Used by LV2 internally. | |||
====Unknown (0x114b)==== | |||
* Used by LV2 internally. | |||
=== | ====Unknown (0x1155)==== | ||
* LV2 | * Used by LV2 internally. | ||
==== | ====Unknown (0x1157)==== | ||
* Used by LV2 internally. | |||
==== | ====Unknown (0x1159)==== | ||
* | * Used by LV2 internally. | ||
==== | ====Unknown (0x115b)==== | ||
* | * Used by LV2 internally. | ||
==== | ====Unknown (0x115d)==== | ||
* | * Used by LV2 internally. | ||
==== | ====Unknown (0x1161)==== | ||
* LV2 | * Used by LV2 internally. | ||
==== | ====Unknown (0x1163)==== | ||
* | * Used by LV2 internally. | ||
==== | ====Unknown (0x1165)==== | ||
* | * Used by LV2 internally. | ||
==== | ====Unknown (0x1167)==== | ||
* | * Used by LV2 internally. | ||
==== | ====Unknown (0x116d)==== | ||
* | * Used by LV2 internally. | ||
==== | ====Unknown (0x116f)==== | ||
* | * Used by LV2 internally. | ||
==== | ====Get Device Status (0xfffb)==== | ||
* | * Used by VSH. | ||
* Not a Gelic device command, handled by LV2 kernel. | |||
* Returned data size in command buffer is '''0x10'''. | |||
==== | ====Unknown (0xfffc)==== | ||
* | * Used by VSH. | ||
* Not a Gelic device command, handled by LV2 kernel. | |||
* LV2 uses LV1 call '''lv1_net_control(0x1 /* bus id */, 0x0 /* dev id */, 0x6 /* get channel info command */, 0x4, 0x0, 0x0)''' | |||
==== | ====Get Channel Information (0xfffd)==== | ||
* | * Used by VSH. | ||
* Not a Gelic device command, handled by LV2 kernel. | |||
* LV2 uses LV1 call '''lv1_net_control(0x1 /* bus id */, 0x0 /* dev id */, 0x6 /* get channel info command */, 0x0, 0x0, 0x0)''' | |||
* Returns supported WLAN channels | |||
==== | ====Set Response Timeout (0xfffe)==== | ||
* Command ''' | * Used by VSH. | ||
* Not a Gelic device command, handled by LV2 kernel. | |||
* Sets timeout value which is used to wait for a response from Gelic device. | |||
* Typical value used by VSH is '''0x989680'''. | |||
* Command buffer size is '''0x14'''. | |||
==== | ====Unknown (0xffff)==== | ||
* | * Used by VSH. | ||
* Not a Gelic device command, handled by LV2 kernel. | |||
* Returns 0x10 bytes in command buffer. | |||
* Returns gelic device state ??? | |||
===== | === Events === | ||
===== Deauthentication Event ===== | |||
* | * Value 0x40 | ||
===== | ===== Connected Event ===== | ||
* | * Value 0x80 | ||
===== | ===== Device Ready Event ===== | ||
* | * Value 0x80000000 | ||
== | == Enabling WLAN Gelic On FAT == | ||
Linux kernel doesn't use Gelic Device Control Interface like GameOS does it. | |||
To get WLAN working on Linux booted with GameOS rights, we have to disable | |||
Gelic Device Control Interface first because it's enabled for GameOS by default. | |||
The value of repository node "ios.net.eurus.lpar" controls access to Gelic Device Control Interface. | |||
It's a bitmap. The position of a bit corresponds to LPAR id. During GameOS booting, HV process 9 (System Manager) sets bit at postion 2 to 1 which means enable Gelic Device Control Interface for LPAR 2. | |||
To disable Gelic Device Control Interface on Linux, first unload Gelic device driver, then set | |||
value of repository node "ios.net.eurus.lpar" to 0 and load Gelic device driver again. After that WLAN should work again but only on FATs. | |||
For PS3 Slim we need a new Linux Gelic device driver which uses Gelic Device Control Interface directly. | |||
==USB WLAN Interface (Codename Jupiter 2)== | |||
* On new PS3 models, WLAN interface is USB. | |||
* '''Good news is that the same commands are used as with LV1 calls 196 and 195'''. | |||
* There are 2 wireless devices: Station and AP. | |||
* I got WLAN scan working. | |||
===Endpoints=== | |||
* LV2 uses 3 USB endpoints of interface 3 to communicate with WLAN. | |||
* Endpoints EP5 IN/OUT, EP6 IN/OUT and EP7 IN/OUT. | |||
* '''WLAN commands''' are sent to endpoint '''EP5 OUT''' with '''interrupt transfers'''. | |||
* '''WLAN events''' and '''WLAN command responses''' are received on endpoint '''EP5 IN''' with '''interrupt transfers'''. | |||
* LV2 opens a USB communication pipe to endpoint EP5 IN and EP5 OUT. | |||
* In my LV2 3.55 dump, pipe to EP5 IN has id '''0x2''' and pipe to EP5 OUT has id '''0x3'''. Array of all opened USB pipes is at address '''0x80000000004bd000''' in my LV2 3.55 dump. | |||
* EP5 is used to send commands to Jupiter and receive events from it. | |||
* EP6 is used to send/receive data packets to/from the 1st WLAN device. | |||
* EP7 is used to send/receive data packets to/from the 2nd WLAN device. | |||
<pre> | |||
Bus 002 Device 002: ID 054c:036f Sony Corp. | |||
Device Descriptor: | |||
bLength 18 | |||
bDescriptorType 1 | |||
bcdUSB 2.00 | |||
bDeviceClass 224 Wireless | |||
bDeviceSubClass 1 Radio Frequency | |||
bDeviceProtocol 1 Bluetooth | |||
bMaxPacketSize0 64 | |||
idVendor 0x054c Sony Corp. | |||
idProduct 0x036f | |||
bcdDevice 20.12 | |||
iManufacturer 1 | |||
iProduct 2 | |||
iSerial 0 | |||
bNumConfigurations 1 | |||
Interface Descriptor: | |||
bLength 9 | |||
bDescriptorType 4 | |||
bInterfaceNumber 3 | |||
bAlternateSetting 0 | |||
bNumEndpoints 2 | |||
bInterfaceClass 255 Vendor Specific Class | |||
bInterfaceSubClass 2 | |||
bInterfaceProtocol 1 | |||
iInterface 0 | |||
Endpoint Descriptor: | |||
bLength 7 | |||
bDescriptorType 5 | |||
bEndpointAddress 0x85 EP 5 IN | |||
bmAttributes 3 | |||
Transfer Type Interrupt | |||
Synch Type None | |||
Usage Type Data | |||
wMaxPacketSize 0x4000 1x 0 bytes | |||
bInterval 1 | |||
Endpoint Descriptor: | |||
bLength 7 | |||
bDescriptorType 5 | |||
bEndpointAddress 0x05 EP 5 OUT | |||
bmAttributes 3 | |||
Transfer Type Interrupt | |||
Synch Type None | |||
Usage Type Data | |||
wMaxPacketSize 0x4000 1x 0 bytes | |||
bInterval 1 | |||
Interface Descriptor: | |||
bLength 9 | |||
bDescriptorType 4 | |||
bInterfaceNumber 4 | |||
bAlternateSetting 0 | |||
bNumEndpoints 2 | |||
bInterfaceClass 255 Vendor Specific Class | |||
bInterfaceSubClass 2 | |||
bInterfaceProtocol 2 | |||
iInterface 0 | |||
Endpoint Descriptor: | |||
bLength 7 | |||
bDescriptorType 5 | |||
bEndpointAddress 0x86 EP 6 IN | |||
bmAttributes 2 | |||
Transfer Type Bulk | |||
Synch Type None | |||
Usage Type Data | |||
wMaxPacketSize 0x0002 1x 2 bytes | |||
bInterval 0 | |||
Endpoint Descriptor: | |||
bLength 7 | |||
bDescriptorType 5 | |||
bEndpointAddress 0x06 EP 6 OUT | |||
bmAttributes 2 | |||
Transfer Type Bulk | |||
Synch Type None | |||
Usage Type Data | |||
wMaxPacketSize 0x0002 1x 2 bytes | |||
bInterval 255 | |||
Interface Descriptor: | |||
bLength 9 | |||
bDescriptorType 4 | |||
bInterfaceNumber 5 | |||
bAlternateSetting 0 | |||
bNumEndpoints 2 | |||
bInterfaceClass 255 Vendor Specific Class | |||
bInterfaceSubClass 2 | |||
bInterfaceProtocol 3 | |||
iInterface 0 | |||
Endpoint Descriptor: | |||
bLength 7 | |||
bDescriptorType 5 | |||
bEndpointAddress 0x87 EP 7 IN | |||
bmAttributes 2 | |||
Transfer Type Bulk | |||
Synch Type None | |||
Usage Type Data | |||
wMaxPacketSize 0x0002 1x 2 bytes | |||
bInterval 0 | |||
Endpoint Descriptor: | |||
bLength 7 | |||
bDescriptorType 5 | |||
bEndpointAddress 0x07 EP 7 OUT | |||
bmAttributes 2 | |||
Transfer Type Bulk | |||
Synch Type None | |||
Usage Type Data | |||
wMaxPacketSize 0x0002 1x 2 bytes | |||
bInterval 255 | |||
</pre> | |||
===Device Initialization=== | |||
* LV2 does 2 control transfers to EP0 during WLAN initialization | |||
* First control transfer sends magic '''0x20''' data to device as '''CLEAR_FEATURE''' request. | |||
* Second control transfer reads '''0x2''' bytes device status. On my PS3 slim, the status data is always '''0x2031''' if you send the right magic. | |||
* Magic data sent in first control transfer is stored in LV2. | |||
* '''If you send wrong magic, the first control transfer will fail !!!''' | |||
* LV2 uses a state machine to initialize the Jupiter device. The state machine has 17 states. | |||
==== Magic Data in Control Transfer ==== | |||
<pre> | |||
unsigned char ps3_usb_wlan_magic_data[] = { | |||
0x76, 0x4e, 0x4b, 0x07, 0x24, 0x42, 0x53, 0xfb, 0x5a, 0xc7, 0xcc, 0x1d, 0xae, 0x00, 0xc6, 0xd8, | |||
0x14, 0x40, 0x61, 0x8b, 0x13, 0x17, 0x4d, 0x7c, 0x3b, 0xb6, 0x90, 0xb8, 0x6e, 0x8b, 0xbb, 0x1d, | |||
}; | |||
</pre> | |||
==== Initialization State Machine ==== | |||
* Implemented in LV2. | |||
=====State 1===== | |||
* Command '''0x114f''' is sent to WLAN device. | |||
=====State 2===== | |||
* Command '''0x1171''' is sent to WLAN device. | |||
=====State 3===== | |||
* LV2 waits for an event from WLAN device. | |||
=====State 4===== | |||
* Command '''0x116f''' is sent to WLAN device. | |||
=====State 5===== | |||
* Command '''0x115b''' is sent to WLAN device. | |||
* Command data sent to WLAN device contains MAC address. | |||
=====State 6===== | |||
* Command '''0x1161''' is sent to WLAN device. | |||
=====State 7===== | |||
* Command '''0x110d''' is sent to WLAN device. | |||
=====State 8===== | |||
* Command '''0x1031''' is sent to WLAN device. | |||
=====State 9===== | |||
* Command '''0x1041''' is sent to WLAN device. | |||
* Command data sent to WLAN device contains MAC address. | |||
=====State 10===== | |||
* Command '''0x29''' is sent to WLAN device. | |||
=====State 11===== | |||
* Command '''0x110b''' is sent to WLAN device. | |||
=====State 12===== | |||
* Command '''0x1109''' is sent to WLAN device. | |||
=====State 13===== | |||
* Command '''0x207''' is sent to WLAN device. | |||
=====State 14===== | |||
* Command '''0x203''' is sent to WLAN device. | |||
=====State 15===== | |||
* Command '''0x105f''' is sent to WLAN device. | |||
* Command data sent to WLAN device contains MAC address, channel info and region code. | |||
=====State 16===== | |||
* LV2 waits for an event from WLAN device. | |||
=====State 17===== | |||
* LV2 accepts commands sent by LV2 syscall 726. | |||
===Test Program=== | |||
* Here is a small program which executes a WLAN scan. | |||
* I used libusb. | |||
====Source Code==== | |||
<pre> | |||
/* | |||
* PS3 USB WLAN | |||
* | |||
* Copyright (C) 2011 glevand ([email protected]) | |||
* All rights reserved. | |||
* | |||
* This program is free software; you can redistribute it and/or modify it | |||
* under the terms of the GNU General Public License as published | |||
* by the Free Software Foundation; version 2 of the License. | |||
* | |||
* This program is distributed in the hope that it will be useful, but | |||
* WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU General Public License along | |||
* with this program; if not, write to the Free Software Foundation, Inc., | |||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |||
*/ | |||
#include <stdio.h> | |||
#include <stdlib.h> | |||
#include <string.h> | |||
#include <ctype.h> | |||
#include <stdint.h> | |||
#include <unistd.h> | |||
#include <pthread.h> | |||
#include <libusb-1.0/libusb.h> | |||
#define USB_VENDOR_ID 0x054c /* $ONY */ | |||
#define USB_PRODUCT_ID 0x036f | |||
#define USB_IFACE_NUMBER 3 | |||
#define USB_INTR_TRANSFER_EP5_IN_BUF_SIZE 0x800 | |||
#define USB_INTR_TRANSFER_EP5_OUT_BUF_SIZE 0x800 | |||
struct wlan_cmd_pkt_hdr { | |||
uint8_t unknown1; | |||
uint8_t unknown2; | |||
uint8_t unknown3; | |||
uint8_t unknown4; | |||
uint16_t unknown5; | |||
uint8_t res1[2]; | |||
uint16_t tag; | |||
uint8_t res2[14]; | |||
} __attribute__ ((packed)); | |||
struct wlan_cmd_hdr { | |||
uint16_t command; | |||
uint16_t tag; | |||
uint16_t status; | |||
uint16_t payload_size; | |||
uint8_t res[4]; | |||
} __attribute__ ((packed)); | |||
struct wlan_event_pkt_hdr { | |||
uint8_t unknown1; | |||
uint8_t unknown2; | |||
uint8_t unknown3; | |||
uint8_t event_count; | |||
} __attribute__ ((packed)); | |||
static libusb_context *usb_ctx; | |||
static libusb_device_handle *usb_dev_handle; | |||
static struct libusb_transfer *usb_intr_transfer_ep5_in; | |||
static unsigned char usb_intr_transfer_ep5_in_buf[USB_INTR_TRANSFER_EP5_IN_BUF_SIZE]; | |||
static unsigned char usb_intr_transfer_ep5_out_buf[USB_INTR_TRANSFER_EP5_OUT_BUF_SIZE]; | |||
static pthread_mutex_t usb_wlan_cmd_mutex; | |||
static pthread_cond_t usb_wlan_cmd_cond; | |||
static int volatile usb_wlan_cmd_busy; | |||
static uint16_t usb_wlan_cmd; | |||
static void *usb_wlan_cmd_data; | |||
static int volatile usb_wlan_cmd_thread_done; | |||
/* | |||
* WLAN won't work without this magic !!! | |||
*/ | |||
static unsigned char usb_magic_data[] = { | |||
0x76, 0x4e, 0x4b, 0x07, 0x24, 0x42, 0x53, 0xfb, 0x5a, 0xc7, 0xcc, 0x1d, 0xae, 0x00, 0xc6, 0xd8, | |||
0x14, 0x40, 0x61, 0x8b, 0x13, 0x17, 0x4d, 0x7c, 0x3b, 0xb6, 0x90, 0xb8, 0x6e, 0x8b, 0xbb, 0x1d, | |||
}; | |||
static unsigned char my_mac_addr[] = { | |||
0x00, 0x11, 0x22, 0x33, 0x44, 0x55, | |||
}; | |||
/* | /* | ||
* | * hexdump | ||
*/ | */ | ||
static int | static void hexdump(const unsigned char *data, unsigned int data_size) | ||
{ | { | ||
int i, j; | |||
for (i = 0; i < data_size; i += 16) { | |||
fprintf(stdout, "%08x:", i); | |||
for (j = 0; j < 16; j++) { | |||
if (i + j < data_size) { | |||
fprintf(stdout, " %02x", data[i + j]); | |||
} else { | |||
fprintf(stdout, " "); | |||
} | |||
} | |||
fprintf(stdout, " |"); | |||
for (j = 0; j < 16; j++) { | |||
if (i + j < data_size) { | |||
if (isprint(data[i + j])) | |||
fprintf(stdout, "%c", data[i + j]); | |||
else | |||
fprintf(stdout, "."); | |||
} else { | |||
fprintf(stdout, " "); | |||
} | |||
} | |||
fprintf(stdout, "|\n"); | |||
} | |||
} | } | ||
/* | /* | ||
* | * usb_handle_wlan_event | ||
*/ | */ | ||
static | static void usb_handle_wlan_event(struct wlan_event_pkt_hdr *wlan_event_pkt_hdr) | ||
{ | { | ||
fprintf(stdout, "%s:%d: === got WLAN event ===\n", __func__, __LINE__); | |||
/* | |||
fprintf(stdout, "%s:%d: event packet header:\n", __func__, __LINE__); | |||
fprintf(stdout, "%s:%d: unknown1 (0x%02x)\n", __func__, __LINE__, | |||
wlan_event_pkt_hdr->unknown1); | |||
fprintf(stdout, "%s:%d: unknown2 (0x%02x)\n", __func__, __LINE__, | |||
wlan_event_pkt_hdr->unknown2); | |||
fprintf(stdout, "%s:%d: unknown3 (0x%02x)\n", __func__, __LINE__, | |||
wlan_event_pkt_hdr->unknown3); | |||
*/ | |||
fprintf(stdout, "%s:%d: event_count (0x%02x)\n", __func__, __LINE__, | |||
wlan_event_pkt_hdr->event_count); | |||
hexdump((unsigned char *) (wlan_event_pkt_hdr + 1), wlan_event_pkt_hdr->event_count * 64); | |||
} | } | ||
/* | /* | ||
* | * usb_handle_wlan_cmd_response | ||
*/ | */ | ||
static | static void usb_handle_wlan_cmd_response(struct wlan_cmd_pkt_hdr *wlan_cmd_pkt_hdr) | ||
{ | { | ||
struct wlan_cmd_hdr *wlan_cmd_hdr; | |||
uint8_t *wlan_cmd_payload; | |||
fprintf(stdout, "%s:%d: === got WLAN command response ===\n", __func__, __LINE__); | |||
wlan_cmd_hdr = (struct wlan_cmd_hdr *) (wlan_cmd_pkt_hdr + 1); | |||
wlan_cmd_payload = (uint8_t *) (wlan_cmd_hdr + 1); | |||
/* convert all header fields to big-endian byte order !!! */ | |||
wlan_cmd_pkt_hdr->unknown5 = le16toh(wlan_cmd_pkt_hdr->unknown5); | |||
wlan_cmd_pkt_hdr->tag = le16toh(wlan_cmd_pkt_hdr->tag); /* returned from request */ | |||
/* | wlan_cmd_hdr->command = le16toh(wlan_cmd_hdr->command); /* request command + 1 */ | ||
wlan_cmd_hdr->tag = le16toh(wlan_cmd_hdr->tag); /* returned from request */ | |||
wlan_cmd_hdr->status = le16toh(wlan_cmd_hdr->status); /* 1 - success | |||
2 - invalid parameters ??? | |||
3 - invalid command ??? */ | |||
wlan_cmd_hdr->payload_size = le16toh(wlan_cmd_hdr->payload_size); /* length of data that follows the header */ | |||
/* | |||
fprintf(stdout, "%s:%d: command packet header:\n", __func__, __LINE__); | |||
fprintf(stdout, "%s:%d: unknown1 (0x%02x)\n", __func__, __LINE__, | |||
wlan_cmd_pkt_hdr->unknown1); | |||
fprintf(stdout, "%s:%d: unknown2 (0x%02x)\n", __func__, __LINE__, | |||
wlan_cmd_pkt_hdr->unknown2); | |||
fprintf( | fprintf(stdout, "%s:%d: unknown3 (0x%02x)\n", __func__, __LINE__, | ||
wlan_cmd_pkt_hdr->unknown3); | |||
fprintf(stdout, "%s:%d: unknown4 (0x%02x)\n", __func__, __LINE__, | |||
wlan_cmd_pkt_hdr->unknown4); | |||
fprintf(stdout, "%s:%d: unknown5 (0x%04x)\n", __func__, __LINE__, | |||
wlan_cmd_pkt_hdr->unknown5); | |||
fprintf(stdout, "%s:%d: tag (0x%04x)\n", __func__, __LINE__, | |||
wlan_cmd_pkt_hdr->tag); | |||
*/ | |||
fprintf(stdout, "%s:%d: command header:\n", __func__, __LINE__); | |||
fprintf(stdout, "%s:%d: command (0x%04x)\n", __func__, __LINE__, | |||
wlan_cmd_hdr->command); | |||
if ((usb_wlan_cmd + 1) != wlan_cmd_hdr->command) | |||
fprintf(stdout, "%s:%d: ==> command does not match, got (0x%04x) expected (0x%04x)\n", | |||
__func__, __LINE__, wlan_cmd_hdr->command, usb_wlan_cmd + 1); | |||
fprintf(stdout, "%s:%d: tag (0x%04x)\n", __func__, __LINE__, | |||
wlan_cmd_hdr->tag); | |||
fprintf(stdout, "%s:%d: status (0x%04x)\n", __func__, __LINE__, | |||
wlan_cmd_hdr->status); | |||
if (wlan_cmd_hdr->status != 0x1) | |||
fprintf(stdout, "%s:%d: ==> command status != 0x1\n", __func__, __LINE__); | |||
fprintf(stdout, "%s:%d: payload_size (0x%04x)\n", __func__, __LINE__, | |||
wlan_cmd_hdr->payload_size); | |||
fprintf(stdout, "%s:%d: command payload:\n", __func__, __LINE__); | |||
hexdump(wlan_cmd_payload, wlan_cmd_hdr->payload_size); | |||
memcpy(usb_wlan_cmd_data, wlan_cmd_payload, wlan_cmd_hdr->payload_size); | |||
pthread_mutex_lock(&usb_wlan_cmd_mutex); | |||
usb_wlan_cmd_busy = 0; | |||
pthread_cond_signal(&usb_wlan_cmd_cond); | |||
pthread_mutex_unlock(&usb_wlan_cmd_mutex); | |||
} | |||
/* | |||
* usb_intr_transfer_ep5_in_cb | |||
*/ | |||
static void usb_intr_transfer_ep5_in_cb(struct libusb_transfer *transfer) | |||
{ | |||
struct wlan_cmd_pkt_hdr *wlan_cmd_pkt_hdr; | |||
int error; | |||
fprintf(stdout, "%s:%d: === got interrupt transfer ===\n", __func__, __LINE__); | |||
fprintf(stdout, "%s:%d: transfer status (%d) length (%d)\n", | |||
__func__, __LINE__, transfer->status, transfer->actual_length); | |||
wlan_cmd_pkt_hdr = (struct wlan_cmd_pkt_hdr *) transfer->buffer; | |||
if (wlan_cmd_pkt_hdr->unknown3 == 0x6) | |||
usb_handle_wlan_cmd_response(wlan_cmd_pkt_hdr); | |||
else if (wlan_cmd_pkt_hdr->unknown3 == 0x8) | |||
usb_handle_wlan_event((struct wlan_event_pkt_hdr *) transfer->buffer); | |||
else | |||
fprintf(stdout, "%s:%d: got unknown packet (0x%02x)\n", | |||
__func__, __LINE__, wlan_cmd_pkt_hdr->unknown3); | |||
memset(usb_intr_transfer_ep5_in_buf, 0, sizeof(usb_intr_transfer_ep5_in_buf)); | |||
libusb_fill_interrupt_transfer(usb_intr_transfer_ep5_in, usb_dev_handle, LIBUSB_ENDPOINT_IN | 0x5, | |||
usb_intr_transfer_ep5_in_buf, sizeof(usb_intr_transfer_ep5_in_buf), | |||
usb_intr_transfer_ep5_in_cb, NULL, 0); | |||
error = libusb_submit_transfer(usb_intr_transfer_ep5_in); | |||
error = | |||
if (error) { | if (error) { | ||
fprintf(stderr, "%s:%d: could not | fprintf(stderr, "%s:%d: could not submit transfer (%d)\n", | ||
__func__, __LINE__, error); | __func__, __LINE__, error); | ||
exit(1); | |||
} | } | ||
} | |||
/* | |||
* usb_intr_transfer_ep5_out_cb | |||
*/ | |||
static void usb_intr_transfer_ep5_out_cb(struct libusb_transfer *transfer) | |||
{ | |||
/* | |||
fprintf(stdout, "%s:%d: sent interrupt transfer\n", __func__, __LINE__); | |||
fprintf(stdout, "%s:%d: transfer status (%d)\n", __func__, __LINE__, transfer->status); | |||
*/ | |||
libusb_free_transfer(transfer); | |||
} | |||
/* | |||
* usb_wlan_cmd_send | |||
*/ | |||
static int usb_wlan_cmd_send(uint16_t command, const uint8_t *data, unsigned int data_size) | |||
{ | |||
struct wlan_cmd_pkt_hdr *wlan_cmd_pkt_hdr; | |||
struct wlan_cmd_hdr *wlan_cmd_hdr; | |||
uint8_t *wlan_cmd_payload; | |||
struct libusb_transfer *transfer; | |||
int error; | |||
fprintf(stdout, "%s:%d: sending command (0x%04x) data size (0x%04x) command size (0x%04x)\n", | |||
__func__, __LINE__, command, data_size, data_size + sizeof(struct wlan_cmd_hdr)); | |||
transfer = libusb_alloc_transfer(0); | |||
if (!transfer) { | |||
fprintf(stderr, "%s:%d: could not allocate transfer\n", __func__, __LINE__); | |||
if ( | error = -1; | ||
fprintf(stderr, "%s:%d: could not | goto fail; | ||
} | } | ||
wlan_cmd_pkt_hdr = (struct wlan_cmd_pkt_hdr *) usb_intr_transfer_ep5_out_buf; | |||
wlan_cmd_hdr = (struct wlan_cmd_hdr *) (wlan_cmd_pkt_hdr + 1); | |||
wlan_cmd_payload = (uint8_t *) (wlan_cmd_hdr + 1); | |||
wlan_cmd_pkt_hdr->unknown1 = 0x1; | |||
wlan_cmd_pkt_hdr->unknown2 = 0x1; | |||
wlan_cmd_pkt_hdr->unknown3 = 0x6; | |||
wlan_cmd_pkt_hdr->unknown4 = 0x0; | |||
wlan_cmd_pkt_hdr->unknown5 = 0x1; | |||
wlan_cmd_pkt_hdr->tag = 0xf00d; /* returned in response */ | |||
wlan_cmd_hdr->command = command; | |||
wlan_cmd_hdr->tag = 0xcafe; /* returned in response */ | |||
wlan_cmd_hdr->status = 0xa; | |||
wlan_cmd_hdr->payload_size = data_size; | |||
data_size | memcpy(wlan_cmd_payload, data, data_size); | ||
usb_wlan_cmd = command; | |||
usb_wlan_cmd_data = (void *) data; | |||
libusb_fill_interrupt_transfer(transfer, usb_dev_handle, LIBUSB_ENDPOINT_OUT | 0x5, | |||
usb_intr_transfer_ep5_out_buf, | |||
sizeof(struct wlan_cmd_pkt_hdr) + sizeof(struct wlan_cmd_hdr) + wlan_cmd_hdr->payload_size, | |||
usb_intr_transfer_ep5_out_cb, NULL, 0); | |||
/* convert all header fields to little-endian byte order !!! */ | |||
wlan_cmd_pkt_hdr->unknown5 = htole16(wlan_cmd_pkt_hdr->unknown5); | |||
wlan_cmd_pkt_hdr->tag = htole16(wlan_cmd_pkt_hdr->tag); | |||
wlan_cmd_hdr->command = htole16(wlan_cmd_hdr->command); | |||
wlan_cmd_hdr->tag = htole16(wlan_cmd_hdr->tag); | |||
wlan_cmd_hdr->status = htole16(wlan_cmd_hdr->status); | |||
wlan_cmd_hdr->payload_size = htole16(wlan_cmd_hdr->payload_size); | |||
error = | error = libusb_submit_transfer(transfer); | ||
if (error) { | if (error) { | ||
fprintf(stderr, "%s:%d: could not | fprintf(stderr, "%s:%d: could not submit transfer (%d)\n", | ||
__func__, __LINE__, error); | __func__, __LINE__, error); | ||
goto fail_free_transfer; | |||
} | } | ||
pthread_mutex_lock(&usb_wlan_cmd_mutex); | |||
usb_wlan_cmd_busy = 1; | |||
while (usb_wlan_cmd_busy) | |||
pthread_cond_wait(&usb_wlan_cmd_cond, &usb_wlan_cmd_mutex); | |||
pthread_mutex_unlock(&usb_wlan_cmd_mutex); | |||
return 0; | |||
fail_free_transfer: | |||
libusb_free_transfer(transfer); | |||
fail: | |||
return error; | |||
} | |||
/* | |||
* usb_wlan_cmd_start_scan | |||
*/ | |||
static int usb_wlan_cmd_start_scan(void) | |||
{ | |||
unsigned char data[256], *ptr; | |||
unsigned int data_size; | |||
memset(data, 0, sizeof(data)); | memset(data, 0, sizeof(data)); | ||
ptr = data; | ptr = data; | ||
*ptr++ = 0x0; | |||
*ptr++ = 0x1; | |||
*ptr++ = 0x64; | |||
*ptr++ = 0x0; | |||
ptr = data + 0xa; | |||
*ptr++ = | *ptr++ = 0x3; | ||
*ptr++ = 13; /* number of channels */ | |||
*ptr++ = 1; /* channels */ | |||
*ptr++ = 2; | |||
*ptr++ = 3; | |||
*ptr++ = 4; | |||
*ptr++ = 5; | |||
*ptr++ = 6; | |||
*ptr++ = 7; | |||
*ptr++ = 8; | |||
*ptr++ = 9; | |||
*ptr++ = 10; | |||
*ptr++ = 11; | |||
*ptr++ = 12; | |||
*ptr++ = 13; | |||
data_size = ptr - data; | |||
return usb_wlan_cmd_send(0x1035, data, data_size); | |||
} | |||
/* | |||
* usb_wlan_cmd_get_scan_results | |||
*/ | |||
static int usb_wlan_cmd_get_scan_results(void) | |||
{ | |||
unsigned char data[1456]; | |||
unsigned int data_size; | |||
memset(data, 0, sizeof(data)); | memset(data, 0, sizeof(data)); | ||
data_size = sizeof(data); | |||
return usb_wlan_cmd_send(0x1033, data, data_size); | |||
} | |||
/* | |||
* usb_wlan_cmd_0x99 | |||
*/ | |||
static int usb_wlan_cmd_0x99(void) | |||
{ | |||
unsigned char data[0x3e]; | |||
unsigned int data_size; | |||
memset(data, 0, sizeof(data)); | |||
data_size = | data_size = sizeof(data); | ||
return usb_wlan_cmd_send(0x99, data, data_size); | |||
} | |||
/* | |||
* usb_wlan_init | |||
*/ | |||
static int usb_wlan_init(void) | |||
{ | |||
unsigned char data[1456], *ptr; | |||
unsigned int data_size; | |||
int error; | |||
/* state 0x1 */ | |||
memset(data, 0, sizeof(data)); | |||
data_size = 0x518; | |||
error = usb_wlan_cmd_send(0x114f, data, data_size); | |||
if (error) { | |||
fprintf(stderr, "%s:%d: could not send command 0x114f (%d)\n", | |||
__func__, __LINE__, error); | |||
return error; | |||
} | |||
sleep(2); | |||
* | /* state 0x2 */ | ||
memset(data, 0, sizeof(data)); | |||
data_size = 0; | |||
error = usb_wlan_cmd_send(0x1171, data, data_size); | |||
error = usb_wlan_cmd_send( | |||
if (error) { | if (error) { | ||
fprintf(stderr, "%s:%d: could not send command | fprintf(stderr, "%s:%d: could not send command 0x1171 (%d)\n", | ||
__func__, __LINE__, error); | __func__, __LINE__, error); | ||
return error; | return error; | ||
Line 7,904: | Line 8,696: | ||
sleep(2); | sleep(2); | ||
/* wait for a WLAN event */ | |||
/* state 0x4 */ | |||
memset(data, 0, sizeof(data)); | memset(data, 0, sizeof(data)); | ||
Line 7,913: | Line 8,709: | ||
data_size = 0x4; | data_size = 0x4; | ||
error = usb_wlan_cmd_send( | error = usb_wlan_cmd_send(0x116f, data, data_size); | ||
if (error) { | if (error) { | ||
fprintf(stderr, "%s:%d: could not send command | fprintf(stderr, "%s:%d: could not send command 0x116f (%d)\n", | ||
__func__, __LINE__, error); | __func__, __LINE__, error); | ||
return error; | return error; | ||
Line 7,921: | Line 8,717: | ||
sleep(2); | sleep(2); | ||
/* state 0x5 */ | |||
memset(data, 0, sizeof(data)); | memset(data, 0, sizeof(data)); | ||
Line 7,926: | Line 8,724: | ||
ptr = data; | ptr = data; | ||
*ptr++ = 0x4; | *ptr++ = 0x1; | ||
ptr = data + 0x4; | |||
memcpy(ptr, my_mac_addr, sizeof(my_mac_addr)); | |||
data_size = | data_size = 0x5e; | ||
error = usb_wlan_cmd_send( | error = usb_wlan_cmd_send(0x115b, data, data_size); | ||
if (error) { | if (error) { | ||
fprintf(stderr, "%s:%d: could not send command | fprintf(stderr, "%s:%d: could not send command 0x115b (%d)\n", | ||
__func__, __LINE__, error); | __func__, __LINE__, error); | ||
return error; | return error; | ||
Line 7,939: | Line 8,740: | ||
sleep(2); | sleep(2); | ||
/* state | /* state 0x6 */ | ||
memset(data, 0, sizeof(data)); | memset(data, 0, sizeof(data)); | ||
ptr = data; | ptr = data + 0x1c; | ||
*ptr++ = | *ptr++ = 0x20; | ||
data_size = 0x20; | |||
error = usb_wlan_cmd_send(0x1161, data, data_size); | |||
error = usb_wlan_cmd_send( | |||
if (error) { | if (error) { | ||
fprintf(stderr, "%s:%d: could not send command | fprintf(stderr, "%s:%d: could not send command 0x1161 (%d)\n", | ||
__func__, __LINE__, error); | __func__, __LINE__, error); | ||
return error; | return error; | ||
} | } | ||
sleep(2); | |||
memset(data, 0, sizeof(data)); | |||
ptr = data + 0xc; | |||
memset(ptr, 0xff, 7 * 4); | |||
data_size = 0x80; | |||
error = | error = usb_wlan_cmd_send(0x110d, data, data_size); | ||
if (error) { | if (error) { | ||
fprintf(stderr, "%s:%d: could not | fprintf(stderr, "%s:%d: could not send command 0x110d (%d)\n", | ||
__func__, __LINE__, error); | __func__, __LINE__, error); | ||
return error; | |||
} | } | ||
error = | sleep(2); | ||
memset(data, 0, sizeof(data)); | |||
data_size = 0x2; | |||
error = usb_wlan_cmd_send(0x1031, data, data_size); | |||
if (error) { | if (error) { | ||
fprintf(stderr, "%s:%d: could not | fprintf(stderr, "%s:%d: could not send command 0x1031 (%d)\n", | ||
__func__, __LINE__, error); | __func__, __LINE__, error); | ||
return error; | |||
} | } | ||
sleep( | sleep(2); | ||
memset(data, 0, sizeof(data)); | |||
ptr = data; | |||
memcpy(ptr, my_mac_addr, sizeof(my_mac_addr)); | |||
data_size = 0x6; | |||
error = | error = usb_wlan_cmd_send(0x1041, data, data_size); | ||
if (error) { | if (error) { | ||
fprintf(stderr, "%s:%d: could not | fprintf(stderr, "%s:%d: could not send command 0x1041 (%d)\n", | ||
__func__, __LINE__, error); | __func__, __LINE__, error); | ||
return error; | |||
} | } | ||
sleep( | sleep(2); | ||
/* state 0xa */ | |||
memset(data, 0, sizeof(data)); | |||
ptr = data; | |||
*ptr++ = 0x2; | |||
*ptr++ = 0x2; | |||
data_size = 0x2; | |||
error = | error = usb_wlan_cmd_send(0x29, data, data_size); | ||
if (error) { | if (error) { | ||
fprintf(stderr, "%s:%d: | fprintf(stderr, "%s:%d: could not send command 0x29 (%d)\n", | ||
__func__, __LINE__, error); | |||
return error; | |||
} | } | ||
sleep(2); | |||
memset(data, 0, sizeof(data)); | |||
ptr = data; | |||
*ptr++ = 0x1; | |||
ptr = data + 8; | |||
*ptr++ = 0x20; | |||
data_size = 0xc; | |||
error = | error = usb_wlan_cmd_send(0x110b, data, data_size); | ||
if (error) { | if (error) { | ||
fprintf(stderr, "%s:%d: could not | fprintf(stderr, "%s:%d: could not send command 0x110b (%d)\n", | ||
__func__, __LINE__, error); | __func__, __LINE__, error); | ||
return error; | |||
} | } | ||
sleep(2); | |||
memset(data, 0, sizeof(data)); | |||
ptr = data; | |||
*ptr++ = 0x1; | |||
ptr = data + 0x4; | |||
*ptr++ = 0x15; | |||
*ptr++ = 0x27; | |||
*ptr++ = 0x12; | |||
*ptr++ = 0x0; | |||
*ptr++ = 0x6; | |||
*ptr++ = 0x0; | |||
ptr = data + 0xc; | |||
*ptr++ = 0x9; | |||
*ptr++ = 0x0; | |||
*ptr++ = 0x1; | |||
ptr = data + 0x10; | |||
*ptr++ = 0xff; | |||
*ptr++ = 0xff; | |||
*ptr++ = 0xff; | |||
*ptr++ = 0xff; | |||
*ptr++ = 0xff; | |||
*ptr++ = 0xff; | |||
data_size = 0x16; | |||
error = | error = usb_wlan_cmd_send(0x1109, data, data_size); | ||
if (error) { | if (error) { | ||
fprintf(stderr, "%s:%d: could not | fprintf(stderr, "%s:%d: could not send command 0x1109 (%d)\n", | ||
__func__, __LINE__, error); | __func__, __LINE__, error); | ||
return error; | |||
} | } | ||
sleep(2); | |||
memset(data, 0, sizeof(data)); | |||
ptr = data; | |||
*ptr++ = 0x1; | |||
data_size = 0x4; | |||
error = usb_wlan_cmd_send(0x207, data, data_size); | |||
if (error) { | |||
fprintf(stderr, "%s:%d: could not send command 0x207 (%d)\n", | |||
__func__, __LINE__, error); | |||
return error; | |||
} | |||
sleep(2); | |||
memset(data, 0, sizeof(data)); | |||
ptr = data; | |||
*ptr++ = 0x4; | |||
data_size = 0x4; | |||
error = usb_wlan_cmd_send(0x203, data, data_size); | |||
if (error) { | |||
fprintf(stderr, "%s:%d: could not send command 0x203 (%d)\n", | |||
__func__, __LINE__, error); | |||
return error; | |||
} | |||
sleep(2); | |||
/* state 0xf */ | |||
memset(data, 0, sizeof(data)); | |||
ptr = data; | |||
== | *ptr++ = 0xff; | ||
*ptr++ = 0x1f; | |||
memcpy(ptr, my_mac_addr, sizeof(my_mac_addr)); | |||
ptr = data + 0x8; | |||
*ptr++ = 0x2; | |||
*ptr++ = 0x2; | |||
data_size = 0xa; | |||
error = usb_wlan_cmd_send(0x105f, data, data_size); | |||
if (error) { | |||
fprintf(stderr, "%s:%d: could not send command 0x105f (%d)\n", | |||
__func__, __LINE__, error); | |||
return error; | |||
} | |||
return 0; | |||
usb_wlan_cmd_send | } | ||
/* | |||
* usb_wlan_cmd_thread | |||
*/ | |||
static void *usb_wlan_cmd_thread(void *arg) | |||
{ | |||
int error; | |||
error = usb_wlan_init(); | |||
if (error) { | |||
fprintf(stderr, "%s:%d: could not initialize device (%d)\n", | |||
__func__, __LINE__, error); | |||
goto done; | |||
} | |||
sleep(5); | |||
error = usb_wlan_cmd_0x99(); | |||
if (error) { | |||
fprintf(stderr, "%s:%d: could not start scanning (%d)\n", | |||
__func__, __LINE__, error); | |||
goto done; | |||
} | |||
error = usb_wlan_cmd_start_scan(); | |||
if (error) { | |||
fprintf(stderr, "%s:%d: could not start scanning (%d)\n", | |||
__func__, __LINE__, error); | |||
goto done; | |||
} | |||
sleep(10); | |||
error = usb_wlan_cmd_get_scan_results(); | |||
if (error) { | |||
fprintf(stderr, "%s:%d: could not get scan results (%d)\n", | |||
__func__, __LINE__, error); | |||
goto done; | |||
} | |||
sleep(10); | |||
done: | |||
usb_wlan_cmd_thread_done = 1; | |||
return NULL; | |||
} | |||
/* | |||
* main | |||
*/ | |||
int main(int argc, char **argv) | |||
{ | |||
unsigned char buf[256]; | |||
pthread_t tid; | |||
struct timeval tv; | |||
int error; | |||
pthread_mutex_init(&usb_wlan_cmd_mutex, NULL); | |||
pthread_cond_init(&usb_wlan_cmd_cond, NULL); | |||
error = libusb_init(&usb_ctx); | |||
if (error) { | |||
fprintf(stderr, "%s:%d: libusb_init failed (%d)\n", __func__, __LINE__, error); | |||
exit(1); | |||
} | |||
libusb_set_debug(usb_ctx, 5); | |||
usb_dev_handle = libusb_open_device_with_vid_pid(usb_ctx, USB_VENDOR_ID, USB_PRODUCT_ID); | |||
if (!usb_dev_handle) { | |||
fprintf(stderr, "%s:%d: could not open device\n", __func__, __LINE__); | |||
exit(1); | |||
} | |||
if(libusb_kernel_driver_active(usb_dev_handle, USB_IFACE_NUMBER)) { | |||
fprintf(stdout, "%s:%d: kernel driver is attached\n", __func__, __LINE__); | |||
error = libusb_detach_kernel_driver(usb_dev_handle, USB_IFACE_NUMBER); | |||
if (error) { | |||
fprintf(stderr, "%s:%d: could not detach kernel driver (%d)\n", | |||
__func__, __LINE__, error); | |||
exit(1); | |||
} | |||
fprintf(stdout, "%s:%d: kernel driver dettached\n", __func__, __LINE__); | |||
} | |||
error = libusb_claim_interface(usb_dev_handle, USB_IFACE_NUMBER); | |||
if (error) { | |||
fprintf(stderr, "%s:%d: could not claim interface (%d)\n", | |||
__func__, __LINE__, error); | |||
exit(1); | |||
} | |||
error = libusb_control_transfer(usb_dev_handle, 0x40, 0x1, 0x9, 0x0, | |||
usb_magic_data, sizeof(usb_magic_data), 0); | |||
if (error < 0) { | |||
fprintf(stderr, "%s:%d: could not do control transfer (%d)\n", | |||
__func__, __LINE__, error); | |||
exit(1); | |||
} | |||
fprintf(stdout, "%s:%d: number of bytes transferred (%d)\n", __func__, __LINE__, error); | |||
error = libusb_control_transfer(usb_dev_handle, 0xc0, 0x0, 0x2, 0x0, buf, 2, 0); | |||
if (error < 0) { | |||
fprintf(stderr, "%s:%d: could not do control transfer (%d)\n", | |||
__func__, __LINE__, error); | |||
exit(1); | |||
} | |||
fprintf(stdout, "%s:%d: number of bytes received (%d)\n", __func__, __LINE__, error); | |||
fprintf(stdout, "%s:%d: 0x%02x 0x%02x\n", __func__, __LINE__, buf[0], buf[1]); | |||
usb_intr_transfer_ep5_in = libusb_alloc_transfer(0); | |||
if (!usb_intr_transfer_ep5_in) { | |||
fprintf(stderr, "%s:%d: could not allocate transfer\n", __func__, __LINE__); | |||
exit(1); | |||
} | |||
memset(usb_intr_transfer_ep5_in_buf, 0, sizeof(usb_intr_transfer_ep5_in_buf)); | |||
libusb_fill_interrupt_transfer(usb_intr_transfer_ep5_in, usb_dev_handle, LIBUSB_ENDPOINT_IN | 0x5, | |||
usb_intr_transfer_ep5_in_buf, sizeof(usb_intr_transfer_ep5_in_buf), | |||
usb_intr_transfer_ep5_in_cb, NULL, 0); | |||
= | error = libusb_submit_transfer(usb_intr_transfer_ep5_in); | ||
if (error) { | |||
fprintf(stderr, "%s:%d: could not submit transfer (%d)\n", | |||
__func__, __LINE__, error); | |||
exit(1); | |||
} | |||
= | error = pthread_create(&tid, NULL, usb_wlan_cmd_thread, NULL); | ||
if (error) { | |||
fprintf(stderr, "%s:%d: could not create WLAN command thread (%d)\n", | |||
__func__, __LINE__, error); | |||
exit(1); | |||
} | |||
== | while (!usb_wlan_cmd_thread_done) { | ||
tv.tv_sec = 1; | |||
tv.tv_usec = 0; | |||
error = libusb_handle_events_timeout(usb_ctx, &tv); | |||
if (error) { | |||
fprintf(stderr, "%s:%d: could not handle events (%d)\n", | |||
__func__, __LINE__, error); | |||
exit(1); | |||
} | |||
} | |||
libusb_free_transfer(usb_intr_transfer_ep5_in); | |||
error = libusb_release_interface(usb_dev_handle, USB_IFACE_NUMBER); | |||
if (error) | |||
fprintf(stderr, "%s:%d: could not release interface (%d)\n", | |||
__func__, __LINE__, error); | |||
libusb_close(usb_dev_handle); | |||
libusb_exit(usb_ctx); | |||
exit(0); | |||
} | } | ||
</pre> | </pre> | ||
=== | ====Output==== | ||
<pre> | |||
glevand@debian-hdd:~/ps3_usb_wlan$ sudo ./ps3_usb_wlan | |||
sudo: unable to resolve host debian-hdd | |||
main:824: number of bytes transferred (32) | |||
main:833: number of bytes received (2) | |||
main:835: 0x20 0x31 | |||
usb_wlan_cmd_send:288: sending command (0x114f) data size (0x0518) command size (0x0524) | |||
=== | usb_intr_transfer_ep5_in_cb:233: === got interrupt transfer === | ||
usb_intr_transfer_ep5_in_cb:236: transfer status (0) length (36) | |||
usb_handle_wlan_cmd_response:158: === got WLAN command response === | |||
usb_handle_wlan_cmd_response:191: command header: | |||
usb_handle_wlan_cmd_response:192: command (0x1150) | |||
usb_handle_wlan_cmd_response:199: tag (0xcafe) | |||
usb_handle_wlan_cmd_response:201: status (0x0006) | |||
usb_handle_wlan_cmd_response:205: ==> command status != 0x1 | |||
usb_handle_wlan_cmd_response:207: payload_size (0x0000) | |||
usb_handle_wlan_cmd_response:210: command payload: | |||
usb_wlan_cmd_send:288: sending command (0x1171) data size (0x0000) command size (0x000c) | |||
usb_intr_transfer_ep5_in_cb:233: === got interrupt transfer === | |||
usb_intr_transfer_ep5_in_cb:236: transfer status (0) length (36) | |||
=== | usb_handle_wlan_cmd_response:158: === got WLAN command response === | ||
usb_handle_wlan_cmd_response:191: command header: | |||
usb_handle_wlan_cmd_response:192: command (0x1172) | |||
usb_handle_wlan_cmd_response:199: tag (0xcafe) | |||
usb_handle_wlan_cmd_response:201: status (0x0001) | |||
usb_handle_wlan_cmd_response:207: payload_size (0x0000) | |||
usb_handle_wlan_cmd_response:210: command payload: | |||
usb_intr_transfer_ep5_in_cb:233: === got interrupt transfer === | |||
usb_intr_transfer_ep5_in_cb:236: transfer status (0) length (68) | |||
usb_handle_wlan_event:133: === got WLAN event === | |||
usb_handle_wlan_event:144: event_count (0x01) | |||
00000000: 00 04 00 00 10 00 00 00 3c 22 02 00 00 00 00 00 |........<"......| | |||
00000010: fc 90 02 c0 00 00 00 00 00 00 00 00 00 00 00 00 |................| | |||
=== | 00000020: 13 00 00 20 00 00 00 00 00 00 00 00 00 00 00 00 |... ............| | ||
00000030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| | |||
usb_wlan_cmd_send:288: sending command (0x116f) data size (0x0004) command size (0x0010) | |||
usb_intr_transfer_ep5_in_cb:233: === got interrupt transfer === | |||
usb_intr_transfer_ep5_in_cb:236: transfer status (0) length (36) | |||
usb_handle_wlan_cmd_response:158: === got WLAN command response === | |||
usb_handle_wlan_cmd_response:191: command header: | |||
usb_handle_wlan_cmd_response:192: command (0x1170) | |||
usb_handle_wlan_cmd_response:199: tag (0xcafe) | |||
usb_handle_wlan_cmd_response:201: status (0x0001) | |||
== | usb_handle_wlan_cmd_response:207: payload_size (0x0000) | ||
usb_handle_wlan_cmd_response:210: command payload: | |||
usb_wlan_cmd_send:288: sending command (0x115b) data size (0x005e) command size (0x006a) | |||
usb_intr_transfer_ep5_in_cb:233: === got interrupt transfer === | |||
usb_intr_transfer_ep5_in_cb:236: transfer status (0) length (36) | |||
usb_handle_wlan_cmd_response:158: === got WLAN command response === | |||
usb_handle_wlan_cmd_response:191: command header: | |||
usb_handle_wlan_cmd_response:192: command (0x115c) | |||
usb_handle_wlan_cmd_response:199: tag (0xcafe) | |||
usb_handle_wlan_cmd_response:201: status (0x0001) | |||
usb_handle_wlan_cmd_response:207: payload_size (0x0000) | |||
usb_handle_wlan_cmd_response:210: command payload: | |||
usb_wlan_cmd_send:288: sending command (0x1161) data size (0x0020) command size (0x002c) | |||
usb_intr_transfer_ep5_in_cb:233: === got interrupt transfer === | |||
usb_intr_transfer_ep5_in_cb:236: transfer status (0) length (36) | |||
=== | usb_handle_wlan_cmd_response:158: === got WLAN command response === | ||
usb_handle_wlan_cmd_response:191: command header: | |||
usb_handle_wlan_cmd_response:192: command (0x1162) | |||
usb_handle_wlan_cmd_response:199: tag (0xcafe) | |||
usb_handle_wlan_cmd_response:201: status (0x0001) | |||
usb_handle_wlan_cmd_response:207: payload_size (0x0000) | |||
usb_handle_wlan_cmd_response:210: command payload: | |||
usb_wlan_cmd_send:288: sending command (0x110d) data size (0x0080) command size (0x008c) | |||
usb_intr_transfer_ep5_in_cb:233: === got interrupt transfer === | |||
===== | usb_intr_transfer_ep5_in_cb:236: transfer status (0) length (36) | ||
usb_handle_wlan_cmd_response:158: === got WLAN command response === | |||
usb_handle_wlan_cmd_response:191: command header: | |||
usb_handle_wlan_cmd_response:192: command (0x110e) | |||
usb_handle_wlan_cmd_response:199: tag (0xcafe) | |||
usb_handle_wlan_cmd_response:201: status (0x0001) | |||
usb_handle_wlan_cmd_response:207: payload_size (0x0000) | |||
usb_handle_wlan_cmd_response:210: command payload: | |||
usb_wlan_cmd_send:288: sending command (0x1031) data size (0x0002) command size (0x000e) | |||
usb_intr_transfer_ep5_in_cb:233: === got interrupt transfer === | |||
usb_intr_transfer_ep5_in_cb:236: transfer status (0) length (38) | |||
===== | usb_handle_wlan_cmd_response:158: === got WLAN command response === | ||
usb_handle_wlan_cmd_response:191: command header: | |||
usb_handle_wlan_cmd_response:192: command (0x1032) | |||
usb_handle_wlan_cmd_response:199: tag (0xcafe) | |||
usb_handle_wlan_cmd_response:201: status (0x0001) | |||
usb_handle_wlan_cmd_response:207: payload_size (0x0002) | |||
usb_handle_wlan_cmd_response:210: command payload: | |||
00000000: 00 00 |.. | | |||
usb_wlan_cmd_send:288: sending command (0x1041) data size (0x0006) command size (0x0012) | |||
usb_intr_transfer_ep5_in_cb:233: === got interrupt transfer === | |||
===== | usb_intr_transfer_ep5_in_cb:236: transfer status (0) length (42) | ||
usb_handle_wlan_cmd_response:158: === got WLAN command response === | |||
usb_handle_wlan_cmd_response:191: command header: | |||
usb_handle_wlan_cmd_response:192: command (0x1042) | |||
usb_handle_wlan_cmd_response:199: tag (0xcafe) | |||
usb_handle_wlan_cmd_response:201: status (0x0001) | |||
usb_handle_wlan_cmd_response:207: payload_size (0x0006) | |||
usb_handle_wlan_cmd_response:210: command payload: | |||
00000000: 00 11 22 33 44 55 |.."3DU | | |||
usb_wlan_cmd_send:288: sending command (0x0029) data size (0x0002) command size (0x000e) | |||
usb_intr_transfer_ep5_in_cb:233: === got interrupt transfer === | |||
usb_intr_transfer_ep5_in_cb:236: transfer status (0) length (38) | |||
== | usb_handle_wlan_cmd_response:158: === got WLAN command response === | ||
usb_handle_wlan_cmd_response:191: command header: | |||
usb_handle_wlan_cmd_response:192: command (0x002a) | |||
usb_handle_wlan_cmd_response:199: tag (0xcafe) | |||
usb_handle_wlan_cmd_response:201: status (0x0001) | |||
usb_handle_wlan_cmd_response:207: payload_size (0x0002) | |||
usb_handle_wlan_cmd_response:210: command payload: | |||
00000000: 02 02 |.. | | |||
usb_wlan_cmd_send:288: sending command (0x110b) data size (0x000c) command size (0x0018) | |||
usb_intr_transfer_ep5_in_cb:233: === got interrupt transfer === | |||
usb_intr_transfer_ep5_in_cb:236: transfer status (0) length (48) | |||
usb_handle_wlan_cmd_response:158: === got WLAN command response === | |||
usb_handle_wlan_cmd_response:191: command header: | |||
usb_handle_wlan_cmd_response:192: command (0x110c) | |||
== | usb_handle_wlan_cmd_response:199: tag (0xcafe) | ||
usb_handle_wlan_cmd_response:201: status (0x0001) | |||
usb_handle_wlan_cmd_response:207: payload_size (0x000c) | |||
usb_handle_wlan_cmd_response:210: command payload: | |||
00000000: 01 00 00 00 00 00 00 00 20 00 00 00 |........ ... | | |||
usb_wlan_cmd_send:288: sending command (0x1109) data size (0x0016) command size (0x0022) | |||
usb_intr_transfer_ep5_in_cb:233: === got interrupt transfer === | |||
usb_intr_transfer_ep5_in_cb:236: transfer status (0) length (58) | |||
=== | usb_handle_wlan_cmd_response:158: === got WLAN command response === | ||
usb_handle_wlan_cmd_response:191: command header: | |||
usb_handle_wlan_cmd_response:192: command (0x110a) | |||
usb_handle_wlan_cmd_response:199: tag (0xcafe) | |||
usb_handle_wlan_cmd_response:201: status (0x0001) | |||
usb_handle_wlan_cmd_response:207: payload_size (0x0016) | |||
usb_handle_wlan_cmd_response:210: command payload: | |||
00000000: 01 00 00 00 15 27 12 00 06 00 00 00 09 00 01 00 |.....'..........| | |||
00000000 | 00000010: ff ff ff ff ff ff |...... | | ||
usb_wlan_cmd_send:288: sending command (0x0207) data size (0x0004) command size (0x0010) | |||
usb_intr_transfer_ep5_in_cb:233: === got interrupt transfer === | |||
usb_intr_transfer_ep5_in_cb:236: transfer status (0) length (40) | |||
usb_handle_wlan_cmd_response:158: === got WLAN command response === | |||
usb_handle_wlan_cmd_response:191: command header: | |||
usb_handle_wlan_cmd_response:192: command (0x0208) | |||
00000000 | usb_handle_wlan_cmd_response:199: tag (0xcafe) | ||
usb_handle_wlan_cmd_response:201: status (0x0001) | |||
usb_handle_wlan_cmd_response:207: payload_size (0x0004) | |||
usb_handle_wlan_cmd_response:210: command payload: | |||
=== | 00000000: 01 00 00 00 |.... | | ||
usb_wlan_cmd_send:288: sending command (0x0203) data size (0x0004) command size (0x0010) | |||
usb_intr_transfer_ep5_in_cb:233: === got interrupt transfer === | |||
usb_intr_transfer_ep5_in_cb:236: transfer status (0) length (40) | |||
usb_handle_wlan_cmd_response:158: === got WLAN command response === | |||
usb_handle_wlan_cmd_response:191: command header: | |||
usb_handle_wlan_cmd_response:192: command (0x0204) | |||
usb_handle_wlan_cmd_response:199: tag (0xcafe) | |||
usb_handle_wlan_cmd_response:201: status (0x0001) | |||
usb_handle_wlan_cmd_response:207: payload_size (0x0004) | |||
usb_handle_wlan_cmd_response:210: command payload: | |||
00000000: 04 00 00 00 |.... | | |||
usb_wlan_cmd_send:288: sending command (0x105f) data size (0x000a) command size (0x0016) | |||
usb_intr_transfer_ep5_in_cb:233: === got interrupt transfer === | |||
usb_intr_transfer_ep5_in_cb:236: transfer status (0) length (36) | |||
usb_handle_wlan_cmd_response:158: === got WLAN command response === | |||
=== | usb_handle_wlan_cmd_response:191: command header: | ||
usb_handle_wlan_cmd_response:192: command (0x1060) | |||
usb_handle_wlan_cmd_response:199: tag (0xcafe) | |||
usb_handle_wlan_cmd_response:201: status (0x0001) | |||
usb_handle_wlan_cmd_response:207: payload_size (0x0000) | |||
usb_handle_wlan_cmd_response:210: command payload: | |||
usb_intr_transfer_ep5_in_cb:233: === got interrupt transfer === | |||
usb_intr_transfer_ep5_in_cb:236: transfer status (0) length (68) | |||
' | usb_handle_wlan_event:133: === got WLAN event === | ||
usb_handle_wlan_event:144: event_count (0x01) | |||
00000000: 80 00 00 00 00 10 00 00 9e 2b 02 00 04 00 00 00 |.........+......| | |||
00000010: fc 90 02 c0 01 00 00 00 00 00 00 00 00 00 00 00 |................| | |||
00000020: 13 00 00 20 00 00 00 00 00 00 00 00 00 00 00 00 |... ............| | |||
00000030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| | |||
usb_wlan_cmd_send:288: sending command (0x0099) data size (0x003e) command size (0x004a) | |||
usb_intr_transfer_ep5_in_cb:233: === got interrupt transfer === | |||
=== | usb_intr_transfer_ep5_in_cb:236: transfer status (0) length (98) | ||
usb_handle_wlan_cmd_response:158: === got WLAN command response === | |||
usb_handle_wlan_cmd_response:191: command header: | |||
usb_handle_wlan_cmd_response:192: command (0x009a) | |||
=== | usb_handle_wlan_cmd_response:199: tag (0xcafe) | ||
usb_handle_wlan_cmd_response:201: status (0x0001) | |||
usb_handle_wlan_cmd_response:207: payload_size (0x003e) | |||
usb_handle_wlan_cmd_response:210: command payload: | |||
00000000: 4a 55 50 49 54 45 52 2d 54 57 4f 2d 46 57 2d 32 |JUPITER-TWO-FW-2| | |||
00000010: 30 2e 30 2e 31 32 2e 70 30 28 4a 61 6e 20 31 39 |0.0.12.p0(Jan 19| | |||
=== | 00000020: 20 32 30 31 30 20 32 31 3a 32 30 3a 35 33 29 00 | 2010 21:20:53).| | ||
00000030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |.............. | | |||
=== | usb_wlan_cmd_send:288: sending command (0x1035) data size (0x0019) command size (0x0025) | ||
usb_intr_transfer_ep5_in_cb:233: === got interrupt transfer === | |||
usb_intr_transfer_ep5_in_cb:236: transfer status (0) length (61) | |||
usb_handle_wlan_cmd_response:158: === got WLAN command response === | |||
usb_handle_wlan_cmd_response:191: command header: | |||
usb_handle_wlan_cmd_response:192: command (0x1036) | |||
usb_handle_wlan_cmd_response:199: tag (0xcafe) | |||
=== | usb_handle_wlan_cmd_response:201: status (0x0001) | ||
usb_handle_wlan_cmd_response:207: payload_size (0x0019) | |||
==== | usb_handle_wlan_cmd_response:210: command payload: | ||
00000000: 00 01 64 00 00 00 00 00 00 00 03 0d 01 02 03 04 |..d.............| | |||
00000010: 05 06 07 08 09 0a 0b 0c 0d |......... | | |||
usb_intr_transfer_ep5_in_cb:233: === got interrupt transfer === | |||
usb_intr_transfer_ep5_in_cb:236: transfer status (0) length (68) | |||
usb_handle_wlan_event:133: === got WLAN event === | |||
usb_handle_wlan_event:144: event_count (0x01) | |||
00000000: 80 00 00 00 04 00 00 00 96 2e 02 00 01 00 00 00 |................| | |||
=== | 00000010: fc 90 02 c0 00 00 00 00 00 00 00 00 00 00 00 00 |................| | ||
00000020: 13 00 00 20 00 00 00 00 00 00 00 00 00 00 00 00 |... ............| | |||
00000030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| | |||
usb_wlan_cmd_send:288: sending command (0x1033) data size (0x05b0) command size (0x05bc) | |||
=== | usb_intr_transfer_ep5_in_cb:233: === got interrupt transfer === | ||
usb_intr_transfer_ep5_in_cb:236: transfer status (0) length (1403) | |||
usb_handle_wlan_cmd_response:158: === got WLAN command response === | |||
usb_handle_wlan_cmd_response:191: command header: | |||
usb_handle_wlan_cmd_response:192: command (0x1034) | |||
usb_handle_wlan_cmd_response:199: tag (0xcafe) | |||
usb_handle_wlan_cmd_response:201: status (0x0001) | |||
usb_handle_wlan_cmd_response:207: payload_size (0x0557) | |||
usb_handle_wlan_cmd_response:210: command payload: | |||
... | |||
Here is scan output (removed by me) | |||
... | |||
=== | |||
=== | |||
=== | |||
=== | |||
=== | |||
=== | |||
=== | |||
</pre> | </pre> | ||