Editing Hypervisor Reverse Engineering

Jump to navigation Jump to search
Warning: You are not logged in. Your IP address will be publicly visible if you make any edits. If you log in or create an account, your edits will be attributed to your username, along with other benefits.

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:
<span style="background:red; color:#ffffff;">Warning, this page is way too long and is voted to be split into seperate sections</span>
[[Category:Software]]
<span style="background:red; color:#ffffff;">Warning, this page way too long and voted to be split into seperate sections</span>


----
----
Line 19: Line 20:
LPAR = Logical Partition  
LPAR = Logical Partition  


lpar1 starts at 0x&lt;unknown&gt;, and it's believed to be the memory space where lv1 stores its variables, flags and other data.  
lpar1 starts at 0x&lt;unknown&gt;, and its believed to be the memory space where lv1 stores its variables, flags and other data.  


lpar2 starts at 0x80000000000 and it's believed to be the memory space where lv2 stores its variables, flags and other data.  
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 180: Line 181:
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.  


== UX System call table 0 - 36  ==
== System call table 0 - 36  ==


0x0035FAE8 (3.15)  
0x0035FAE8 (3.15)  
Line 187: Line 188:


=== System call numbers  ===
=== System call numbers  ===
0x0 - void eosh(void) //end_of_signal_handling(void)


0x1 - pid_t getpid(void)  
0x1 - getpid(void)  


0x2 - pid_t getppid(void)  
0x2 - getppid(void)  


0x3 - pid_t fork(void)  
0x3 - fork(void)  


0x4 - void exit(int status)
0x4 - exit  


0x5 - void execv(const char *path, char *const argv[])  
0x5 - exec(filename)  


0x6 - void wait(int *status)  
0x6 - wait(status)  


0x7 - int open(const char *path, int flags)  
0x7 - open(filename)  


0x8 - void close(int fd)  
0x8 - close(fd)  


0x9 - ssize_t read(int fd, void *buf, unsigned int nbyte)
0x9 - read  


0xA - ssize_t write(int fd, const void *buf, unsigned int nbyte)
0xA - write  


0xB - void lseek(int fd, long offset, int whence)
0xB - seek


0xC - unlink(const char *path)  
0xC - unlink(filename)  


0xD - void signal(int sig, void *func(int sig))
0xD - signal  


0xE - int kill(int pid, int signal_type)  
0xE - kill(pid, signal type)  


0xF - int brk(void *)
0xF - brk  


0x10 - int socket(int af, int type, int protocol) (supports only address family 0x1F, type 0x0 and protocol 0x0)  
0x10 - socket(af, type, protocol) (supports only address family 0x1F, type 0x0 and protocol 0x0)  


0x11 - int bind(int sockfd , const sockaddr *addr, unsigned int addrlen)
0x11 - bind  


0x12 - int listen(int sockfd, int backlog)  
0x12 - listen(fd, backlog)  


0x13 - int accept(int sockfd, sockaddr *addr, unsigned int *addrlen)
0x13 - accept  


0x14 - int connect(int sockfd, const sockaddr *serv_addr, unsigned int addrlen)
0x14 - connect  


0x15 - void putchar(int c)
0x15 -&nbsp;?


0x16 - int pause(void)  
0x16 - pause(void)  


0x17 - int sleep(unsigned int seconds)  
0x17 - sleep(seconds)  


0x18 - int mmap(void *addr, unsigned long size, int prot, int flags, int fd, long offset, void *mapped_addr)  
0x18 - mmap(addr, size, prot, flags, fd, offset)  


0x19 - int munmap (void *addr, unsigned long size)
0x19 - munmap  


0x1A - int chdir(const char *path)
0x1A - some fs func for directories, perhaps readdir


0x1B - void getchar(char *c)
0x1B -&nbsp;?


0x1C - map_pages(...) (used for alloc)  
0x1C - map_pages (used for alloc)  


0x1D - unmap_pages(...) (used for free)  
0x1D - unmap_pages (used for free)  


0x1E - select(...)
0x1E - select  


0x1F - getcwd(...)
0x1F - getcwd  


0x20 - Not used
0x20 -&nbsp;?


0x21 - alarm(...)
0x21 - alarm  


0x22 - ioctl(...)
0x22 - ioctl  


0x23 - pme_memalign(...)
0x23 - _map_pages


0x24 - ?
0x24 - _unmap_pages


== PMI System call table 0x10000 - 0x100FF  ==
== System call table 0x10000 - 0x100FF  ==


0x0035DE78 (3.15)  
0x0035DE78 (3.15)  
Line 269: Line 269:
=== System call numbers  ===
=== System call numbers  ===


0x10000 - allocate_memory(LPAR id, size, log2 of page size,&nbsp;?,&nbsp;?) / construct_memory_segment
0x10000 - allocate_memory_region(LPAR id, size, log2 of page size,&nbsp;?,&nbsp;?)  


0x10001 - query_logical_partition_address_region_info
0x10001 - lpar_query_address_region_info


0x10002 - translate_logical_partition_to_physical_address(LPAR id, LPAR address, physical addr)  
0x10002 - lpar_memory_addr_to_phys_addr(LPAR id, LPAR address, physical addr)  
 
0x10003 - map_physical_address_region
 
0x10004 - unmap_physical_address_region


0x10005 - construct_logical_pu  
0x10005 - construct_logical_pu  
0x10006 - destruct_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)  
0x1000A - get_logical_console_info
0x1000B - get_remote_file_size
0x1000C - read_remote_file
0x1000D - write_remote_file


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  
0x1001B - destruct_event_receive_port
0x1001C - request_to_connect_event_ports
0x1001D - connect_event_ports
0x1001E - destruct_event_send_port
0x1001F - send_event_externally
0x10020 - get_status_of_event_send_port
0x10021 - get_event_port_connection_request
0x10022 - end_of_control_signal_processing


0x10024 - shutdown_logical_partition(LPAR id, shutdown command)  
0x10024 - shutdown_logical_partition(LPAR id, shutdown command)  
Line 320: Line 290:


0x10026 - get_logical_partition_info  
0x10026 - get_logical_partition_info  
0x10027 - read_privilege_set
0x10028 - modify_privilege_set
0x10029 - get_remote_file_size_long_name
0x1002A - read_remote_file_long_name
0x1002B - write_remote_file_long_name


0x1002C - construct_scheduling_table  
0x1002C - construct_scheduling_table  
Line 335: Line 295:
0x1002D - set_scheduling_slot  
0x1002D - set_scheduling_slot  


0x1002E - load_scheduling_table
0x1002E - ?
 
0x10032 - poweroff


0x10033 - get_remote_file_name
0x10032 - accesses system console


0x10034 - allocate_cp_channel
0x10034 - ?


0x10035 - release_cp_channel
0x10035 - ?


0x10036 - power_down
0x10036 - accesses system console


0x10037 - ?
0x10037 - ?
Line 353: Line 311:
0x10039 - ?
0x10039 - ?


0x10040 - construct_spe_type_1(SPE id, shaddow_addr) / construct_logical_spu
0x10040 - construct_spe_type_1(SPE id, shaddow_addr)  


0x10041 - destruct_spe(SPE id) / destruct_logical_spu
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 321:
0x10044 - disable_spe_execution  
0x10044 - disable_spe_execution  


0x10045 - read_spu_puint_mb(unsigned long spu_id, unsigned long msg)
0x10045 - set_spe_interrupt_mask
 
0x10046 - read_spe_problem_state_register(spe id, register offset, value) / read_spu_problem_state_area_register


0x10047 - write_spe_problem_state_register(spe id, register offset, value) / write_spu_problem_state_area_register
0x10046 - read_spe_problem_state_register(spe id, register offset, value)  


0x1004A - install_revoke_list
0x10047 - write_spe_problem_state_register(spe id, register offset, value)


0x1004B - disable_spe_loading  
0x1004B - disable_spe_loading  
0x1004C - install_access_control_table?
0x1004D - get_storage_status?
0x1004E - get_region_table_bits?
0x1004F - commit_region_update?
0x10050 - abort_region_update?
0x10051 - set_storage_tampered?


0x10053 - pmi_set_guest_os_mode  
0x10053 - pmi_set_guest_os_mode  


0x1007F - pause
0x10081 - accesses system console
 
0x10080 - get_total_execution_time
 
0x10081 - reset
 
0x10083 - construct_logical_rsx


0x10084 - construct_virtual_uart(LPAR id, VUART id, VUART data buffer size)  
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)  
0x10086 - establish_virtual_uart_channel


0x10088 - RSX_syscall_10088(LPAR id)  
0x10088 - RSX_syscall_10088(LPAR id)  
Line 415: Line 351:
0x100C2 - modify_repository_node_value(LPAR id)  
0x100C2 - modify_repository_node_value(LPAR id)  


0x100C3 - remove_repository_node(LPAR id)
0x100C3 - remove_repository_node_value(LPAR id)


= Process  =
= Process  =
Line 423: Line 359:
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.  
 
0x0036C930 (4.30)
 
0x0036C8B0 (4.21)
 
0x00365458 (4.11)


0x0035F8D0 (3.55)
0x0035F8D0 (3.55)
Line 570: Line 500:
*0x000A9870 (PID 6)  
*0x000A9870 (PID 6)  
*0x00084B80 (PID 9)
*0x00084B80 (PID 9)
In JIG 2.43:
*(PID3) <- ss_server3
*(PID4) <- ss_sc_init_pu
*(PID5) <- ss_server2
*(PID6) <- ss_server1
*(PID7) <- factory_data_mngr_server
*(PID8) <- updater_frontend
(see [http://pastie.org/pastes/9407461/text?key=f6bk5lof0g4bgeu6xrn5ua this])


= PThread  =
= PThread  =
Line 671: Line 591:
== Member variables  ==
== Member variables  ==


offset 0x0 - pointer to previous AddressProtectionDomain object  
offset 0x8 - pointer to previous AddressProtectionDomain object  


offset 0x8 - pointer to next AddressProtectionDomain object  
offset 0x10 - pointer to next AddressProtectionDomain object  


offset 0x10 - poiinter to pointer to SLB entries  
offset 0x18 - poiinter to pointer to SLB entries  


offset 0x18 - pointer to AddressSpace object that owns this object  
offset 0x20 - pointer to AddressSpace object that owns this object  


offset 0x2A - pointer to previous ProtectionPage  
offset 0x34 - pointer to previous ProtectionPage  


offset 0x34 - pointer to next ProtectionPage  
offset 0x3C - pointer to next ProtectionPage  


offset 0x40 - Mutex object
offset 0x48 - Mutex object  


= ProtectionPage  =
= ProtectionPage  =
Line 840: Line 760:
=== vtable  ===
=== vtable  ===


0x003569F8 (3.15)
0x003569F8 (3.15)  


== IOIF device file objects  ==
== IOIF device file objects  ==
Line 1,026: Line 946:
=== vtable  ===
=== vtable  ===


0x352308 (3.15)
0x000x352308 (3.15)  


=== Member variables  ===
=== Member variables  ===
Line 1,705: Line 1,625:


*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''' ([[Authority ID|LPAR Authority ID]]) is evaluated for this purpose.  
*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,678:


*The storage subsystem is a storage device itself.  
*The storage subsystem is a storage device itself.  
*It's a pseudo device used to notify a LPAR when storage devices become e.g. ready.  
*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,756:


*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 '''[[Authority ID|LPAR Authority ID]]'''. If this test fails then the command is NOT executed.
*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,009:


*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 '''[[Authority ID|LPAR Authority ID]]'''. If this test fails then the command is NOT executed.
*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,609:


*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 '''[[Authority ID|LPAR Authority ID]]'''. If this test fails then the command is NOT executed.
*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,742: Line 2,662:
block size = 512  
block size = 512  


*It's a pseudo device.  
*It's a psuedo device.  
*'''This storage device redirects all requests to the region 1 of HDD storage device&nbsp;!!!'''
*'''This storage device redirects all requests to the region 1 of HDD storage device&nbsp;!!!'''


Line 3,475: Line 3,395:
! Address of Data in HV Dump  
! Address of Data in HV Dump  
! Size of Data
! Size of Data
! Entry Id
|-
|-
| 0  
| 0  
| lv1ldr
| -
| 0x0C150000  
| 0x0C150000  
| 0x1E5CC
| 0x1E5CC
| 0x01
|-
|-
| 1  
| 1  
Line 3,487: Line 3,405:
| 0x00011000  
| 0x00011000  
| 0xE8D0
| 0xE8D0
| 0x00
|-
|-
| 2  
| 2  
Line 3,493: Line 3,410:
| 0x00020000  
| 0x00020000  
| 0x16DA0
| 0x16DA0
| 0x02
|-
|-
| 3  
| 3  
Line 3,499: Line 3,415:
| 0x00055000  
| 0x00055000  
| 0x12E44
| 0x12E44
| 0x04
|-
|-
| 4  
| 4  
Line 3,505: Line 3,420:
| 0x00037000  
| 0x00037000  
| 0x1DAE4
| 0x1DAE4
| 0x03
|-
|-
| 5  
| 5  
Line 3,511: Line 3,425:
| 0x00068000  
| 0x00068000  
| 0x860
| 0x860
| 0x0C
|-
|-
| 6  
| 6  
| QA Flag
| -
| 0x00069010  
| 0x00069010  
| 0x8
| 0x8
| 0x0F
|-
|-
| 7  
| 7  
| QA Flag Token
| -
| 0x00069020  
| 0x00069020  
| 0x50
| 0x50
| 0x10
|-
|-
| 8  
| 8  
| Trace Level
| -
| 0x00069070  
| 0x00069070  
| 0x8
| 0x8
| 0x11
|}
|}


Line 3,593: Line 3,503:
=== appldr  ===
=== appldr  ===


*'''appldr''' is used for decryption of SELFs or EDATs
*'''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,512:
==== Loading appldr  ====
==== Loading appldr  ====


*64 bit memory address of '''appldr''' is written into 32 bit SPU register '''SPU_In_Mbox'''  
*64 bit memory address of '''isoldr''' is written into 32 bit SPU register '''SPU_In_Mbox'''  
*'''metldr''' is loaded
*'''metldr''' is loaded


Line 3,989: Line 3,899:
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,359:
| 0xA  
| 0xA  
| 0x1B6  
| 0x1B6  
| Makes a triple beep
| Makes a double beep
|-
|-
| 0x29  
| 0x29  
Line 4,461: Line 4,371:
| Makes a continuous beep
| Makes a continuous beep
|}
|}
field 1 seems relative to beep tone, as 0x25 sounds different


=== Active System Managers in HV dump 3.15  ===
=== Active System Managers in HV dump 3.15  ===
Line 4,656: Line 4,565:
| 0x8000  
| 0x8000  
| 8  
| 8  
| 0x8001 - 0x8005
|  
| [[Updater_Frontend|Updater Frontend]]
|  
|-
|-
| 0x9000  
| 0x9000  
Line 4,666: Line 4,575:
| 0x10000  
| 0x10000  
| 0x23  
| 0x23  
| 0x10001-0x10007
| -  
| [[SB_Manager|SBM (South Bridge Manager)]]
| -
|-
|-
| 0x11000  
| 0x11000  
Line 4,702: Line 4,611:
| 0x16  
| 0x16  
| 0x22001 - 0x22004
| 0x22001 - 0x22004
| [[Factory_Data_Manager|Factory Data Manager]]
|  
|-
|-
| 0x24000  
| 0x24000  
Line 4,740: Line 4,649:
     uint32_t retval;
     uint32_t retval;
     uint8_t res[4];
     uint8_t res[4];
     uint64_t laid;            /* LPAR Authority ID */
     uint64_t laid;            /* LPAR authority id */
     uint64_t paid;            /* Program Authority ID */
     uint64_t paid;            /* Program authority id */
}
}
</pre>
</pre>
Line 4,772: Line 4,681:
*The size of the body depends on a used service.
*The size of the body depends on a used service.


= LPAR Memory Management  =
== 0x14000 - SLL (Secure LPAR Loader) ==
 
== Memory Region class ==


This class is the base class for different memory region types.  
*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/&lt;LPAR id&gt;/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'''


=== vtable  ===
{| class="wikitable FCK__ShowTableBorders"
|-
! Packet ID
! Description
|-
| 0x14004
| Load GOS
|-
| 0x14005
| Unload GOS
|}


0x003578B0 (3.15)  
== 0x15000 - SPL (Secure Profile Loader) ==


=== Member variables  ===
*DEFAULT.SPP file is stored on '''/dev/rflash1'''


offset 0x40 - pointer to LPAR object that owns this memory region
{| class="wikitable FCK__ShowTableBorders"
|-
! Packet ID
! Description
|-
| 0x15001
| Get LPAR Parameter Size/Get LPAR Parameter
|-
| 0x15003
| Get Contents Size/Get Contents
|-
| 0x15009
| Get Component
|}


offset 0x48 - type of memory region (8 bytes)
=== SPP File  ===


offset 0x50 - LPAR start address of memory region
*The file is encrypted but can be read by using 0x15003 service of SPL
*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&nbsp;% 256&nbsp;!= 0) then header check fails
*'''Finally i was able to decrypt profile file from 3.41 but by using SPE HV calls only&nbsp;!!! And Linux Manager is still there&nbsp;!!!'''
*The decrypted file is a binary file


offset 0x58 - size of memory region (8 bytes)
Here are the contents of [[Default.spp#3.56_RETAIL.2FCEX]] from 3.55. <br />
Here are the contents of [[Default.spp#3.55_RETAIL.2FCEX]] from 3.55. <br />
Here are the contents of [[Default.spp#3.41_RETAIL.2FCEX]] from 3.41. <br />
Here are the contents of [[Default.spp#3.15_RETAIL.2FCEX]] from 3.15. <br />
Here are the contents of [[Default.spp#1.00_DEBUG.2FDEX]] from 1.00 Debug Firmware. <br />


offset 0x60 - flags (8 bytes)
==== SPP Header  ====


offset 0xA0 - log2 of page size
offset 0x2 - header format version (2 bytes)


=== Generating New LPAR Memory Region Addresses ===
offset 0x4 - header size (4 bytes)


generate_new_lpar_mem_region_address(?, memory region size, log2(page size), ?, ?) - 002C82E8 (3.15)
offset 0x18 - number of segments (4 bytes)  


generate_new_lpar_mem_region_address - 002C6570 (3.41)
==== Segments  ====


*The function returns a new LPAR memory region address.
*Segments follow after the header
*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'''.
*SPP file contains several segments.


==== Encoding LPAR Memory Region Start Addresses and Sizes ====
Here is the list of profile segments from 3.41:


*Size of LPAR memory region is encoded in the LPAR memory region start address.
{| class="wikitable FCK__ShowTableBorders"
*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.
! Name
*Before incrementing, the counter is shifted left by '''log2(LPAR Memory Region Size)''' and ored with '''log2(LPAR Memory Region Size) << 42'''.
! 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
|}


  LPAR Memory Region Start Address >> 42 = log2(LPAR Memory Region Size)
== 0x15003 - Get Contents Size/Get Contents ==


LPAR Memory Region Start Address = (log2(LPAR Memory Region Size) << 42) |
*This service provides the contents of a segment specified by a service requester
    (counter << log2(LPAR Memory Region Size))
*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


===== LPAR Memory Region Address Counter =====
== 0x17000 - Indi Info Manager  ==


*LPAR Memory Region Address Counter is stored at address: '''0x38(LPAR ptr) + 0x9E8'''
{| class="wikitable FCK__ShowTableBorders"
*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
! Packet ID
*LPAR1's Memory Region Address Counter is at address '''0x00677A48''' in HV dump 3.41
! Description
*LPAR2's Memory Region Address Counter is at address '''0x00161E68''' in HV dump 3.41
|-
 
| 0x17001
== Physical Memory Region class  ==
| Read EID Data Size By Index/Read metldr Size
 
|-
This type of memory region is created e.g. in '''lv1_allocate_memory''' HV call or in '''syscall 0x10000'''.
| 0x17002
 
| Read EID Data By Index/Read metldr
=== vtable  ===
|-
 
| 0x17003
0x00357D08 (3.15)
| Read ID Data
 
|-
=== Member variables  ===
| 0x17004
 
| Read System Data
offset 0xB0 - pointer to object that stores a list of addresses of physical pages owned by this memory region
|-
 
| 0x17005
offset 0xB8 - pointer to LPAR object that owns this memory region
| Write System Data?
|-
| 0x17006
| Write smth?
|-
| 0x17007
| Read System Data From EEPROM
|-
| 0x17008
| not implemented
|-
| 0x17009
| unknown
|-
| 0x1700A
| not implemented
|-
| 0x1700B
| not implemented
|-
| 0x1700C
| not implemented
|-
| 0x1700D
| not implemented
|-
| 0x1700E
| not implemented
|-
| 0x1700F
| not implemented
|-
| 0x17010
| unknown
|-
| 0x17011
| unknown
|-
| 0x17012
| unknown
|-
| 0x17013
| Read eEID Size
|-
| 0x17014
| Write eEID/Write metldr
|-
| 0x17015
| Read cISD Size
|-
| 0x17016
| Read cISD
|-
| 0x17017
| Write cISD
|}


offset 0xC0 - reference counter (8 bytes)
*Indi Info Manager is accessed e.g. in '''syscall 868''' on GameOS


=== Objects ===
=== 0x17001 - Read EID Data Size By Index ===


Here is the list of physical memory region objects i found in HV 3.15.  
*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"
{| class="wikitable FCK__ShowTableBorders"
|-
|-
! Address in HV dump
! Index
! LPAR id
! Size Of Data
! LPAR Start Address
! Description
! Size
|-
! Flags
| 0
! log2(Page Size)
| 0x860
! Physical Page Addresses
| EID0
|-
|-
| 0x006B5510
| 1  
| 1  
| 0x300000001000
| 0x2A0
| 0x1000
| EID1
| 0x0
|-
| 0xC
| 2
| 0x672000
| 0x730
| EID2
|-
|-
| 0x006B5E50
| 3
| 1
| 0x100
| 0x440000040000
| EID3
| 0x20000
| 0x0
| 0x11
| 0x6C0000
|-
|-
| 0x006B6980
| 4
| 1
| 0x030
| 0x440000060000
| EID4
| 0x20000
| 0x0
| 0x11
| 0x6E0000
|-
|-
| 0x006B7F00
| 5
| 1
| 0xA00
| 0x400000040000
| EID5
| 0x10000
|-
| 0x0
| 6
| 0x10
| 0x020
| 0x100000
| cISD0
|-
| 7
| 0x200
| cISD1
|-
| 8
| 0x010
| cISD2
|-
|-
| 0x003A80F0
| 9
| 2
| 0x030
| 0x6C0058000000
| cCSD0
| 0x7000000
| 0x4
| 0x18
| 0x1000000 - 0x7000000
|-
|-
| 0x003BE800
| 2
| 0x300000047000
| 0x1000  
| 0x1000  
| 0x0
| 0xe960
| 0xC
| metldr - size is version dependand
| 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.  
=== 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'''.


=== GameOS Physical Memory Regions ===
=== 0x17007 - Read System Data From EEPROM ===


*GameOS allocates nearly all physical memory of PS3 for itself&nbsp;!!! That is why new HV calls '''lv1_allocate_memory''' with large memory region sizes will fail.
*Reads data from SC EEPROM
*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.
*An index is passed to the service. The index is mapped to a specific SC EEPROM offset.


Here is the list of physical memory regions of GameOS i found in HV 3.41:  
Here is the list of possible EEPROM offsets from HV 3.15:  


{| class="wikitable FCK__ShowTableBorders"
{| class="wikitable FCK__ShowTableBorders"
|-
|-
! Start Address
! Index
! Size
! SC EEPROM Offset
! Access Right
! Size Of Data
! Max Page Size  
! Flags
! Real Addresses
|-
|-
| 0x0
| 0
| 0x1000000
| 0x48D20
| 0x3
| 6
| 0x18
| 0x8
| 0x1000000 - 0x1FFF000
|-
|-
| 0x500000300000
| 1
| 0xA0000
| 0x48D28
| 0x3
| 6
| 0x10
| 0x8
| 0x380000 - 0x38F000, 0x3B0000 - 0x3BF000, 0x1E0000 - 0x1FF000, 0x3C0000 - 0x3FF000, 0xFF00000 - 0xFF1F000
|-
|-
| 0x700020000000
| 2
| 0xE900000 (huge memory region)
| 0x48D30
| 0x3
| 6
| 0x14
|-
| 0x0
| 3
| 0x400000 - 0x5FF000, 0x800000 - 0xFFF000, 0x2000000 - 0xFEFF000
| 0x48D38
| 6
|-
| 4
| 0x48D00
| 4
|-
| 5
| 0x48D04
| 4
|-
| 6
| 0x48D08
| 4
|}
|}


== HTAB Memory Region class ==
=== 0x17014 - Write eEID/Write metldr ===
 
*'''Holy crap, it writes passed data to the region of FLASH memory where eEID or metldr data is stored&nbsp;!!!'''
*'''And GameOS is allowed to use this service&nbsp;!!!'''
*'''Do not experiment with this service if you don't know what it does or else your PS3 will not work anymore&nbsp;!!!'''
 
=== 0x17015 - Read cISD Size  ===


This memory region is created when a HTAB is mapped into LPAR's address space. It's created in '''lv1_map_htab''' HV call.
*Returns size of data '''cISD''' that is stored on '''FLASH storage device region 0'''


=== vtable ===
=== 0x17016 - Read cISD ===


0x00357C98 (3.15)
*Returns data '''cISD''' that is stored on '''FLASH storage device region 0'''


=== Member variables ===
=== 0x17017 - Write cISD ===


offset 0xB0 - pointer to VAS object that owns the HTAB
*'''Writes passed data to the region of FLASH memory where cISD data is stored&nbsp;!!!'''


=== Objects ===
== 0x18000 - DM (Dispatcher Manager) ==


Here is the list of HTAB memory region objects i found in HV 3.15.  
*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/&lt;LPAR id&gt;/vuart/10'''. When the file '''/proc/partitions/&lt;LPAR id&gt;/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"
|-
|-
! Address in HV dump
! Packet ID
! LPAR id
! Description
! VAS id
! LPAR Start Address
! Size
! Flags
! log2(Page Size)
|-
| 0x001FE0F0
| 2
| 3
| 0x500000C00000
| 0x100000
| 0xC000000000000000
| 0x14
|-
|-
| 0x003BD850
| 0x18001
| 2
| Construct Service Port
| 3
| 0x500004300000
| 0x100000
| 0xC000000000000000
| 0x14
|-
|-
| 0x003BDEA0
| 0x18002
| 2
| Destruct Service Port
| 3
| 0x500004500000
| 0x100000
| 0xC000000000000000
| 0x14
|}
|}


=== GameOS HTAB ===
=== Dispatcher Manager Messages ===


*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'''
==== Dispatcher Manager Header  ====
*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 ===
*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"
|-
! 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
|}
 
== 0x25000 - User Token Manager  ==


Here is the dump of SLB entries from GameOS 3.41:
{| class="wikitable FCK__ShowTableBorders"
<pre>0x8000000008000000  0x0000000000000500
|-
0x8000000208000000  0x0000000000020500
! Packet ID
0x8000000300000000  0x0000000000030510
! Description
0x0000000000000000  0x0000000000000000
|-
0x0000000080000000  0x0000000000038C00
| 0x25001
0x00000000A0000000  0x000000000003AC00
| Encrypt User Token
0x00000000C0000000  0x000000000003CC00
|-
0x0000000000000000  0x0000000000000000
| 0x25002
0x0000000000000000  0x0000000000000000
| Decrypt User Token
0x0000000000000000  0x0000000000000000
|}
0x0000000000000000  0x0000000000000000
 
0x0000000000000000 0x0000000000000000
=== User Token ===
0x0000000000000000  0x0000000000000000
 
0x0000000000000000  0x0000000000000000
*Before User Token Manager encrypts a received user token it checks it's format.
0x0000000000000000  0x0000000000000000
*User Tokens are processed by '''spu_utoken_processor.self'''
0x0000000000000000  0x0000000000000000
*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.
0x0000000000000000  0x0000000000000000
 
0x0000000000000000 0x0000000000000000
==== User Token Format ====
0x0000000000000000  0x0000000000000000
<pre>stuct user_token_attr
0x0000000000000000  0x0000000000000000
{
0x0000000000000000  0x0000000000000000
    uint32_t type;                                /* 0x00000001, value&nbsp;!= 0x00000001 means attribute list ends here */
0x0000000000000000  0x0000000000000000
    uint32_t size;                                /* 8 + sizeof(data) */
0x0000000000000000  0x0000000000000000
    /* data follows here, size of data may be 0 */
0x0000000000000000  0x0000000000000000
}
0x0000000000000000  0x0000000000000000
 
0x0000000000000000  0x0000000000000000
struct user_token
0x0000000000000000  0x0000000000000000
{
0x0000000000000000  0x0000000000000000
    uint32_t magic;                                /* 0x73757400 = "sut\0" */
0x0000000000000000  0x0000000000000000
    uint32_t format_version;                      /* 0x00000001 */
0x0000000000000000  0x0000000000000000
    uint64_t size;
0x0000000000000000  0x0000000000000000
    uint8_t idps[16];
0x0000000000000000  0x0000000000000000
    uint64_t expire_date;
0x8000000010057960  0x8000000000313E78
    uint64_t capability;
0x8000000010057940  0x0000000000000000
    union
0x800000000001B698  0x0000000000000000
    {
0x8000000010057930  0x8000000000490708
        stuct user_token_attr attrs[0];
0x80000000002B6C68  0x80000000003DE928
        uint8_t dummy[3072];
0x8000000010057EC0  0x80000000003DE920
    } attrs;
0x0000000000000000  0x8000000000309810
    /* 0xC30 */
0x80000000004B3000  0x0000000000000000
    uint8_t digest[20];
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>
</pre>
== SPE MMIO Memory Region class  ==
= LPAR Memory Management  =
 
== 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'''.  
This class is the base class for different memory region types.  


=== vtable  ===
=== vtable  ===


0x003583F8 (3.15)  
0x003578B0 (3.15)  


=== Member variables  ===
=== Member variables  ===


=== Objects  ===
offset 0x40 - pointer to LPAR object that owns this memory region
 
offset 0x48 - type of memory region (8 bytes)


Here is the list of SPE memory region objects i found in HV 3.15.
offset 0x50 - LPAR start address of memory region  


{| class="wikitable FCK__ShowTableBorders"
offset 0x58 - size of memory region (8 bytes)
|-
 
! Address in HV dump  
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 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 list of physical memory region objects i found in HV 3.15.
 
{| class="wikitable FCK__ShowTableBorders"
|-
! Address in HV dump  
! LPAR id  
! LPAR id  
! SPE
! LPAR Start Address  
! LPAR Start Address  
! Size  
! Size  
! Physical Address
! Flags  
! Flags  
! log2(Page Size)
! log2(Page Size)  
! Physical Page Addresses
|-
|-
| 0x003ABC20
| 0x006B5510
| 2
| 1
| 0x300000001000
| 0x1000
| 0x0
| 0xC
| 0x672000
|-
| 0x006B5E50
| 1
| 0x440000040000
| 0x20000
| 0x0
| 0x11
| 0x6C0000
|-
| 0x006B6980
| 1
| 0x440000060000
| 0x20000
| 0x0
| 0x11
| 0x6E0000
|-
| 0x006B7F00
| 1  
| 1  
| 0x4C0000880000
| 0x400000040000
| 0x80000
| 0x10000
| 0x20000080000
| 0x0
| 0xA000000000000000
| 0x10
| 0xC
| 0x100000
|-
|-
| 0x003AAD70
| 0x003A80F0
| 2  
| 2  
| 2
| 0x6C0058000000
| 0x4C0000980000
| 0x7000000
| 0x80000
| 0x4
| 0x20000100000
| 0x18
| 0xA000000000000000
| 0x1000000 - 0x7000000
| 0xC
|-
|-
| 0x003A8880
| 0x003BE800
| 2  
| 2  
| 3
| 0x300000047000
| 0x4C0000780000
| 0x1000
| 0x80000
| 0x0
| 0x20000180000
| 0xC
| 0xA000000000000000
| 0x1FA000
| 0xC
|-
|-
| 0x003B4F70
| 0x006BDAA0
| 2  
| 2  
| 4
| 0x0
| 0x4C0000A80000
| 0x8000000
| 0x80000
| 0x8
| 0x20000200000
| 0x1B (single huge page)
| 0xA000000000000000
| 0x8000000
| 0xC
|-
| 0x003AB700
| 2
| 5
| 0x4C0000680000
| 0x80000
| 0x20000280000
| 0xA000000000000000
| 0xC
|-
| 0x003B5BE0
| 2
| 6
| 0x4C0000B80000
| 0x80000
| 0x20000300000
| 0xA000000000000000
| 0xC
|}
|}


== SPE Shadow Registers Memory Region class  ==
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.


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'''.
=== GameOS Physical Memory Regions  ===


=== vtable  ===
*GameOS allocates nearly all physical memory of PS3 for itself&nbsp;!!! 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.


0x00358448 (3.15)
Here is the list of physical memory regions of GameOS i found in HV 3.41:
 
=== Objects  ===
 
Here is the list of SPE Shadow Registers memory region objects i found in HV 3.15.


{| class="wikitable FCK__ShowTableBorders"
{| class="wikitable FCK__ShowTableBorders"
|-
|-
! Address in HV dump
! Start Address  
! LPAR id
! SPE
! LPAR Start Address  
! Size  
! Size  
! Physical Address
! Access Right
! Max Page Size
! Flags  
! Flags  
! log2(Page Size)
! Real Addresses
|-
| 0x0
| 0x1000000
| 0x3
| 0x18
| 0x8
| 0x1000000 - 0x1FFF000
|-
|-
| 0x003ABDA0
| 0x500000300000
| 2
| 0xA0000
| 1
| 0x3
| 0x300000012000
| 0x10
| 0x1000
| 0x8
| -  
| 0x380000 - 0x38F000, 0x3B0000 - 0x3BF000, 0x1E0000 - 0x1FF000, 0x3C0000 - 0x3FF000, 0xFF00000 - 0xFF1F000
| 0xA000000000000000
| 0xC
|-
|-
| 0x003B4290
| 0x700020000000
| 2
| 0xE900000 (huge memory region)
| 2
| 0x3
| 0x300000014000
| 0x14
| 0x1000
| 0x0
| -  
| 0x400000 - 0x5FF000, 0x800000 - 0xFFF000, 0x2000000 - 0xFEFF000
| 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  ==
== HTAB 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'''.  
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  ===
=== vtable  ===


0x00352468 (3.15)  
0x00357C98 (3.15)  


=== Member variables  ===
=== Member variables  ===


offset 0xA8 - physical address where the device MMIO region is mapped to
offset 0xB0 - pointer to VAS object that owns the HTAB


=== Objects  ===
=== Objects  ===


Here is the list of Device MMIO memory region objects i found in HV 3.15.  
Here is the list of HTAB memory region objects i found in HV 3.15.  


{| class="wikitable FCK__ShowTableBorders"
{| class="wikitable FCK__ShowTableBorders"
Line 5,258: Line 5,373:
! Address in HV dump  
! Address in HV dump  
! LPAR id  
! LPAR id  
! VAS id
! LPAR Start Address  
! LPAR Start Address  
! Size  
! Size  
! Flags  
! Flags  
! log2(Page Size)  
! log2(Page Size)
! Physical Address
! Device
|-
|-
| 0x001FDF00
| 0x001FE0F0
| 2  
| 2  
| 0x4000001D0000
| 3
| 0x10000
| 0x500000C00000
| 0x8000000000000000
| 0x100000
| 0xC
| 0xC000000000000000
| 0x24003010000
| 0x14
| USB controller
|-
|-
| 0x003B3850
| 0x003BD850
| 2  
| 2  
| 0x400000200000
| 3
| 0x10000
| 0x500004300000
| 0x8000000000000000
| 0x100000
| 0xC
| 0xC000000000000000
| 0x24003020000
| 0x14
| USB controller
|-
|-
| 0x003B6E50
| 0x003BDEA0
| 2  
| 2  
| 0x4000001E0000
| 3
| 0x10000
| 0x500004500000
| 0x8000000000000000
| 0x100000
| 0xC
| 0xC000000000000000
| 0x24003810000
| 0x14
| USB controller
|-
| 0x003B9950
| 2
| 0x4000001F0000
| 0x10000
| 0x8000000000000000
| 0xC
| 0x24003820000
| USB controller
|}
|}


== GPU Device Memory Region class ==
=== GameOS HTAB ===


This type of memory region is created e.g. in '''lv1_gpu_open''', '''lv1_gpu_device_map''' and '''lv1_undocumented_function_114'''.
*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'''
=== vtable  ===
*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


0x00357C48 (3.15)
=== GameOS SLB  ===


=== Member variables  ===
Here is the dump of SLB entries from GameOS 3.41:
 
<pre>0x8000000008000000  0x0000000000000500
offset 0xA8 - physical address
0x8000000208000000  0x0000000000020500
 
0x8000000300000000  0x0000000000030510
=== Objects  ===
0x0000000000000000  0x0000000000000000
 
0x0000000080000000  0x0000000000038C00
Here is the list of Device GPU memory region objects i found in HV 3.15.  
0x00000000A0000000  0x000000000003AC00
 
0x00000000C0000000  0x000000000003CC00
{| class="wikitable FCK__ShowTableBorders"
0x0000000000000000  0x0000000000000000
|-
0x0000000000000000  0x0000000000000000
! Address in HV dump
0x0000000000000000  0x0000000000000000
! LPAR id
0x0000000000000000  0x0000000000000000
! LPAR Start Address
0x0000000000000000  0x0000000000000000
! Size
0x0000000000000000  0x0000000000000000
! Flags
0x0000000000000000  0x0000000000000000
! log2(Page Size)
0x0000000000000000  0x0000000000000000
! Physical Address
0x0000000000000000  0x0000000000000000
|-
0x0000000000000000  0x0000000000000000
| 0x003AF380
0x0000000000000000  0x0000000000000000
| 2
0x0000000000000000  0x0000000000000000
| 0x700190000000
0x0000000000000000  0x0000000000000000
| 0xFE00000
0x0000000000000000  0x0000000000000000
| 0x8000000000000000
0x0000000000000000  0x0000000000000000
| 0x14
0x0000000000000000  0x0000000000000000
| 0x28080000000
0x0000000000000000  0x0000000000000000
|-
0x0000000000000000  0x0000000000000000
| 0x003AF500
0x0000000000000000  0x0000000000000000
| 2
0x0000000000000000  0x0000000000000000
| 0x4000001A0000
0x0000000000000000  0x0000000000000000
| 0xC000
0x0000000000000000  0x0000000000000000
| 0x8000000000000000
0x0000000000000000  0x0000000000000000
| 0xC
0x0000000000000000  0x0000000000000000
| 0x3C0000
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"
|-
|-
| 0x003AF680
! Address in HV dump
| 2  
! LPAR id
| 0x4800006C0000
! SPE
| 0x40000
! LPAR Start Address
| 0x8000000000000000
! Size
| 0xC  
! Physical Address
| 0x2808FE00000
! Flags
! log2(Page Size)
|-
| 0x003ABC20
| 2  
| 1
| 0x4C0000880000
| 0x80000
| 0x20000080000
| 0xA000000000000000
| 0xC
|-
| 0x003AAD70
| 2
| 2
| 0x4C0000980000
| 0x80000
| 0x20000100000
| 0xA000000000000000
| 0xC
|-
|-
| 0x003AFC30
| 0x003A8880
| 2  
| 2  
| 0x440000380000
| 3
| 0x20000
| 0x4C0000780000
| 0x8000000000000000
| 0x80000
| 0xC
| 0x20000180000
| 0x28000C00000
| 0xA000000000000000
| 0xC
|-
|-
| 0x003BB420
| 0x003B4F70
| 2  
| 2  
| 0x3C0000108000
| 4
| 0x8000
| 0x4C0000A80000
| 0x8000000000000000
| 0x80000
| 0xC  
| 0x20000200000
| 0x28000080100
| 0xA000000000000000
|}
| 0xC
 
|-
== Direct Map Memory Region class ==
| 0x003AB700
 
| 2
This type of memory region is created in HV call '''lv1_undocumented_function_114'''.
| 5
'''lv1_undocumented_function_114''' allows you to map any memory address into LPAR's memory address.
| 0x4C0000680000
 
| 0x80000
* The HV call '''lv1_undocumented_function_115''' destroys a memory region of this type.
| 0x20000280000
* HV allows GameOS to create objects of this type of size 0 only !!! But it can be exploited with a dangling HTAB entry.
| 0xA000000000000000
 
| 0xC
=== vtable  ===
|-
 
| 0x003B5BE0
0x00357C48 (3.15)
| 2
 
| 6
=== Member variables  ===
| 0x4C0000B80000
 
| 0x80000
offset 0xA8 - physical address
| 0x20000300000
| 0xA000000000000000
| 0xC
|}


=== Exploiting HV with memory glitching and HV call lv1_undocumented_function_114 ===
== SPE Shadow Registers Memory Region class  ==


Here is a short description of the method i used to exploit HV from GameOS 3.15 and 3.41.
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'''.  


* First i used the Geohot's method to create a dangling HTAB entry.
=== vtable  ===
* 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  ==
0x00358448 (3.15)


LPAR_get_memory_region_by_start_address - 0x002C7C40 (3.15)
=== Objects  ===


LPAR_get_memory_region_by_address - 0x002C7DA8 (3.15)
Here is the list of SPE Shadow Registers memory region objects i found in HV 3.15.


LPAR_mem_addr_to_phys_addr(LPAR id, LPAR address, phys_addr) - 0x002FB8F0 (3.15)
{| class="wikitable FCK__ShowTableBorders"
 
|-
LPAR_construct_direct_mapping_mem_region - 0x002D4D04 (3.15)
! Address in HV dump
 
! LPAR id  
= Network Devices  =
! SPE
 
! LPAR Start Address
== Ethernet Gelic Device  ==
! Size
 
! Physical Address
device id = 0
! Flags
 
! log2(Page Size)
MAC Address: 00:1F:A7:C6:2A:C5
|-
| 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 memory base address = 0x24003004000 (size = 0x1000)
== Device MMIO Memory Region class  ==


== WLAN Gelic Device  ==
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'''.


device id = 0
=== vtable  ===


MAC Address: 02:1F:A7:C6:2A:C5 (locally administered)  
0x00352468 (3.15)  


=== Net Manager ===
=== Member variables ===


*Net Manager runs in Process 9
offset 0xA8 - physical address where the device MMIO region is mapped to  
*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 ===
=== Objects ===


The device supports 3 ioctl commands:
Here is the list of Device MMIO memory region objects i found in HV 3.15.


*0 - 0x002AC10C (3.15)  
{| class="wikitable FCK__ShowTableBorders"
*1 - 0x002AC250 (3.15)
|-
*2 - EURUS_STAT 0x002AC320 (3.15)
! 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
|}


=== Methods ===
== GPU Device Memory Region class ==


net_control_cmd_GELIC_LV1_POST_WLAN_CMD - 0x0024A55C (3.15)
This type of memory region is created e.g. in '''lv1_gpu_open''', '''lv1_gpu_device_map''' and '''lv1_undocumented_function_114'''.  


net_control_wlan_cmd_GELIC_EURUS_CMD_ASSOC - 0x00246C78 (3.15)
=== vtable  ===


net_control_wlan_cmd_GELIC_EURUS_CMD_START_SCAN - 0x00248A14 (3.15)
0x00357C48 (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  ===
=== Member variables  ===


offset 0x30 - type (8 bytes)
offset 0xA8 - physical address


offset 0x38 - pointer to LPAR that owns this Outlet object
=== Objects  ===


offset 0x48 - outlet id (8 bytes)
Here is the list of Device GPU memory region objects i found in HV 3.15.


offset 0x90 - VIRQ assigned to this Outlet object (4 bytes)  
{| class="wikitable FCK__ShowTableBorders"
 
|-
== Event Receive Port class  ==
! Address in HV dump
 
! LPAR id
*This type of Outlet is created e.g. in '''lv1_construct_event_receive_port''' and in '''syscall 0x1001A'''.
! LPAR Start Address
*HV calls '''lv1_connect_irq_plug''' and '''lv1_connect_irq_plug_ext''' assigns a VIRQ to Event Receive Port object.
! Size
 
! Flags
=== vtable  ===
! log2(Page Size)  
 
! Physical Address
0x00357E88
|-
 
| 0x003AF380
== VUART Outlet  ==
| 2
 
| 0x700190000000
*HV supports only one VUART Outlet per LPAR
| 0xFE00000
*'''lv1_configure_virtual_uart_irq''' constructs a VUART Outlet object and passes the address of LPAR's VUART IRQ Bitmap to HV
| 0x8000000000000000
 
| 0x14
=== vtable  ===
| 0x28080000000
 
|-
0x00357DC0
| 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
|}


=== VUART IRQ Bitmap  ===
== Direct Map Memory Region class ==


*At address 0x38(LPAR ptr) + 0x158 is the VUART IRQ Bitmap owned by HV for LPAR (4 * 8 bytes = 256 bits)
This type of memory region is created in HV call '''lv1_undocumented_function_114'''.
*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'''
'''lv1_undocumented_function_114''' allows you to map any memory address into LPAR's memory address.
*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  =
* 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.


*Logical PPE is used for interrupt management of LPAR.
=== vtable  ===
*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  ==
0x00357C48 (3.15)


0x00357DF0 (3.15)
=== Member variables  ===


== Member variables  ==
offset 0xA8 - physical address


offset 0x90 - pointer to an object that contains VIRQ-Outlet mapping table for thread 0
=== Exploiting HV with memory glitching and HV call lv1_undocumented_function_114 ===


offset 0x98 - pointer to an object that contains VIRQ-Outlet mapping table for thread 1
Here is a short description of the method i used to exploit HV from GameOS 3.15 and 3.41.


== Objects  ==
* 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.
Here is the list of Logical PPE objects i found in HV 3.15.  
* 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 :-)


{| class="wikitable FCK__ShowTableBorders"
== Methods  ==
|-
! Address in HV dump
! LPAR id
! PPE id
|-
| 0x0069C7F0
| 1
| 1
|-
| 0x007A8900
| 2
| 1
|}


== Virtual IRQ - Outlet Mapping  ==
LPAR_get_memory_region_by_start_address - 0x002C7C40 (3.15)


*HV maintains 2 tables per PPE that map a VIRQ to an Outlet object.
LPAR_get_memory_region_by_address - 0x002C7DA8 (3.15)
*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  ===
LPAR_mem_addr_to_phys_addr(LPAR id, LPAR address, phys_addr) - 0x002FB8F0 (3.15)


0x0069C990 (3.15) - address of VIRQ-Outlet table for '''LPAR 1 PPE 1 Thread 0''' (not empty)  
LPAR_construct_direct_mapping_mem_region - 0x002D4D04 (3.15)


{| class="wikitable FCK__ShowTableBorders"
= Network Devices  =
|-
! 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 ===
== Ethernet Gelic Device ==


0x0069D9B0 (3.15) - address of VIRQ-Outlet table for '''LPAR 1 PPE 1 Thread 1''' (empty)
device id = 0


=== LPAR 2 PPE 1 Thread 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)


0x000A06B0 (3.15) - address of VIRQ-Outlet table for '''LPAR 2 PPE 1 Thread 0''' (not empty)  
net_control_wlan_cmd_GELIC_EURUS_CMD_SET_WEP_CFG - 0x00249F24 (3.15)  


{| class="wikitable FCK__ShowTableBorders"
net_control_wlan_cmd_GELIC_EURUS_CMD_SET_WPA_CFG - 0x002497B8 (3.15)
|-
 
! VIRQ
= Event Notification  =
! Address of Outlet object in HV dump
 
! Description
*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.
| 20
*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.
| 0x003AA210
 
| -
== Outlet class  ==
|-
 
| 21
This is the base Outlet class. There are different types of Outlet and they derive from this base class.
| 0x003AFEC0
 
| -
=== vtable  ===
|-
 
| 22
0x00357DC0 (3.15)
| 0x001FC010
 
| -
=== Member variables  ===
|-
 
| 23
offset 0x30 - type (8 bytes)
| 0x003A8E50
 
| -
offset 0x38 - pointer to LPAR that owns this Outlet object
|-
 
| 24
offset 0x48 - outlet id (8 bytes)
| 0x001FFED0
 
| SPE 0 Class 0 Interrupt
offset 0x90 - VIRQ assigned to this Outlet object (4 bytes)
|-
 
| 25
== Event Receive Port class  ==
| 0x003AE160
 
| SPE 0 Class 1 Interrupt
*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.
| 26
 
| 0x003AE350
=== vtable  ===
| SPE 0 Class 2 Interrupt
 
|-
0x00357E88
| 27
 
| 0x003AB100
== VUART Outlet  ==
| SPE 1 Class 0 Interrupt
 
|-
*HV supports only one VUART Outlet per LPAR
| 28
*'''lv1_configure_virtual_uart_irq''' constructs a VUART Outlet object and passes the address of LPAR's VUART IRQ Bitmap to HV
| 0x003AB2F0
 
| SPE 1 Class 1 Interrupt
=== vtable  ===
|-
 
| 29
0x00357DC0
| 0x003AB4E0
 
| SPE 1 Class 2 Interrupt
=== VUART IRQ Bitmap  ===
|-
 
| 30
*At address 0x38(LPAR ptr) + 0x158 is the VUART IRQ Bitmap owned by HV for LPAR (4 * 8 bytes = 256 bits)
| 0x003AA6A0
*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'''
| SPE 2 Class 0 Interrupt
*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.
| 31
*'''GameOS 3.41''' VUART IRQ bitmap is at address '''0x80000000003556E8''' and of size '''32 bytes (256 bits, each bit corresponds to a VUART port)'''.
| 0x003AA890
*'''GameOS 3.15''' VUART IRQ bitmap is at address '''0x8000000000354768'''.
| SPE 2 Class 1 Interrupt
 
|-
= Logical PPE  =
| 32
 
| 0x003AAA80
*Logical PPE is used for interrupt management of LPAR.
| SPE 2 Class 2 Interrupt
*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
| 33
*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)
| 0x003B44A0
*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
| SPE 3 Class 0 Interrupt
 
|-
== vtable  ==
| 34
 
| 0x003B4690
0x00357DF0 (3.15)
| SPE 3 Class 1 Interrupt
 
== Member variables  ==
 
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"
|-
|-
| 35
! Address in HV dump
| 0x003B4AD0
! LPAR id
| SPE 3 Class 2 Interrupt
! PPE id
|-
|-
| 36
| 0x0069C7F0
| 0x003B5300
| 1
| SPE 4 Class 0 Interrupt
| 1
|-
|-
| 37
| 0x007A8900
| 0x003B54F0
| 2
| SPE 4 Class 1 Interrupt
| 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"
|-
|-
| 38
! VIRQ
| 0x003B56E0
! Address of Outlet object in HV dump
| SPE 4 Class 2 Interrupt
! Description
|-
|-
| 39
| 58
| 0x003AE7C0
| 0x00090D10
| SPE 5 Class 0 Interrupt
| -
|-
|-
| 40
| 59
| 0x003AE9B0
| 0x006BAC50
| SPE 5 Class 1 Interrupt
| -
|-
|-
| 41
| 60
| 0x003AEBA0
| 0x006B3ED0
| SPE 5 Class 2 Interrupt
| FLASH storage device / Storage device notification for LPAR 1
|-
|-
| 42
| 61
| 0x003B2040
| 0x00697E70
| Storage device notification for LPAR 2
|-
| 43
| 0x003AEE30
| VUART interrupts
| VUART interrupts
|-
|-
| 44
| 62
| 0x001FEAA0
| 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"
|-
|-
| 45
! VIRQ
| 0x001FEED0
! Address of Outlet object in HV dump
| HDD storage device
! Description
|-
|-
| 46
| 20
| 0x003B5E20
| 0x003AA210
| -
| -
|-
|-
| 47
| 21
| 0x003B7040
| 0x003AFEC0
| -
| -
|-
|-
| 48
| 22
| 0x003B9B40
| 0x001FC010
| -
| -
|-
|-
| 49
| 23
| 0x003B3A40
| 0x003A8E50
| -
| -
|-
|-
| 50
| 24
| 0x003BACA0
| 0x001FFED0
| Gelic device
| SPE 0 Class 0 Interrupt
|-
|-
| 51
| 25
| 0x003BAE10
| 0x003AE160
| UNKNOWN storage device
| SPE 0 Class 1 Interrupt
|-
|-
| 52
| 26
| 0x003B8350
| 0x003AE350
| -
| SPE 0 Class 2 Interrupt
|}
 
=== 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
| 27
! Address of Outlet object in HV dump
| 0x003AB100
! Description
| SPE 1 Class 0 Interrupt
|-
|-
| 16
| 28
| 0x003B2480
| 0x003AB2F0
| -
| SPE 1 Class 1 Interrupt
|-
|-
| 17
| 29
| 0x003B2590
| 0x003AB4E0
| -
| SPE 1 Class 2 Interrupt
|-
|-
| 18
| 30
| 0x003B26A0
| 0x003AA6A0
| -
| SPE 2 Class 0 Interrupt
|-
|-
| 19
| 31
| 0x003B27B0
| 0x003AA890
| -
| SPE 2 Class 1 Interrupt
|}
 
== IRQ State Bitmap  ==
 
*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&nbsp;!!!
*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)  =
 
*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
| 32
! Address of VUART object in HV dump
| 0x003AAA80
! Description
| SPE 2 Class 2 Interrupt
|-
|-
| 0
| 33
| 0x0060FD20
| 0x003B44A0
| This VUART is connected with the '''VUART 0 (/dev/sc0)''' of LPAR 1
| SPE 3 Class 0 Interrupt
|-
|-
| 1
| 34
| 0x0060FE20
| 0x003B4690
| This VUART is connected with the '''VUART 1 (/dev/sc1)''' of LPAR 1
| SPE 3 Class 1 Interrupt
|-
|-
| 2  
| 35
| 0x0060FF20
| 0x003B4AD0
| This VUART is not connected to some peer VUART but i guess that it should be connected to '''VUART 2 (/dev/sc2)''' of LPAR1
| 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
|-
|-
| 3
| 42
| 0x006124E0
| 0x003B2040
| This VUART is connected with the '''VUART 3 (/dev/sc3)''' of LPAR 1
| Storage device notification for LPAR 2
|-
|-
| 4
| 43
| 0x00612DF0
| 0x003AEE30
| '''lv1_get_rtc''' and '''syscall 0x10036''' communicate with this VUART.
| VUART interrupts
|}
|-
 
| 44
== Interrupt Handling  ==
| 0x001FEAA0
 
| -
spider_sc_interrupt_handler - 0x0020A68C (3.15)
|-
 
| 45
== Methods  ==
| 0x001FEED0
 
| HDD storage device
sc_vuart_4_get_peer_vuart - 0x002ED384 (3.15)
|-
 
| 46
sc_send - 0x0020A908 (3.15)
| 0x003B5E20
 
| -
sc_receive - 0x0020A354 (3.15)
|-
 
| 47
sc_vuart_rx_trigger_callback - 0x002ED470 (3.15)
| 0x003B7040
 
| -
== lv1_get_rtc  ==
|-
 
| 48
*'''lv1_get_rtc''' communicates with SC VUART 4.
| 0x003B9B40
*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.
| 49
 
| 0x003B3A40
== SYSCON Protocol ==
| -
|-
| 50
| 0x003BACA0
| Gelic device
|-
| 51
| 0x003BAE10
| UNKNOWN storage device
|-
| 52
| 0x003B8350
| -
|}


* I was able to enable SYSCON Manager debug messages in HV Process 5
=== LPAR 2 PPE 1 Thread 1  ===
* 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 ===
0x007A89E0 (3.15) - address of VIRQ-Outlet table for '''LPAR 2 PPE 1 Thread 1''' (not empty)


* Packet header is of size '''0x10''' bytes.
{| class="wikitable FCK__ShowTableBorders"
* 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'''
! VIRQ
* The '''2nd byte''' in every SYSCON message has to be '''1''' or else the function '''sc_send''' fails.
! Address of Outlet object in HV dump
* The '''word''' at offset '''0x8''' is the '''SC VUART index'''.
! Description
* The '''half-words''' at offset '''0xC''' and '''0xE''' have to be equal or the function '''sc_send''' fails.
|-
 
| 16
<pre>
| 0x003B2480
struct sc_hdr
| -
{
|-
    uint8_t field0;
| 17
    uint8_t field1;          /* always 1 */
| 0x003B2590
    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) */
| 18
    uint16_t size1;          /* body size */
| 0x003B26A0
    uint16_t size2;          /* body size */
| -
};
|-
</pre>
| 19
| 0x003B27B0
| -
|}


==== Calculating Packet Header Checksum ====
== IRQ State Bitmap  ==


<pre>
*There is one IRQ State Bitmap (256 bits = 32 bytes) per thread of Logical PPE
/* calculating SC packet header checksum */
*'''HSPRG0 value is per thread''', so there are 2 HSPRG0 values in HV dump&nbsp;!!!
*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
* sc_hdr_cksum
*/
uint16_t sc_hdr_cksum(struct sc_hdr *sc_hdr)
{
    uint8_t *ptr;
    uint32_t sum;


    ptr = (uint8_t *) sc_hdr;
0x8948FC0 - physical address of LPAR's IRQ State Bitmap for Thread 1 of LINUX LPAR
    sum = 0;


    for (i = 0; i < 6; i++)
= System Controller (SC or SYSCON) =
        sum += *ptr++;


    sum += 0x8000;
*Data received from SC is sent to a VUART
*'''lv1_get_rtc''' and '''syscall 0x10036''' communicate with '''SC VUART 4'''.


    return sum & 0xffff;
=== VUART Table  ===
}


struct sc_hdr sc_hdr;
*Address of SC VUART Table - 0x00610410 (3.15).
*There are 5 VUARTs for SC in HV 3.15


memset(&sc_hdr, 0, sizeof(sc_hdr));
Here is the SC VUART table from HV 3.15:


sc_hdr.cksum = sc_hdr_cksum(sc_hdr);
{| class="wikitable FCK__ShowTableBorders"
 
|-
/* fill sc header here */
! 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.
|}


sc_hdr.cksum = sc_hdr_cksum(sc_hdr);
== Interrupt Handling  ==
</pre>


=== Packet Body ===
spider_sc_interrupt_handler - 0x0020A68C (3.15)


* Packet body follows packet header
== Methods  ==
* Packet body size is stored at offset '''0xC''' and '''0xE''' in packet header and is of size 2 bytes


=== Reading SYSCON EPROM (NVS Service) ===
sc_vuart_4_get_peer_vuart - 0x002ED384 (3.15)  


Here is a command which is sent to SYSCON to read 1 byte of EPROM at offset 0x48C07 (Product Mode):
sc_send - 0x0020A908 (3.15)
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:
sc_receive - 0x0020A354 (3.15)
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 ===
sc_vuart_rx_trigger_callback - 0x002ED470 (3.15)


* '''Used by PS2EMU System Manager in HV process 9 when PS2 EMU is booted'''
== lv1_get_rtc  ==


==== PCI Bus Power On ====
*'''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.


'''Request to SC1:'''
== SYSCON Protocol ==
0x10 0x01 0x00 0x00 0x00 0x00 0x80 0x11 0x00 0x00 0x00 0x00 0x00 0x02 0x00 0x02 0x31 0x01


==== PCI Bus Power Off ====
* 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.


'''Request to SC1:'''
=== Packet Header ===
0x10 0x01 0x00 0x00 0x00 0x00 0x80 0x11 0x00 0x00 0x00 0x00 0x00 0x02 0x00 0x02 0x31 0x00


=== Ring Buzzer ===
* Packet header is of size '''0x10''' bytes.
 
* At offset '''0x6''' of SYSCON packet is the header checksum which is of size '''2''' bytes.
'''Request:'''
* '''The header checkum is just a sum of first 6 header bytes and 0x8000 constant'''
0x16 0x01 0x00 0x00 0x00 0x00 0x80 0x17 0x00 0x00 0x00 0x00 0x00 0x08 0x00 0x08 0x20 0x00 0x00 0x00 0x00 0x00 0x00 0x00
* 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'''.
=SYSCON=
* The '''half-words''' at offset '''0xC''' and '''0xE''' have to be equal or the function '''sc_send''' fails.
Crossreference: [http://wiki.gitbrew.org/index.php/PS3:HvReverseEngineering#SYSCON gitbrew.org::SYSCON] <br />
 
SYSCON MMIO registers can be accessed on Linux with a driver using lv1_undocumented_function_114, e.g. '''ps3sbmmio'''.
Use ps3sbmmio device driver carefully, an access at some addresses could shutdown your PS3.
 
==Packet Header==
 
* Size is '''0x10'''.


<pre>
<pre>
struct sc_hdr {
struct sc_hdr
     uint8_t service_id;
{
     uint8_t version;             /* must be 1 !!! */
     uint8_t field0;
    uint16_t transaction_id;      /* returned in response */
     uint8_t field1;         /* always 1 */
     uint8_t res[2];
     uint8_t field2[4];
     uint16_t cksum;               /* checksum of first 6 header bytes */
     uint16_t cksum;         /* header checksum */
     uint32_t communication_tag;   /* SYSCON tag: 0-4 */
     uint32_t index;         /* syscon index (0 - /dev/sc0, 1 - /dev/sc1, 2 - /dev/sc2, 3 - /dev/sc3) */
     uint16_t payload_size[2];    /* body size */
     uint16_t size1;         /* body size */
     uint16_t size2;          /* body size */
};
};
</pre>
</pre>


==Sending Packets==
==== Calculating Packet Header Checksum ====


* Before sending new packet to SYSCON, the Hypervisor checks 2 words at offsets 0x2400008DFF0 and 0x2400008CFF4.
* The Hypervisor busy waits until (value + 1) at offset 0x2400008CFF4 is NOT equal to value at offset 0x2400008DFF0.
* The packet is sent with 4 byte transfers.
* First, the Hypervisor sends the header of the packet, 4 word transfers.
* The header is written beginning at the address 0x2400008D000.
* After that the Hypervisor sends the body of the packet, with 4 byte transfers too.
* The body is written beginning at the address 0x2400008D010.
* If the packet size is NOT divisible by 4 then the Hypervisor sends the remaining bytes (at most 3) as a word padded with 0s.
* After the packet body was written, the Hypervisor calculates checksum of the whole packet and writes it at the address where the last word of packet body was written + 4.
<pre>
<pre>
uint32_t cksum = 0;
/* calculating SC packet header checksum */
 
/*
* sc_hdr_cksum
*/
uint16_t sc_hdr_cksum(struct sc_hdr *sc_hdr)
{
    uint8_t *ptr;
    uint32_t sum;


for (i = 0; i < packet_size; i++)
    ptr = (uint8_t *) sc_hdr;
     cksum -= packet[i];
     sum = 0;


cksum = cksum & 0xffff;
    for (i = 0; i < 6; i++)
</pre>
        sum += *ptr++;
* After the packet checksum was written, the Hypervisor reads the value at offset 0x2400008DFF0, modifies it and stores back:
<pre>
value = value + 1;
value &= 0xffff;
value = (value << 16) | value;
</pre>
* To notify the SYSCON about the new packet, the Hypervisor writes 0x1 to address 0x2400008E100.


==Receiving Packets==
    sum += 0x8000;


* The Hypervisor installs an interrupt handler for the SYSCON.
    return sum & 0xffff;
* First, the Hypervisor reads a word from address 0x2400008E000, ors it with 0xFFFFFFFD and writes the value back.
}
* Then, the Hypervisor reads a word from address 0x2400008E004 and tests if bit 0x2 is set or not. The bit 0x2 should be not 0 or else the Hypervisor panics.
* After that, the Hypervisor reads a word at address 0x2400008CFF0 and 0x2400008DFF4. If there is a new packet pending from SYSCON, then the (value + 1) at 0x2400008CFF0 should be equal the value at 0x2400008DFF4.
* The Hypervisor reads the header of the packet beginning at the address 0x2400008C000.
* The header is read with 4 word transfers by the Hypervisor.
* The byte at offset 1 in the packet header must be 1 or else the Hypervisor discards the packet as invalid.
* The Hypervisor calculates the checksum of the packet header and checks it with the checksum stored in the header. If they don't match then the Hypervisor discards the packet.
* The Hypervisor reads the body of the packet beginning at the address 0x2400008C010.
* The header and the body of the received packet can be read as many times as you want !!! They remain until next SYSCON packet is received
which gives us the possibility to communicate with SYSCON on Linux easily :)


==Test==
struct sc_hdr sc_hdr;


'''1. Before sending SYSCON packet''':
memset(&sc_hdr, 0, sizeof(sc_hdr));
<pre>
root@debian-hdd:~# dd if=/dev/ps3sbmmio bs=1 count=4 skip=$((0x8cff4)) status=noxfer | hexdump -C


00000000  01 18 01 18                                      |....|
sc_hdr.cksum = sc_hdr_cksum(sc_hdr);
00000004


root@debian-hdd:~# dd if=/dev/ps3sbmmio bs=1 count=4 skip=$((0x8dff0)) status=noxfer | hexdump -C
/* fill sc header here */


00000000  01 18 01 18                                      |....|
sc_hdr.cksum = sc_hdr_cksum(sc_hdr);
00000004
</pre>


root@debian-hdd:~# dd if=/dev/ps3sbmmio bs=1 count=4 skip=$((0x8cff0)) status=noxfer | hexdump -C
=== Packet Body ===


00000000  01 24 01 24                                      |.$.$|
* Packet body follows packet header
00000004
* Packet body size is stored at offset '''0xC''' and '''0xE''' in packet header and is of size 2 bytes


root@debian-hdd:~# dd if=/dev/ps3sbmmio bs=1 count=4 skip=$((0x8dff4)) status=noxfer | hexdump -C
=== Reading SYSCON EPROM (NVS Service) ===


00000000 01 24 01 24                                      |.$.$|
Here is a command which is sent to SYSCON to read 1 byte of EPROM at offset 0x48C07 (Product Mode):
00000004
  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
</pre>


'''2. SYSCON packet was sent by using ps3dm_scm read_eprom.'''
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


'''3. After sending SYSCON packet''':
=== PCI Bus Power ===
<pre>
root@debian-hdd:~# dd if=/dev/ps3sbmmio bs=1 count=4 skip=$((0x8cff4)) status=noxfer | hexdump -C


00000000  01 19 01 19                                      |....|
* '''Used by PS2EMU System Manager in HV process 9 when PS2 EMU is booted'''
00000004


root@debian-hdd:~# dd if=/dev/ps3sbmmio bs=1 count=4 skip=$((0x8dff0)) status=noxfer | hexdump -C
==== PCI Bus Power On ====


00000000 01 19 01 19                                      |....|
'''Request to SC1:'''
00000004
  0x10 0x01 0x00 0x00 0x00 0x00 0x80 0x11 0x00 0x00 0x00 0x00 0x00 0x02 0x00 0x02 0x31 0x01


root@debian-hdd:~# dd if=/dev/ps3sbmmio bs=1 count=4 skip=$((0x8cff0)) status=noxfer | hexdump -C
==== 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


00000000  01 25 01 25                                      |.%.%|
=== Ring Buzzer ===
00000004


root@debian-hdd:~# dd if=/dev/ps3sbmmio bs=1 count=4 skip=$((0x8dff4)) status=noxfer | hexdump -C
'''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


00000000  01 25 01 25                                      |.%.%|
=SYSCON=
00000004
Crossreference: [http://wiki.gitbrew.org/index.php/PS3:HvReverseEngineering#SYSCON gitbrew.org::SYSCON] <br />
</pre>


'''4. Received Header'''
SYSCON MMIO registers can be accessed on Linux with a driver using lv1_undocumented_function_114, e.g. '''ps3sbmmio'''.
Use ps3sbmmio device driver carefully, an access at some addresses could shutdown your PS3.


<pre>
==Packet Header==
root@debian-hdd:~# dd if=/dev/ps3sbmmio bs=1 count=16 skip=$((0x8c000)) status=noxfer | hexdump -C


00000000  14 01 00 00 00 00 80 15  00 00 00 03 00 05 00 05  |................|
* Size is '''0x10'''.
00000010


<pre>
struct sc_hdr {
    uint8_t service_id;
    uint8_t version;              /* must be 1 !!! */
    uint16_t transaction_id;      /* returned in response */
    uint8_t res[2];
    uint16_t cksum;              /* checksum of first 6 header bytes */
    uint32_t index;              /* SYSCON index: 0-4 */
    uint16_t payload_size[2];    /* body size */
};
</pre>
</pre>


'''5. Received Body'''
==Sending Packets==


* Before sending new packet to SYSCON, the Hypervisor checks 2 words at offsets 0x2400008DFF0 and 0x2400008CFF4.
* The Hypervisor busy waits until (value + 1) at offset 0x2400008CFF4 is NOT equal to value at offset 0x2400008DFF0.
* The packet is sent with 4 byte transfers.
* First, the Hypervisor sends the header of the packet, 4 word transfers.
* The header is written beginning at the address 0x2400008D000.
* After that the Hypervisor sends the body of the packet, with 4 byte transfers too.
* The body is written beginning at the address 0x2400008D010.
* If the packet size is NOT divisible by 4 then the Hypervisor sends the remaining bytes (at most 3) as a word padded with 0s.
* After the packet body was written, the Hypervisor calculates checksum of the whole packet and writes it at the address where the last word of packet body was written + 4.
<pre>
<pre>
root@debian-hdd:~# dd if=/dev/ps3sbmmio bs=1 count=8 skip=$((0x8c010)) status=noxfer | hexdump -C
uint32_t cksum = 0;
 
for (i = 0; i < packet_size; i++)
    cksum -= packet[i];


00000000  00 00 c7 01 ff 00 00 00                          |..Ç.ÿ...|
cksum = cksum & 0xffff;
00000008
</pre>
* After the packet checksum was written, the Hypervisor reads the value at offset 0x2400008DFF0, modifies it and stores back:
<pre>
value = value + 1;
value &= 0xffff;
value = (value << 16) | value;
</pre>
</pre>
* To notify the SYSCON about the new packet, the Hypervisor writes 0x1 to address 0x2400008E100.


==Examples==
==Receiving Packets==
 
===Get RTC===


* Used by LV1 call '''lv1_get_rtc'''
* The Hypervisor installs an interrupt handler for the SYSCON.
* Communication with SYSCON 4
* First, the Hypervisor reads a word from address 0x2400008E000, ors it with 0xFFFFFFFD and writes the value back.
* Then, the Hypervisor reads a word from address 0x2400008E004 and tests if bit 0x2 is set or not. The bit 0x2 should be not 0 or else the Hypervisor panics.
* After that, the Hypervisor reads a word at address 0x2400008CFF0 and 0x2400008DFF4. If there is a new packet pending from SYSCON, then the (value + 1) at 0x2400008CFF0 should be equal the value at 0x2400008DFF4.
* The Hypervisor reads the header of the packet beginning at the address 0x2400008C000.
* The header is read with 4 word transfers by the Hypervisor.
* The byte at offset 1 in the packet header must be 1 or else the Hypervisor discards the packet as invalid.
* The Hypervisor calculates the checksum of the packet header and checks it with the checksum stored in the header. If they don't match then the Hypervisor discards the packet.
* The Hypervisor reads the body of the packet beginning at the address 0x2400008C010.
* The header and the body of the received packet can be read as many times as you want !!! They remain until next SYSCON packet is received
which gives us the possibility to communicate with SYSCON on Linux easily :)
 
==Test==


Request:
'''1. Before sending SYSCON packet''':
<pre>
<pre>
# write packet
root@debian-hdd:~# dd if=/dev/ps3sbmmio bs=1 count=4 skip=$((0x8cff4)) status=noxfer | hexdump -C


# echo "0: 13 01 0000 0000 8014 00000004 0001 0001 33 00 00 00 0000ff1f" | xxd -c256 -r | \
00000000  01 18 01 18                                      |....|
      dd of=/dev/ps3sbmmio bs=1 seek=$((0x8d000)) status=noxfer
00000004


# dump packet counter
root@debian-hdd:~# dd if=/dev/ps3sbmmio bs=1 count=4 skip=$((0x8dff0)) status=noxfer | hexdump -C


# dd if=/dev/ps3sbmmio bs=1 count=4 skip=$((0x8dff0)) status=noxfer | hexdump -C
00000000  01 18 01 18                                       |....|
 
00000000  00 c0 00 c0                                       |.À.À|
00000004
00000004


# increment packet counter
root@debian-hdd:~# dd if=/dev/ps3sbmmio bs=1 count=4 skip=$((0x8cff0)) status=noxfer | hexdump -C


echo "0: 00c1 00c1" | xxd -c256 -r | dd of=/dev/ps3sbmmio bs=1 seek=$((0x8dff0)) status=noxfer
00000000  01 24 01 24                                      |.$.$|
00000004


# kick packet
root@debian-hdd:~# dd if=/dev/ps3sbmmio bs=1 count=4 skip=$((0x8dff4)) status=noxfer | hexdump -C
 
# echo "0: 00000001" | xxd -c256 -r | dd of=/dev/ps3sbmmio bs=1 seek=$((0x8e100)) status=noxfer


00000000  01 24 01 24                                      |.$.$|
00000004
</pre>
</pre>


Response:
'''2. SYSCON packet was sent by using ps3dm_scm read_eprom.'''


'''3. After sending SYSCON packet''':
<pre>
<pre>
# dump packet counter
root@debian-hdd:~# dd if=/dev/ps3sbmmio bs=1 count=4 skip=$((0x8cff4)) status=noxfer | hexdump -C
 
00000000  01 19 01 19                                      |....|
00000004


# dd if=/dev/ps3sbmmio bs=1 count=4 skip=$((0x8dff0)) status=noxfer | hexdump -C
root@debian-hdd:~# dd if=/dev/ps3sbmmio bs=1 count=4 skip=$((0x8dff0)) status=noxfer | hexdump -C


00000000  00 c1 00 c1                                       |.Á.Á|
00000000  01 19 01 19                                       |....|
00000004
00000004


# dump response packet
root@debian-hdd:~# dd if=/dev/ps3sbmmio bs=1 count=4 skip=$((0x8cff0)) status=noxfer | hexdump -C
 
00000000  01 25 01 25                                      |.%.%|
00000004


# dd if=/dev/ps3sbmmio bs=1 count=24 skip=$((0x8c000)) status=noxfer | hexdump -C
root@debian-hdd:~# dd if=/dev/ps3sbmmio bs=1 count=4 skip=$((0x8dff4)) status=noxfer | hexdump -C


00000000  13 01 00 00 00 00 80 14  00 00 00 04 00 08 00 08  |................|
00000000  01 25 01 25                                      |.%.%|
00000010  00 00 00 00 15 af 47 6b                          |.....¯Gk|
00000004
00000018
</pre>
</pre>


===Ring Buzzer===
'''4. Received Header'''
 
<pre>
root@debian-hdd:~# dd if=/dev/ps3sbmmio bs=1 count=16 skip=$((0x8c000)) status=noxfer | hexdump -C
 
00000000  14 01 00 00 00 00 80 15  00 00 00 03 00 05 00 05  |................|
00000010
 
</pre>
 
'''5. Received Body'''
 
<pre>
root@debian-hdd:~# dd if=/dev/ps3sbmmio bs=1 count=8 skip=$((0x8c010)) status=noxfer | hexdump -C
 
00000000  00 00 c7 01 ff 00 00 00                          |..Ç.ÿ...|
00000008
</pre>
 
==Examples==
 
===Get RTC===


* Used by System Manager
* Used by LV1 call '''lv1_get_rtc'''
* Communication with SYSCON 1
* Communication with SYSCON 4


Request:
Request:
<pre>
<pre>
# write packet
# write packet


# echo "0: 16 01 1620 0000 804d 00000001 0008 0008 20 29 0a 00 000001b6 0000fdcb" | xxd -c256 -r | \
# echo "0: 13 01 0000 0000 8014 00000004 0001 0001 33 00 00 00 0000ff1f" | xxd -c256 -r | \
       dd of=/dev/ps3sbmmio bs=1 seek=$((0x8d000)) status=noxfer
       dd of=/dev/ps3sbmmio bs=1 seek=$((0x8d000)) status=noxfer


Line 6,132: Line 6,484:


# echo "0: 00000001" | xxd -c256 -r | dd of=/dev/ps3sbmmio bs=1 seek=$((0x8e100)) status=noxfer
# echo "0: 00000001" | xxd -c256 -r | dd of=/dev/ps3sbmmio bs=1 seek=$((0x8e100)) status=noxfer
# you should hear a beep


</pre>
</pre>
Line 6,150: Line 6,500:


# dd if=/dev/ps3sbmmio bs=1 count=24 skip=$((0x8c000)) status=noxfer | hexdump -C
# dd if=/dev/ps3sbmmio bs=1 count=24 skip=$((0x8c000)) status=noxfer | hexdump -C
00000000  16 01 16 20 00 00 80 4d 00 00 00 01 00 01 00 01 |... ...M........|
 
00000010  00 00 00 00 00 00 fe e3                           |......þã|
00000000  13 01 00 00 00 00 80 14 00 00 00 04 00 08 00 08 |................|
00000010  00 00 00 00 15 af 47 6b                           |.....¯Gk|
00000018
00000018
</pre>
</pre>


=Isolation=
===Ring Buzzer===
Crossreference: [http://wiki.gitbrew.org/wikibrew/PS3:HvReverseEngineering#Isolation gitbrew.org::Isolation] <br />


==Running Isolated SPE Modules On OtherOS++ Linux==
* Used by System Manager
* Communication with SYSCON 1


* spp_verifier is a kernel module which shows you how to run isolated SPE modules on OtherOS++ Linux.
Request:
* It decrypts default.spp profile
* Tested on 3.41 and 3.55.
* You can modify it easily to run other SPE modules.


<pre>
<pre>
root@debian-hdd:/home/glevand/spp_verifier# cat spp_verifier_355.self > /proc/spp_verifier/spu
# write packet
root@debian-hdd:/home/glevand/spp_verifier# cat default_355.spp > /proc/spp_verifier/profile
 
root@debian-hdd:/home/glevand/spp_verifier# echo 1 > /proc/spp_verifier/run
# echo "0: 16 01 1620 0000 804d 00000001 0008 0008 20 29 0a 00 000001b6 0000fdcb" | xxd -c256 -r | \
root@debian-hdd:/home/glevand/spp_verifier# cat /proc/spp_verifier/debug
      dd of=/dev/ps3sbmmio bs=1 seek=$((0x8d000)) status=noxfer
 
# dump packet counter


PPE id (0x0000000000000001) VAS id (0x0000000000000002)
# dd if=/dev/ps3sbmmio bs=1 count=4 skip=$((0x8dff0)) status=noxfer | hexdump -C
lv1_construct_logical_spe (0x00000000)
 
SPE id (0x000000000000002b)
00000000  00 c0 00 c0                                      |.À.À|
lv1_undocumented_function_209 (0x00000000)
00000004
shadow execution status (0x0000000000000002)
 
# increment packet counter
 
echo "0: 00c1 00c1" | xxd -c256 -r | dd of=/dev/ps3sbmmio bs=1 seek=$((0x8dff0)) status=noxfer
 
# kick packet
 
# echo "0: 00000001" | xxd -c256 -r | dd of=/dev/ps3sbmmio bs=1 seek=$((0x8e100)) status=noxfer
 
# you should hear a beep
 
</pre>
 
Response:
 
<pre>
# dump packet counter
 
# dd if=/dev/ps3sbmmio bs=1 count=4 skip=$((0x8dff0)) status=noxfer | hexdump -C
 
00000000  00 c1 00 c1                                      |.Á.Á|
00000004
 
# dump response packet
 
# dd if=/dev/ps3sbmmio bs=1 count=24 skip=$((0x8c000)) status=noxfer | hexdump -C
00000000  16 01 16 20 00 00 80 4d  00 00 00 01 00 01 00 01  |... ...M........|
00000010  00 00 00 00 00 00 fe e3                          |......þã|
00000018
 
</pre>
 
=Isolation=
Crossreference: [http://wiki.gitbrew.org/wikibrew/PS3:HvReverseEngineering#Isolation gitbrew.org::Isolation] <br />
 
==Running Isolated SPE Modules On OtherOS++ Linux==
 
* spp_verifier is a kernel module which shows you how to run isolated SPE modules on OtherOS++ Linux.
* It decrypts default.spp profile
* Tested on 3.41 and 3.55.
* You can modify it easily to run other SPE modules.
 
<pre>
root@debian-hdd:/home/glevand/spp_verifier# cat spp_verifier_355.self > /proc/spp_verifier/spu
root@debian-hdd:/home/glevand/spp_verifier# cat default_355.spp > /proc/spp_verifier/profile
root@debian-hdd:/home/glevand/spp_verifier# echo 1 > /proc/spp_verifier/run
root@debian-hdd:/home/glevand/spp_verifier# cat /proc/spp_verifier/debug
 
PPE id (0x0000000000000001) VAS id (0x0000000000000002)
lv1_construct_logical_spe (0x00000000)
SPE id (0x000000000000002b)
lv1_undocumented_function_209 (0x00000000)
shadow execution status (0x0000000000000002)
lv1_get_spe_interrupt_status(1) (0x00000000)
lv1_get_spe_interrupt_status(1) (0x00000000)
interrupt status 1 (0x0000000000000000)
interrupt status 1 (0x0000000000000000)
Line 6,438: Line 6,839:
* Command buffer size is '''0xe'''
* Command buffer size is '''0xe'''


offset 0xC - 0,1 or 2 (1 byte)
offset 0xC - ??? (1 byte)


offset 0xD - 2 (1 byte)
offset 0xD - ??? (1 byte)


====Set AP WEP Configuration (0x5b)====
====Set AP WEP Configuration (0x5b)====
Line 9,421: Line 9,822:
Received 8 bytes of data:
Received 8 bytes of data:
  00    00 06 00 00 00 00 00 04                            ........         
  00    00 06 00 00 00 00 00 04                            ........         
</pre>
</pre>
 
 
===Eject Media===
===Eject Media===
 
 
<pre>
<pre>
sg_raw /dev/sr0 0x1b 00 00 00 02 00
sg_raw /dev/sr0 0x1b 00 00 00 02 00
</pre>
</pre>
 
 
===Load Media===
===Load Media===
 
 
<pre>
<pre>
sg_raw /dev/sr0 0x1b 00 00 00 03 00
sg_raw /dev/sr0 0x1b 00 00 00 03 00
</pre>
</pre>
 
 
===Mode Select 10===
===Mode Select 10===
 
 
====Enable Buffer Write====
====Enable Buffer Write====
 
 
* Uses '''PF 0x1''', '''SP 0x0''' and '''parameter list length 0x10'''
* Uses '''PF 0x1''', '''SP 0x0''' and '''parameter list length 0x10'''
* Uses the following parameter list: '''0x00 0x0e 0x00 0x00 0x00 0x00 0x00 0x00 0x2d 0x6 <buffer id> 0x00 0x00 0x00 0x00 0x00'''
* Uses the following parameter list: '''0x00 0x0e 0x00 0x00 0x00 0x00 0x00 0x00 0x2d 0x6 <buffer id> 0x00 0x00 0x00 0x00 0x00'''
* '''Enables writing to BD drive flash, e.g. to HRL buffer !!!'''
* '''Enables writing to BD drive flash, e.g. to HRL buffer !!!'''
 
 
Test with sg3-utils which enables write to HRL buffer:
Test with sg3-utils which enables write to HRL buffer:
<pre>
<pre>
sg_raw /dev/sr0 55 10 00 00 00 00 00 00 10 00 00 0e 00 00 00 00 00 00 2d 06 04 00 00 00 00 00
sg_raw /dev/sr0 55 10 00 00 00 00 00 00 10 00 00 0e 00 00 00 00 00 00 2d 06 04 00 00 00 00 00
</pre>
</pre>
 
 
===Write Buffer===
===Write Buffer===
 
 
* Used e.g. by Update Manager to send BD firmware to BD drive
* Used e.g. by Update Manager to send BD firmware to BD drive
* '''Mode 0x5 (Download microcode and save)''' is used e.g. to write HRL to BD drive flash
* '''Mode 0x5 (Download microcode and save)''' is used e.g. to write HRL to BD drive flash
* '''Mode 0x7 (Download microcode with offsets and save)''' is used e.g. to write BD firmware to BD drive flash
* '''Mode 0x7 (Download microcode with offsets and save)''' is used e.g. to write BD firmware to BD drive flash
 
 
==AACS==
==AACS==
 
 
===AACS SPU Module===
===AACS SPU Module===
 
 
* BD player on GameOS uses '''AacsModule.spu.isoself''' (/dev_flash/bdplayer) to perform AACS authentication
* BD player on GameOS uses '''AacsModule.spu.isoself''' (/dev_flash/bdplayer) to perform AACS authentication
* Tested on OtherOS++ 3.55
* Tested on OtherOS++ 3.55
* Host certificate, host private key and AACS LA public key are stored encrypted with AES-256-CTR in the SPU module and are decrypted when the SPU module is loaded or when it's accessed first. The AES-256-CTR key and IV are in the SPU module too.
* Host certificate, host private key and AACS LA public key are stored encrypted with AES-256-CTR in the SPU module and are decrypted when the SPU module is loaded or when it's accessed first. The AES-256-CTR key and IV are in the SPU module too.
* 4.76 uses new Host certificate
 
 
====Communication====
====Communication====
 
 
* BD player reads '''EID3''' with '''Indi Info Manager 0x17001/0x17002''' services and passes it to SPU module
* BD player reads '''EID3''' with '''Indi Info Manager 0x17001/0x17002''' services and passes it to SPU module
* '''EID3 is NEVER used in the SPU module although BD player passes it to the SPU module'''
* '''EID3 is NEVER used in the SPU module although BD player passes it to the SPU module'''
* Data is exchanged with the SPU module through '''SPU In Mbox''', '''SPU Out Intr Mbox''' and a data buffer in XDR memory of size '''0x2000''' bytes.
* Data is exchanged with the SPU module through '''SPU In Mbox''', '''SPU Out Intr Mbox''' and a data buffer in XDR memory of size '''0x2000''' bytes.
 
 
====Commands====
====Commands====
 
 
* The SPU module supports max '''0x78''' commands but not all are implemented
* The SPU module supports max '''0x78''' (til 4.75, 0x57 since 4.76) commands but not all are implemented
* After a command is finished by the SPU module, it sends the status of the command to PPU through '''SPU Out Intr Mbox'''. Value 0 means success.
* After a command is finished by the SPU module, it sends the status of the command to PPU through '''SPU Out Intr Mbox'''. Value 0 means success.
 
=====Read 4 Bytes from XDR Buffer (0x2)=====
 
* It just reads 4 bytes of data from the XDR buffer passed to the SPU module.
 
=====Set KCD (0x1e)=====
 
* Sends KCD (Key Conversion Data) to the SPU module.
* KCD is encrypted with the Bus Key which was established previously by AACS authentication.
 
=====Init AES_H (0x34)=====
 
* Initializes AES_H hashing function.
 
=====Calculate AES_H 1 (0x35)=====
 
* Calculates AES_H hash of the data stored in XDR buffer.
 
=====Calculate AES_H 2 (0x36)=====
 
* Calculates AES_H hash of the data stored in XDR buffer.
 
=====Generate Host Nonce (0x3c)=====
 
* Generates a nonce which is returned in command '''0x3d'''
 
=====Get Host Nonce and Certificate (0x3d)=====
 
* The data returned by this command is of size '''0x14 (Nonce) + 0x5c (Host Certificate)'''
* The data returned by this command is sent by BD player with SCSI command '''SEND KEY''' to BD drive during AACS authentication
* '''Host Certificate is easy to get from the SPU module, e.g. with aacs_module on OtherOS++'''
* The data contains a nonce, host public key and host certificate signature.
 
=====Set Drive Nonce and Certificate (0x3e)=====
 
* Stores BD drive nonce and certificate in local memory of SPU
 
=====Verify Drive Certificate (0x3f)=====
 
=====Set Drive Key (0x40)=====
 
=====Sign Host Key (0x44)=====
 
=====Get Host Key (0x45)=====
 
=====Calculate Bus Key (0x46)=====
 
=====Set Volume ID (0x47)=====
 
* Sends volume id and its MAC to the SPU module
 
=====Calculate Volume ID MAC (0x48)=====
 
* Calculates MAC of the passed volume id
 
=====Verify Volume ID MAC (0x49)=====
 
* Verifies MAC of the passed volume id
 
=====Set PMSN (0x4a)=====
 
* Sends PMSN and its MAC to the SPU module
 
=====Calculate PMSN MAC (0x4b)=====
 
* Calculates MAC of the passed PMSN
 
=====Verify PMSN (0x4c)=====
 
* Verifies MAC of the passed PMSN
 
=====Set Media ID (0x4d)=====
 
* Sends media id and its MAC to the SPU module
 
=====Calculate Media ID MAC (0x4e)=====
 
* Calculates MAC of the passed media id
 
=====Verify Media ID MAC (0x4f)=====
 
* Verifies MAC of the passed media id
 
=====Unknown (0x54)=====
 
=====Verify Host/Drive Revocation (0x55)=====
 
* BD player stores HRL/DRL list entries in XDR buffer and passes it to the SPU module for verification


=====Terminate Session (0xfefefeff)=====


{| class="wikitable sortable"
|+ style="caption-side:bottom; color:#e76700;"|''No full list!''
! colspan="2" style="background-color:#FFEBAD;"| Command in FW !! rowspan="2" style="background-color:#FFEBAD;"| Name !! rowspan="2" style="background-color:#FFEBAD;"| Parameters !! rowspan="2" style="background-color:#FFEBAD;"| Info
|-
! style="background-color:#FFEBAD;"| -4.75 !! style="background-color:#FFEBAD;"| 4.76+
|-
| 0x02|| 0x34 || Read 4 Bytes from XDR Buffer || ||
* It just reads 4 bytes of data from the XDR buffer passed to the SPU module.
|-
| 0x1C|| 0x48 || Set KCD || ||
* Sends KCD (Key Conversion Data) to the SPU module.
* KCD is encrypted with the Bus Key which was established previously by AACS authentication.
|-
| 0x34|| 0x23 || Init AES_H || ||
* Initializes AES_H hashing function.
|-
| 0x35|| 0x22 || Calculate AES_H 1 || ||
* Calculates AES_H hash of the data stored in XDR buffer.
|-
| || 0x21 ||  || 2x 4 Bytes ||
Signed CSS CheckCRL
|-
| || 0x56||  || ||
Get Random Seed
|-
| || 0x32||  || ||
Unknown
|-
| 0x36|| 0x24 || Calculate AES_H 2 || ||
* Calculates AES_H hash of the data stored in XDR buffer.
|-
| 0x3C|| 0x12 || Generate Host Nonce || ||
* Generates a nonce which is returned in command '''0x3D''' / '''0x0C'''
|-
| 0x3D|| 0x0C || Get Host Nonce and Certificate || ||
* The data returned by this command is of size '''0x14 (Nonce) + 0x5c (Host Certificate)'''
* The data returned by this command is sent by BD player with SCSI command '''SEND KEY''' to BD drive during AACS authentication
* '''Host Certificate is easy to get from the SPU module, e.g. with aacs_module on OtherOS++'''
* The data contains a nonce, host public key and host certificate signature.
|-
| 0x3E|| 0x0D|| Set Drive Nonce and Certificate || ||
* Stores BD drive nonce and certificate in local memory of SPU
|-
| 0x3F|| 0x0E|| Verify Drive Certificate || ||
|-
| 0x40|| 0x0A|| Set Drive Key || ||
|-
| 0x44|| 0x10 || Sign Host Key || ||
|-
| 0x45|| 0x0B || Get Host Key || ||
|-
| 0x46|| 0x14 || Calculate Bus Key || ||
|-
| 0x47|| 0x1C || Set Volume ID || ||
* Sends volume id and its MAC to the SPU module
|-
| 0x48|| 0x1D || Calculate Volume ID MAC || ||
* Calculates MAC of the passed volume id
|-
| 0x49|| 0x15 || Verify Volume ID MAC || ||
* Verifies MAC of the passed volume id
|-
| 0x4A|| 0x1A || Set PMSN || ||
* Sends PMSN and its MAC to the SPU module
|-
| 0x4B|| 0x1B || Calculate PMSN MAC || ||
* Calculates MAC of the passed PMSN
|-
| 0x4C|| 0x16 || Verify PMSN || ||
* Sends media id and its MAC to the SPU module
|-
| 0x4D|| 0x18 || Set Media ID || ||
* Sends media id and its MAC to the SPU module
|-
| 0x4E|| 0x19 || Calculate Media ID MAC || ||
* Calculates MAC of the passed media id
|-
| 0x4F|| 0x17 || Verify Media ID MAC || ||
* Verifies MAC of the passed media id
|-
| 0x55|| 0x1F || Verify Host/Drive Revocation || ||
* BD player stores HRL/DRL list entries in XDR buffer and passes it to the SPU module for verification
|-
| 0x72|| 0x25 ||  || || OCRL related, Content Revocation List
|-
| 0x74|| 0x26 ||  || || OCRT related
|-
| 0x75|| 0x27 ||  || || OSIG related
|-
| 0xFEFEFEFF|| 0xFEFEFEFF|| Terminate Session || ||
* AACS SPU module runs and processes commands as long as you need
* AACS SPU module runs and processes commands as long as you need
* After a command is complete, the SPU module waits for the next command
* After a command is complete, the SPU module waits for the next command
* This command terminates the current session and stops SPU module
* This command terminates the current session and stops SPU module
|-
|}


===Drive Revocation List (DRL)===
===Drive Revocation List (DRL)===
Line 10,547: Line 10,944:


====P-Block====
====P-Block====
Decrypted P-Block (and EID4) contains region settings (see below)
In decrypted P-Block(bytes 0x30 and 0x32) and in EID4(first byte) these bytes match [[Product Code]]:
{| class="wikitable sortable" style="font-size:small; border:2px ridge #999999;"
|-
! Hex !! bitflag !! [[Product Code]] !! Console Type !! Remarks
|-
| 0xFF || '''11111111''' || {{TID80}} || No BD playback on that [[Product Code]]
|-
| 0xFF || '''11111111''' || {{TID81}} || No BD playback on that [[Product Code]]
|-
| 0xFF || '''11111111''' || {{TID82}} || No BD playback on that [[Product Code]]
|-
| 0x01 || 0000000'''1''' || {{TID83}} || bit 0 (Region 0: Japan?)
|-
| 0x02 || 000000'''1'''0 || {{TID84}} || bit 1 (Region 1: USA & Canada, Bermuda, and US Territories)
|-
| 0x04 || 00000'''1'''00 || {{TID85}} || bit 2 (Region 2: Europe (with the exceptions of Russia, Ukraine, Belarus), South Africa, Swaziland, Middle East, Egypt, Lesotho, and Greenland)
|-
| 0x10 || 000'''1'''0000 || {{TID86}} || bit 4 (Region 3: Southeastern Asia)
|-
| 0x04 || 00000'''1'''00 || {{TID87}} || bit 2 (Region 2: Europe (with the exceptions of Russia, Ukraine, Belarus), South Africa, Swaziland, Middle East, Egypt, Lesotho, and Greenland)
|-
| 0x08 || 0000'''1'''000 || {{TID88}} || bit 3 (Region 4: Latin America and Australia)
|-
| 0x08 || 0000'''1'''000 || {{TID89}} || bit 3 (Region 4: Latin America and Australia)
|-
| 0x20 || 00'''1'''00000 || {{TID8A}} || bit 5 (Region 5: Russia, Asia (non-southeast), and Africa)
|-
| 0x10 || 000'''1'''0000 || {{TID8B}} || bit 4 (Region 3: Southeastern Asia)
|-
| 0x20 || 00'''1'''00000 || {{TID8C}} || bit 5 (Region 5: Russia, Asia (non-southeast), and Africa)
|-
| 0x40 || 0'''1'''000000 || {{TID8D}} || bit 6? (Region 6: China)
|-
| 0x10 || 000'''1'''0000 || {{TID8E}} || bit 4  (Region 3: Southeastern Asia)
|-
| 0x08 || 0000'''1'''000 || {{TID8F}} || bit 3 (Region 4: Latin America and Australia)
|-
| 0xFF || '''11111111''' || {{TIDA0}} || No BD playback on that [[Product Code]]
|-
|}


=====Creating=====
=====Creating=====
Line 10,750: Line 11,104:
lv1_destruct_logical_spe (0x00000000)
lv1_destruct_logical_spe (0x00000000)
</pre>
</pre>
{{Reverse engineering}}<noinclude>[[Category:Main]]</noinclude>
Please note that all contributions to PS3 Developer wiki are considered to be released under the GNU Free Documentation License 1.2 (see PS3 Developer wiki:Copyrights for details). If you do not want your writing to be edited mercilessly and redistributed at will, then do not submit it here.
You are also promising us that you wrote this yourself, or copied it from a public domain or similar free resource. Do not submit copyrighted work without permission!

To protect the wiki against automated edit spam, we kindly ask you to solve the following hCaptcha:

Cancel Editing help (opens in new window)