HV Syscall Reference: Difference between revisions

From PS3 Developer wiki
Jump to navigation Jump to search
m (Upto syscall 99 ported)
 
(44 intermediate revisions by 10 users not shown)
Line 221: Line 221:
|R4
|R4
|vas_id - virtual address space id of the PPE
|vas_id - virtual address space id of the PPE
|-
|R5
|htab_size_log2 - 18, 19 or 20 (256KB, 512KB or 1MB)
|-
|R6
|number_of_sizes - How many page sizes are specified in page_sizes
|-
|R7
|page_sizes - see lv1_construct_virtual_address_space
|}
|}


Line 227: Line 236:
Regardless of the ppe_id, when called from kernel module init function, vas_id always seems to be 11.
Regardless of the ppe_id, when called from kernel module init function, vas_id always seems to be 11.
----
----
=== lv1_query_logical_partition_address_region_info ===
=== lv1_query_logical_partition_address_region_info ===


Line 775: Line 785:
=== lv1_detect_pending_interrupts ===
=== lv1_detect_pending_interrupts ===


Not used in current kernel.
Not used in current kernel. Used in ps2_gxemu.


===== Abstract Call =====
===== Abstract Call =====
Line 790: Line 800:
|-
|-
|R3
|R3
|p1 - unknown
|p1 - unknown (only 0 value is supported)
|-
|-
! colspan="2" | Outputs
! colspan="2" | Outputs
Line 798: Line 808:
|-
|-
|R3
|R3
|Status?
|Status
|-
|-
|R4
|R4
|v1 - Unknown
|v1 - irq_bitmap[0]
|-
|-
|R5
|R5
|v2 - Unknown
|v2 - irq_bitmap[1]
|-
|-
|R6
|R6
|v3 - Unknown
|v3 - irq_bitmap[2]
|-
|-
|R7
|R7
|v4 - Unknown
|v4 - irq_bitmap[3]
|-
|-
|}
|}


Notes:
Notes:<br>
 
Return 256 bit irq bitmap for previously connected irq plugs (using lv1_connect_irq_plug).<br>
Info taken from kboot-10\dl\linux-2.6.16\include\asm-powerpc\lv1calltab.h (kboot-20061208)
Info taken from kboot-10\dl\linux-2.6.16\include\asm-powerpc\lv1calltab.h (kboot-20061208)
----
----
=== lv1_end_of_interrupt ===
=== lv1_end_of_interrupt ===


Line 1,263: Line 1,274:
|}
|}
----
----
=== lv1_undocumented_function_62 ===
=== lv1_undocumented_function_62 ===
SPE (isolation, it updates a SLB entry, writes to SLB_Index, SLB_VSID, SLB_ESID and SLB_Invalidate_Entry registers)
----
=== lv1_set_slb_for_logical_spu ===


Exists in PAL 1.7; Returned -4 (LV1_DENIED_BY_POLICY) when passed 0 in R3 to R10.
Exists in PAL 1.7; Returned -4 (LV1_DENIED_BY_POLICY) when passed 0 in R3 to R10.
----  
----
 
=== lv1_undocumented_function_63 ===
=== lv1_undocumented_function_63 ===


Line 1,636: Line 1,655:
----
----
=== lv1_undocumented_function_89 ===
=== lv1_undocumented_function_89 ===
SPE (writes to MFC_TLB_Invalidate_Entry register)


Exists in PAL 1.7; Returned -6 (LV1_NO_ENTRY) when passed 0 in R3 to R10.
Exists in PAL 1.7; Returned -6 (LV1_NO_ENTRY) when passed 0 in R3 to R10.
----
----
=== lv1_create_repository_node ===
=== lv1_create_repository_node ===


Line 1,686: Line 1,708:


This call is not used within the current Kernel, so the parameter list is based on speculation.
This call is not used within the current Kernel, so the parameter list is based on speculation.
It will still return 0 if the specified node already exists, and it will not change current data.


See “lv1_get_repository_node_value” for an example of actual key/value usage within the Kernel.
See “lv1_get_repository_node_value” for an example of actual key/value usage within the Kernel.
----
----
=== lv1_get_repository_node_value ===
=== lv1_get_repository_node_value ===


Line 1,884: Line 1,908:
|00000000000001 (1)
|00000000000001 (1)
|00000000000000 (0)
|00000000000000 (0)
|Flash format ?
|Flash format.<br> v1: 1 = NAND , 2 = VFLASH?
|-
|-
|sys.hw.config.#0
|sys.hw.config.#0
Line 1,904: Line 1,928:
|00000000000000 (0)
|00000000000000 (0)
|00000000000000 (0)
|00000000000000 (0)
|
|System Debug Flag
|-
|-
|sys.flash.boot.#0
|sys.flash.boot.#0
Line 2,012: Line 2,036:
|}
|}
----
----
=== lv1_modify_repository_node_value ===
=== lv1_modify_repository_node_value ===


Line 2,149: Line 2,174:
=== lv1_set_dabr ===
=== lv1_set_dabr ===


Sets dabr (data address breakpoint register) - an exception should be thrown upon access to data at this address (range?)
Sets dabr (Data Address Breakpoint Register) and dabrx (Data Address Breakpoint Register Extension)


===== Kernel Call =====
===== Kernel Call =====


  result = lv1_set_dabr( /*IN*/ dabr, DABR_KERNEL | DABR_USER);
  result = lv1_set_dabr( /*IN*/ dabr, dabrx);


===== Parameters =====
===== Parameters =====
Line 2,164: Line 2,189:
|-
|-
|R3
|R3
|dabr - data address
|dabr - see notes
|-
|-
|R4
|R4
|(DABR_KERNEL | DABR_USER) - see notes
|dabrx - see notes
|-
|-
! colspan="2" | Outputs
! colspan="2" | Outputs
Line 2,180: Line 2,205:


Notes:
Notes:
*DABR:
Bit(s) Name Description
0:60  DAB  Data Address Breakpoint
61    BT  Breakpoint Translation
62    DW  Data Write
63    DR  Data Read


DABR_KERNEL and DABR_USER are defined in “setup.c” as follows
*DABRX
Bit(s) Name  Description
0:59        Reserved
60    BTI  Breakpoint Translation Ignore
61:63  PRIVM Privilege Mask
61    HYP  Hypervisor state - unsupported in LV1
62    PNH  Privileged but Non-Hypervisor state
63    PRO  Problem state
When PRIVM in dabrx is 0 or when any unsupported or reserved bit in dabrx is active, both dabr and dabrx writes are not performed and 0x2FFFFFFEF is returned. <br><br>
DABRX is defined in “setup.c” as follows
  enum {DABR_USER = 1, DABR_KERNEL = 2,};
  enum {DABR_USER = 1, DABR_KERNEL = 2,};
----
----
=== lv1_set_vmx_graphics_mode ===
=== lv1_set_vmx_graphics_mode ===


Line 2,222: Line 2,263:
The Cell Broadband Engine Programming Handbook has this to say on the subject: The first implementation of the Cell Broadband Engine Architecture (CBEA) (the CBE processor) supports instructions with a graphics rounding mode. This mode allows programs written with vector/SIMD multimedia extension instructions to produce floating-point results that are equivalent in precision to those written in the SPU instruction set. In this mode, as in the SPU environment, the default rounding mode is round to zero, denormals are treated as zero, and there are no infinities or NaNs.
The Cell Broadband Engine Programming Handbook has this to say on the subject: The first implementation of the Cell Broadband Engine Architecture (CBEA) (the CBE processor) supports instructions with a graphics rounding mode. This mode allows programs written with vector/SIMD multimedia extension instructions to produce floating-point results that are equivalent in precision to those written in the SPU instruction set. In this mode, as in the SPU environment, the default rounding mode is round to zero, denormals are treated as zero, and there are no infinities or NaNs.


To change this mode, bit 12 in the HID1 register (known as grap_md or grap_mode in various documents). HID1 is a HV privileged resource, hence to change the mode from Supervisor mode requires a HV call.
This call change bit 12 (known as grap_md or grap_mode in various documents) in the HID1 register. Hardware Implementation Register 1 is a HV privileged resource, hence to change the mode from Supervisor mode requires a HV call.


Reference Documents: Cell Broadband Engine Programming Handbook V1.1 Cell Broadband Engine Registers V1.5
Reference Documents: Cell Broadband Engine Programming Handbook V1.1 Cell Broadband Engine Registers V1.5
Line 2,232: Line 2,273:
When recompiled into Kernel module init function, accepts values of 0 and 1 for p1. All other values return -17 (LV1_ILLEGAL_PARAMETER_VALUE)
When recompiled into Kernel module init function, accepts values of 0 and 1 for p1. All other values return -17 (LV1_ILLEGAL_PARAMETER_VALUE)
----
----
=== lv1_set_thread_switch_control_register ===
=== lv1_set_thread_switch_control_register ===


Line 2,265: Line 2,307:
Info taken from kboot-10\dl\linux-2.6.16\include\asm-powerpc\lv1calltab.h (kboot-20061208)
Info taken from kboot-10\dl\linux-2.6.16\include\asm-powerpc\lv1calltab.h (kboot-20061208)
----
----
=== lv1_undocumented_function_99 ===
=== lv1_authenticate_program_segment ===
previous alias: lv1_undocumented_function_99
 
SPE (isolation, syscall 0x10043, syscall 0x10042, syscall 0x1004A)


Exists in PAL 1.7; Returned -4 (LV1_DENIED_BY_POLICY) when passed 0 in R3 to R10.
Exists in PAL 1.7; Returned -4 (LV1_DENIED_BY_POLICY) when passed 0 in R3 to R10.
----
----
=== lv1_undocumented_function_102 ===
Returns current TB ticks
Exists in PAL 1.7; Returned 0 (LV1_SUCCESS) and R4 = 0x692F5D1E7h when passed 0 in R3 to R10.
----
=== lv1_get_total_execution_time ===
Not used in current kernel. Does not exist in 3.15 HV dump.
===== Abstract Call =====
result = lv1_get_total_execution_time( /*IN*/ p1, p2, /*OUT*/ &v1 );
===== Parameters =====
{| class="wikitable"
|-
! colspan="2" | Inputs
|-
!Register
!Description
|-
|R3
|p1 - Unknown
|-
|R4
|p2 - Unknown
|-
! colspan="2" | Outputs
|-
!Register
!Description
|-
|R3
|Status?
|-
|R4
|v1 - Unknown
|-
|}
Notes:
I always get LV1_NOT_IMPLEMENTED
----
=== lv1_undocumented_function_105 ===
Exists in PAL 1.7. Returns -17 (LV1_ILLEGAL_PARAMETER_VALUE, 0, 0, C000000000537EF8h, F09B89AF5001h, 6C0061D8E190h, C0000000008DF718h,
F09B89AF5001h, when passed 0 in R3 to R10.
----
=== lv1_undocumented_function_106 ===
Exists in PAL 1.7. Returns the same as [[HV_Syscall_Reference#lv1_undocumented_function_105|lv1_undocumented_function_105]].
----
=== lv1_undocumented_function_107 ===
Exists in PAL 1.7. Returns the same as [[HV_Syscall_Reference#lv1_undocumented_function_105|lv1_undocumented_function_105]].
----
=== lv1_undocumented_function_108 ===
Exists in PAL 1.7. Returns the same as [[HV_Syscall_Reference#lv1_undocumented_function_105|lv1_undocumented_function_105]].
----
=== lv1_undocumented_function_109 ===
Exists in PAL 1.7. Returns the same as [[HV_Syscall_Reference#lv1_undocumented_function_105|lv1_undocumented_function_105]].
----
=== lv1_read_remote_file ===
===== Parameters =====
{| class="wikitable"
|-
! colspan="2" | Inputs
|-
!Register
!Description
|-
|R3
|u32 type
|-
|R4
|u32 *path
|-
|R5
|u64 offset
|-
|R6
|u32 *buf
|-
|R7
|u64 size
|-
! colspan="2" | Outputs
|-
!Register
!Description
|-
|R3
|status - 0 = OK, LV1_TYPE_MISMATCH when type is not 1. Other values are unknown but indicate failure.
|-
|R4
|n_read
|-
|}
----
=== lv1_write_remote_file ===
===== Parameters =====
{| class="wikitable"
|-
! colspan="2" | Inputs
|-
!Register
!Description
|-
|R3
|u32 type
|-
|R4
|u32 *path
|-
|R5
|u64 offset
|-
|R6
|u32 *buf
|-
|R7
|u64 size
|-
! colspan="2" | Outputs
|-
!Register
!Description
|-
|R3
|status
|-
|R4
|n_write
|-
|}
----
=== lv1_get_remote_file_size ===
===== Parameters =====
{| class="wikitable"
|-
! colspan="2" | Inputs
|-
!Register
!Description
|-
|R3
|u32 type
|-
|R4
|u32 *path
|-
! colspan="2" | Outputs
|-
!Register
!Description
|-
|R3
|status
|-
|R4
|file_size
|-
|}----
=== lv1_map_physical_address_region ===
===== Parameters =====
{| class="wikitable"
|-
! colspan="2" | Inputs
|-
!Register
!Description
|-
|R3
|start -
|-
|R4
|page_size -
|-
|R5
|size -
|-
! colspan="2" | Outputs
|-
!Register
!Description
|-
|R3
|Status - 0 = OK, Other values are unknown, but indicate failure.
|-
|R4
|lpar_addr -
|-
|}
----
=== lv1_unmap_physical_address_region ===
===== Parameters =====
{| class="wikitable"
|-
! colspan="2" | Inputs
|-
!Register
!Description
|-
|R3
|lpar_addr -
|-
! colspan="2" | Outputs
|-
!Register
!Description
|-
|R3
|Status - 0 = OK, Other values are unknown, but indicate failure.
|-
|}
----
=== lv1_allocate_io_segment ===
Allocate an io segment.
===== kboot Call =====
result = lv1_allocate_io_segment( /*IN*/ ioas_id, segment_size, io_page_size, /*OUT*/ &ioif_addr );
===== Parameters =====
{| class="wikitable"
|-
! colspan="2" | Inputs
|-
!Register
!Description
|-
|R3
|ioas_id - io address space id
|-
|R4
|segment_size - io segment size
|-
|R5
|io_page_size - io page size, 0xC, 0×10, 0×14
|-
! colspan="2" | Outputs
|-
!Register
!Description
|-
|R3
|Status - 0 = OK, Other values are unknown, but indicate failure.
|-
|R4
|ioif_addr - io interface address
|-
|}
Notes:
Code taken from kboot-10\dl\linux-2.6.16\sound\powerpc\snd_ps3pf.c (kboot-20061208)
ret64 = lv1_allocate_io_segment(0,          /* io space */
    IO_SEGMENTSIZE, /* segment size */
    IO_PAGESIZE_SHIFT, /* io page size */
    &(ioif_map_info_array[current_segment].ioif_addr));
----
=== lv1_release_io_segment ===
Release an io segment.
===== kboot Call =====
result = lv1_release_io_segment( /*IN*/ ioas_id, ioif_addr );
===== Parameters =====
{| class="wikitable"
|-
! colspan="2" | Inputs
|-
!Register
!Description
|-
|R3
|ioas_id - io address space id
|-
|R4
|ioif_addr - io interface address
|-
! colspan="2" | Outputs
|-
!Register
!Description
|-
|R3
|Status - 0 = OK, Other values are unknown, but indicate failure.
|-
|}
Notes:
Code taken from kboot-10\dl\linux-2.6.16\sound\powerpc\snd_ps3pf.c (kboot-20061208)
ret64 = lv1_release_io_segment(0, /* io space */
    ioif_map_info_array[current_segment].ioif_addr);
----
=== lv1_allocate_ioid ===
Not used in current kernel.
===== Abstract Call =====
result = lv1_allocate_ioid( /*IN*/ p1, /*OUT*/ &v1 );
===== Parameters =====
{| class="wikitable"
|-
! colspan="2" | Inputs
|-
!Register
!Description
|-
|R3
|SBZ
|-
! colspan="2" | Outputs
|-
!Register
!Description
|-
|R3
|Status?
|-
|R4
|the ioid
|-
|}
Notes:
Info taken from kboot-10\dl\linux-2.6.16\include\asm-powerpc\lv1calltab.h (kboot-20061208)
----
=== lv1_release_ioid ===
Not used in current Kernel.
===== Abstract Call =====
result = lv1_release_ioid( /*IN*/ p1, p2 );
===== Parameters =====
{| class="wikitable"
|-
! colspan="2" | Inputs
|-
!Register
!Description
|-
|R3
|p1 - Unknown
|-
|R4
|p2 - Unknown
|-
! colspan="2" | Outputs
|-
!Register
!Description
|-
|R3
|Status?
|-
|}
Notes:
Info taken from kboot-10\dl\linux-2.6.16\include\asm-powerpc\lv1calltab.h (kboot-20061208)
----
=== lv1_construct_io_irq_outlet ===
Construct an outlet for a non-virtualized device interrupt.
===== Kernel Call =====
result = lv1_construct_io_irq_outlet( /*IN*/ interrupt_id, /*OUT*/ &outlet );
===== Parameters =====
{| class="wikitable"
|-
! colspan="2" | Inputs
|-
!Register
!Description
|-
|R3
|interrupt_id - interrupt id
|-
! colspan="2" | Outputs
|-
!Register
!Description
|-
|R3
|Status - 0 = OK, Other values are unknown, but indicate failure.
|-
|R4
|outlet - interrupt outlet
|-
|}
----
=== lv1_destruct_io_irq_outlet ===
Destruct a previously constructed device interrupt outlet.
===== Kernel Call =====
result = lv1_destruct_io_irq_outlet( /*IN*/ outlet );
===== Parameters =====
{| class="wikitable"
|-
! colspan="2" | Inputs
|-
!Register
!Description
|-
|R3
|outlet - interrupt outlet
|-
! colspan="2" | Outputs
|-
!Register
!Description
|-
|R3
|Status - 0 = OK, Other values are unknown, but indicate failure.
|}
----
=== lv1_map_htab ===
Map the hash page table.
===== Kernel Call =====
result = lv1_map_htab( /*IN*/ 0, /*OUT*/ &htab_addr );
===== Parameters =====
{| class="wikitable"
|-
! colspan="2" | Inputs
|-
!Register
!Description
|-
|R3
|0 - Unknown (lpid?)
|-
! colspan="2" | Outputs
|-
!Register
!Description
|-
|R3
|Status?
|-
|R4
|htab_addr - hash page table address
|}
Notes:
In “htab.c” return code is assigned, but not used. Must be translated and ioremapped before it can be used in the kernel. It’s 1MB long
----
=== lv1_unmap_htab ===
Unmap the hash page table.
===== Kernel Call =====
lv1_unmap_htab( /*IN*/ htab_addr );
===== Parameters =====
{| class="wikitable"
|-
! colspan="2" | Inputs
|-
!Register
!Description
|-
|R3
|htab_addr - hash page table address
|-
! colspan="2" | Outputs
|-
!Register
!Description
|-
|R3
|Status?
|}
----
=== lv1_read_remote_file_long_name ===
===== Parameters =====
{| class="wikitable"
|-
! colspan="2" | Inputs
|-
!Register
!Description
|-
|R3
|u32 type
|-
|R4
|u32 *path
|-
|R5
|u32 path_len
|-
|R6
|u64 offset
|-
|R7
|u32 *buf
|-
|R8
|u64 size
|-
! colspan="2" | Outputs
|-
!Register
!Description
|-
|R3
|status
|-
|R4
|n_read
|-
|}
----
=== lv1_write_remote_file_long_name ===
===== Parameters =====
{| class="wikitable"
|-
! colspan="2" | Inputs
|-
!Register
!Description
|-
|R3
|u32 type
|-
|R4
|u32 *path
|-
|R5
|u32 path_len
|-
|R6
|u64 offset
|-
|R7
|u32 *buf
|-
|R8
|u64 size
|-
! colspan="2" | Outputs
|-
!Register
!Description
|-
|R3
|status
|-
|R4
|n_write
|-
|}
----
=== lv1_get_remote_file_size_long_name ===
===== Parameters =====
{| class="wikitable"
|-
! colspan="2" | Inputs
|-
!Register
!Description
|-
|R3
|u32 type
|-
|R4
|u32 *path
|-
|R5
|u32 path_len
|-
! colspan="2" | Outputs
|-
!Register
!Description
|-
|R3
|status
|-
|R4
|file_size
|-
|}
----
=== lv1_get_version_info ===
Returns PS3 firmware version information.
===== Kernel Call =====
result = lv1_get_version_info( /*OUT*/ &raw );
===== Parameters =====
{| class="wikitable"
|-
! colspan="2" | Outputs
|-
!Register
!Description
|-
|R3
|Status - 0 = OK, Other values are unknown, but indicate failure.
|-
|R4
|raw - firmware data (see notes)
|}
Notes:
The firmware information is accessed using the following union:
union ps3_firmware_version {
u64 raw;
struct {
u16 pad;
u16 major;
u16 minor;
u16 rev;
};
};
----
=== lv1_undocumented_function_134 ===
Exists in PAL 1.7. Returns 0 when passed R3-R10=0.
----
=== lv1_undocumented_function_135 ===
Exists in PAL 1.7. Returns -6 (LV1_NO_ENTRY) in R3, rest same as  [[HV_Syscall_Reference#lv1_undocumented_function_105|lv1_undocumented_function_105]].
----
=== lv1_undocumented_function_136 ===
Exists in PAL 1.7. Returns -6 (LV1_NO_ENTRY) in R3, rest same as  [[HV_Syscall_Reference#lv1_undocumented_function_105|lv1_undocumented_function_105]].
----
=== lv1_undocumented_function_137 ===
SPE
Exists in PAL 1.7. Returns -4 (LV1_DENIED_BY_POLICY) when passed 0 in R3-R10.
----
=== lv1_undocumented_function_138 ===
SPE
Exists in PAL 1.7. Returns -4 (LV1_DENIED_BY_POLICY) when passed 0 in R3-R10.
----
=== lv1_construct_lpm ===
Not used in current kernel.
===== Abstract Call =====
result = lv1_construct_lpm( /*IN*/ p1, p2, p3, p4, p5, p6, /*OUT*/ &v1, &v2, &v3 );
===== Parameters =====
{| class="wikitable"
|-
! colspan="2" | Inputs
|-
!Register
!Description
|-
|R3
|p1 - node_id, this is the node id of the processor, 0 is only valid value
|-
|R4
|p2 - tb_type, 0 is none, 1 is internal
|-
|R5
|p3 - Unknown, is 0
|-
|R6
|p4 - Unknown, is 0
|-
|R7
|p5 - tb_cache in lpar, 128 byte aligned
|-
|R8
|p6 - tb_cache_size
|-
! colspan="2" | Outputs
|-
!Register
!Description
|-
|R3
|Status
|-
|R4
|v1 - lpm_id
|-
|R5
|v2 - outlet_id
|-
|R6
|v3 - tb_size
|-
|}
----
=== lv1_destruct_lpm ===
Not used in current kernel.
===== Abstract Call =====
result = lv1_destruct_lpm( /*IN*/ p1 );
===== Parameters =====
{| class="wikitable"
|-
! colspan="2" | Inputs
|-
!Register
!Description
|-
|R3
|p1 - lpm_id
|-
! colspan="2" | Outputs
|-
!Register
!Description
|-
|R3
|Status?
|-
|}
----
=== lv1_start_lpm ===
Not used in current kernel.
===== Abstract Call =====
result = lv1_start_lpm( /*IN*/ p1 );
===== Parameters =====
{| class="wikitable"
|-
! colspan="2" | Inputs
|-
!Register
!Description
|-
|R3
|p1 - lpm_id
|-
! colspan="2" | Outputs
|-
!Register
!Description
|-
|R3
|Status?
|-
|}
----
=== lv1_stop_lpm ===
Not used in current kernel.
===== Abstract Call =====
result = lv1_stop_lpm( /*IN*/ p1, /*OUT*/ &v1 );
===== Parameters =====
{| class="wikitable"
|-
! colspan="2" | Inputs
|-
!Register
!Description
|-
|R3
|p1 - Unknown
|-
! colspan="2" | Outputs
|-
!Register
!Description
|-
|R3
|Status?
|-
|R4
|v1 - Unknown
|-
|}
----
=== lv1_copy_lpm_trace_buffer ===
Not used in current kernel.
===== Abstract Call =====
result = lv1_copy_lpm_trace_buffer( /*IN*/ p1, p2, p3 /*OUT*/ &v1 );
===== Parameters =====
{| class="wikitable"
|-
! colspan="2" | Inputs
|-
!Register
!Description
|-
|R3
|p1 - lpm_id
|-
|R3
|p2 - offset
|-
|R3
|p3 - request
|-
! colspan="2" | Outputs
|-
!Register
!Description
|-
|R3
|Status
|-
|R4
|v1 - tmp
|-
|}
----
=== lv1_add_lpm_event_bookmark ===
Not in current kernel.
===== Abstract Call =====
result = lv1_add_lpm_event_bookmark( /*IN*/ p1, p2, p3, p4, p5 );
===== Parameters =====
{| class="wikitable"
|-
! colspan="2" | Inputs
|-
!Register
!Description
|-
|R3
|p1 - Unknown
|-
|R3
|p2 - Unknown
|-
|R3
|p3 - Unknown
|-
|R6
|p4 - Unknown
|-
|R7
|p5 - Unknown
|-
! colspan="2" | Outputs
|-
!Register
!Description
|-
|R3
|Status?
|-
|}
----
=== lv1_delete_lpm_event_bookmark ===
Not used in current kernel.
===== Abstract Call =====
result = lv1_delete_lpm_event_bookmark( /*IN*/ p1, p2, p3 );
===== Parameters =====
{| class="wikitable"
|-
! colspan="2" | Inputs
|-
!Register
!Description
|-
|R3
|p1 - Unknown
|-
|R3
|p2 - Unknown
|-
|R3
|p3 - Unknown
|-
! colspan="2" | Outputs
|-
!Register
!Description
|-
|R3
|Status?
|-
|}
----
=== lv1_set_lpm_interrupt_mask ===
Not used in current kernel.
===== Abstract Call =====
result = lv1_set_lpm_interrupt_mask( /*IN*/ p1, p2, p3, /*OUT*/ &v1 );
===== Parameters =====
{| class="wikitable"
|-
! colspan="2" | Inputs
|-
!Register
!Description
|-
|R3
|p1 - Unknown
|-
|R3
|p2 - Unknown
|-
|R3
|p3 - Unknown
|-
! colspan="2" | Outputs
|-
!Register
!Description
|-
|R3
|Status?
|-
|R4
|v1 - Unknown
|-
|}
----
=== lv1_get_lpm_interrupt_status ===
Not used in current kernel.
===== Abstract Call =====
result = lv1_get_lpm_interrupt_status( /*IN*/ p1, /*OUT*/ &v1 );
===== Parameters =====
{| class="wikitable"
|-
! colspan="2" | Inputs
|-
!Register
!Description
|-
|R3
|p1 - Unknown
|-
! colspan="2" | Outputs
|-
!Register
!Description
|-
|R3
|Status?
|-
|R4
|v1 - Unknown
|-
|}
----
=== lv1_set_lpm_general_control ===
Not used in current kernel.
===== Abstract Call =====
result = lv1_set_lpm_general_control( /*IN*/ p1, p2, p3, p4, p5, /*OUT*/ &v1, &v2 );
===== Parameters =====
{| class="wikitable"
|-
! colspan="2" | Inputs
|-
!Register
!Description
|-
|R3
|p1 - Unknown
|-
|R4
|p2 - Unknown
|-
|R5
|p3 - Unknown
|-
|R6
|p4 - Unknown
|-
|R7
|p5 - Unknown
|-
! colspan="2" | Outputs
|-
!Register
!Description
|-
|R3
|Status?
|-
|R4
|v1 - Unknown
|-
|R5
|v2 - Unknown
|-
|}
----
=== lv1_set_lpm_interval ===
Not used in current kernel.
===== Abstract Call =====
result = lv1_set_lpm_interval( /*IN*/ p1, p2, p3, /*OUT*/ &v1 );
===== Parameters =====
{| class="wikitable"
|-
! colspan="2" | Inputs
|-
!Register
!Description
|-
|R3
|p1 - Unknown
|-
|R4
|p2 - Unknown
|-
|R5
|p3 - Unknown
|-
! colspan="2" | Outputs
|-
!Register
!Description
|-
|R3
|Status?
|-
|R4
|v1 - Unknown
|-
|}
----
=== lv1_set_lpm_trigger_control ===
Not used in current kernel.
===== Abstract Call =====
result = lv1_set_lpm_trigger_control( /*IN*/ p1, p2, p3, /*OUT*/ &v1 );
===== Parameters =====
{| class="wikitable"
|-
! colspan="2" | Inputs
|-
!Register
!Description
|-
|R3
|p1 - Unknown
|-
|R4
|p2 - Unknown
|-
|R5
|p3 - Unknown
|-
! colspan="2" | Outputs
|-
!Register
!Description
|-
|R3
|Status?
|-
|R4
|v1 - Unknown
|-
|}
----
=== lv1_set_lpm_counter_control ===
Not used in current kernel.
===== Abstract Call =====
result = lv1_set_lpm_counter_control( /*IN*/ p1, p2, p3, p4, /*OUT*/ &v1 );
===== Parameters =====
{| class="wikitable"
|-
! colspan="2" | Inputs
|-
!Register
!Description
|-
|R3
|p1 - Unknown
|-
|R4
|p2 - Unknown
|-
|R5
|p3 - Unknown
|-
|R6
|p4 - Unknown
|-
! colspan="2" | Outputs
|-
!Register
!Description
|-
|R3
|Status?
|-
|R4
|v1 - Unknown
|-
|}
----
=== lv1_set_lpm_group_control ===
Not used in current kernel.
===== Abstract Call =====
result = lv1_set_lpm_group_control( /*IN*/ p1, p2, p3, /*OUT*/ &v1 );
===== Parameters =====
{| class="wikitable"
|-
! colspan="2" | Inputs
|-
!Register
!Description
|-
|R3
|p1 - Unknown
|-
|R4
|p2 - Unknown
|-
|R5
|p3 - Unknown
|-
! colspan="2" | Outputs
|-
!Register
!Description
|-
|R3
|Status?
|-
|R4
|v1 - Unknown
|-
|}
----
=== lv1_set_lpm_debug_bus_control ===
Not used in current kernel.
===== Abstract Call =====
result = lv1_set_lpm_debug_bus_control( /*IN*/ p1, p2, p3, /*OUT*/ &v1 );
===== Parameters =====
{| class="wikitable"
|-
! colspan="2" | Inputs
|-
!Register
!Description
|-
|R3
|p1 - Unknown
|-
|R4
|p2 - Unknown
|-
|R5
|p3 - Unknown
|-
! colspan="2" | Outputs
|-
!Register
!Description
|-
|R3
|Status?
|-
|R4
|v1 - Unknown
|-
|}
----
=== lv1_set_lpm_counter ===
Not used in current kernel.
===== Abstract Call =====
result = lv1_set_lpm_counter( /*IN*/ p1, p2, p3, p4, p5, /*OUT*/ &v1, &v2 );
===== Parameters =====
{| class="wikitable"
|-
! colspan="2" | Inputs
|-
!Register
!Description
|-
|R3
|p1 - Unknown
|-
|R4
|p2 - Unknown
|-
|R5
|p3 - Unknown
|-
|R6
|p4 - Unknown
|-
|R7
|p5 - Unknown
|-
! colspan="2" | Outputs
|-
!Register
!Description
|-
|R3
|Status?
|-
|R4
|v1 - Unknown
|-
|R5
|v2 - Unknown
|-
|}
----
=== lv1_set_lpm_signal ===
Not used in current kernel.
===== Abstract Call =====
result = lv1_set_lpm_signal( /*IN*/ p1, p2, p3, p4, p5, p6, p7 );
===== Parameters =====
{| class="wikitable"
|-
! colspan="2" | Inputs
|-
!Register
!Description
|-
|R3
|p1 - Unknown
|-
|R4
|p2 - Unknown
|-
|R5
|p3 - Unknown
|-
|R6
|p4 - Unknown
|-
|R7
|p5 - Unknown
|-
|R8
|p6 - Unknown
|-
|R9
|p7 - Unknown
|-
! colspan="2" | Outputs
|-
!Register
!Description
|-
|R3
|Status?
|-
|}
----
=== lv1_set_lpm_spr_trigger ===
Not used in current kernel.
===== Abstract Call =====
result = lv1_set_lpm_spr_trigger( /*IN*/ p1, p2 );
===== Parameters =====
{| class="wikitable"
|-
! colspan="2" | Inputs
|-
!Register
!Description
|-
|R3
|p1 - Unknown
|-
|R4
|p2 - Unknown
|-
! colspan="2" | Outputs
|-
!Register
!Description
|-
|R3
|Status?
|-
|}
----
=== lv1_insert_htab_entry ===
Used in current kernel.
===== Kernel Call =====
result = lv1_insert_htab_entry( /*IN*/ p1, p2, p3, p4, p5, p6, /*OUT*/ &v1, &v2, &v3 );
===== Parameters =====
{| class="wikitable"
|-
! colspan="2" | Inputs
|-
!Register
!Description
|-
|R3
|p1 - htab ID, 0 or returns -6
|-
|R4
|p2 - hpte_group, 0 or returns -17
|-
|R5
|p3 - hpte_v
|-
|R6
|p4 - hpte_r
|-
|R7
|p5 - Bolted flag
|-
|R8
|p6 - flags?
|-
! colspan="2" | Outputs
|-
!Register
!Description
|-
|R3
|Status?
|-
|R4
|v1 - inserted_index
|-
|R5
|v2 - evicted_v
|-
|R6
|v3 - evicted_r
|-
|}
Notes: Kernel usage:
result = lv1_insert_htab_entry(PS3_LPAR_VAS_ID_CURRENT, hpte_group,
      hpte_v, hpte_r,
      HPTE_V_BOLTED, 0,
      &inserted_index,
      &evicted_v, &evicted_r);
----
=== lv1_read_virtual_uart ===
Read data from a VUART port into a provided buffer.
===== Kernel Call =====
result = lv1_read_virtual_uart( /*IN*/ port_number, buffer, bytes, /*OUT*/ bytes_read );
===== Parameters =====
{| class="wikitable"
|-
! colspan="2" | Inputs
|-
!Register
!Description
|-
|R3
|port_number - VUART port number
|-
|R4
|buffer - pointer to buffer (must be address in lpar)
|-
|R5
|bytes - buffer size?
|-
! colspan="2" | Outputs
|-
!Register
!Description
|-
|R3
|Status - 0 = OK, Other values are unknown, but indicate failure.
|-
|R4
|bytes_read - number of bytes read into buffer
|-
|}
----
=== lv1_write_virtual_uart ===
Write a buffer of data to a VUART port.
===== Kernel Call =====
result = lv1_write_virtual_uart( /*IN*/ port_number, buffer, bytes, /*OUT*/ bytes_written );
===== Parameters =====
{| class="wikitable"
|-
! colspan="2" | Inputs
|-
!Register
!Description
|-
|R3
|port_number - VUART port number
|-
|R4
|buffer - pointer to buffer (must be address in lpar)
|-
|R5
|bytes - buffer size?
|-
! colspan="2" | Outputs
|-
!Register
!Description
|-
|R3
|Status - 0 = OK, Other values are unknown, but indicate failure.
|-
|R4
|bytes_written - number of bytes written to VUART
|-
|}
----
=== lv1_set_virtual_uart_param ===
Set a parameter for a port on the VUART.
===== Kernel Call =====
result = lv1_set_virtual_uart_param( /*IN*/ port_number, param_id, param_value );
===== Parameters =====
{| class="wikitable"
|-
! colspan="2" | Inputs
|-
!Register
!Description
|-
|R3
|port_number - VUART port number
|-
|R4
|param_id - id of parameter to set (see notes)
|-
|R5
|param_value - parameter value
|-
! colspan="2" | Outputs
|-
!Register
!Description
|-
|R3
|Status - 0 = OK, Other values are unknown, but indicate failure.
|-
|}
See [[HV_Syscall_Reference#lv1_get_virtual_uart_param|lv1_get_virtual_uart_param]] for parameter information.
----
=== lv1_get_virtual_uart_param ===
Get a parameter for a port on the VUART.
===== Kernel Call =====
result = lv1_get_virtual_uart_param( /*IN*/ port_number, param_id, /*OUT*/ &param_value );
===== Parameters =====
{| class="wikitable"
|-
! colspan="2" | Inputs
|-
!Register
!Description
|-
|R3
|port_number - VUART port number
|-
|R4
|param_id - id of parameter to set (see notes)
|-
! colspan="2" | Outputs
|-
!Register
!Description
|-
|R3
|Status - 0 = OK, Other values are unknown, but indicate failure.
|-
|R4
|param_value - parameter value
|-
|}
VUART parameters defined in vuart.c:
{| class="wikitable"
|-
!Parameter
!param_id
!Notes
|-
|PARAM_TX_TRIGGER
|0
|
|-
|PARAM_RX_TRIGGER
|1
|
|-
|PARAM_INTERRUPT_MASK
|2
|
|-
|PARAM_RX_BUF_SIZE
|3
|read only
|-
|PARAM_RX_BYTES
|4
|read only
|-
|PARAM_TX_BUF_SIZE
|5
|read only, not referenced in current Kernel
|-
|PARAM_TX_BYTES
|6
|read only, not referenced in current Kernel
|-
|PARAM_INTERRUPT_STATUS
|7
|read only
|-
|}
----
=== lv1_configure_virtual_uart_irq ===
Configure the VUART IRQ.
===== Kernel Call =====
result = lv1_configure_virtual_uart_irq( /*IN*/ lpar_addr, /*OUT*/ &outlet );
===== Parameters =====
{| class="wikitable"
|-
! colspan="2" | Inputs
|-
!Register
!Description
|-
|R3
|lpar_addr - logical partition address of virtual uart interrupt bitmap
|-
! colspan="2" | Outputs
|-
!Register
!Description
|-
|R3
|Status - 0 = OK, Other values are unknown, but indicate failure.
|-
|R4
|outlet - irq outlet
|-
|}
Notes:
Comment from interrupt.c:
/**
* The system supports only a single virtual uart, so multiple calls without
* freeing the interrupt will return a wrong state error.
*/
----
=== lv1_undocumented_function_167 ===
SPE (isolation, reads from SPU_Out_Intr_Mbox and MFC_CNTL registers)
Exists on PAL 1.7. Returns -4 (LV1_DENIED_BY_POLICY) when passed 0 in R3 to R10.
----
=== lv1_undocumented_function_168 ===
SPE (isolation, writes to MFC_CNTL register)
Exists on PAL 1.7. Returns -4 (LV1_DENIED_BY_POLICY) when passed 0 in R3 to R10.
----
=== lv1_open_device ===
Open the device for a given bus and device id.
===== Kernel Call =====
result = lv1_open_device( /*IN*/ bus_id, dev_id, 0 );
===== Parameters =====
{| class="wikitable"
|-
! colspan="2" | Inputs
|-
!Register
!Description
|-
|R3
|bus_id - bus id
|-
|R4
|dev_id - device id
|-
|R5
|0 - Unknown
|-
! colspan="2" | Outputs
|-
!Register
!Description
|-
|R3
|Status: LV1_SUCCESS (0) - OK
LV1_NO_ENTRY (-6) - invalid dev_id
LV1_BUSY (-9) - device already open
LV1_ILLEGAL_PARAMETER_VALUE (-17) - invalid bus_id
|-
|}
Notes:
Valid values for bus_id and dev_id can be obtained from the repository (see [[HV_Syscall_Reference#lv1_get_repository_node_value|lv1_get_repository_node_value]]).
Once open, functions such as [[HV_Syscall_Reference#lv1_map_device_mmio_region|lv1_map_device_mmio_region]] and [[HV_Syscall_Reference#lv1_allocate_device_dma_region|lv1_allocate_device_dma_region]] can be used to map the device into memory.
The value of R5 does not seem to affect the outcome of the call (powers of 2 in the 64 bit range were tested). One reason for the flag could be to indicate whether to open the device in shared mode or not (and thus prevent the LV1_BUSY return code).
----
=== lv1_close_device ===
Close the device for a given bus and device id.
===== Kernel Call =====
result = lv1_close_device( /*IN*/ bus_id, dev_id );
===== Parameters =====
{| class="wikitable"
|-
! colspan="2" | Inputs
|-
!Register
!Description
|-
|R3
|bus_id - bus id
|-
|R4
|dev_id - device id
|-
! colspan="2" | Outputs
|-
!Register
!Description
|-
|R3
|Status - 0 = OK, Other values are unknown, but indicate failure.
|-
|}
----
=== lv1_map_device_mmio_region ===
Map an MMIO region to the specified device.
===== Kernel Call =====
result = lv1_map_device_mmio_region( /*IN*/ bus_id, dev_id, bus_addr, size, page_size, /*OUT*/ &lpar_addr );
===== Parameters =====
{| class="wikitable"
|-
! colspan="2" | Inputs
|-
!Register
!Description
|-
|R3
|bus_id - bus id
|-
|R4
|dev_id - device id
|-
|R5
|bus_addr - address of the region
|-
|R6
|size - size of the region
|-
|R7
|page_size - page size of the region
|-
! colspan="2" | Outputs
|-
!Register
!Description
|-
|R3
|Status - 0 = OK, Other values are unknown, but indicate failure.
|-
|R4
|lpar_addr - logical partition address of the mapped region
|-
|}
----
=== lv1_unmap_device_mmio_region ===
Unmap an MMIO region from the specified device.
===== Kernel Call =====
result = lv1_unmap_device_mmio_region( /*IN*/ bus_id, dev_id, lpar_addr );
===== Parameters =====
{| class="wikitable"
|-
! colspan="2" | Inputs
|-
!Register
!Description
|-
|R3
|bus_id - bus id
|-
|R4
|dev_id - device id
|-
|R5
|lpar_addr - logical partition address of the mapped region
|-
! colspan="2" | Outputs
|-
!Register
!Description
|-
|R3
|Status - 0 = OK, Other values are unknown, but indicate failure.
|-
|}
----
=== lv1_allocate_device_dma_region ===
Allocate a DMA region for the specified device.
===== Kernel Call =====
result = lv1_allocate_device_dma_region( /*IN*/ bus_id, dev_id, io_size, io_pagesize, flag, /*OUT*/ &dma_region );
===== Parameters =====
{| class="wikitable"
|-
! colspan="2" | Inputs
|-
!Register
!Description
|-
|R3
|bus_id - bus id
|-
|R4
|dev_id - device id
|-
|R5
|io_size - region size
|-
|R6
|io_pagesize - specified as a PAGE_SHIFT (i.e. n where pagesize = 2^n)
|-
|R7
|flag - 0=32 bit mode, 2=8 bit mode
|-
! colspan="2" | Outputs
|-
!Register
!Description
|-
|R3
|Status - 0 = OK, Other values are unknown, but indicate failure.
|-
|R4
|dma_region - dma region address
|-
|}
Notes: When the device is little endian, the mode must be set to 8 bit for 8 bit DMA to work as expected, otherwise the bytes will be read/written in the wrong order. OTOH, this mode requires that 16 and 32-bit values are byte-swapped by the CPU since they will appear as little endian in memory.
----
=== lv1_free_device_dma_region ===
Free a previously allocated DMA region for the specified device.
===== Kernel Call =====
lv1_free_device_dma_region( /*IN*/ bus_id, dev_id, dma_region );
===== Parameters =====
{| class="wikitable"
|-
! colspan="2" | Inputs
|-
!Register
!Description
|-
|R3
|bus_id - bus id
|-
|R4
|dev_id - device id
|-
|R5
|dma_region - dma region address
|-
! colspan="2" | Outputs
|-
!Register
!Description
|-
|R3
|Status?
|-
|}
----
=== lv1_map_device_dma_region ===
Map a DMA region for the specified device.
===== Kernel Call =====
result = lv1_map_device_dma_region( /*IN*/ bus_id, dev_id, lpar_addr, dma_region, size, flags );
===== Parameters =====
{| class="wikitable"
|-
! colspan="2" | Inputs
|-
!Register
!Description
|-
|R3
|bus_id - bus id
|-
|R4
|dev_id - device id
|-
|R5
|lpar_addr - logical partition address
|-
|R6
|dma_region - dma region address
|-
|R7
|size - region size
|-
|R8
|flags - see notes
|-
! colspan="2" | Outputs
|-
!Register
!Description
|-
|R3
|Status - 0 = OK, Other values are unknown, but indicate failure.
|-
|}
Notes:
In “mm.c” and “ps3_storage.c”, flags parameter is always specified as 0xf800000000000000UL. They are the same flags as the IOPTE entry ones.
----
=== lv1_unmap_device_dma_region ===
Unmap a DMA region for the specified device.
===== Kernel Call =====
result = lv1_unmap_device_dma_region( /*IN*/ bus_id, dev_id, dma_region, size );
===== Parameters =====
{| class="wikitable"
|-
! colspan="2" | Inputs
|-
!Register
!Description
|-
|R3
|bus_id - bus id
|-
|R4
|dev_id - device id
|-
|R5
|dma_region - dma region address
|-
|R6
|size - region size
|-
! colspan="2" | Outputs
|-
!Register
!Description
|-
|R3
|Status - 0 = OK, Other values are unknown, but indicate failure.
|-
|}
----
=== lv1_read_pci_config ===
Read external PCI config. ''PS3tool only?''
===== kboot Call =====
result = lv1_read_pci_config( /*IN*/ bus_id, pci_bus_id, dev_id, func_id, offset, size, /*OUT*/ &config_data );
===== Parameters =====
{| class="wikitable"
|-
! colspan="2" | Inputs
|-
!Register
!Description
|-
|R3
|bus_id - ps3 bus id
|-
|R4
|pci_bus_id - pci bus id
|-
|R5
|dev_id - pci device id
|-
|R6
|func_id - pci function
|-
|R7
|offset - offset to store data within config_data
|-
|R8
|size - size of config_data
|-
! colspan="2" | Outputs
|-
!Register
!Description
|-
|R3
|Status - 0 = OK, Other values are unknown, but indicate failure.
|-
|R4
|config_data - pci config data
|-
|}
Notes:
Code taken from kboot-10\dl\linux-2.6.16\arch\powerpc\platforms\ps3pf\pci.c (kboot-20061208)
status = lv1_read_pci_config(p->bus_id, p->bus_pci_bus, p->bus_pci_dev, p->bus_pci_func,
(uint64_t)offset, size, &data);
----
=== lv1_write_pci_config ===
Write external PCI config. ''PS3tool only?''
===== kboot Call =====
result = lv1_write_pci_config( /*IN*/ bus_id, pci_bus_id, dev_id, func_id, offset, size, config_data );
===== Parameters =====
{| class="wikitable"
|-
! colspan="2" | Inputs
|-
!Register
!Description
|-
|R3
|bus_id - ps3 bus id
|-
|R4
|pci_bus_id - pci bus id
|-
|R5
|dev_id - pci device id
|-
|R6
|func_id - pci function
|-
|R7
|offset - offset to store data within config_data
|-
|R8
|size - size of config_data
|-
|R9
|config_data - pci config data
|-
! colspan="2" | Outputs
|-
!Register
!Description
|-
|R3
|Status - 0 = OK, Other values are unknown, but indicate failure.
|-
|}
Notes:
Code taken from kboot-10\dl\linux-2.6.16\arch\powerpc\platforms\ps3pf\pci.c (kboot-20061208)
status = lv1_write_pci_config(p->bus_id, p->bus_pci_bus, p->bus_pci_dev, p->bus_pci_func,
    (uint64_t)offset, size, (uint64_t)val);
if(status) {
    /* lv1_write_pci_config can't write reg from 0x10 to 0x3f */
}
----
=== lv1_read_pci_io ===
Not used in current kernel.
===== Abstract Call =====
result = lv1_read_pci_io( /*IN*/ p1, p2, p3, p4, /*OUT*/ &v1 );
===== Parameters =====
{| class="wikitable"
|-
! colspan="2" | Inputs
|-
!Register
!Description
|-
|R3
|p1 - Unknown
|-
|R4
|p2 - Unknown
|-
|R5
|p3 - Unknown
|-
|R6
|p4 - Unknown
|-
! colspan="2" | Outputs
|-
!Register
!Description
|-
|R3
|Status?
|-
|R4
|v1 - Unknown
|-
|}
Notes:
Info taken from kboot-10\dl\linux-2.6.16\include\asm-powerpc\lv1calltab.h (kboot-20061208)
----
=== lv1_write_pci_io ===
Not used in current kernel.
===== Abstract Call =====
result = lv1_write_pci_io( /*IN*/ p1, p2, p3, p4, p5 );
===== Parameters =====
{| class="wikitable"
|-
! colspan="2" | Inputs
|-
!Register
!Description
|-
|R3
|p1 - Unknown
|-
|R4
|p2 - Unknown
|-
|R5
|p3 - Unknown
|-
|R6
|p4 - Unknown
|-
! colspan="2" | Outputs
|-
!Register
!Description
|-
|R3
|Status?
|-
|}
Notes:
Info taken from kboot-10\dl\linux-2.6.16\include\asm-powerpc\lv1calltab.h (kboot-20061208)
----
=== lv1_undocumented_function_182 ===
Exists in PAL 3.15. Nothing known so far.
Note: probably a function that allocates or frees memory.
----
=== lv1_undocumented_function_183 ===
Exists in PAL 3.15. Nothing known so far.
Note: probably a function that allocates or frees memory.
----
=== lv1_net_add_multicast_address ===
Add multicast address to the specified network device.
===== Kernel Call =====
result = lv1_net_add_multicast_address( /*IN*/ bus_id, dev_id, addr, flag );
===== Parameters =====
{| class="wikitable"
|-
! colspan="2" | Inputs
|-
!Register
!Description
|-
|R3
|bus_id - bus id
|-
|R4
|dev_id - device id
|-
|R5
|addr - see notes
|-
|R6
|flag - see notes
|-
! colspan="2" | Outputs
|-
!Register
!Description
|-
|R3
|Status - 0 = OK, Other values are unknown, but indicate failure.
|-
|}
Notes:
From “gelic_net.c”, addr can also take special values of 0 and GELIC_NET_BROADCAST_ADDR (0xffffffff) and flag is assigned values of 0 and 1.
----
=== lv1_net_remove_multicast_address ===
Remove multicast address on the specified network device.
===== Kernel Call =====
result = lv1_net_remove_multicast_address( /*IN*/ bus_id, dev_id, 0, 1 );
===== Parameters =====
{| class="wikitable"
|-
! colspan="2" | Inputs
|-
!Register
!Description
|-
|R3
|bus_id - bus id
|-
|R4
|dev_id - device id
|-
|R5
|0 - Unknown
|-
|R6
|1 - Unknown
|-
! colspan="2" | Outputs
|-
!Register
!Description
|-
|R3
|Status - 0 = OK, Other values are unknown, but indicate failure.
|-
|}
----
=== lv1_net_start_tx_dma ===
Start DMA transmit on the specified network device.
===== Kernel Call =====
result = lv1_net_start_tx_dma( /*IN*/ bus_id, dev_id, bus_addr, 0 );
===== Parameters =====
{| class="wikitable"
|-
! colspan="2" | Inputs
|-
!Register
!Description
|-
|R3
|bus_id - bus id
|-
|R4
|dev_id - device id
|-
|R5
|bus_addr - dma address?
|-
|R6
|0 - Unknown
|-
! colspan="2" | Outputs
|-
!Register
!Description
|-
|R3
|Status - 0 = OK, Other values are unknown, but indicate failure.
|-
|}
----
=== lv1_net_stop_tx_dma ===
Stop DMA transmit on the specified network device.
===== Kernel Call =====
result = lv1_net_stop_tx_dma( /*IN*/ bus_id, dev_id, 0 );
===== Parameters =====
{| class="wikitable"
|-
! colspan="2" | Inputs
|-
!Register
!Description
|-
|R3
|bus_id - bus id
|-
|R4
|dev_id - device id
|-
|R5
|0 - Unknown
|-
! colspan="2" | Outputs
|-
!Register
!Description
|-
|R3
|Status - 0 = OK, Other values are unknown, but indicate failure.
|-
|}
----
=== lv1_net_start_rx_dma ===
Start DMA receive on the specified network device.
===== Kernel Call =====
result = lv1_net_start_rx_dma( /*IN*/ bus_id, dev_id, bus_addr, 0 );
===== Parameters =====
{| class="wikitable"
|-
! colspan="2" | Inputs
|-
!Register
!Description
|-
|R3
|bus_id - bus id
|-
|R4
|dev_id - device id
|-
|R5
|bus_addr - dma address?
|-
|R6
|0 - Unknown
|-
! colspan="2" | Outputs
|-
!Register
!Description
|-
|R3
|Status - 0 = OK, Other values are unknown, but indicate failure.
|-
|}
----
=== lv1_net_stop_rx_dma ===
Stop DMA receive on the specified network device.
===== Kernel Call =====
result = lv1_net_stop_rx_dma( /*IN*/ bus_id, dev_id, 0 );
===== Parameters =====
{| class="wikitable"
|-
! colspan="2" | Inputs
|-
!Register
!Description
|-
|R3
|bus_id - bus id
|-
|R4
|dev_id - device id
|-
|R5
|0 - Unknown
|-
! colspan="2" | Outputs
|-
!Register
!Description
|-
|R3
|Status - 0 = OK, Other values are unknown, but indicate failure.
|-
|}
----
=== lv1_net_set_interrupt_status_indicator  ===
Set the interrupt status indicator for the specified network device.
===== Kernel Call =====
result = lv1_net_set_interrupt_status_indicator( /*IN*/ bus_id, dev_id, irq_status_addr, 0 );
===== Parameters =====
{| class="wikitable"
|-
! colspan="2" | Inputs
|-
!Register
!Description
|-
|R3
|bus_id - bus id
|-
|R4
|dev_id - device id
|-
|R5
|irq_status_addr - lpar address of the irq status indicator
|-
|R6
|0 - Unknown
|-
! colspan="2" | Outputs
|-
!Register
!Description
|-
|R3
|Status - 0 = OK, Other values are unknown, but indicate failure.
|-
|}
----
=== lv1_net_set_interrupt_mask ===
Sets the interrupt mask for specified network device.
===== Kernel Call =====
result = lv1_net_set_interrupt_mask( /*IN*/ bus_id, dev_id, mask, 0 );
===== Parameters =====
{| class="wikitable"
|-
! colspan="2" | Inputs
|-
!Register
!Description
|-
|R3
|bus_id - bus id
|-
|R4
|dev_id - device id
|-
|R5
|mask - interrupt mask
|-
|R6
|0 - Unknown
|-
! colspan="2" | Outputs
|-
!Register
!Description
|-
|R3
|Status - 0 = OK, Other values are unknown, but indicate failure.
|-
|}
----
=== lv1_net_control ===
Send a control command to the specified network device.
===== Kernel Call =====
result = lv1_net_control( /*IN*/ bus_id, dev_id, p1, p2, p3, p4, /*OUT*/ &v1, &v2 );
===== Parameters =====
{| class="wikitable"
|-
! colspan="2" | Inputs
|-
!Register
!Description
|-
|R3
|bus_id - bus id
|-
|R4
|dev_id - device id
|-
|R5
|p1 - command dependent input parameter
|-
|R6
|p2 - command dependent input parameter
|-
|R7
|p3 - command dependent input parameter
|-
|R8
|p4 - command dependent input parameter
|-
! colspan="2" | Outputs
|-
!Register
!Description
|-
|R3
|Status - 0 = OK, Other values are unknown, but indicate failure.
|-
|R4
|v1 - command dependent output parameter
|-
|R5
|v2 - command dependent output parameter
|-
|}
----
=== lv1_undocumented_function_195 ===
WLAN Gelic device
Exists in PAL 1.7. Returns -3 (LV1_NO_PRIVILEGE) when passed 0 in R3 to R10.
----
=== lv1_undocumented_function_196 ===
WLAN Gelic device
Exists in PAL 1.7. Returns -3 (LV1_NO_PRIVILEGE) when passed 0 in R3 to R10.
----
=== lv1_connect_interrupt_event_receive_port ===
Assign a virtual interrupt to a system bus device.
===== Kernel Call =====
result = lv1_connect_interrupt_event_receive_port( /*IN*/ bus_id, dev_id, outlet, interrupt_id );
===== Parameters =====
{| class="wikitable"
|-
! colspan="2" | Inputs
|-
!Register
!Description
|-
|R3
|bus_id - device bus id
|-
|R4
|dev_id - device id
|-
|R5
|outlet - interrupt outlet
|-
|R6
|interrupt_id - interrupt id
|-
! colspan="2" | Outputs
|-
!Register
!Description
|-
|R3
|Status - 0 = OK, Other values are unknown, but indicate failure.
|-
|}
----
=== lv1_disconnect_interrupt_event_receive_port ===
Disconnect a virtual interrupt from a system bus device.
===== Kernel Call =====
result = lv1_disconnect_interrupt_event_receive_port( /*IN*/ bus_id, dev_id, outlet, interrupt_id );
===== Parameters =====
{| class="wikitable"
|-
! colspan="2" | Inputs
|-
!Register
!Description
|-
|R3
|bus_id - device bus id
|-
|R4
|dev_id - device id
|-
|R5
|outlet - interrupt outlet
|-
|R6
|interrupt_id - interrupt id
|-
! colspan="2" | Outputs
|-
!Register
!Description
|-
|R3
|Status - 0 = OK, Other values are unknown, but indicate failure.
|-
|}
----
=== lv1_get_spe_all_interrupt_statuses ===
Not used in current kernel.
===== Abstract Call =====
result = lv1_get_spe_all_interrupt_statuses( /*IN*/ p1, /*OUT*/ &v1 );
===== Parameters =====
{| class="wikitable"
|-
! colspan="2" | Inputs
|-
!Register
!Description
|-
|R3
|p1 - Unknown
|-
! colspan="2" | Outputs
|-
!Register
!Description
|-
|R3
|Status?
|-
|R4
|v1 - Unknown
|-
|}
----
=== lv1_undocumented_function_200 ===
SPE (isolation)
Exists in PAL 1.7. Returns -4 (LV1_DENIED_BY_POLICY) when passed 0 in R3 to R10.
----
=== lv1_undocumented_function_201 ===
SPE (isolation)
Exists in PAL 1.7. Returns -4 (LV1_DENIED_BY_POLICY) when passed 0 in R3 to R10.
----
=== lv1_deconfigure_virtual_uart_irq ===
Deconfigure the VUART IRQ.
===== Kernel Call =====
result = lv1_deconfigure_virtual_uart_irq();
===== Parameters =====
{| class="wikitable"
|-
! colspan="2" | Outputs
|-
!Register
!Description
|-
|R3
|Status - 0 = OK, Other values are unknown, but indicate failure.
|-
|}
----
=== lv1_enable_logical_spe ===
Enables a logical SPE.
===== Kernel Call =====
status = lv1_enable_logical_spe( /*IN*/ spe_id, resource_id );
===== Parameters =====
{| class="wikitable"
|-
! colspan="2" | Inputs
|-
!Register
!Description
|-
|R3
|spe_id - logical spe id
|-
|R4
|resource_id - spe resource id (prevously retrieved from Kernel repository)
|-
! colspan="2" | Outputs
|-
!Register
!Description
|-
|R3
|Status - 0 = OK, Other values are unknown, but indicate failure.
|-
|}
----
=== lv1_undocumented_function_209 ===
SPE (isolation)
Exists in PAL 1.7. Returns -4 (LV1_DENIED_BY_POLICY) when passed 0 in R3 to R10.
----
=== lv1_gpu_open ===
Open the GPU. Call [[HV_Syscall_Reference#lv1_gpu_close|lv1_gpu_close]] to close the GPU.
===== Kernel Call =====
status = lv1_gpu_open( /*IN*/ p1 );
===== Parameters =====
{| class="wikitable"
|-
! colspan="2" | Inputs
|-
!Register
!Description
|-
|R3
|p1 - Unknown, Kernel only ever passes 0, though other randomly chosen values seem to succeed.
|-
! colspan="2" | Outputs
|-
!Register
!Description
|-
|R3
|Status: 0 = LV1_SUCCESS, -6 = LV1_NO_ENTRY
|-
|}
Notes:
When called from Kernel module init function, if GPU is already open, subsequent calls to lv1_gpu_open return LV1_NO_ENTRY (-6). Closing the GPU and re-opening succeeds.
----
=== lv1_gpu_close ===
Closes the GPU. Must be called once for every call to [[HV_Syscall_Reference#lv1_gpu_open|lv1_gpu_open]].
===== Kernel Call =====
status = lv1_gpu_close();
===== Parameters =====
{| class="wikitable"
|-
! colspan="2" | Outputs
|-
!Register
!Description
|-
|R3
|Status - 0 = OK, Other values are unknown, but indicate failure.
|-
|}
----
=== lv1_gpu_device_map ===
Map a device into logical address space. Address needs to be ioremapped before use.
===== kboot Call =====
result = lv1_gpu_device_map( /*IN*/ dev_id, /*OUT*/ &lpar_addr, &lpar_size );
===== Parameters =====
{| class="wikitable"
|-
! colspan="2" | Inputs
|-
!Register
!Description
|-
|R3
|dev_id - device id (see notes)
|-
! colspan="2" | Outputs
|-
!Register
!Description
|-
|R3
|Status - 0 = OK, Other values are unknown, but indicate failure.
|-
|R4
|lpar_addr - logical partition address of device block
|-
|R5
|lpar_size - size of device block
|-
|}
Notes:
Info taken from kboot-10\dl\linux-2.6.16\sound\powerpc\snd_ps3pf.c (kboot-20061208) where the audio front-end registers are mapped into memory. Two calls to lv1_gpu_device_map are performed, the first when dev_id = 1, to obtain the audio interrupt (Audio IRQ Outlet) and a second time when dev_id = 2 to obtain a mapping of the register block (Audio Registers).
lpar_addr is a virtual address, created by the Hypervisor. Multiple calls to lv1_gpu_device_map with the same dev_id return successfully, but the lpar_address returned for each is different (if there have been no intermediary lv1_gpu_device_unmap calls). These various virtual lpar_addr values all alias the same physical location in memory.
===== Test Results =====
{| class="wikitable"
|-
! colspan="5" | lv1_gpu_device_map
|-
!dev_id
!result
!lpar_addr
!lpar_size
!Comment
|-
|0
|ffffffffffffffef
|98d2f7d44da1ceae
|0100000000000000
|result = LV1_ILLEGAL_PARAMETER_VALUE
|-
|1
|0000000000000000
|0000300000022000
|0000000000001000
|Audio IRQ Outlet (map1_dump)
|-
|2
|0000000000000000
|00003c0000128000
|0000000000008000
|Audio_Registers (map2_dump)
|-
|3
|0000000000000000
|0000300000026000
|0000000000001000
|??? - Any attempt to dereference this lpar_addr locks up the PS3
|-
|4
|ffffffffffffffef
|0000300000026000
|0000000000001000
|result = LV1_ILLEGAL_PARAMETER_VALUE
|-
|5
|0000000000000000
|0000300000028000
|0000000000001000
|??? - (map5_dump)
|-
|6
|0000000000000000
|0000300000029000
|0000000000001000
|??? - (map6_dump)
|-
|7
|0000000000000000
|00003000002A0000
|0000000000010000
|??? - (map7_dump)
|-
|8
|0000000000000000
|000030000002B000
|0000000000001000
|video RAM at offset 0x0ff10000- (map8_dump)
|-
|9-255
| -20
|???
|???
|result = LV1_NOT_IMPLEMENTED
|-
|}
It is interesting that when dev_id = 4, LV1_ILLEGAL_PARAMETER_VALUE is returned with lpar_addr and lpar_size set to the values returned from the previous call - for the first call when dev_id = 0, values also appear to be set (though these could be garbage values)
===== Devices 1 & 2 =====
dev_id 1 gives a location used to process IRQ’s from the audio and dev_id 2 gives the base address of the Audio Hardware registers. From published Sony documents (http://www.watch.impress.co.jp/game/docs/20060329/3dps303.htm), Audio is believed to be on the RSX, this call seems to confirm that. Access to the audio after this mapping call (it would appear) bypasses the Hypervisor and occurs directly on the RSX hardware. 3,5,6,7,8 are currently unknown. Presumably 0 and 4 are otherwise valid parameters blocked by the Hypervisor for OtherOS (ie, they may function for Games) otherwise I would have expected a return result of -20 for them. So rather than just being a bridge for audio into HDMI, it is for all audio.
Also interesting is that the GPU version number returned by [[HV_Syscall_Reference#lv1_gpu_context_allocate|lv1_gpu_context_allocate]] appears at address 0×10 in the device 1 dump, though this of course may be complete coincidence.
===== Device 7 =====
dev_id 7 appears to be a video device. It is not possible to map the entire reported memory space (0×10000), only areas 0×0000 to 0x0fff and 0×2000 to 0x2fff (discovered via laborious trial and error testing, mapping other areas causes the PS3 to hang without warning). In both mappable areas, the current screen resolution can be seen at locations 0×200 and 0×210. Changes to the ps3 video mode (e.g. using the ps3videomode utility) can be observed in the mapped areas, but modifying the values directly does not affect the screen resolution. Although both areas contain different values, there appear to be parts in common, as changing the values at 0×200 and 0×210 directly in one area also causes the same values in the other area to change.
Given the screen resolution connection, it could be possible that this device is a mapping of the GPU display heads:
*Out of 16Kb, only two areas are mappable (= number of accessible display heads)
*Mappable areas are 2Kb apart → 8 total display heads (= size of display heads array returned by [[HV_Syscall_Reference#lv1_gpu_context_allocate|lv1_gpu_context_allocate]])
===== Device 8 =====
dev_id 8 appears to be a mapping of video RAM at offset 0x0ff10000. This region of video memory is referenced by RSX DMA objects but its purpose is unknown.
----
=== lv1_gpu_device_unmap ===
Unmaps the device from logical address space.
===== kboot Call =====
lv1_gpu_device_unmap( /*IN*/ dev_id );
===== Parameters =====
{| class="wikitable"
|-
! colspan="2" | Inputs
|-
!Register
!Description
|-
|R3
|dev_id - device id (see [[HV_Syscall_Reference#lv1_gpu_device_map|lv1_gpu_device_map]])
|-
! colspan="2" | Outputs
|-
!Register
!Description
|-
|R3
|Status?
|-
|}
Notes:
Info taken from kboot-10\dl\linux-2.6.16\sound\powerpc\snd_ps3pf.c (kboot-20061208)
----
=== lv1_gpu_memory_allocate ===
Allocate GPU memory.
===== Kernel Call =====
status = lv1_gpu_memory_allocate(ddr_size, 0, 0, 0, 0, &memory_handle, &ddr_lpar);
===== Parameters =====
{| class="wikitable"
|-
! colspan="2" | Inputs
|-
!Register
!Description
|-
|R3
|ddr_size - amount of DDR to reserve? (see notes)
|-
|R4
|tile_max_size in bytes. Max value 512*1024.
|-
|R5
|zcull_max_size in bytes. Max value 3075*1024.
|-
|R6
|tile_max_areas. Max value 15.
|-
|R7
|zcull_max_areas. Max value 8.
|-
! colspan="2" | Outputs
|-
!Register
!Description
|-
|R3
|status: 0 = LV1_SUCCESS, -17 = LV1_ILLEGAL_PARAMETER_VALUE
|-
|R4
|memory_handle - used by [[HV_Syscall_Reference#lv1_gpu_context_allocate|lv1_gpu_context_allocate]] and [[HV_Syscall_Reference#lv1_gpu_memory_free|lv1_gpu_memory_free]]??
|-
|R5
|ddr_lpar - remappable address of allocated video memory, unused by Kernel.
|-
|}
Notes:
ddr_size accepts values (0..252) * 2^20 - values not divisible by 2^20 (1 MB) and above the range result in a return value of -17 (LV1_ILLEGAL_PARAMETER_VALUE). [Verified by Strontium Dog on an AU PS3 V1.5 firmware]
Bits 52-63 of ddr_size seem to be ignored or correspond to flags. The lower bits correspond to the amount of allocated video RAM. A call to [[HV_Syscall_Reference#lv1_gpu_context_allocate|lv1_gpu_context_allocate]] using the returned memory_handle will create a RSX DMA object handle 0xfeed0000 corresponding to the region of allocated memory. Multiple calls to [[HV_Syscall_Reference#lv1_gpu_memory_allocate|lv1_gpu_memory_allocate]] with non-zero ddr_size will change the start of this region. The DMA object limit is set to ddr_size - 1. Before FW 2.1, a ddr_size of 0 was accepted, in which case a DMA object starting at zero and of limit 0xffffffff was created. Note that in this case, the start of this region is always zero even if previous calls to [[HV_Syscall_Reference#lv1_gpu_memory_allocate|lv1_gpu_memory_allocate]] with non-zero ddr_size were performed. As of FW 2.1 and above, a zero ddr_size is not accepted anymore.
Parameters r4-r7 are unknown. Maximum values for these parameters are respectively 512kB, 3075kB, 15 and 8. They refer to shared scarce resources, as allocations are retained across multiple calls to [[HV_Syscall_Reference#lv1_gpu_memory_allocate|lv1_gpu_memory_allocate]]. When attached to a context during [[HV_Syscall_Reference#lv1_gpu_context_allocate|lv1_gpu_context_allocate]], the values of these parameters are reported in the lpar_driver_info structure of the context.
Cell separates multiple OS into Logical Partitions (lpar) described at http://research.scea.com/research/html/CellGDC05/13.html. PS3 GPU memory is referred to as DDR (or GDDR) whereas system memory is XDR. 256 MB of each are installed in PS3 though only XDR is currently available for use by OtherOS.
To make use of the allocated DDR ddr_lpar needs to be transformed into a usable address using:
ddr_address = ioremap_flags(ddr_lpar, ddr_size, _PAGE_NO_CACHE);
Be aware that the memory that holds the physical GPU frame buffer is not allocated by the Kernel, just used. So on the first call to this, some or all of the memory you request (depending on now much you request) may be actually used as the frame buffer. You will know this, because your writes to memory will mysteriously disappear up to 20ms after you perform them. Note that direct access to video ram is very slow (~10MB/s).
===== Test Results =====
{| class="wikitable"
|-
!Register
!Hex
!Decimal
!Comments
|-
|R3
|0x000000000fc00000
|(264241152)
|252 MB
|-
|R4
|0×0000000000000000
|(0)
|
|-
|R5
|0×0000000000000000
|(0)
|
|-
|R6
|0×0000000000000000
|(0)
|
|-
|R7
|0×0000000000000000
|(0)
|
|-
! colspan="4" | Outputs
|-
|R3
|0×0000000000000000
|(0)
|LV1_SUCCESS
|-
|R4
|0x000000005a5a5a5b
|(...)
|memory handle
|-
|R5
|0x00007001a0000000
|(...)
|ddr logical partition address
|-
|}
----
=== lv1_gpu_memory_free ===
Free memory handle returned by [[HV_Syscall_Reference#lv1_gpu_memory_allocate|lv1_gpu_memory_allocate]]. Must be called to dispose of the handle returned by [[HV_Syscall_Reference#lv1_gpu_memory_allocate|lv1_gpu_memory_allocate]].
===== Kernel Call =====
status = lv1_gpu_memory_free(ps3fb.memory_handle);
===== Parameters =====
{| class="wikitable"
|-
! colspan="2" | Inputs
|-
!Register
!Description
|-
|R3
|Memory handle returned by [[HV_Syscall_Reference#lv1_gpu_memory_allocate|lv1_gpu_memory_allocate]]
|-
! colspan="2" | Outputs
|-
!Register
!Description
|-
|R3
|Status - 0 = OK, Other values are unknown, but indicate failure.
|-
|}
----
=== lv1_gpu_context_iomap ===
Map system RAM address to GPU through the Cell FlexIO interface.
===== Kernel Call =====
status = lv1_gpu_context_iomap(ps3fb.context_handle, GPU_IOIF,
      xdr_lpar, ps3fb_videomemory.size, 0);
===== Parameters =====
{| class="wikitable"
|-
! colspan="2" | Inputs
|-
!Register
!Description
|-
|R3
|ps3fb.context_handle as allocated by [[HV_Syscall_Reference#lv1_gpu_context_allocate|lv1_gpu_context_allocate]]
|-
|R4
|GPU_IOIF = 0x0d000000UL - GPU address where the system RAM virtual framebuffer is remapped
|-
|R5
|xdr_lpar - lpar version of the physical address of the virtual frame buffer in local memory. (Note: the lpar version = the physical address in the PS3)
|-
|R6
|ps3fb_videomemory.size = The size of the virtual frame buffer
|-
|R7
|0 - IOPTE flags - bitfield describing protection, coherency and ordering of the I/O mapping. Any combination of 0 or 2^{11 (cache hint),59 (read ordering),60 (write ordering),61 (coherency),62 (read protection) ,63 (write protection)} seems valid
|-
! colspan="2" | Outputs
|-
!Register
!Description
|-
|R3
|Status - 0 = OK, LV1_TYPE_MISMATCH (-8) if R5 set to a DDR lpar address, LV1_ILLEGAL_PARAMETER_VALUE (-17) if any other bit set in R7 than described above
|-
|}
This function creates a mapping in GPU address space so that the RSX can access system RAM. The Kernel uses it to associate the virtual framebuffer residing in system RAM to the GPU, so that so that transfers can be initiated by the RSX from the system RAM to the video RAM using the [[HV_Syscall_Reference#lv1_gpu_context_attribute|lv1_gpu_context_attribute]]:fb_blit() call.
Comments:
It was previously suspected that GPU_IOIF was the address of GPU MMIO registers. However GPU_IOIF is a GPU address, not a lpar address, and therefore has no meaning on the Linux side, and cannot be directly mapped from the Linux address space. Reserving the memory block (using request_mem_region) and mapping (using ioremap) results in a block of memory that is used by Linux (nothing resembling IO registers was observed whilst single frame stepping a gfx demo). [was: As you’ve previously discovered that the top of RAM is 0x0e00 0000, GPU_IOIF here is 16Mb below that. That’s typically the size of the a graphics card PCI IO region on a PC, so given the name, I’d strongly suggest it’s not GPU memory that’s being mapped but the GPU IO registers. Although why this address range would overlap with RAM is a mystery.]
GPU_IOIF was successfully set to other values (0×00000000, 0×02000000, 0×04000000) with Linux booting and displaying correctly. A value of 0x0f000000 causes the PS3 to hang (need to retest 0x0e0000000)
Although it looks like GPU_IOIF would overlap video RAM, the RSX differentiates between the two by associating different DMA objects to the source and destination of the blit. The source is associated with DMA object handle 0xfeed0001 which targets system memory, while the destination is associated with DMA object handle 0xfeed0000 which targets video memory. This has been observed by analysing the FIFO commands sent to the GPU by the hypervisor during the [[HV_Syscall_Reference#lv1_gpu_context_attribute|lv1_gpu_context_attribute]]:fb_setup() and [[HV_Syscall_Reference#lv1_gpu_context_attribute|lv1_gpu_context_attribute]]:fb_blit() calls.
It seems a call to [[HV_Syscall_Reference#lv1_gpu_context_iomap|lv1_gpu_context_iomap]](handle, bus_addr, xdr_lpar, size, flags) is equivalent to a series of call to [[HV_Syscall_Reference#lv1_put_iopte|lv1_put_iopte]]:
int i;
int context_number; /* derived from handle, 1st allocated context 0, 2nd allocated context 1, etc... */
for (i = 0; i < size; i += 1024 * 1024) {
lv1_put_iopte(0,            /* IO ASID */
      ((0x08ULL + context_number) << 28) | bus_addr) + i, /* IO address */
      xdr_lpar + i, /* Logical Partition address */
              1,            /* PS3_AUDIO_IOID, actually RSX IOID */
      flags);
}
Tested by replacing the call to [[HV_Syscall_Reference#lv1_gpu_context_iomap|lv1_gpu_context_iomap]] with the code above in ps3fb.c.
----
=== lv1_undocumented_function_222 ===
Located @ 0x20D648 in 3.15 HV.
Does something with GPU Register 0x140, doesn't take arguments or return anything.
----
=== lv1_gpu_context_attribute ===
This is a multifunction call.
==== General Case ====
===== Abstract Call =====
status = lv1_gpu_context_attribute(ps3fb.context_handle, operation_code,
      p1, p2, p3, p4 );
===== Parameters =====
{| class="wikitable"
|-
! colspan="2" | Inputs
|-
!Register
!Description
|-
|R3
|ps3fb.context_handle as allocated by [[HV_Syscall_Reference#lv1_gpu_context_allocate|lv1_gpu_context_allocate]]
|-
|R4
|operation_code - The code of the operation to perform.
|-
|R5
|p1 - Parameter 1 to the operation
|-
|R6
|p2 - Parameter 2 to the operation
|-
|R7
|p3 - Parameter 3 to the operation
|-
|R8
|p4 - Parameter 4 to the operation
|-
! colspan="2" | Outputs
|-
!Register
!Description
|-
|R3
|Status - 0 = OK, Other values are unknown, but indicate failure.
|-
|}
===== Operations =====
The operation code can be one of the following:
{| class="wikitable"
|-
!Operation
!Code
!Details
!Address in 3.15
|-
|No Entry
|0×0000
|Not a valid operation, returns LV1_NO_ENTRY (-6)
|
|-
|L1GPU_CONTEXT_ATTRIBUTE_FIFO_SETUP
|0×0001
|fifo_setup
|0×210910
|-
|Unknown
|0×0002
|fifo_pause, (rsx_ctx, 2, 0, 0, 0, 0)
|0x2108ec
|-
|Unknown
|0×0003
|fifo_continue,  (rsx_ctx, 3, 0, 0, 0, 0)
|0x2107c0
|-
|No Entry
|0×0004-0x00FF
|Not a valid operation, returns LV1_NO_ENTRY (-6)
|
|-
|L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_MODE_SET
|0×0100
|display_mode_set
|0x21092c
|-
|L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_SYNC
|0×0101
|display_sync
|0×210318
|-
|L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_FLIP
|0×0102
|display_flip
|0×210588
|-
|Unknown
|0×0103
|Unknown function, returns LV1_SUCCESS(0) when called with 0,0,0,0
|0×210994
|-
|Unknown
|0×0104
|Unknown function, returns LV1_SUCCESS(0) when called with 0,0,0,0
|0×210754
|-
|Unknown
|0×0105
|Unknown function, returns LV1_SUCCESS(0) when called with 0,0,0,0
|0×210828
|-
|Unknown
|0×0106
|cellGcmFunc4 ? , returns LV1_SUCCESS(0) when called with 0,0,0,0
|0x2109ac
|-
|Unknown
|0×0107
|Unknown function, returns LV1_SUCCESS(0) when called with 0,0,0,0 – Doesn’t Exist in the 3.15 HV.
|N/A
|-
|Unknown
|0×0108
|set interrupt frequency, returns LV1_ILLEGAL_PARAMETER_VALUE(-17) when called with 0,0,0,0
|0x21063c
|-
|Unknown
|0×0109
|Unknown function, returns LV1_SUCCESS(0) when called with 0,0,0,0
|0x2104e8
|-
|Unknown
|0x010A
|init gcm channel, (e.g. (rsx_ctx, 0x10A, 0, 0, 0x80000000, 0))
|0×210888
|-
|No Entry
|0x010B-0x01FF
|Not a valid operation, returns LV1_NO_ENTRY (-6)
|
|-
|Unknown
|0×0200
|Crashes the PS3 when called with 0,0,0,0. See CN2 – Doesn’t exist in 3.15
|N/A
|-
|Unknown
|0×0201
|Unknown function, returns LV1_SUCCESS(0) when called with 0,0,0,0
|0×210724
|-
|Unknown
|0×0202
|generate rsx graphics error ?, returns LV1_SUCCESS(0) when called with 0,0,0,0. See CN3
|0x21083c
|-
|No Entry
|0×0203-0x02FF
|Not a valid operation, returns LV1_NO_ENTRY (-6)
|
|-
|Unknown
|0×0300
|tile, (set invalidate tile, set tile, bind tile, unbind tile)
|0x2108c0
|-
|Unknown
|0×0301
|Zcull, (set Zcull, bind Zcull, unbind Zcull)
|0x2104bc
|-
|Unknown
|0×0302
|Unknown function. found @ 0x2105E8 in the 3.15 HV
|0x2105e8
|-
|No Entry
|0×0303-0x03FF
|Not a valid operation, returns LV1_NO_ENTRY (-6)
|
|-
|Unknown
|0×0400
|Unknown function, returns LV1_SUCCESS(0) when called with 0,0,0,0
|0x2109d8
|-
|No Entry
|0×0401-0x05FF
|Not a valid operation, returns LV1_NO_ENTRY (-6)
|
|-
|L1GPU_CONTEXT_ATTRIBUTE_FB_SETUP
|0×0600
|fb_setup
|0×210788
|-
|L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT
|0×0601
|fb_blit
|0x2107ec
|-
|L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT_SYNC
|0×0602
|fb_blit_sync
|0×210964
|-
|L1GPU_CONTEXT_ATTRIBUTE_FB_CLOSE
|0×0603
|Added on FW >= 2.1 and used in recent Linux kernel (called with 0,0,0,0) to undo fb_setup. Not a Valid operation on older firmware.
|0×210694
|-
|No Entry
|0×0604-0x0FFF
|Not a valid operation, returns LV1_NO_ENTRY (-6)
|
|-
|}
L1GPU_CONTEXT_ATTRIBUTE_FIFO_SETUP is undocumented and has been discovered by probing.
===== Notes =====
Probing this call by passing in an unknown operation_code and parameters of 0, seems to return a status of LV1_SUCCESS (0) whereas if the operation is not a valid id, the call returns LV1_NO_ENTRY (-6)
====== Crash Note 1 (CN1) ======
Symptoms of Crash:
No Video.
Keyboard/Mouse unresponsive.
Green Power Light lit steady.
Requires hard power off to clear (holding power button on front unresponsive).
====== Crash Note 2 (CN2) ======
Symptoms of Crash:
No Video.
Keyboard/Mouse unresponsive.
Three quick beeps from internal PS3 beeper.
Power Light lit blinks red.
Pressing power Led makes it steady red, pressing again reboots.
====== Crash Note 3 (CN3) ======
Symptoms of Crash:
Video remains on display (from time preceding call).
All video updates cease. 
Linux Kernel reports repeatedly: "lv1_gpu_context_attribute FB_BLIT failed: status -32768"
Rebooted PS3 to clear using front power button, this did not fix condition.  Hard power reset required to clear.
==== lv1_gpu_context_attribute:display_mode_set ====
Sets up the display mode? In the 3.15 firmware, this function doesn’t actually do anything.
It takes 3 32bit parameters but then doesn’t do anything with them. Always returns 0.
This is a specific operation of the generic operation [[HV_Syscall_Reference#lv1_gpu_context_attribute|lv1_gpu_context_attribute]](...);
===== Kernel Call =====
status = lv1_gpu_context_attribute(0x0,L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_MODE_SET,
  0, 0, 1, 0);
===== Parameters =====
{| class="wikitable"
|-
! colspan="2" | Inputs
|-
!Register
!Description
|-
|R3
|ps3fb.context_handle as allocated by [[HV_Syscall_Reference#lv1_gpu_context_allocate|lv1_gpu_context_allocate]] theoretically. The Kernel actually passes 0 for this operation, so it must not be required.
|-
|R4
|operation_code - L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_MODE_SET (0×100)
|-
|R5
|p1 - 0 - Unknown.
|-
|R6
|p2 - 0 - Unknown.
|-
|R7
|head - 0 = Head A (Unfitted to the Retail PS3), 1 = Head B the active head on the PS3.
|-
|R8
|p4 - 0 - unused.
|-
! colspan="2" | Outputs
|-
!Register
!Description
|-
|R3
|Status - 0 = OK, Other values are unknown, but indicate failure.
|-
|}
==== lv1_gpu_context_attribute:display_sync ====
Sets up some sort of Display Sync attribute mode.
This is a specific operation of the generic operation [[HV_Syscall_Reference#lv1_gpu_context_attribute|lv1_gpu_context_attribute]](...);
===== Kernel Call =====
status = lv1_gpu_context_attribute(0x0,L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_SYNC,
  head, L1GPU_DISPLAY_SYNC_VSYNC, 0, 0);
===== Parameters =====
{| class="wikitable"
|-
! colspan="2" | Inputs
|-
!Register
!Description
|-
|R3
|ps3fb.context_handle as allocated by [[HV_Syscall_Reference#lv1_gpu_context_allocate|lv1_gpu_context_allocate]] theoretically. The Kernel actually passes 0 for this operation, so it must not be required.
|-
|R4
|operation_code - L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_SYNC (0×101)
|-
|R5
|head - 0 = Head A (Unfitted to the PC), 1 = Head B the active head on the PS3.
|-
|R6
|sync_type - L1GPU_DISPLAY_SYNC_VSYNC = Enable VSync?
Possibly also L1GPU_DISPLAY_SYNC_HSYNC = Enable HSync?
|-
|R7
|p3 - 0 - Unknown, seems unused.
|-
|R8
|p4 - 0 - Unknown, seems unused.
|-
! colspan="2" | Outputs
|-
!Register
!Description
|-
|R3
|Status - 0 = OK, Other values are unknown, but indicate failure.
|-
|}
==== lv1_gpu_context_attribute:display_flip ====
Set the start of the current video page in video memory.
This is a specific operation of the generic operation [[HV_Syscall_Reference#lv1_gpu_context_attribute|lv1_gpu_context_attribute]](...);
===== Kernel Call =====
status = lv1_gpu_context_attribute(ps3fb.context_handle,
          L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_FLIP,
          head, offset, 0, 0);
===== Parameters =====
{| class="wikitable"
|-
! colspan="2" | Inputs
|-
!Register
!Description
|-
|R3
|ps3fb.context_handle as allocated by [[HV_Syscall_Reference#lv1_gpu_context_allocate|lv1_gpu_context_allocate]] theoretically.
|-
|R4
|operation_code - L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_FLIP (0×102)
|-
|R5
|head - 0 = Head A (Unfitted to the PC), 1 = Head B the active head on the PS3.
|-
|R6
|offset - Offset from start of video memory to set as active displayed memory.
|-
|R7
|p3 - 0 - Unknown, seems unused.
|-
|R8
|p4 - 0 - Unknown, seems unused.
|-
! colspan="2" | Outputs
|-
!Register
!Description
|-
|R3
|Status - 0 = OK, Other values are unknown, but indicate failure.
|-
|}
==== lv1_gpu_context_attribute:fb_setup ====
Set the start of the current video page in video memory.
This is a specific operation of the generic operation [[HV_Syscall_Reference#lv1_gpu_context_attribute|lv1_gpu_context_attribute]](...);
===== Kernel Call =====
status = lv1_gpu_context_attribute(ps3fb.context_handle,
L1GPU_CONTEXT_ATTRIBUTE_FB_SETUP,
xdr_lpar, ps3fb_videomemory.size,
GPU_IOIF, 0);
===== Parameters =====
{| class="wikitable"
|-
! colspan="2" | Inputs
|-
!Register
!Description
|-
|R3
|ps3fb.context_handle as allocated by [[HV_Syscall_Reference#lv1_gpu_context_allocate|lv1_gpu_context_allocate]] theoretically.
|-
|R4
|operation_code - L1GPU_CONTEXT_ATTRIBUTE_FB_SETUP (0×600)
|-
|R5
|xdr_lpar - Address of command FIFO
|-
|R6
|ps3fb_videomemory.size - Size of command FIFO
|-
|R7
|GPU_IOIF = 0x0d000000UL. - GPU address of command FIFO (was: I dont know what this address is. Maybe its the address of the frame buffers in Video memory???)
|-
|R8
|p4 - 0 - Unknown, seems unused.
|-
! colspan="2" | Outputs
|-
!Register
!Description
|-
|R3
|Status - 0 = OK, Other values are unknown, but indicate failure.
|-
|}
Part of patch to move FIFO from start of video memory to end:
status = lv1_gpu_context_attribute(ps3fb.context_handle,
    L1GPU_CONTEXT_ATTRIBUTE_FB_SETUP,
-   xdr_lpar, ps3fb_videomemory.size,
-   GPU_IOIF, 0);
+   xdr_lpar + ps3fb.xdr_size,
+   GPU_CMD_BUF_SIZE,
+   GPU_IOIF + ps3fb.xdr_size, 0);
The memory map used to look like:
{| class="wikitable"
|-
!Address
!Description
|-
|xdr_lpar
|FIFO region
|-
|xdr_lpar + ???
|not used
|-
|xdr_lpar + ps3fb_videomemory.size - 2 * frame size
|frame 2
|-
|xdr_lpar + ps3fb_videomemory.size - frame size
|frame 1
|-
|xdr_lpar + ps3fb_videomemory.size
|END
|-
|}
The memory map of ps3fb now looks like this:
{| class="wikitable"
|-
!Address
!Description
|-
|xdr_lpar
|frame 1
|-
|xdr_lpar + FB_OFF(1)
|frame 2
|-
|xdr_lpar + FB_OFF(2)
|not used
|-
|xdr_lpar + ps3fb_videomemory.size - GPU_CMD_BUF_SIZE
|FIFO region
|-
|xdr_lpar + ps3fb_videomemory.size
|END
|-
|}
The FIFO section of the memory range is now not mapped into Linux’s address space.
So, from that change we can see that R5 and R7 are moved by the size of the xdr_size (videomemory_size-GPU_CMD_BUF_SIZE) so both refer to the FIFO buffer in different addressing schemes (probably physical memory address and LPAR address)
More discussion on this is at http://forums.ps2dev.org/viewtopic.php?t=8364
==== lv1_gpu_context_attribute:fb_blit ====
Block Image Transfer from Main memory to GPU memory.
This is a specific operation of the generic operation [[HV_Syscall_Reference#lv1_gpu_context_attribute|lv1_gpu_context_attribute]](...);
===== Kernel Call =====
status = lv1_gpu_context_attribute(ps3fb.context_handle,
          L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT,
  offset, fb_ioif,
  L1GPU_FB_BLIT_WAIT_FOR_COMPLETION |
  (xres << 16) | yres,
  xres * BPP);
===== Parameters =====
{| class="wikitable"
|-
! colspan="2" | Inputs
|-
!Register
!Description
|-
|R3
|ps3fb.context_handle as allocated by [[HV_Syscall_Reference#lv1_gpu_context_allocate|lv1_gpu_context_allocate]] theoretically.
|-
|R4
|operation_code - L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT (0×601)
|-
|R5
|destination GPU address (offset in video RAM).
|-
|R6
|source GPU address (GPU_IOIF + offset, for system RAM mapped by [[HV_Syscall_Reference#lv1_gpu_context_iomap|lv1_gpu_context_iomap]]).
|-
|R7
|0×0000 : 0×0000 : xres : yres - x,y size of the blit.
|-
|R8
|line_length - span, number of bytes in a line. As of Firmware 1.90, lower 32-bit is destination span, upper 32-bit if not null is source span.
|-
! colspan="2" | Outputs
|-
!Register
!Description
|-
|R3
|Status - 0 = OK, Other values are unknown, but indicate failure.
|-
|}
==== lv1_gpu_context_attribute:fb_blit_sync  ====
This call is never made by the Kernel
This is a specific operation of the generic operation [[HV_Syscall_Reference#lv1_gpu_context_attribute|lv1_gpu_context_attribute]](...);
===== Abstract Call =====
status = lv1_gpu_context_attribute(ps3fb.context_handle,
          L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT_SYNC,
          p1, p2, p3, p4);
===== Parameters =====
{| class="wikitable"
|-
! colspan="2" | Inputs
|-
!Register
!Description
|-
|R3
|ps3fb.context_handle as allocated by [[HV_Syscall_Reference#lv1_gpu_context_allocate|lv1_gpu_context_allocate]] theoretically.
|-
|R4
|ooperation_code - L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT_SYNC (0×602)
|-
|R5
|p1 - Unknown.
|-
|R6
|p2 - Unknown.
|-
|R7
|p3 - Unknown.
|-
|R8
|p4 - Unknown.
|-
! colspan="2" | Outputs
|-
!Register
!Description
|-
|R3
|Status - 0 = OK, Other values are unknown, but indicate failure.
|-
|}
I would expect this call to be very similar, if not identical to fb_blit.
----
=== lv1_gpu_context_intr ===
Tests the current IRQ state of the GPU
===== Kernel Call =====
status = lv1_gpu_context_intr(ps3fb.context_handle, &v1);
===== Parameters =====
{| class="wikitable"
|-
! colspan="2" | Inputs
|-
!Register
!Description
|-
|R3
|ps3fb.context_handle as allocated by [[HV_Syscall_Reference#lv1_gpu_context_allocate|lv1_gpu_context_allocate]].
|-
! colspan="2" | Outputs
|-
!Register
!Description
|-
|R3
|Status - 0 = OK, Other values are unknown, but indicate failure.
|-
|R4
|IRQ Bitmap of all pending IRQ’s. This is a bitset.
A bit = 0 means IRQ not pending, 1 = IRQ pending.
Bit GPU_INTR_STATUS_VSYNC_0 = 0. IRQ for vsync on head A. Unused by Kernel
Bit GPU_INTR_STATUS_VSYNC_1 = 1. IRQ for vsync on head B. Used by Kernel
Bit GPU_INTR_STATUS_FLIP_0 = 2. IRQ for flip on head A. Unused by Kernel
Bit GPU_INTR_STATUS_FLIP_1 = 3. IRQ for flip on head B. Unused by Kernel
Bit GPU_INTR_STATUS_QUEUE_0 = 4. IRQ for queue on head A. Unused by Kernel
Bit GPU_INTR_STATUS_QUEUE_1 = 5. IRQ for queue on head B. Unused by Kernel
|-
|}
----
=== lv1_gpu_attribute ===
Set a GPU attribute.
===== kboot Call =====
result = lv1_gpu_attribute( /*IN*/ p1, p2, p3, p4, p5 );
===== Parameters =====
{| class="wikitable"
|-
! colspan="2" | Inputs
|-
!Register
!Description
|-
|R3
|p1 - unknown
|-
|R4
|p2 - unknown
|-
|R5
|p3 - unknown
|-
|R6
|p4 - unknown
|-
|R7
|p5 - unknown
|-
! colspan="2" | Outputs
|-
!Register
!Description
|-
|R3
|Status - 0 = OK, Other values are unknown, but indicate failure.
|-
|}
Notes:
Code taken from kboot-10\dl\linux-2.6.16\sound\powerpc\snd_ps3pf.c (kboot-20061208)
ret64 = lv1_gpu_attribute(0x100, 0x007, val, 0, 0);
===== Test Results =====
{| class="wikitable"
|-
!p1
!p2
!p3
!p4
!p5
!Status
|-
|0×100
|0
|0
|0
|0
|-17 (LV1_ILLEGAL_PARAMETER_VALUE)
|-
|0×105
|0
|0
|0
|0
|0 (LV1_SUCCESS)
|-
|0×202
|0
|0
|0
|0
|0 (LV1_SUCCESS)
|-
|0×400
|0
|0
|0
|0
|0 (LV1_SUCCESS)
|-
|0×401
|0
|0
|0
|0
|0 (LV1_SUCCESS)
|-
|0×402
|0
|0
|0
|0
|0 (LV1_SUCCESS)
|-
|0×403
|0
|0
|0
|0
|0 (LV1_SUCCESS)
|-
|other values in 0-0×1000000
|0
|0
|0
|0
|-20 (LV1_NOT_IMPLEMENTED)
|-
|}
----
=== lv1_undocumented_function_229 ===
Existed in PAL 1.7. Returned -17 (LV1_ILLEGAL_PARAMETER_VALUE) when passed 0 in R3 to R10.
Does not exist as of PAL 3.15.
----
=== lv1_undocumented_function_230 ===
Exists in PAL 3.15. Unknown function; found in 3.15 HV dump.
----
=== lv1_undocumented_function_231 ===
Exists in PAL 1.7. Returns -17 (LV1_ILLEGAL_PARAMETER_VALUE), 100000000000000h, 9000000000000000h, C000000000537EF8h, F09B89AF5001h, D0000000002B3084h in R3 to R8 when passed 0 in R3 to R10.
----
=== lv1_get_rtc ===
Gets the current value of the PS3’s real time clock and time base value.
===== Kernel Call =====
result = lv1_get_rtc( /*OUT*/ &rtc_val, &tb_val );
===== Parameters =====
{| class="wikitable"
|-
! colspan="2" | Outputs
|-
!Register
!Description
|-
|R3
|Status - 0 = OK, Other values are unknown, but indicate failure.
|-
|R4
|rtc_val - real time clock value
|-
|R5
|tb_val - time base value
|-
|}
----
=== lv1_undocumented_function ===
Exists in PAL 3.15. Unknown function; found in 3.15 HV dump.
----
=== lv1_set_ppe_periodic_tracer_frequency ===
Not used in current kernel.
===== Abstract Call =====
result = lv1_set_ppe_periodic_tracer_frequency( /*IN*/ p1 );
===== Parameters =====
{| class="wikitable"
|-
! colspan="2" | Inputs
|-
!Register
!Description
|-
|R3
|p1 - unknown
|-
! colspan="2" | Outputs
|-
!Register
!Description
|-
|R3
|Status?
|-
|}
----
=== lv1_start_ppe_periodic_tracer ===
Not used in current kernel.
===== Abstract Call =====
result = lv1_start_ppe_periodic_tracer( /*IN*/ p1, p2, p3, p4, p5 );
===== Parameters =====
{| class="wikitable"
|-
! colspan="2" | Inputs
|-
!Register
!Description
|-
|R3
|p1 - unknown
|-
|R4
|p2 - unknown
|-
|R5
|p3 - unknown
|-
|R6
|p4 - unknown
|-
|R7
|p5 - unknown
|-
! colspan="2" | Outputs
|-
!Register
!Description
|-
|R3
|Status?
|-
|}
----
=== lv1_stop_ppe_periodic_tracer ===
Not used in current kernel.
===== Abstract Call =====
result = lv1_stop_ppe_periodic_tracer( /*IN*/ p1, /*OUT*/ &v1 );
===== Parameters =====
{| class="wikitable"
|-
! colspan="2" | Inputs
|-
!Register
!Description
|-
|R3
|p1 - unknown
|-
! colspan="2" | Outputs
|-
!Register
!Description
|-
|R3
|Status?
|-
|R4
|v1 - Unknown
|-
|}
----
=== lv1_undocumented_function_243 ===
Exists in PAL 1.7. Returns -6 (LV1_NO_ENTRY) when passed 0 in R3 to R10.
----
=== lv1_undocumented_function_244 ===
Exists in PAL 1.7. Returns 0 (LV1_SUCCESS) when passed 0 in R3 to R10.
----
=== lv1_storage_read ===
Read a buffer of data from the specified device.
===== Kernel Call =====
result = lv1_storage_read( /*IN*/ dev_id, region_id, start_sector, sector_count, 0, buffer, /*OUT*/ &lv1_tag );
===== Parameters =====
{| class="wikitable"
|-
! colspan="2" | Inputs
|-
!Register
!Description
|-
|R3
|dev_id - device id
|-
|R4
|region_id - ?
|-
|R5
|start_sector - start sector of read
|-
|R6
|sector_count - number of sectors to read
|-
|R7
|0 - ? comment says /* flags */
|-
|R8
|buffer - lpar address of buffer
|-
! colspan="2" | Outputs
|-
!Register
!Description
|-
|R3
|Status - 0 = OK, Other values are unknown, but indicate failure.
|-
|R4
|lv1_tag - tag to identify operation?
|-
|}
----
=== lv1_storage_write ===
Write a buffer of data to the specified device.
===== Kernel Call =====
result = lv1_storage_write( /*IN*/ dev_id, region_id, start_sector, sector_count, 0, buffer, /*OUT*/ &lv1_tag );
===== Parameters =====
{| class="wikitable"
|-
! colspan="2" | Inputs
|-
!Register
!Description
|-
|R3
|dev_id - device id
|-
|R4
|region_id - ?
|-
|R5
|start_sector - start sector of write
|-
|R6
|sector_count - number of sectors to write
|-
|R7
|0 - ? comment says /* flags */
|-
|R8
|buffer - lpar address of buffer
|-
! colspan="2" | Outputs
|-
!Register
!Description
|-
|R3
|Status - 0 = OK, Other values are unknown, but indicate failure.
|-
|R4
|lv1_tag - tag to identify operation?
|-
|}
Notes: The buffer address must be nonzero – even if zero is an otherwise valid address.
----
=== lv1_undocumented_function_247 ===
Exists in PAL 1.7. Returns -11 (LV1_WRONG_STATE) when passed 0 in R3 to R10.
Does not exist as of PAL 3.15.
----
=== lv1_storage_send_device_command ===
Send a command to the specified device.
===== Kernel Call =====
result = lv1_storage_send_device_command( /*IN*/ dev_id, cmd_id, cmd_block, cmd_size, data_buffer, blocks, /*OUT*/ &lv1_tag );
===== Parameters =====
{| class="wikitable"
|-
! colspan="2" | Inputs
|-
!Register
!Description
|-
|R3
|dev_id - device id
|-
|R4
|cmd_id - see notes
|-
|R5
|cmd_block - lpar address of command block?
|-
|R6
|cmd_size - size of command block?
|-
|R7
|data_buffer - lpar address of data buffer?
|-
|R8
|blocks - number of data blocks?
|-
! colspan="2" | Outputs
|-
!Register
!Description
|-
|R3
|Status - 0 = OK, Other values are unknown, but indicate failure.
|-
|R4
|lv1_tag - tag to identify operation?
|-
|}
Notes:
Command ids specified in ps3_storage.h:
{| class="wikitable"
|-
!Command
!cmd_id
|-
|LV1_STORAGE_SEND_ATAPI_COMMAND
|0x01
|-
|LV1_STORAGE_ATA_HDDOUT
|0x23
|-
|}
----
=== lv1_storage_get_async_status ===
Get status of asynchronous storage operations for the specified device?
===== Kernel Call =====
result = lv1_storage_get_async_status( /*IN*/ dev_id, /*OUT*/ &lv1_tag, &lv1_status );
===== Parameters =====
{| class="wikitable"
|-
! colspan="2" | Inputs
|-
!Register
!Description
|-
|R3
|dev_id - device id
|-
! colspan="2" | Outputs
|-
!Register
!Description
|-
|R3
|Status - 0 = OK, Other values are unknown, but indicate failure.
|-
|R4
|lv1_tag - tag to identify operation?
|-
|R5
|lv1_status - 0 = OK, else error
|-
|}
----
=== lv1_undocumented_function_250 ===
Storage device
Exists in PAL 1.7. Returns -11 (LV1_WRONG_STATE) when passed 0 in R3 to R10.
----
=== lv1_undocumented_function_251 ===
Storage device
Exists in PAL 1.7. Returns -11 (LV1_WRONG_STATE) when passed 0 in R3 to R10.
----
=== lv1_undocumented_function_252 ===
Storage device
Exists in PAL 1.7. Returns -11 (LV1_WRONG_STATE) when passed 0 in R3 to R10.
----
=== lv1_undocumented_function_253 ===
Storage device
Exists in PAL 1.7. Returns -11 (LV1_WRONG_STATE) when passed 0 in R3 to R10.
----
=== lv1_storage_check_async_status ===
Check status of an asynchronous storage operation on the specified device.
===== Kernel Call =====
result = lv1_storage_check_async_status( /*IN*/ dev_id, lv1_tag, /*OUT*/ &lv1_status );
===== Parameters =====
{| class="wikitable"
|-
! colspan="2" | Inputs
|-
!Register
!Description
|-
|R3
|dev_id - device id
|-
|R4
|lv1_tag - tag to identify operation?
|-
! colspan="2" | Outputs
|-
!Register
!Description
|-
|R3
|Status - 0 = OK, Other values are unknown, but indicate failure.
|-
|R4
|lv1_status - 0 = OK, else error
|-
|}
----
=== lv1_panic ===
Panic! Causes the OtherOS to be halted.
===== Kernel Call =====
lv1_panic( /*IN*/ reboot );
===== Parameters =====
{| class="wikitable"
|-
! colspan="2" | Inputs
|-
!Register
!Description
|-
|R3
|reboot: 0 = power off, 1 = reboot after panic
|-
! colspan="2" | Outputs
|-
!Register
!Description
|-
! colspan="2" |It is not expected that this call returns, so no Outputs.
|-
|}
Notes:
This hypervisor call causes the PS3 to shutdown immediately, without performing any cleanup or callbacks. Remember to sync filesystems before calling this function!
It seems that any non-zero value in R3 causes a reboot after panic, rather than just 1.
The code in the kernel does all manner of things to actually reboot, including sending vuart messages to some other process running in a different LPAR. I haven’t investigated enough to see exactly what it does, but calling lv1_panic(0) from my my code in the hypervisor causes a panic with the red light flashing until the power button is pressed whereas the kernel’s shutdown code doesn’t.
{{Development}}<noinclude>[[Category:Main]]</noinclude>

Latest revision as of 10:24, 9 November 2024

HV Syscalls[edit | edit source]

NOTE: Update with graf's work. It'll probably fill in some of the undocumented functions.

lv1_allocate_memory[edit | edit source]

Create a memory region in the Hypervisor Virtual Address Space (vas)

Kernel Call[edit | edit source]
result = lv1_allocate_memory( /*IN*/ size, page_size_exp, 0, flags, /*OUT*/ &addr, &muid );
Parameters[edit | edit source]
Inputs
Register Description
R3 size - of the region to allocate, must be a multiple of page_size
R4 page_size_exp - where required page_size = 2 ^ page_size_exp
R5 0 - Unknown, see notes
R6 flags - (from linux/include/asm-powerpc/lv1call.h)

bit 63: transferability: TF_NO = 0×00, TF_YES = 0×01
bit 62: destruction_scheme: DS_NO_CONNECTIONS = 0×00, DS_ANYTIME = 0×02
bit 61: fail or alternative: FA_FAIL = 0×00, FA_ALTERNATIVE = 0×04
bit 60: need LPAR address 0: ADDR_ANY = 0×00, ADDR_0 = 0×08
function unknown.

Outputs
Register Description
R3 Status - 0 = OK, LV1_RESOURCE_SHORTAGE (-2), LV1_NO_ENTRY (-6), LV1_DUPLICATE_ENTRY (-7)
R4 addr - LPAR Address of region
R5 muid - Unknown, unused by Kernel

Notes:

page_size_exp takes values of 12 (page_size = 4K) to 21 (page_size = 2M) before LV1_RESOURCE_SHORTAGE (-2) is returned under a fully booted Linux OS. Higher values (24, page_size = 16M) can be found in the actual kernel source and can presumably be made before the OS has fully booted. page_size_exp values below 12 cause a return status of LV1_ILLEGAL_PARAMETER_VALUE (-17).

Input R5 was speculated to be the initialization value for the allocated region, but appears not to be the case. Values other than 0 or 1 appear to return a status of LV1_NO_ENTRY (-6), though a valid value of page_size_exp appears to be checked first (-17 is returned for invalid values of page_size_exp, regardless of the value of R5).

Allocations with flags = 0×00, 0×01, 0×02, 0×03 and 0×04 were successful though the effects of the flags could not be tested at this point. Allocations with flags >= 0×400 return LV1_ILLEGAL_PARAMETER_VALUE.

Initial tests allocating memory with flags = 0×08 (ADDR_0, presumably request physical address rather than logical partition address) result in a status of LV1_DUPLICATE_ENTRY (-7). This and the previous return value of -6 suggest an association with a database of some kind (repository values or memory maps?). It appears that some form of allocation may be taking place as LV1_ILLEGAL_PARAMETER_VALUE and LV1_RESOURCE_SHORTAGE are reported for invalid input parameters, rather than LV1_DUPLICATE_ENTRY.

For all successful allocations so far, output muid (R5) = 1


lv1_write_htab_entry[edit | edit source]

Write an entry to the hash page table.

Kernel Call[edit | edit source]
result = lv1_write_htab_entry( /*IN*/ vas_id, slot, va, pa );
Parameters[edit | edit source]
Inputs
Register Description
R3 vas_id - virtual address space id (0 for current)
R4 slot - table slot to write entry to
R5 va - first half of PTE
R6 pa - second half of PTE, except RPN is replaced with LPAR address
Outputs
Register Description
R3 Status - 0 = OK, Other values are unknown, but indicate failure.

lv1_construct_virtual_address_space[edit | edit source]

Construct a PPE virtual address space.

Kernel Call[edit | edit source]
result = lv1_construct_virtual_address_space( /*IN*/ htab_size, number_of_sizes, page_sizes, /*OUT*/ &vas_id, &act_htab_size );
Parameters[edit | edit source]
Inputs
Register Description
R3 htab_size - must be 18, 19 or 20 (256KB, 512KB or 1MB)
R4 number_of_sizes - How many page sizes are specified in page_sizes
R5 page_sizes - see notes
Outputs
Register Description
R3 Status - 0 = OK, Other values are unknown, but indicate failure.
R4 vas_id - virtual address space id
R5 act_htab_size - actual hash table size?

Notes:

Page sizes are specified as the power of two for the desired sizes. Each power of two is stored as an 8 bit field in page_sizes, starting from the MSB.

The “pages_sizes” parameter is set in “mm.c” using the following function:

page_sizes = make_page_sizes(PAGE_SHIFT_16M, PAGE_SHIFT_64K);

static unsigned long make_page_sizes(unsigned long a, unsigned long b)
{
	return (a << 56) | (b << 48);
}

lv1_invalidate_htab_entries[edit | edit source]

Not used in current kernel.

Abstract Call[edit | edit source]
result = lv1_invalidate_htab_entries( /*IN*/ p1, p2, p3, p4, p5 );
Parameters[edit | edit source]
Inputs
Register Description
R3 p1 - Unknown
R4 p2 - Unknown
R5 p3 - Unknown
R6 p4 - Unknown
R7 p5 - Unknown
Outputs
Register Description
R3 Status?

lv1_get_virtual_address_space_id_of_ppe[edit | edit source]

Returns the virtual address space id of the PPE.

Kernel Call[edit | edit source]
result = lv1_get_virtual_address_space_id_of_ppe( /*IN*/ ppe_id , /*OUT*/ &vas_id );
Parameters[edit | edit source]
Inputs
Register Description
R3 PPE id
Outputs
Register Description
R3 status: 0 = LV1_SUCCESS
R4 vas_id - virtual address space id of the PPE
R5 htab_size_log2 - 18, 19 or 20 (256KB, 512KB or 1MB)
R6 number_of_sizes - How many page sizes are specified in page_sizes
R7 page_sizes - see lv1_construct_virtual_address_space

Notes:

Regardless of the ppe_id, when called from kernel module init function, vas_id always seems to be 11.


lv1_query_logical_partition_address_region_info[edit | edit source]

Retrieve address region information for the specified logical partition address region.

Kernel Call[edit | edit source]
result = lv1_query_logical_partition_address_region_info( /*IN*/ 0,
   /*OUT*/ &start_address, &size, &access_right, &max_page_size, &flags);
Parameters[edit | edit source]
Inputs
Register Description
R3 0 - logical partition address region (lpar)
Outputs
Register Description
R3 status: 0 = LV1_SUCCESS
R4 start_address - start address of logical partition address region
R5 size - size of logical partition address region
R6 access_right - ?
R7 max_page_size - maximum page size of logical partition address region? or order of the allocation?
R8 flags - ?

Notes:

Only the “max_page_size” parameter is currently used by the Kernel, in “mm.c”

Test Results[edit | edit source]
Register Hex Decimal Comment
R3 0x00000000 (0) value does not seem to effect result
Outputs
R3 0×00000000 (0) LV1_SUCCESS
R4 0×00000000 (0) start_address
R5 0×08000000 (134217728) size - 128 Mb
R6 0×00000003 (3) access_right
R7 0x0000001b (27) max_page_size
R8 0×00000008 (8) flags

This suggests lpar 0 is a special lpar representing the first 128MB of RAM that are always available at boot time. In this case, max_page_size seems to correspond to the order of the allocation (2**27 = 128 MB). The meaning of access_right and flags is unknown.

Also works on a lpar obtained from lv1_allocate_memory, for example

lv1_allocate_memory(4096 /* size */, 12 /* page size */, 0, 0, &lpar, &muid);
lv1_query_logical_partition_address_region_info(lpar, &start_address, &size, &access_right, &max_page_size, &flags);

returns:

Register Hex Decimal Comment
R3 0x30000001f00 (3298534891264) lpar obtained from lv1_allocate_memory
Outputs
R3 0×00000000 (0) LV1_SUCCESS
R4 0×30000001f00 (0) start_address (same as input lpar)
R5 0×00001000 (4096) size - 4kB
R6 0×00000003 (3) access_right
R7 0x0000000c (12) max_page_size
R8 0×00000000 (0) flags

lv1_select_virtual_address_space[edit | edit source]

Select an alternative virtual address space.

Kernel Call[edit | edit source]
result = lv1_select_virtual_address_space( /*IN*/ vas_id );
Parameters[edit | edit source]
Inputs
Register Description
R3 vas_id - virtual address space id
Outputs
Register Description
R3 Status - 0 = OK, Other values are unknown, but indicate failure.

Notes:

In “mm.c” When destructing a virtual address space, a call to select address space 0 (default?) is performed first.

Calling lv1_select_virtual_address_space(0) from a kernel module init function causes the PS3 to hang.


lv1_undocumented_function_8[edit | edit source]

Returns current HV uptime. (NOTE: Use graf's work here)


lv1_pause[edit | edit source]

Called during the Kernel idle loop - puts the PPE thread into an inactive state.

Kernel Call[edit | edit source]
result = lv1_pause( /*IN*/ mode );
Parameters[edit | edit source]
Inputs
Register Description
R3 mode: 0 = wake on DEC interrupt, 1 = ignore DEC interrupt
Outputs
Register Description
R3 status: 0 = LV1_SUCCESS, -17 = LV1_ILLEGAL_PARAMETER_VALUE

Notes:

LV1_ILLEGAL_PARAMETER_VALUE is returned for values of “mode” other than 0 or 1.

Comment from setup.c

/*
* lv1_pause() puts the PPE thread into inactive state until an
* irq on an unmasked plug exists. MSR[EE] has no effect.
* flags: 0 = wake on DEC interrupt, 1 = ignore DEC interrupt.
*/

lv1_destruct_virtual_address_space[edit | edit source]

Destruct a virtual address space.

Kernel Call[edit | edit source]
lv1_destruct_virtual_address_space( /*IN*/ vas_id );
Parameters[edit | edit source]
Inputs
Register Description
R3 vas_id - virtual address space id
Outputs
Register Description
R3 Status?

Notes:

Called with 0 in R3 crashes my PS3. Light turns red, appears to be off


lv1_configure_irq_state_bitmap[edit | edit source]

Register the address of a HV plug-outlet bitmap with the Hypervisor.

Kernel Call[edit | edit source]
result = lv1_configure_irq_state_bitmap( /*IN*/ ppe_id, cpu_id, bmp_addr );
Parameters[edit | edit source]
Inputs
Register Description
R3 ppe_id - PPE id
R4 cpu_id - PPE CPU id
R5 bmp_addr - lpar address of state bitmap
Outputs
Register Description
R3 Status - 0 = OK, Other values are unknown, but indicate failure.

Notes:

Comment from interrupt.c:

/**
* The HV mantains per SMT thread mappings of HV outlet to HV plug on
* behalf of the guest.  These mappings are implemented as 256 bit guest
* supplied bitmaps indexed by plug number.  The addresses of the bitmaps
* are registered with the HV through lv1_configure_irq_state_bitmap().
* The HV requires that the 512 bits of status + mask not cross a page
* boundary.  PS3_BMP_MINALIGN is used to define this minimal 64 byte
* alignment.
*
* The HV supports 256 plugs per thread, assigned as {0..255}, for a total
* of 512 plugs supported on a processor.  To simplify the logic this
* implementation equates HV plug value to Linux virq value, constrains each
* interrupt to have a system wide unique plug number, and limits the range
* of the plug values to map into the first dword of the bitmaps.  This
* gives a usable range of plug values of  {NUM_ISA_INTERRUPTS..63}.  Note
* that there is no constraint on how many in this set an individual thread
* can acquire.
*/

lv1_connect_irq_plug_ext[edit | edit source]

Connect a HV outlet to a CPU and virtual irq.

Kernel Call[edit | edit source]
result = lv1_connect_irq_plug_ext( /*IN*/ ppe_id, cpu_id, virq, outlet, 0 );
Parameters[edit | edit source]
Inputs
Register Description
R3 ppe_id - PPE id
R4 cpu_id - PPE CPU id
R5 virq - virtual irq
R6 outlet - HV outlet
R7 0 - unknown
Outputs
Register Description
R3 Status - 0 = OK, Other values are unknown, but indicate failure.

lv1_release_memory[edit | edit source]

Releases a previously allocated memory region. Return code is not checked.

Kernel Call[edit | edit source]
lv1_release_memory( /*IN*/ base );
Parameters[edit | edit source]
Inputs
Register Description
R3 base - base address of memory region
Outputs
Register Description
R3 Status??

lv1_put_iopte[edit | edit source]

Put an io page table entry.

Kernel Call[edit | edit source]
result = lv1_put_iopte( /*IN*/ ioas_id, ioif_addr, lpar_addr, io_id, flags );
Parameters[edit | edit source]
Inputs
Register Description
R3 ioas_id - io address space id
R4 ioif_addr - io interface address
R5 lpar_addr - logical partition address
R6 io_id - io id
R7 flags - see notes
Outputs
Register Description
R3 Status??

Notes:

Code taken from kboot-10\dl\linux-2.6.16\sound\powerpc\snd_ps3pf.c (kboot-20061208)

ret64 = lv1_put_iopte(0, /* io address space id */
   ioif_map_info_array[current_segment].ioif_addr + current_page * IO_PAGESIZE, /* ioif addr */
   p_to_lp(current_paddr), /* lpar addr */
   PS3PF_AUDIO_IOID, IOPTE_READONLY | IOPTE_COHERENT | IOPTE_STRICT_ORDER);

lv1_disconnect_irq_plug_ext[edit | edit source]

Disconnect a virtual irq from its HV outlet.

Kernel Call[edit | edit source]
lv1_disconnect_irq_plug_ext( /*IN*/ ppe_id, cpu_id, virq );
Parameters[edit | edit source]
Inputs
Register Description
R3 ppe_id - PPE id
R4 cpu_id - PPE CPU id
R5 virq - virtual irq
R7 flags - see notes
Outputs
Register Description
R3 Status?

lv1_construct_event_receive_port[edit | edit source]

Creates an outlet that can be used with a virtual irq to receive system events.

Kernel Call[edit | edit source]
result = lv1_construct_event_receive_port( /*OUT*/ &outlet );
Parameters[edit | edit source]
Outputs
Register Description
R3 Status - 0 = OK, Other values are unknown, but indicate failure.
R4 outlet - event outlet

lv1_destruct_event_receive_port[edit | edit source]

Destruct a previously constructed event receiving port.

Kernel Call[edit | edit source]
result = lv1_destruct_event_receive_port( /*IN*/ outlet );
Parameters[edit | edit source]
Inputs
Register Description
R3 outlet - event outlet
Outputs
Register Description
R3 Status - 0 = OK, Other values are unknown, but indicate failure.

lv1_send_event_locally[edit | edit source]

Signal the specified event.

Kernel Call[edit | edit source]
result = lv1_send_event_locally( /*IN*/ outlet );
Parameters[edit | edit source]
Inputs
Register Description
R3 outlet - event outlet
Outputs
Register Description
R3 Status - 0 = OK, Other values are unknown, but indicate failure.

lv1_detect_pending_interrupts[edit | edit source]

Not used in current kernel. Used in ps2_gxemu.

Abstract Call[edit | edit source]
result = lv1_detect_pending_interrupts( /*IN*/ p1, /*OUT*/ &v1, &v2, &v3, &v4 );
Parameters[edit | edit source]
Inputs
Register Description
R3 p1 - unknown (only 0 value is supported)
Outputs
Register Description
R3 Status
R4 v1 - irq_bitmap[0]
R5 v2 - irq_bitmap[1]
R6 v3 - irq_bitmap[2]
R7 v4 - irq_bitmap[3]

Notes:
Return 256 bit irq bitmap for previously connected irq plugs (using lv1_connect_irq_plug).
Info taken from kboot-10\dl\linux-2.6.16\include\asm-powerpc\lv1calltab.h (kboot-20061208)


lv1_end_of_interrupt[edit | edit source]

Indicate the end of an interrupt handler has been reached.

kboot Call[edit | edit source]
result = lv1_end_of_interrupt( /*IN*/ irq );
Parameters[edit | edit source]
Inputs
Register Description
R3 irq - interrupt number
Outputs
Register Description
R3 Status - 0 = OK, Other values are unknown, but indicate failure.

Notes:

Comment in kboot-10\dl\linux-2.6.16\arch\powerpc\platforms\ps3pf\pic.c (kboot-20061208)

/* 
 lv1_end_of_interrupt must be called at end_irq. 
 Some lv1 drivers clear irq status in it.
*/

lv1_connect_irq_plug[edit | edit source]

Bind a virtual interrupt to a CPU.

kboot Call[edit | edit source]
result = lv1_connect_irq_plug( /*IN*/ virq, hwirq );
Parameters[edit | edit source]
Inputs
Register Description
R3 virq - virtual interrupt
R4 hwirq - hardware interrupt
Outputs
Register Description
R3 Status - 0 = OK, Other values are unknown, but indicate failure.

Notes:

Info taken from kboot-10/dl/linux-2.6.16/patches/cell-support/2.6.19-rc6-arnd1/ps3-support/ps3-interrupt.patch (kboot-20061208)


lv1_disconnect_irq_plug[edit | edit source]

Unbind a virtual interrupt from a CPU.

kboot Call[edit | edit source]
lv1_disconnect_irq_plug( /*IN*/ virq );
Parameters[edit | edit source]
Inputs
Register Description
R3 virq - virtual interrupt
Outputs
Register Description
R3 Status?

Notes:

Info taken from kboot-10/dl/linux-2.6.16/patches/cell-support/2.6.19-rc6-arnd1/ps3-support/ps3-interrupt.patch (kboot-20061208)


lv1_end_of_interrupt_ext[edit | edit source]

Indicate that the end of an interrupt handler has been reached.

Kernel Call[edit | edit source]
lv1_end_of_interrupt_ext( /*IN*/ ppe_id, cpu_id, virq );
Parameters[edit | edit source]
Inputs
Register Description
R3 ppe_id - PPE id
R4 cpu_id - PPE CPU id
R5 virq - virtual irq
Outputs
Register Description
R3 Status?

lv1_did_update_interrupt_mask[edit | edit source]

Indicate that CPU interrupt mask has been updated.

Kernel Call[edit | edit source]
lv1_did_update_interrupt_mask( /*IN*/ ppe_id, cpu_id );
Parameters[edit | edit source]
Inputs
Register Description
R3 ppe_id - PPE id
R4 cpu_id - PPE CPU id
Outputs
Register Description
R3 Status?

lv1_shutdown_logical_partition[edit | edit source]

Not used in current kernel.

Abstract Call[edit | edit source]
result = lv1_shutdown_logical_partition( /*IN*/ p1 );
Parameters[edit | edit source]
Inputs
Register Description
R3 p1 - shutdown command (see notes)
Outputs
Register Description
R3 Status?

Notes:

Comment from kboot-10/dl/linux-2.6.16/include/asm-powerpc/lv1call.h (kboot-20061208)

/* values for lv1_shutdown_logical_partition */
#define LV1_SHUTDOWN_LP_HALT		1
#define LV1_SHUTDOWN_LP_POWER_OFF	2
#define LV1_SHUTDOWN_LP_RESTART	3

lv1_destruct_logical_spe[edit | edit source]

Destructs a logical SPE.

Kernel Call[edit | edit source]
result = lv1_destruct_logical_spe( /*IN*/ spe_id );
Parameters[edit | edit source]
Inputs
Register Description
R3 spe_id - spe id
Outputs
Register Description
R3 Status - 0 = OK, Other values are unknown, but indicate failure.

lv1_construct_logical_spe[edit | edit source]

Constructs a logical SPE.

Kernel Call[edit | edit source]
status = lv1_construct_logical_spe( /*IN*/ PAGE_SHIFT, PAGE_SHIFT, PAGE_SHIFT, PAGE_SHIFT, PAGE_SHIFT, vas_id, SPE_TYPE_LOGICAL,
		/*OUT*/ &priv2_addr, &problem_phys, &local_store_phys, &unused, &shadow_addr, &spe_id );
Parameters[edit | edit source]
R3
Inputs
Register Description
R3 PAGE_SHIFT
R4 PAGE_SHIFT
R5 PAGE_SHIFT
R6 PAGE_SHIFT
R7 PAGE_SHIFT
R8 vas_id - virtual address space id
R9 SPE_TYPE_LOGICAL (0)
Outputs
Register Description
Status - 0 = OK, Other values are unknown, but indicate failure.
R4 priv2_addr - lpar address of spe priv2 area
R5 problem_phys - lpar address of spu_problem area
R6 local_store_phys - lpar address of spu local storage
R7 unused
R8 shadow_addr - lpar address of spe register shadow area
R9 spe_id - logical spe id

Notes:

R7 out parameter was referred to in a previous codebase as “ctxt_addr”.

Test Results[edit | edit source]
priv2_addr problem_phys local_store_phys unused shadow_addr spe_id
0x4c0000660000 0x4c0000640000 0x4c0000600000 0×0 0x30000000d000 11
0x4c0000760000 0x4c0000740000 0x4c0000700000 0×0 0x30000000f000 15
0x4c0000860000 0x4c0000840000 0x4c0000800000 0×0 0×300000011000 19
0x4c0000960000 0x4c0000940000 0x4c0000900000 0×0 0×300000013000 23
0x4c0000a60000 0x4c0000a40000 0x4c0000a00000 0×0 0×300000015000 27
0x4c0000b60000 0x4c0000b40000 0x4c0000b00000 0×0 0×300000017000 31

For each entry, only two separate lpar are allocated by the hypervisor. Indeed, calling lv1_query_logical_partition_address_region_info on priv2_addr, problem_phys, local_store_phys and shadow_addr for the first entry returns the following info:

0x4c0000660000
lpar start_address size access_right max_page_size flags comment
0x4c0000600000 524288 0×3 (RW) 12 0xa000000000000000 SPU MMIO lpar, privilege state 2 region (128kB)
0x4c0000640000 0x4c0000600000 524288 0×3 (RW) 12 0xa000000000000000 SPU MMIO lpar, problem state region (128kB)
0x4c0000600000 0x4c0000600000 524288 0×3 (RW) 12 0xa000000000000000 SPU MMIO lpar, local store region (256kB)
0x30000000d000 0x30000000d000 4096 0×1 (RO) 12 0xa000000000000000 SPU shadow registers lpar (4kB, read-only)

From this info we see a single lpar is used for all the SPU MMIO region (see figure 5-1 CBE Memory Map of the Cell Broadband Engine Programming Handbook) and another lpar is used for the SPE registers.


lv1_set_spe_interrupt_mask[edit | edit source]

Set the interrupt mask of a specific spe.

Kernel Call[edit | edit source]
lv1_set_spe_interrupt_mask( /*IN*/ spe_id, class, mask );
Parameters[edit | edit source]
Inputs
Register Description
R3 spe_id - spe id
R4 class - spe interrupt class
R5 mask - spe interrupt mask
Outputs
Register Description
R3 Status?

lv1_undocumented_function_62[edit | edit source]

SPE (isolation, it updates a SLB entry, writes to SLB_Index, SLB_VSID, SLB_ESID and SLB_Invalidate_Entry registers)


lv1_set_slb_for_logical_spu[edit | edit source]

Exists in PAL 1.7; Returned -4 (LV1_DENIED_BY_POLICY) when passed 0 in R3 to R10.


lv1_undocumented_function_63[edit | edit source]

Does not exist in 3.15.

Exists in PAL 1.7; Returned -4 (LV1_DENIED_BY_POLICY) when passed 0 in R3 to R10.


lv1_set_spe_transition_notifier[edit | edit source]

Not used in current kernel.

Abstract Call[edit | edit source]
result = lv1_set_spe_transition_notifier( /*IN*/ p1, p2, p3 );
Parameters[edit | edit source]
Inputs
Register Description
R3 spe_id - logical spe id
R4 0 - Unknown usage
Outputs
Register Description
R3 Status - 0 = OK, Other values are unknown, but indicate failure.

lv1_disable_logical_spe[edit | edit source]

Disables a logical SPE.

Kernel Call[edit | edit source]
result = lv1_disable_logical_spe( /*IN*/ spe_id, 0 );
Parameters[edit | edit source]
Inputs
Register Description
R3 spe_id - logical spe id
R4 0 - Unknown usage
Outputs
Register Description
R3 Status - 0 = OK, Other values are unknown, but indicate failure.

lv1_clear_spe_interrupt_status[edit | edit source]

Clear the interrupt status of a specific spe.

Kernel Call[edit | edit source]
lv1_clear_spe_interrupt_status( /*IN*/ spe_id, class, stat, 0 );
Parameters[edit | edit source]
Inputs
Register Description
R3 spe_id - logical spe id
R4 class - spe interrupt class
R5 stat - new interrupt status?
R6 0 - Unknown
Outputs
Register Description
R3 Status?

lv1_get_spe_interrupt_status[edit | edit source]

Get the interrupt status of a specific spe.

Kernel Call[edit | edit source]
lv1_get_spe_interrupt_status( /*IN*/ spe_id, class, /*OUT*/ &stat );
Parameters[edit | edit source]
Inputs
Register Description
R3 spe_id - logical spe id
R4 class - spe interrupt class
Outputs
Register Description
R3 Status?
R4 stat - interrupt status

lv1_get_logical_ppe_id[edit | edit source]

Returns the logical PPE id.

Kernel Call[edit | edit source]
status = lv1_get_logical_ppe_id( /*OUT*/ &ppe_id );
Parameters[edit | edit source]
Outputs
Register Description
R3 Status?
R4 logical PPE id

Notes:

When called from kernel module init function, ppe_id always seem to be 1.


lv1_set_interrupt_mask[edit | edit source]

Not used in current kernel.

Abstract Call[edit | edit source]
result = lv1_set_interrupt_mask( /*IN*/ p1, p2, p3, p4, p5 );
Parameters[edit | edit source]
Inputs
Register Description
R3 p1 - Unknown
R4 p2 - Unknown
R5 p3 - Unknown
R6 p4 - Unknown
R7 p5 - Unknown
Outputs
Register Description
R3 Status?

lv1_get_logical_partition_id[edit | edit source]

Called during Kernel setup.

The single output parameter, logical partition id, is later used as a parameter to call other Hypervisor functions.

Kernel Call[edit | edit source]
result = lv1_get_logical_partition_id(/*OUT*/ &lp_id );
Parameters[edit | edit source]
Outputs
register Description
R3 result: 0 = LV1_SUCCESS
R4 lp_id - logical partition id

Notes:

When called from kernel module init function, lp_id always seems to be 2.

The “read_node” function contained in “repository.c” is passed a parameter, lpar_id (logical partition id). If lpar_id is equal to PS3_LPAR_ID_CURRENT (0) then lv1_get_logical_partition_id is called to retrieve the current logical partition id. Any other value for lpar_id is passed directly to the following HV calls, though the only other value in use appears to be PS3_LPAR_ID_PME (1)


lv1_undocumented_function_75[edit | edit source]

Exists in PAL 1.7; Returned 0 (LV1_SUCCESS) when passed 0 in R3 to R10.


lv1_configure_execution_time_variable[edit | edit source]

Not used in current kernel.

Abstract Call[edit | edit source]
result = lv1_configure_execution_time_variable( /*IN*/ p1 );
Parameters[edit | edit source]
Inputs
Register Description
R3 p1 - Unknown
Outputs
Register Description
R3 Status?

lv1_get_spe_irq_outlet[edit | edit source]

Get an IRQ outlet of a certain class from the specified SPE.

Kernel Call[edit | edit source]
result = lv1_get_spe_irq_outlet( /*IN*/ spe_id, class, /*OUT*/ &outlet );
Parameters[edit | edit source]
Inputs
Register Description
R3 spe_id - logical spe id
R4 class - spe interrupt class (0, 1 or 2)
Outputs
Register Description
R3 Status - 0 = OK, Other values are unknown, but indicate failure.
R4 outlet - irq outlet

SPE Interrupt Class:

Class Description Examples
0 Errors SPE errors, DMA errors, DMA alignment errors
1 DMA translation exceptions MFC page faults, segment faults
2 Application events SPE stop and signal, DMA completion interrupt, mailbox interrupts

lv1_set_spe_privilege_state_area_1_register[edit | edit source]

Sets a register in SPE privilege area 1.

Kernel Call[edit | edit source]
lv1_set_spe_privilege_state_area_1_register( /*IN*/ spe_id, offset, value );
Parameters[edit | edit source]
Inputs
Register Description
R3 spe_id - spe id
R4 offset - register offset, 0, 0x600, 0x710, 0x808, 0x820
R5 value - register value
Outputs
Register Description
R3 Status?

lv1_undocumented_function_89[edit | edit source]

SPE (writes to MFC_TLB_Invalidate_Entry register)

Exists in PAL 1.7; Returned -6 (LV1_NO_ENTRY) when passed 0 in R3 to R10.


lv1_create_repository_node[edit | edit source]

The repository appears to be an area of storage for use by the Hypervisor.

Abstract Call[edit | edit source]
status = lv1_create_repository_node(/*IN*/ n1, n2, n3, n4, v1, v2 );
Parameters[edit | edit source]
Inputs
Register Description
R3 top level key
R4 2nd level key
R5 3rd level key
R6 4th level key
R7 value 1
R8 value 2
Outputs
Register Description
R3 Status - 0 = OK, Other values are unknown, but indicate failure.

Notes:

This call is not used within the current Kernel, so the parameter list is based on speculation. It will still return 0 if the specified node already exists, and it will not change current data.

See “lv1_get_repository_node_value” for an example of actual key/value usage within the Kernel.


lv1_get_repository_node_value[edit | edit source]

The repository appears to be an area of storage for use by the Hypervisor. 256-bit keys are used to reference 128-bit values stored in the repository. Functions exist to create, get, modify and remove repository nodes.

See notes below for usage speculation.

Kernel Call[edit | edit source]
status = lv1_get_repository_node_value(/*IN*/ lpar_id, n1, n2, n3, n4 /*OUT*/ &v1, &v2 );
Parameters[edit | edit source]
Inputs
Register Description
R3 logical partion id
R4 top level key
R5 2nd level key
R6 3rd level key
R7 4th level key
Outputs
Register Description
R3 Status: 0 = OK, -6 = LV1_NO_ENTRY
R4 value 1
R5 value 2

Notes:

The logical partition id is also required as an input parameter to get a repository node value, but this parameter does not appear to be passed when creating, modifying or removing nodes.

There are instances in the Kernel code where the keys are constructed from string values, which appear to follow a 4-level key/subkey hierarchy.

Test Results[edit | edit source]

Calling lv1_get_repository_node_value for the node ‘bi.pu.#1.rm_size’ produces the following result:

bi.pu.(1).rm_size - Real mode memory size
Register Hex Value Value Comment
R3 0000000000000002 (2) PS3_LPAR_ID_CURRENT
R4 0000000062690000 ....bi.. boot info?
R5 7075000000000000 pu...... processor unit
R6 0000000000000001 ........ pu id (1)
R7 726d5f73697a6500 rm_size. real mode size
Outputs
R3 0000000000000000 (0) LV1_SUCCESS
R4 0000000008000000 (134217728) 128 Mb
R5 0000000000000000 (0)

Other nodes referenced in “repository.c”:

lpar_id = PS3_LPAR_ID_CURRENT (0×2)
Node v1 v2 Comment
bi.spun.#0.#0 0000000000000006 (6) 0 (0) number of physical spus reserved
bi.spursvn.#0.#0 0000000000000006 (6) 0 (0) number of spu resource reservations
bi.spursv.(0..5).#0 8000000000000000 (PS3_SPU_RESOURCE_TYPE_EXCLUSIVE) (0..5) spu resource reservation id value
bi.boot_dat.address.#0 0000000007fff000 (134213632) 0 (0) boot data address
bi.boot_dat.size.#0 0000000000000800 (2048) 0 (0) boot data size
bi.pu.(1).rm_size 0000000008000000 (134217728) 0 (0) real mode limit
bi.rgntotal.#0.#0 000000000f800000 (260046848) 0 (0) max memory size
lpar_id = PS3_LPAR_ID_PME (0×1)
Node v1 v2 Comment
ben.#0.#0.#0 0000000000000001 (1) 0000000000000000 (0) Unused - in function “ps3_repository_read_num_be”
be(0).#0.#0.#0 0000000000000000 (0) 0000000000000000 (0) be node id (used to retrieve clock freq)
be.(0).clock.#0 0000000004c1a6c0 (79800000) 0000000000000000 (0) decrementer frequency (3.2 Ghz / 40)
lpar_id = PS3_LPAR_ID_PME (0×1) - FW 3.15 PAL 60GB PS3, First Generation (Fat)
Node v1 v2 Comment
sys.flash.fmt.#0 00000000000001 (1) 00000000000000 (0) Flash format.
v1: 1 = NAND , 2 = VFLASH?
sys.hw.config.#0 20000000fffffeff 00000000000000 (0) 0×20000000000000 mask + something
sys.flash.ext.#0 000000000000ff (255) 00000000000000 (0)
plat.id.#0.#0 436f6b4231300000 (ASCII‘CokB10’) 00000000000000 (0) Platform ID
sys.ac.sd.#0 00000000000000 (0) 00000000000000 (0) System Debug Flag
sys.flash.boot.#0 00000000000000 (0) 00000000000000 (0)
be.0.lpm.priv 00000000000002 (2) 00000000780101 (7864577)
rsx.rdcy.1.#0 ffff0d020a02ffff 00000000000000 (0)
rsx.rdcy.2.#0 ffffffffffffffff 00000000000000 (0)
rsx.rdcy.3.#0 00000000000000 (0) 00000000000000 (0)
rsx.rdcy.4.#0 00000000000000 (0) 00000000000000 (0)
rsx.rdcy.5.#0 00000000000000 (0) 00000000000000 (0)
rsx.rdcy.6.#0 00000000000000 (0) 00000000000000 (0)
rsx.rdcy.7.#0 00000000000000 (0) 00000000000000 (0)
rsx.rdcy.8.#0 00000000000000 (0) 00000000000000 (0)
mu.1.size.#0 00000010000000 (268435456) 00000000000000 (0)
be.0.tb_clk.#0 00000004c1a6c0 (79800000) 00000000000000 (0)
be.0.nclk.#0 000000be420e00 (3192000000) 00000000000000 (0)
ios.net.eurus.lpar 00000000000000 (0) 00000000000000 (0)
sys.syscon.pversion.#0 00000000000001 (1) 00000000000000 (0)
sys.param.load.rom1st 00000000000001 (1) 00000000000000 (0)
lv1.maxplgid.#0.#0 00000000000100 (256) 00000000000000 (0)
lv1.specver.#0.#0 00000300010005 00000000000000 (0) Matches firmware 3.1.5
lv1.buildid.#0.#0 00000000000000 (0) 00000000000000 (0)
lv1.ts.size.#0 00000000000000 (0) 00000000000000 (0)
lv1.ts.start.#0 00000010000000 (268435456) 00000000000000 (0)

lv1_modify_repository_node_value[edit | edit source]

The repository appears to be an area of storage for use by the Hypervisor.

Abstract Call[edit | edit source]
status = lv1_modify_repository_node_value(/*IN*/ n1, n2, n3, n4, v1, v2 );
Parameters[edit | edit source]
Inputs
Register Description
R3 top level key
R4 2nd level key
R5 3rd level key
R6 4th level key
R7 value 1
R8 value 2
Outputs
Register Description
R3 Status - 0 = OK, Other values are unknown, but indicate failure.

Parameter list based on speculation. Not used in current Kernel.


lv1_remove_repository_node[edit | edit source]

The repository appears to be an area of storage for use by the Hypervisor.

Abstract Call[edit | edit source]
status = lv1_remove_repository_node( /*IN*/ n1, n2, n3, n4 );
Parameters[edit | edit source]
Inputs
Register Description
R3 top level key
R4 2nd level key
R5 3rd level key
R6 4th level key
Outputs
Register Description
R3 Status - 0 = OK, Other values are unknown, but indicate failure.

Parameter list based on speculation. Not used in current Kernel.


lv1_read_htab_entries[edit | edit source]

Not used in current Kernel.

Abstract Call[edit | edit source]
result = lv1_read_htab_entries( /*IN*/ p1, p2, /*OUT*/ &v1, &v2, &v3, &v4, &v5 );
Parameters[edit | edit source]
Inputs
Register Description
R3 p1 - vas_id
R4 p2 - offset
Outputs
Register Description
R3 Status?
R4 v1 - unknown
R5 v2 - unknown
R6 v3 - unknown
R7 v4 - unknown
R8 v5 - unknown

Notes: offset is 64-bit indexed. r4-r7 seem to be right from the htab. r8 is 16-bit indexed reading from something 0xFFFB is max offset


lv1_set_dabr[edit | edit source]

Sets dabr (Data Address Breakpoint Register) and dabrx (Data Address Breakpoint Register Extension)

Kernel Call[edit | edit source]
result = lv1_set_dabr( /*IN*/ dabr, dabrx);
Parameters[edit | edit source]
Inputs
Register Description
R3 dabr - see notes
R4 dabrx - see notes
Outputs
Register Description
R3 Status - 0 = OK, Other values are unknown, but indicate failure.

Notes:

  • DABR:
Bit(s) Name Description
0:60   DAB  Data Address Breakpoint
61     BT   Breakpoint Translation
62     DW   Data Write
63     DR   Data Read
  • DABRX
Bit(s) Name  Description
0:59         Reserved
60     BTI   Breakpoint Translation Ignore
61:63  PRIVM Privilege Mask
61     HYP   Hypervisor state - unsupported in LV1
62     PNH   Privileged but Non-Hypervisor state
63     PRO   Problem state

When PRIVM in dabrx is 0 or when any unsupported or reserved bit in dabrx is active, both dabr and dabrx writes are not performed and 0x2FFFFFFEF is returned.

DABRX is defined in “setup.c” as follows

enum {DABR_USER = 1, DABR_KERNEL = 2,};

lv1_set_vmx_graphics_mode[edit | edit source]

Set the Single Precision mode of the vmx graphics units in the PPU

Abstract Call[edit | edit source]
result = lv1_set_vmx_graphics_mode( mode );
Parameters[edit | edit source]
Inputs
Register Description
R3 mode - 0 = IEEE 754-1985 SIMD rounding mode for VMX/Altivec Instructions
mode - 1 = SPE-compatible SIMD graphics-rounding mode for VMX/Altivec Instructions
Outputs
Register Description
R3 result: 0 = LV1_SUCCESS, -17 = LV1_ILLEGAL_PARAMETER_VALUE

Notes:

This is a call to set the single precision rounding mode of the VMX units in the Cell PPUs. The AltiVec/VMX SIMD/Vector processing unit has 2 rounding modes for dealing with Single-precision floating-point. IEEE 754-1985 and SPE-compatible SIMD graphics-rounding mode.

The Cell Broadband Engine Programming Handbook has this to say on the subject: The first implementation of the Cell Broadband Engine Architecture (CBEA) (the CBE processor) supports instructions with a graphics rounding mode. This mode allows programs written with vector/SIMD multimedia extension instructions to produce floating-point results that are equivalent in precision to those written in the SPU instruction set. In this mode, as in the SPU environment, the default rounding mode is round to zero, denormals are treated as zero, and there are no infinities or NaNs.

This call change bit 12 (known as grap_md or grap_mode in various documents) in the HID1 register. Hardware Implementation Register 1 is a HV privileged resource, hence to change the mode from Supervisor mode requires a HV call.

Reference Documents: Cell Broadband Engine Programming Handbook V1.1 Cell Broadband Engine Registers V1.5

Tests:

Info taken from kboot-10\dl\linux-2.6.16\include\asm-powerpc\lv1calltab.h (kboot-20061208)

When recompiled into Kernel module init function, accepts values of 0 and 1 for p1. All other values return -17 (LV1_ILLEGAL_PARAMETER_VALUE)


lv1_set_thread_switch_control_register[edit | edit source]

Not used in current Kernel.

Abstract Call[edit | edit source]
result = lv1_set_thread_switch_control_register( /*IN*/ p1 );
Parameters[edit | edit source]
Inputs
Register Description
R3 p1 - Unknown
Outputs
Register Description
R3 Status?

Notes:

Info taken from kboot-10\dl\linux-2.6.16\include\asm-powerpc\lv1calltab.h (kboot-20061208)


lv1_authenticate_program_segment[edit | edit source]

previous alias: lv1_undocumented_function_99

SPE (isolation, syscall 0x10043, syscall 0x10042, syscall 0x1004A)

Exists in PAL 1.7; Returned -4 (LV1_DENIED_BY_POLICY) when passed 0 in R3 to R10.


lv1_undocumented_function_102[edit | edit source]

Returns current TB ticks

Exists in PAL 1.7; Returned 0 (LV1_SUCCESS) and R4 = 0x692F5D1E7h when passed 0 in R3 to R10.


lv1_get_total_execution_time[edit | edit source]

Not used in current kernel. Does not exist in 3.15 HV dump.

Abstract Call[edit | edit source]
result = lv1_get_total_execution_time( /*IN*/ p1, p2, /*OUT*/ &v1 );
Parameters[edit | edit source]
Inputs
Register Description
R3 p1 - Unknown
R4 p2 - Unknown
Outputs
Register Description
R3 Status?
R4 v1 - Unknown

Notes:

I always get LV1_NOT_IMPLEMENTED


lv1_undocumented_function_105[edit | edit source]

Exists in PAL 1.7. Returns -17 (LV1_ILLEGAL_PARAMETER_VALUE, 0, 0, C000000000537EF8h, F09B89AF5001h, 6C0061D8E190h, C0000000008DF718h, F09B89AF5001h, when passed 0 in R3 to R10.


lv1_undocumented_function_106[edit | edit source]

Exists in PAL 1.7. Returns the same as lv1_undocumented_function_105.


lv1_undocumented_function_107[edit | edit source]

Exists in PAL 1.7. Returns the same as lv1_undocumented_function_105.


lv1_undocumented_function_108[edit | edit source]

Exists in PAL 1.7. Returns the same as lv1_undocumented_function_105.


lv1_undocumented_function_109[edit | edit source]

Exists in PAL 1.7. Returns the same as lv1_undocumented_function_105.


lv1_read_remote_file[edit | edit source]

Parameters[edit | edit source]
Inputs
Register Description
R3 u32 type
R4 u32 *path
R5 u64 offset
R6 u32 *buf
R7 u64 size
Outputs
Register Description
R3 status - 0 = OK, LV1_TYPE_MISMATCH when type is not 1. Other values are unknown but indicate failure.
R4 n_read

lv1_write_remote_file[edit | edit source]

Parameters[edit | edit source]
Inputs
Register Description
R3 u32 type
R4 u32 *path
R5 u64 offset
R6 u32 *buf
R7 u64 size
Outputs
Register Description
R3 status
R4 n_write

lv1_get_remote_file_size[edit | edit source]

Parameters[edit | edit source]
Inputs
Register Description
R3 u32 type
R4 u32 *path
Outputs
Register Description
R3 status
R4 file_size

----

lv1_map_physical_address_region[edit | edit source]

Parameters[edit | edit source]
Inputs
Register Description
R3 start -
R4 page_size -
R5 size -
Outputs
Register Description
R3 Status - 0 = OK, Other values are unknown, but indicate failure.
R4 lpar_addr -

lv1_unmap_physical_address_region[edit | edit source]

Parameters[edit | edit source]
Inputs
Register Description
R3 lpar_addr -
Outputs
Register Description
R3 Status - 0 = OK, Other values are unknown, but indicate failure.



lv1_allocate_io_segment[edit | edit source]

Allocate an io segment.

kboot Call[edit | edit source]
result = lv1_allocate_io_segment( /*IN*/ ioas_id, segment_size, io_page_size, /*OUT*/ &ioif_addr );
Parameters[edit | edit source]
Inputs
Register Description
R3 ioas_id - io address space id
R4 segment_size - io segment size
R5 io_page_size - io page size, 0xC, 0×10, 0×14
Outputs
Register Description
R3 Status - 0 = OK, Other values are unknown, but indicate failure.
R4 ioif_addr - io interface address

Notes:

Code taken from kboot-10\dl\linux-2.6.16\sound\powerpc\snd_ps3pf.c (kboot-20061208)

ret64 = lv1_allocate_io_segment(0,           /* io space */
   IO_SEGMENTSIZE, /* segment size */
   IO_PAGESIZE_SHIFT, /* io page size */
   &(ioif_map_info_array[current_segment].ioif_addr));

lv1_release_io_segment[edit | edit source]

Release an io segment.

kboot Call[edit | edit source]
result = lv1_release_io_segment( /*IN*/ ioas_id, ioif_addr );
Parameters[edit | edit source]
Inputs
Register Description
R3 ioas_id - io address space id
R4 ioif_addr - io interface address
Outputs
Register Description
R3 Status - 0 = OK, Other values are unknown, but indicate failure.

Notes:

Code taken from kboot-10\dl\linux-2.6.16\sound\powerpc\snd_ps3pf.c (kboot-20061208)

ret64 = lv1_release_io_segment(0, /* io space */
   ioif_map_info_array[current_segment].ioif_addr);

lv1_allocate_ioid[edit | edit source]

Not used in current kernel.

Abstract Call[edit | edit source]
result = lv1_allocate_ioid( /*IN*/ p1, /*OUT*/ &v1 );
Parameters[edit | edit source]
Inputs
Register Description
R3 SBZ
Outputs
Register Description
R3 Status?
R4 the ioid

Notes:

Info taken from kboot-10\dl\linux-2.6.16\include\asm-powerpc\lv1calltab.h (kboot-20061208)


lv1_release_ioid[edit | edit source]

Not used in current Kernel.

Abstract Call[edit | edit source]
result = lv1_release_ioid( /*IN*/ p1, p2 );
Parameters[edit | edit source]
Inputs
Register Description
R3 p1 - Unknown
R4 p2 - Unknown
Outputs
Register Description
R3 Status?

Notes:

Info taken from kboot-10\dl\linux-2.6.16\include\asm-powerpc\lv1calltab.h (kboot-20061208)


lv1_construct_io_irq_outlet[edit | edit source]

Construct an outlet for a non-virtualized device interrupt.

Kernel Call[edit | edit source]
result = lv1_construct_io_irq_outlet( /*IN*/ interrupt_id, /*OUT*/ &outlet );
Parameters[edit | edit source]
Inputs
Register Description
R3 interrupt_id - interrupt id
Outputs
Register Description
R3 Status - 0 = OK, Other values are unknown, but indicate failure.
R4 outlet - interrupt outlet

lv1_destruct_io_irq_outlet[edit | edit source]

Destruct a previously constructed device interrupt outlet.

Kernel Call[edit | edit source]
result = lv1_destruct_io_irq_outlet( /*IN*/ outlet );
Parameters[edit | edit source]
Inputs
Register Description
R3 outlet - interrupt outlet
Outputs
Register Description
R3 Status - 0 = OK, Other values are unknown, but indicate failure.

lv1_map_htab[edit | edit source]

Map the hash page table.

Kernel Call[edit | edit source]
result = lv1_map_htab( /*IN*/ 0, /*OUT*/ &htab_addr );
Parameters[edit | edit source]
Inputs
Register Description
R3 0 - Unknown (lpid?)
Outputs
Register Description
R3 Status?
R4 htab_addr - hash page table address

Notes:

In “htab.c” return code is assigned, but not used. Must be translated and ioremapped before it can be used in the kernel. It’s 1MB long


lv1_unmap_htab[edit | edit source]

Unmap the hash page table.

Kernel Call[edit | edit source]
lv1_unmap_htab( /*IN*/ htab_addr );
Parameters[edit | edit source]
Inputs
Register Description
R3 htab_addr - hash page table address
Outputs
Register Description
R3 Status?

lv1_read_remote_file_long_name[edit | edit source]

Parameters[edit | edit source]
Inputs
Register Description
R3 u32 type
R4 u32 *path
R5 u32 path_len
R6 u64 offset
R7 u32 *buf
R8 u64 size
Outputs
Register Description
R3 status
R4 n_read

lv1_write_remote_file_long_name[edit | edit source]

Parameters[edit | edit source]
Inputs
Register Description
R3 u32 type
R4 u32 *path
R5 u32 path_len
R6 u64 offset
R7 u32 *buf
R8 u64 size
Outputs
Register Description
R3 status
R4 n_write

lv1_get_remote_file_size_long_name[edit | edit source]

Parameters[edit | edit source]
Inputs
Register Description
R3 u32 type
R4 u32 *path
R5 u32 path_len
Outputs
Register Description
R3 status
R4 file_size

lv1_get_version_info[edit | edit source]

Returns PS3 firmware version information.

Kernel Call[edit | edit source]
result = lv1_get_version_info( /*OUT*/ &raw );
Parameters[edit | edit source]
Outputs
Register Description
R3 Status - 0 = OK, Other values are unknown, but indicate failure.
R4 raw - firmware data (see notes)

Notes:

The firmware information is accessed using the following union:

union ps3_firmware_version {
	u64 raw;
	struct {
		u16 pad;
		u16 major;
		u16 minor;
		u16 rev;
	};
};

lv1_undocumented_function_134[edit | edit source]

Exists in PAL 1.7. Returns 0 when passed R3-R10=0.


lv1_undocumented_function_135[edit | edit source]

Exists in PAL 1.7. Returns -6 (LV1_NO_ENTRY) in R3, rest same as lv1_undocumented_function_105.


lv1_undocumented_function_136[edit | edit source]

Exists in PAL 1.7. Returns -6 (LV1_NO_ENTRY) in R3, rest same as lv1_undocumented_function_105.


lv1_undocumented_function_137[edit | edit source]

SPE

Exists in PAL 1.7. Returns -4 (LV1_DENIED_BY_POLICY) when passed 0 in R3-R10.


lv1_undocumented_function_138[edit | edit source]

SPE

Exists in PAL 1.7. Returns -4 (LV1_DENIED_BY_POLICY) when passed 0 in R3-R10.


lv1_construct_lpm[edit | edit source]

Not used in current kernel.

Abstract Call[edit | edit source]
result = lv1_construct_lpm( /*IN*/ p1, p2, p3, p4, p5, p6, /*OUT*/ &v1, &v2, &v3 );
Parameters[edit | edit source]
Inputs
Register Description
R3 p1 - node_id, this is the node id of the processor, 0 is only valid value
R4 p2 - tb_type, 0 is none, 1 is internal
R5 p3 - Unknown, is 0
R6 p4 - Unknown, is 0
R7 p5 - tb_cache in lpar, 128 byte aligned
R8 p6 - tb_cache_size
Outputs
Register Description
R3 Status
R4 v1 - lpm_id
R5 v2 - outlet_id
R6 v3 - tb_size

lv1_destruct_lpm[edit | edit source]

Not used in current kernel.

Abstract Call[edit | edit source]
result = lv1_destruct_lpm( /*IN*/ p1 );
Parameters[edit | edit source]
Inputs
Register Description
R3 p1 - lpm_id
Outputs
Register Description
R3 Status?

lv1_start_lpm[edit | edit source]

Not used in current kernel.

Abstract Call[edit | edit source]
result = lv1_start_lpm( /*IN*/ p1 );
Parameters[edit | edit source]
Inputs
Register Description
R3 p1 - lpm_id
Outputs
Register Description
R3 Status?

lv1_stop_lpm[edit | edit source]

Not used in current kernel.

Abstract Call[edit | edit source]
result = lv1_stop_lpm( /*IN*/ p1, /*OUT*/ &v1 );
Parameters[edit | edit source]
Inputs
Register Description
R3 p1 - Unknown
Outputs
Register Description
R3 Status?
R4 v1 - Unknown

lv1_copy_lpm_trace_buffer[edit | edit source]

Not used in current kernel.

Abstract Call[edit | edit source]
result = lv1_copy_lpm_trace_buffer( /*IN*/ p1, p2, p3 /*OUT*/ &v1 );
Parameters[edit | edit source]
Inputs
Register Description
R3 p1 - lpm_id
R3 p2 - offset
R3 p3 - request
Outputs
Register Description
R3 Status
R4 v1 - tmp

lv1_add_lpm_event_bookmark[edit | edit source]

Not in current kernel.

Abstract Call[edit | edit source]
result = lv1_add_lpm_event_bookmark( /*IN*/ p1, p2, p3, p4, p5 );
Parameters[edit | edit source]
Inputs
Register Description
R3 p1 - Unknown
R3 p2 - Unknown
R3 p3 - Unknown
R6 p4 - Unknown
R7 p5 - Unknown
Outputs
Register Description
R3 Status?

lv1_delete_lpm_event_bookmark[edit | edit source]

Not used in current kernel.

Abstract Call[edit | edit source]
result = lv1_delete_lpm_event_bookmark( /*IN*/ p1, p2, p3 );
Parameters[edit | edit source]
Inputs
Register Description
R3 p1 - Unknown
R3 p2 - Unknown
R3 p3 - Unknown
Outputs
Register Description
R3 Status?

lv1_set_lpm_interrupt_mask[edit | edit source]

Not used in current kernel.

Abstract Call[edit | edit source]
result = lv1_set_lpm_interrupt_mask( /*IN*/ p1, p2, p3, /*OUT*/ &v1 );
Parameters[edit | edit source]
Inputs
Register Description
R3 p1 - Unknown
R3 p2 - Unknown
R3 p3 - Unknown
Outputs
Register Description
R3 Status?
R4 v1 - Unknown

lv1_get_lpm_interrupt_status[edit | edit source]

Not used in current kernel.

Abstract Call[edit | edit source]
result = lv1_get_lpm_interrupt_status( /*IN*/ p1, /*OUT*/ &v1 );
Parameters[edit | edit source]
Inputs
Register Description
R3 p1 - Unknown
Outputs
Register Description
R3 Status?
R4 v1 - Unknown

lv1_set_lpm_general_control[edit | edit source]

Not used in current kernel.

Abstract Call[edit | edit source]
result = lv1_set_lpm_general_control( /*IN*/ p1, p2, p3, p4, p5, /*OUT*/ &v1, &v2 );
Parameters[edit | edit source]
Inputs
Register Description
R3 p1 - Unknown
R4 p2 - Unknown
R5 p3 - Unknown
R6 p4 - Unknown
R7 p5 - Unknown
Outputs
Register Description
R3 Status?
R4 v1 - Unknown
R5 v2 - Unknown

lv1_set_lpm_interval[edit | edit source]

Not used in current kernel.

Abstract Call[edit | edit source]
result = lv1_set_lpm_interval( /*IN*/ p1, p2, p3, /*OUT*/ &v1 );
Parameters[edit | edit source]
Inputs
Register Description
R3 p1 - Unknown
R4 p2 - Unknown
R5 p3 - Unknown
Outputs
Register Description
R3 Status?
R4 v1 - Unknown

lv1_set_lpm_trigger_control[edit | edit source]

Not used in current kernel.

Abstract Call[edit | edit source]
result = lv1_set_lpm_trigger_control( /*IN*/ p1, p2, p3, /*OUT*/ &v1 );
Parameters[edit | edit source]
Inputs
Register Description
R3 p1 - Unknown
R4 p2 - Unknown
R5 p3 - Unknown
Outputs
Register Description
R3 Status?
R4 v1 - Unknown

lv1_set_lpm_counter_control[edit | edit source]

Not used in current kernel.

Abstract Call[edit | edit source]
result = lv1_set_lpm_counter_control( /*IN*/ p1, p2, p3, p4, /*OUT*/ &v1 );
Parameters[edit | edit source]
Inputs
Register Description
R3 p1 - Unknown
R4 p2 - Unknown
R5 p3 - Unknown
R6 p4 - Unknown
Outputs
Register Description
R3 Status?
R4 v1 - Unknown

lv1_set_lpm_group_control[edit | edit source]

Not used in current kernel.

Abstract Call[edit | edit source]
result = lv1_set_lpm_group_control( /*IN*/ p1, p2, p3, /*OUT*/ &v1 );
Parameters[edit | edit source]
Inputs
Register Description
R3 p1 - Unknown
R4 p2 - Unknown
R5 p3 - Unknown
Outputs
Register Description
R3 Status?
R4 v1 - Unknown

lv1_set_lpm_debug_bus_control[edit | edit source]

Not used in current kernel.

Abstract Call[edit | edit source]
result = lv1_set_lpm_debug_bus_control( /*IN*/ p1, p2, p3, /*OUT*/ &v1 );
Parameters[edit | edit source]
Inputs
Register Description
R3 p1 - Unknown
R4 p2 - Unknown
R5 p3 - Unknown
Outputs
Register Description
R3 Status?
R4 v1 - Unknown

lv1_set_lpm_counter[edit | edit source]

Not used in current kernel.

Abstract Call[edit | edit source]
result = lv1_set_lpm_counter( /*IN*/ p1, p2, p3, p4, p5, /*OUT*/ &v1, &v2 );
Parameters[edit | edit source]
Inputs
Register Description
R3 p1 - Unknown
R4 p2 - Unknown
R5 p3 - Unknown
R6 p4 - Unknown
R7 p5 - Unknown
Outputs
Register Description
R3 Status?
R4 v1 - Unknown
R5 v2 - Unknown

lv1_set_lpm_signal[edit | edit source]

Not used in current kernel.

Abstract Call[edit | edit source]
result = lv1_set_lpm_signal( /*IN*/ p1, p2, p3, p4, p5, p6, p7 );
Parameters[edit | edit source]
Inputs
Register Description
R3 p1 - Unknown
R4 p2 - Unknown
R5 p3 - Unknown
R6 p4 - Unknown
R7 p5 - Unknown
R8 p6 - Unknown
R9 p7 - Unknown
Outputs
Register Description
R3 Status?

lv1_set_lpm_spr_trigger[edit | edit source]

Not used in current kernel.

Abstract Call[edit | edit source]
result = lv1_set_lpm_spr_trigger( /*IN*/ p1, p2 );
Parameters[edit | edit source]
Inputs
Register Description
R3 p1 - Unknown
R4 p2 - Unknown
Outputs
Register Description
R3 Status?

lv1_insert_htab_entry[edit | edit source]

Used in current kernel.

Kernel Call[edit | edit source]
result = lv1_insert_htab_entry( /*IN*/ p1, p2, p3, p4, p5, p6, /*OUT*/ &v1, &v2, &v3 );
Parameters[edit | edit source]
Inputs
Register Description
R3 p1 - htab ID, 0 or returns -6
R4 p2 - hpte_group, 0 or returns -17
R5 p3 - hpte_v
R6 p4 - hpte_r
R7 p5 - Bolted flag
R8 p6 - flags?
Outputs
Register Description
R3 Status?
R4 v1 - inserted_index
R5 v2 - evicted_v
R6 v3 - evicted_r

Notes: Kernel usage:

result = lv1_insert_htab_entry(PS3_LPAR_VAS_ID_CURRENT, hpte_group,
				       hpte_v, hpte_r,
				       HPTE_V_BOLTED, 0,
				       &inserted_index,
				       &evicted_v, &evicted_r);

lv1_read_virtual_uart[edit | edit source]

Read data from a VUART port into a provided buffer.

Kernel Call[edit | edit source]
result = lv1_read_virtual_uart( /*IN*/ port_number, buffer, bytes, /*OUT*/ bytes_read );
Parameters[edit | edit source]
Inputs
Register Description
R3 port_number - VUART port number
R4 buffer - pointer to buffer (must be address in lpar)
R5 bytes - buffer size?
Outputs
Register Description
R3 Status - 0 = OK, Other values are unknown, but indicate failure.
R4 bytes_read - number of bytes read into buffer

lv1_write_virtual_uart[edit | edit source]

Write a buffer of data to a VUART port.

Kernel Call[edit | edit source]
result = lv1_write_virtual_uart( /*IN*/ port_number, buffer, bytes, /*OUT*/ bytes_written );
Parameters[edit | edit source]
Inputs
Register Description
R3 port_number - VUART port number
R4 buffer - pointer to buffer (must be address in lpar)
R5 bytes - buffer size?
Outputs
Register Description
R3 Status - 0 = OK, Other values are unknown, but indicate failure.
R4 bytes_written - number of bytes written to VUART

lv1_set_virtual_uart_param[edit | edit source]

Set a parameter for a port on the VUART.

Kernel Call[edit | edit source]
result = lv1_set_virtual_uart_param( /*IN*/ port_number, param_id, param_value );
Parameters[edit | edit source]
Inputs
Register Description
R3 port_number - VUART port number
R4 param_id - id of parameter to set (see notes)
R5 param_value - parameter value
Outputs
Register Description
R3 Status - 0 = OK, Other values are unknown, but indicate failure.

See lv1_get_virtual_uart_param for parameter information.


lv1_get_virtual_uart_param[edit | edit source]

Get a parameter for a port on the VUART.

Kernel Call[edit | edit source]
result = lv1_get_virtual_uart_param( /*IN*/ port_number, param_id, /*OUT*/ &param_value );
Parameters[edit | edit source]
Inputs
Register Description
R3 port_number - VUART port number
R4 param_id - id of parameter to set (see notes)
Outputs
Register Description
R3 Status - 0 = OK, Other values are unknown, but indicate failure.
R4 param_value - parameter value

VUART parameters defined in vuart.c:

Parameter param_id Notes
PARAM_TX_TRIGGER 0
PARAM_RX_TRIGGER 1
PARAM_INTERRUPT_MASK 2
PARAM_RX_BUF_SIZE 3 read only
PARAM_RX_BYTES 4 read only
PARAM_TX_BUF_SIZE 5 read only, not referenced in current Kernel
PARAM_TX_BYTES 6 read only, not referenced in current Kernel
PARAM_INTERRUPT_STATUS 7 read only

lv1_configure_virtual_uart_irq[edit | edit source]

Configure the VUART IRQ.

Kernel Call[edit | edit source]
result = lv1_configure_virtual_uart_irq( /*IN*/ lpar_addr, /*OUT*/ &outlet );
Parameters[edit | edit source]
Inputs
Register Description
R3 lpar_addr - logical partition address of virtual uart interrupt bitmap
Outputs
Register Description
R3 Status - 0 = OK, Other values are unknown, but indicate failure.
R4 outlet - irq outlet

Notes:

Comment from interrupt.c:

/**
* The system supports only a single virtual uart, so multiple calls without
* freeing the interrupt will return a wrong state error.
*/

lv1_undocumented_function_167[edit | edit source]

SPE (isolation, reads from SPU_Out_Intr_Mbox and MFC_CNTL registers)

Exists on PAL 1.7. Returns -4 (LV1_DENIED_BY_POLICY) when passed 0 in R3 to R10.


lv1_undocumented_function_168[edit | edit source]

SPE (isolation, writes to MFC_CNTL register)

Exists on PAL 1.7. Returns -4 (LV1_DENIED_BY_POLICY) when passed 0 in R3 to R10.


lv1_open_device[edit | edit source]

Open the device for a given bus and device id.

Kernel Call[edit | edit source]
result = lv1_open_device( /*IN*/ bus_id, dev_id, 0 );
Parameters[edit | edit source]
Inputs
Register Description
R3 bus_id - bus id
R4 dev_id - device id
R5 0 - Unknown
Outputs
Register Description
R3 Status: LV1_SUCCESS (0) - OK

LV1_NO_ENTRY (-6) - invalid dev_id LV1_BUSY (-9) - device already open LV1_ILLEGAL_PARAMETER_VALUE (-17) - invalid bus_id

Notes:

Valid values for bus_id and dev_id can be obtained from the repository (see lv1_get_repository_node_value).

Once open, functions such as lv1_map_device_mmio_region and lv1_allocate_device_dma_region can be used to map the device into memory.

The value of R5 does not seem to affect the outcome of the call (powers of 2 in the 64 bit range were tested). One reason for the flag could be to indicate whether to open the device in shared mode or not (and thus prevent the LV1_BUSY return code).


lv1_close_device[edit | edit source]

Close the device for a given bus and device id.

Kernel Call[edit | edit source]

result = lv1_close_device( /*IN*/ bus_id, dev_id );

Parameters[edit | edit source]
Inputs
Register Description
R3 bus_id - bus id
R4 dev_id - device id
Outputs
Register Description
R3 Status - 0 = OK, Other values are unknown, but indicate failure.

lv1_map_device_mmio_region[edit | edit source]

Map an MMIO region to the specified device.

Kernel Call[edit | edit source]
result = lv1_map_device_mmio_region( /*IN*/ bus_id, dev_id, bus_addr, size, page_size, /*OUT*/ &lpar_addr );
Parameters[edit | edit source]
Inputs
Register Description
R3 bus_id - bus id
R4 dev_id - device id
R5 bus_addr - address of the region
R6 size - size of the region
R7 page_size - page size of the region
Outputs
Register Description
R3 Status - 0 = OK, Other values are unknown, but indicate failure.
R4 lpar_addr - logical partition address of the mapped region

lv1_unmap_device_mmio_region[edit | edit source]

Unmap an MMIO region from the specified device.

Kernel Call[edit | edit source]
result = lv1_unmap_device_mmio_region( /*IN*/ bus_id, dev_id, lpar_addr );
Parameters[edit | edit source]
Inputs
Register Description
R3 bus_id - bus id
R4 dev_id - device id
R5 lpar_addr - logical partition address of the mapped region
Outputs
Register Description
R3 Status - 0 = OK, Other values are unknown, but indicate failure.

lv1_allocate_device_dma_region[edit | edit source]

Allocate a DMA region for the specified device.

Kernel Call[edit | edit source]
result = lv1_allocate_device_dma_region( /*IN*/ bus_id, dev_id, io_size, io_pagesize, flag, /*OUT*/ &dma_region );
Parameters[edit | edit source]
Inputs
Register Description
R3 bus_id - bus id
R4 dev_id - device id
R5 io_size - region size
R6 io_pagesize - specified as a PAGE_SHIFT (i.e. n where pagesize = 2^n)
R7 flag - 0=32 bit mode, 2=8 bit mode
Outputs
Register Description
R3 Status - 0 = OK, Other values are unknown, but indicate failure.
R4 dma_region - dma region address

Notes: When the device is little endian, the mode must be set to 8 bit for 8 bit DMA to work as expected, otherwise the bytes will be read/written in the wrong order. OTOH, this mode requires that 16 and 32-bit values are byte-swapped by the CPU since they will appear as little endian in memory.


lv1_free_device_dma_region[edit | edit source]

Free a previously allocated DMA region for the specified device.

Kernel Call[edit | edit source]
lv1_free_device_dma_region( /*IN*/ bus_id, dev_id, dma_region );
Parameters[edit | edit source]
Inputs
Register Description
R3 bus_id - bus id
R4 dev_id - device id
R5 dma_region - dma region address
Outputs
Register Description
R3 Status?

lv1_map_device_dma_region[edit | edit source]

Map a DMA region for the specified device.

Kernel Call[edit | edit source]
result = lv1_map_device_dma_region( /*IN*/ bus_id, dev_id, lpar_addr, dma_region, size, flags );
Parameters[edit | edit source]
Inputs
Register Description
R3 bus_id - bus id
R4 dev_id - device id
R5 lpar_addr - logical partition address
R6 dma_region - dma region address
R7 size - region size
R8 flags - see notes
Outputs
Register Description
R3 Status - 0 = OK, Other values are unknown, but indicate failure.

Notes:

In “mm.c” and “ps3_storage.c”, flags parameter is always specified as 0xf800000000000000UL. They are the same flags as the IOPTE entry ones.


lv1_unmap_device_dma_region[edit | edit source]

Unmap a DMA region for the specified device.

Kernel Call[edit | edit source]
result = lv1_unmap_device_dma_region( /*IN*/ bus_id, dev_id, dma_region, size );
Parameters[edit | edit source]
Inputs
Register Description
R3 bus_id - bus id
R4 dev_id - device id
R5 dma_region - dma region address
R6 size - region size
Outputs
Register Description
R3 Status - 0 = OK, Other values are unknown, but indicate failure.

lv1_read_pci_config[edit | edit source]

Read external PCI config. PS3tool only?

kboot Call[edit | edit source]
result = lv1_read_pci_config( /*IN*/ bus_id, pci_bus_id, dev_id, func_id, offset, size, /*OUT*/ &config_data );
Parameters[edit | edit source]
Inputs
Register Description
R3 bus_id - ps3 bus id
R4 pci_bus_id - pci bus id
R5 dev_id - pci device id
R6 func_id - pci function
R7 offset - offset to store data within config_data
R8 size - size of config_data
Outputs
Register Description
R3 Status - 0 = OK, Other values are unknown, but indicate failure.
R4 config_data - pci config data

Notes:

Code taken from kboot-10\dl\linux-2.6.16\arch\powerpc\platforms\ps3pf\pci.c (kboot-20061208)

status = lv1_read_pci_config(p->bus_id, p->bus_pci_bus, p->bus_pci_dev, p->bus_pci_func,
	(uint64_t)offset, size, &data);

lv1_write_pci_config[edit | edit source]

Write external PCI config. PS3tool only?

kboot Call[edit | edit source]
result = lv1_write_pci_config( /*IN*/ bus_id, pci_bus_id, dev_id, func_id, offset, size, config_data );
Parameters[edit | edit source]
Inputs
Register Description
R3 bus_id - ps3 bus id
R4 pci_bus_id - pci bus id
R5 dev_id - pci device id
R6 func_id - pci function
R7 offset - offset to store data within config_data
R8 size - size of config_data
R9 config_data - pci config data
Outputs
Register Description
R3 Status - 0 = OK, Other values are unknown, but indicate failure.

Notes:

Code taken from kboot-10\dl\linux-2.6.16\arch\powerpc\platforms\ps3pf\pci.c (kboot-20061208)

status = lv1_write_pci_config(p->bus_id, p->bus_pci_bus, p->bus_pci_dev, p->bus_pci_func,
   (uint64_t)offset, size, (uint64_t)val);
if(status) {
   /* lv1_write_pci_config can't write reg from 0x10 to 0x3f */
}

lv1_read_pci_io[edit | edit source]

Not used in current kernel.

Abstract Call[edit | edit source]
result = lv1_read_pci_io( /*IN*/ p1, p2, p3, p4, /*OUT*/ &v1 );
Parameters[edit | edit source]
Inputs
Register Description
R3 p1 - Unknown
R4 p2 - Unknown
R5 p3 - Unknown
R6 p4 - Unknown
Outputs
Register Description
R3 Status?
R4 v1 - Unknown

Notes:

Info taken from kboot-10\dl\linux-2.6.16\include\asm-powerpc\lv1calltab.h (kboot-20061208)


lv1_write_pci_io[edit | edit source]

Not used in current kernel.

Abstract Call[edit | edit source]
result = lv1_write_pci_io( /*IN*/ p1, p2, p3, p4, p5 );
Parameters[edit | edit source]
Inputs
Register Description
R3 p1 - Unknown
R4 p2 - Unknown
R5 p3 - Unknown
R6 p4 - Unknown
Outputs
Register Description
R3 Status?

Notes:

Info taken from kboot-10\dl\linux-2.6.16\include\asm-powerpc\lv1calltab.h (kboot-20061208)


lv1_undocumented_function_182[edit | edit source]

Exists in PAL 3.15. Nothing known so far. Note: probably a function that allocates or frees memory.


lv1_undocumented_function_183[edit | edit source]

Exists in PAL 3.15. Nothing known so far. Note: probably a function that allocates or frees memory.


lv1_net_add_multicast_address[edit | edit source]

Add multicast address to the specified network device.

Kernel Call[edit | edit source]
result = lv1_net_add_multicast_address( /*IN*/ bus_id, dev_id, addr, flag );
Parameters[edit | edit source]
Inputs
Register Description
R3 bus_id - bus id
R4 dev_id - device id
R5 addr - see notes
R6 flag - see notes
Outputs
Register Description
R3 Status - 0 = OK, Other values are unknown, but indicate failure.

Notes:

From “gelic_net.c”, addr can also take special values of 0 and GELIC_NET_BROADCAST_ADDR (0xffffffff) and flag is assigned values of 0 and 1.


lv1_net_remove_multicast_address[edit | edit source]

Remove multicast address on the specified network device.

Kernel Call[edit | edit source]
result = lv1_net_remove_multicast_address( /*IN*/ bus_id, dev_id, 0, 1 );
Parameters[edit | edit source]
Inputs
Register Description
R3 bus_id - bus id
R4 dev_id - device id
R5 0 - Unknown
R6 1 - Unknown
Outputs
Register Description
R3 Status - 0 = OK, Other values are unknown, but indicate failure.

lv1_net_start_tx_dma[edit | edit source]

Start DMA transmit on the specified network device.

Kernel Call[edit | edit source]
result = lv1_net_start_tx_dma( /*IN*/ bus_id, dev_id, bus_addr, 0 );
Parameters[edit | edit source]
Inputs
Register Description
R3 bus_id - bus id
R4 dev_id - device id
R5 bus_addr - dma address?
R6 0 - Unknown
Outputs
Register Description
R3 Status - 0 = OK, Other values are unknown, but indicate failure.

lv1_net_stop_tx_dma[edit | edit source]

Stop DMA transmit on the specified network device.

Kernel Call[edit | edit source]
result = lv1_net_stop_tx_dma( /*IN*/ bus_id, dev_id, 0 );
Parameters[edit | edit source]
Inputs
Register Description
R3 bus_id - bus id
R4 dev_id - device id
R5 0 - Unknown
Outputs
Register Description
R3 Status - 0 = OK, Other values are unknown, but indicate failure.

lv1_net_start_rx_dma[edit | edit source]

Start DMA receive on the specified network device.

Kernel Call[edit | edit source]
result = lv1_net_start_rx_dma( /*IN*/ bus_id, dev_id, bus_addr, 0 );
Parameters[edit | edit source]
Inputs
Register Description
R3 bus_id - bus id
R4 dev_id - device id
R5 bus_addr - dma address?
R6 0 - Unknown
Outputs
Register Description
R3 Status - 0 = OK, Other values are unknown, but indicate failure.

lv1_net_stop_rx_dma[edit | edit source]

Stop DMA receive on the specified network device.

Kernel Call[edit | edit source]
result = lv1_net_stop_rx_dma( /*IN*/ bus_id, dev_id, 0 );
Parameters[edit | edit source]
Inputs
Register Description
R3 bus_id - bus id
R4 dev_id - device id
R5 0 - Unknown
Outputs
Register Description
R3 Status - 0 = OK, Other values are unknown, but indicate failure.

lv1_net_set_interrupt_status_indicator[edit | edit source]

Set the interrupt status indicator for the specified network device.

Kernel Call[edit | edit source]
result = lv1_net_set_interrupt_status_indicator( /*IN*/ bus_id, dev_id, irq_status_addr, 0 );
Parameters[edit | edit source]
Inputs
Register Description
R3 bus_id - bus id
R4 dev_id - device id
R5 irq_status_addr - lpar address of the irq status indicator
R6 0 - Unknown
Outputs
Register Description
R3 Status - 0 = OK, Other values are unknown, but indicate failure.

lv1_net_set_interrupt_mask[edit | edit source]

Sets the interrupt mask for specified network device.

Kernel Call[edit | edit source]
result = lv1_net_set_interrupt_mask( /*IN*/ bus_id, dev_id, mask, 0 );
Parameters[edit | edit source]
Inputs
Register Description
R3 bus_id - bus id
R4 dev_id - device id
R5 mask - interrupt mask
R6 0 - Unknown
Outputs
Register Description
R3 Status - 0 = OK, Other values are unknown, but indicate failure.

lv1_net_control[edit | edit source]

Send a control command to the specified network device.

Kernel Call[edit | edit source]
result = lv1_net_control( /*IN*/ bus_id, dev_id, p1, p2, p3, p4, /*OUT*/ &v1, &v2 );
Parameters[edit | edit source]
Inputs
Register Description
R3 bus_id - bus id
R4 dev_id - device id
R5 p1 - command dependent input parameter
R6 p2 - command dependent input parameter
R7 p3 - command dependent input parameter
R8 p4 - command dependent input parameter
Outputs
Register Description
R3 Status - 0 = OK, Other values are unknown, but indicate failure.
R4 v1 - command dependent output parameter
R5 v2 - command dependent output parameter

lv1_undocumented_function_195[edit | edit source]

WLAN Gelic device

Exists in PAL 1.7. Returns -3 (LV1_NO_PRIVILEGE) when passed 0 in R3 to R10.


lv1_undocumented_function_196[edit | edit source]

WLAN Gelic device

Exists in PAL 1.7. Returns -3 (LV1_NO_PRIVILEGE) when passed 0 in R3 to R10.


lv1_connect_interrupt_event_receive_port[edit | edit source]

Assign a virtual interrupt to a system bus device.

Kernel Call[edit | edit source]
result = lv1_connect_interrupt_event_receive_port( /*IN*/ bus_id, dev_id, outlet, interrupt_id );
Parameters[edit | edit source]
Inputs
Register Description
R3 bus_id - device bus id
R4 dev_id - device id
R5 outlet - interrupt outlet
R6 interrupt_id - interrupt id
Outputs
Register Description
R3 Status - 0 = OK, Other values are unknown, but indicate failure.

lv1_disconnect_interrupt_event_receive_port[edit | edit source]

Disconnect a virtual interrupt from a system bus device.

Kernel Call[edit | edit source]
result = lv1_disconnect_interrupt_event_receive_port( /*IN*/ bus_id, dev_id, outlet, interrupt_id );
Parameters[edit | edit source]
Inputs
Register Description
R3 bus_id - device bus id
R4 dev_id - device id
R5 outlet - interrupt outlet
R6 interrupt_id - interrupt id
Outputs
Register Description
R3 Status - 0 = OK, Other values are unknown, but indicate failure.

lv1_get_spe_all_interrupt_statuses[edit | edit source]

Not used in current kernel.

Abstract Call[edit | edit source]
result = lv1_get_spe_all_interrupt_statuses( /*IN*/ p1, /*OUT*/ &v1 );
Parameters[edit | edit source]
Inputs
Register Description
R3 p1 - Unknown
Outputs
Register Description
R3 Status?
R4 v1 - Unknown

lv1_undocumented_function_200[edit | edit source]

SPE (isolation)

Exists in PAL 1.7. Returns -4 (LV1_DENIED_BY_POLICY) when passed 0 in R3 to R10.


lv1_undocumented_function_201[edit | edit source]

SPE (isolation)

Exists in PAL 1.7. Returns -4 (LV1_DENIED_BY_POLICY) when passed 0 in R3 to R10.


lv1_deconfigure_virtual_uart_irq[edit | edit source]

Deconfigure the VUART IRQ.

Kernel Call[edit | edit source]
result = lv1_deconfigure_virtual_uart_irq();
Parameters[edit | edit source]
Outputs
Register Description
R3 Status - 0 = OK, Other values are unknown, but indicate failure.

lv1_enable_logical_spe[edit | edit source]

Enables a logical SPE.

Kernel Call[edit | edit source]
status = lv1_enable_logical_spe( /*IN*/ spe_id, resource_id );
Parameters[edit | edit source]
Inputs
Register Description
R3 spe_id - logical spe id
R4 resource_id - spe resource id (prevously retrieved from Kernel repository)
Outputs
Register Description
R3 Status - 0 = OK, Other values are unknown, but indicate failure.

lv1_undocumented_function_209[edit | edit source]

SPE (isolation)

Exists in PAL 1.7. Returns -4 (LV1_DENIED_BY_POLICY) when passed 0 in R3 to R10.


lv1_gpu_open[edit | edit source]

Open the GPU. Call lv1_gpu_close to close the GPU.

Kernel Call[edit | edit source]
status = lv1_gpu_open( /*IN*/ p1 );
Parameters[edit | edit source]
Inputs
Register Description
R3 p1 - Unknown, Kernel only ever passes 0, though other randomly chosen values seem to succeed.
Outputs
Register Description
R3 Status: 0 = LV1_SUCCESS, -6 = LV1_NO_ENTRY

Notes:

When called from Kernel module init function, if GPU is already open, subsequent calls to lv1_gpu_open return LV1_NO_ENTRY (-6). Closing the GPU and re-opening succeeds.


lv1_gpu_close[edit | edit source]

Closes the GPU. Must be called once for every call to lv1_gpu_open.

Kernel Call[edit | edit source]
status = lv1_gpu_close();
Parameters[edit | edit source]
Outputs
Register Description
R3 Status - 0 = OK, Other values are unknown, but indicate failure.

lv1_gpu_device_map[edit | edit source]

Map a device into logical address space. Address needs to be ioremapped before use.

kboot Call[edit | edit source]
result = lv1_gpu_device_map( /*IN*/ dev_id, /*OUT*/ &lpar_addr, &lpar_size );
Parameters[edit | edit source]
Inputs
Register Description
R3 dev_id - device id (see notes)
Outputs
Register Description
R3 Status - 0 = OK, Other values are unknown, but indicate failure.
R4 lpar_addr - logical partition address of device block
R5 lpar_size - size of device block

Notes:

Info taken from kboot-10\dl\linux-2.6.16\sound\powerpc\snd_ps3pf.c (kboot-20061208) where the audio front-end registers are mapped into memory. Two calls to lv1_gpu_device_map are performed, the first when dev_id = 1, to obtain the audio interrupt (Audio IRQ Outlet) and a second time when dev_id = 2 to obtain a mapping of the register block (Audio Registers).

lpar_addr is a virtual address, created by the Hypervisor. Multiple calls to lv1_gpu_device_map with the same dev_id return successfully, but the lpar_address returned for each is different (if there have been no intermediary lv1_gpu_device_unmap calls). These various virtual lpar_addr values all alias the same physical location in memory.

Test Results[edit | edit source]
lv1_gpu_device_map
dev_id result lpar_addr lpar_size Comment
0 ffffffffffffffef 98d2f7d44da1ceae 0100000000000000 result = LV1_ILLEGAL_PARAMETER_VALUE
1 0000000000000000 0000300000022000 0000000000001000 Audio IRQ Outlet (map1_dump)
2 0000000000000000 00003c0000128000 0000000000008000 Audio_Registers (map2_dump)
3 0000000000000000 0000300000026000 0000000000001000 ??? - Any attempt to dereference this lpar_addr locks up the PS3
4 ffffffffffffffef 0000300000026000 0000000000001000 result = LV1_ILLEGAL_PARAMETER_VALUE
5 0000000000000000 0000300000028000 0000000000001000 ??? - (map5_dump)
6 0000000000000000 0000300000029000 0000000000001000 ??? - (map6_dump)
7 0000000000000000 00003000002A0000 0000000000010000 ??? - (map7_dump)
8 0000000000000000 000030000002B000 0000000000001000 video RAM at offset 0x0ff10000- (map8_dump)
9-255 -20 ??? ??? result = LV1_NOT_IMPLEMENTED

It is interesting that when dev_id = 4, LV1_ILLEGAL_PARAMETER_VALUE is returned with lpar_addr and lpar_size set to the values returned from the previous call - for the first call when dev_id = 0, values also appear to be set (though these could be garbage values)

Devices 1 & 2[edit | edit source]

dev_id 1 gives a location used to process IRQ’s from the audio and dev_id 2 gives the base address of the Audio Hardware registers. From published Sony documents (http://www.watch.impress.co.jp/game/docs/20060329/3dps303.htm), Audio is believed to be on the RSX, this call seems to confirm that. Access to the audio after this mapping call (it would appear) bypasses the Hypervisor and occurs directly on the RSX hardware. 3,5,6,7,8 are currently unknown. Presumably 0 and 4 are otherwise valid parameters blocked by the Hypervisor for OtherOS (ie, they may function for Games) otherwise I would have expected a return result of -20 for them. So rather than just being a bridge for audio into HDMI, it is for all audio.

Also interesting is that the GPU version number returned by lv1_gpu_context_allocate appears at address 0×10 in the device 1 dump, though this of course may be complete coincidence.

Device 7[edit | edit source]

dev_id 7 appears to be a video device. It is not possible to map the entire reported memory space (0×10000), only areas 0×0000 to 0x0fff and 0×2000 to 0x2fff (discovered via laborious trial and error testing, mapping other areas causes the PS3 to hang without warning). In both mappable areas, the current screen resolution can be seen at locations 0×200 and 0×210. Changes to the ps3 video mode (e.g. using the ps3videomode utility) can be observed in the mapped areas, but modifying the values directly does not affect the screen resolution. Although both areas contain different values, there appear to be parts in common, as changing the values at 0×200 and 0×210 directly in one area also causes the same values in the other area to change.

Given the screen resolution connection, it could be possible that this device is a mapping of the GPU display heads:

  • Out of 16Kb, only two areas are mappable (= number of accessible display heads)
  • Mappable areas are 2Kb apart → 8 total display heads (= size of display heads array returned by lv1_gpu_context_allocate)
Device 8[edit | edit source]

dev_id 8 appears to be a mapping of video RAM at offset 0x0ff10000. This region of video memory is referenced by RSX DMA objects but its purpose is unknown.


lv1_gpu_device_unmap[edit | edit source]

Unmaps the device from logical address space.

kboot Call[edit | edit source]
lv1_gpu_device_unmap( /*IN*/ dev_id );
Parameters[edit | edit source]
Inputs
Register Description
R3 dev_id - device id (see lv1_gpu_device_map)
Outputs
Register Description
R3 Status?

Notes:

Info taken from kboot-10\dl\linux-2.6.16\sound\powerpc\snd_ps3pf.c (kboot-20061208)


lv1_gpu_memory_allocate[edit | edit source]

Allocate GPU memory.

Kernel Call[edit | edit source]
status = lv1_gpu_memory_allocate(ddr_size, 0, 0, 0, 0, &memory_handle, &ddr_lpar);
Parameters[edit | edit source]
Inputs
Register Description
R3 ddr_size - amount of DDR to reserve? (see notes)
R4 tile_max_size in bytes. Max value 512*1024.
R5 zcull_max_size in bytes. Max value 3075*1024.
R6 tile_max_areas. Max value 15.
R7 zcull_max_areas. Max value 8.
Outputs
Register Description
R3 status: 0 = LV1_SUCCESS, -17 = LV1_ILLEGAL_PARAMETER_VALUE
R4 memory_handle - used by lv1_gpu_context_allocate and lv1_gpu_memory_free??
R5 ddr_lpar - remappable address of allocated video memory, unused by Kernel.

Notes:

ddr_size accepts values (0..252) * 2^20 - values not divisible by 2^20 (1 MB) and above the range result in a return value of -17 (LV1_ILLEGAL_PARAMETER_VALUE). [Verified by Strontium Dog on an AU PS3 V1.5 firmware]

Bits 52-63 of ddr_size seem to be ignored or correspond to flags. The lower bits correspond to the amount of allocated video RAM. A call to lv1_gpu_context_allocate using the returned memory_handle will create a RSX DMA object handle 0xfeed0000 corresponding to the region of allocated memory. Multiple calls to lv1_gpu_memory_allocate with non-zero ddr_size will change the start of this region. The DMA object limit is set to ddr_size - 1. Before FW 2.1, a ddr_size of 0 was accepted, in which case a DMA object starting at zero and of limit 0xffffffff was created. Note that in this case, the start of this region is always zero even if previous calls to lv1_gpu_memory_allocate with non-zero ddr_size were performed. As of FW 2.1 and above, a zero ddr_size is not accepted anymore.

Parameters r4-r7 are unknown. Maximum values for these parameters are respectively 512kB, 3075kB, 15 and 8. They refer to shared scarce resources, as allocations are retained across multiple calls to lv1_gpu_memory_allocate. When attached to a context during lv1_gpu_context_allocate, the values of these parameters are reported in the lpar_driver_info structure of the context.

Cell separates multiple OS into Logical Partitions (lpar) described at http://research.scea.com/research/html/CellGDC05/13.html. PS3 GPU memory is referred to as DDR (or GDDR) whereas system memory is XDR. 256 MB of each are installed in PS3 though only XDR is currently available for use by OtherOS.

To make use of the allocated DDR ddr_lpar needs to be transformed into a usable address using:

ddr_address = ioremap_flags(ddr_lpar, ddr_size, _PAGE_NO_CACHE);

Be aware that the memory that holds the physical GPU frame buffer is not allocated by the Kernel, just used. So on the first call to this, some or all of the memory you request (depending on now much you request) may be actually used as the frame buffer. You will know this, because your writes to memory will mysteriously disappear up to 20ms after you perform them. Note that direct access to video ram is very slow (~10MB/s).

Test Results[edit | edit source]
Register Hex Decimal Comments
R3 0x000000000fc00000 (264241152) 252 MB
R4 0×0000000000000000 (0)
R5 0×0000000000000000 (0)
R6 0×0000000000000000 (0)
R7 0×0000000000000000 (0)
Outputs
R3 0×0000000000000000 (0) LV1_SUCCESS
R4 0x000000005a5a5a5b (...) memory handle
R5 0x00007001a0000000 (...) ddr logical partition address

lv1_gpu_memory_free[edit | edit source]

Free memory handle returned by lv1_gpu_memory_allocate. Must be called to dispose of the handle returned by lv1_gpu_memory_allocate.

Kernel Call[edit | edit source]
status = lv1_gpu_memory_free(ps3fb.memory_handle);
Parameters[edit | edit source]
Inputs
Register Description
R3 Memory handle returned by lv1_gpu_memory_allocate
Outputs
Register Description
R3 Status - 0 = OK, Other values are unknown, but indicate failure.

lv1_gpu_context_iomap[edit | edit source]

Map system RAM address to GPU through the Cell FlexIO interface.

Kernel Call[edit | edit source]
status = lv1_gpu_context_iomap(ps3fb.context_handle, GPU_IOIF, 
			       xdr_lpar, ps3fb_videomemory.size, 0);
Parameters[edit | edit source]
Inputs
Register Description
R3 ps3fb.context_handle as allocated by lv1_gpu_context_allocate
R4 GPU_IOIF = 0x0d000000UL - GPU address where the system RAM virtual framebuffer is remapped
R5 xdr_lpar - lpar version of the physical address of the virtual frame buffer in local memory. (Note: the lpar version = the physical address in the PS3)
R6 ps3fb_videomemory.size = The size of the virtual frame buffer
R7 0 - IOPTE flags - bitfield describing protection, coherency and ordering of the I/O mapping. Any combination of 0 or 2^{11 (cache hint),59 (read ordering),60 (write ordering),61 (coherency),62 (read protection) ,63 (write protection)} seems valid
Outputs
Register Description
R3 Status - 0 = OK, LV1_TYPE_MISMATCH (-8) if R5 set to a DDR lpar address, LV1_ILLEGAL_PARAMETER_VALUE (-17) if any other bit set in R7 than described above

This function creates a mapping in GPU address space so that the RSX can access system RAM. The Kernel uses it to associate the virtual framebuffer residing in system RAM to the GPU, so that so that transfers can be initiated by the RSX from the system RAM to the video RAM using the lv1_gpu_context_attribute:fb_blit() call.

Comments:

It was previously suspected that GPU_IOIF was the address of GPU MMIO registers. However GPU_IOIF is a GPU address, not a lpar address, and therefore has no meaning on the Linux side, and cannot be directly mapped from the Linux address space. Reserving the memory block (using request_mem_region) and mapping (using ioremap) results in a block of memory that is used by Linux (nothing resembling IO registers was observed whilst single frame stepping a gfx demo). [was: As you’ve previously discovered that the top of RAM is 0x0e00 0000, GPU_IOIF here is 16Mb below that. That’s typically the size of the a graphics card PCI IO region on a PC, so given the name, I’d strongly suggest it’s not GPU memory that’s being mapped but the GPU IO registers. Although why this address range would overlap with RAM is a mystery.]

GPU_IOIF was successfully set to other values (0×00000000, 0×02000000, 0×04000000) with Linux booting and displaying correctly. A value of 0x0f000000 causes the PS3 to hang (need to retest 0x0e0000000)

Although it looks like GPU_IOIF would overlap video RAM, the RSX differentiates between the two by associating different DMA objects to the source and destination of the blit. The source is associated with DMA object handle 0xfeed0001 which targets system memory, while the destination is associated with DMA object handle 0xfeed0000 which targets video memory. This has been observed by analysing the FIFO commands sent to the GPU by the hypervisor during the lv1_gpu_context_attribute:fb_setup() and lv1_gpu_context_attribute:fb_blit() calls.

It seems a call to lv1_gpu_context_iomap(handle, bus_addr, xdr_lpar, size, flags) is equivalent to a series of call to lv1_put_iopte:

int i;
int context_number; /* derived from handle, 1st allocated context 0, 2nd allocated context 1, etc... */

for (i = 0; i < size; i += 1024 * 1024) {
	lv1_put_iopte(0,             /* IO ASID */
		      ((0x08ULL + context_number) << 28) | bus_addr) + i, /* IO address */ 
		      xdr_lpar + i, /* Logical Partition address */
	              1,            /* PS3_AUDIO_IOID, actually RSX IOID */
		      flags);
}

Tested by replacing the call to lv1_gpu_context_iomap with the code above in ps3fb.c.


lv1_undocumented_function_222[edit | edit source]

Located @ 0x20D648 in 3.15 HV.

Does something with GPU Register 0x140, doesn't take arguments or return anything.


lv1_gpu_context_attribute[edit | edit source]

This is a multifunction call.

General Case[edit | edit source]

Abstract Call[edit | edit source]
status = lv1_gpu_context_attribute(ps3fb.context_handle, operation_code, 

p1, p2, p3, p4 );

Parameters[edit | edit source]
Inputs
Register Description
R3 ps3fb.context_handle as allocated by lv1_gpu_context_allocate
R4 operation_code - The code of the operation to perform.
R5 p1 - Parameter 1 to the operation
R6 p2 - Parameter 2 to the operation
R7 p3 - Parameter 3 to the operation
R8 p4 - Parameter 4 to the operation
Outputs
Register Description
R3 Status - 0 = OK, Other values are unknown, but indicate failure.
Operations[edit | edit source]

The operation code can be one of the following:

Operation Code Details Address in 3.15
No Entry 0×0000 Not a valid operation, returns LV1_NO_ENTRY (-6)
L1GPU_CONTEXT_ATTRIBUTE_FIFO_SETUP 0×0001 fifo_setup 0×210910
Unknown 0×0002 fifo_pause, (rsx_ctx, 2, 0, 0, 0, 0) 0x2108ec
Unknown 0×0003 fifo_continue, (rsx_ctx, 3, 0, 0, 0, 0) 0x2107c0
No Entry 0×0004-0x00FF Not a valid operation, returns LV1_NO_ENTRY (-6)
L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_MODE_SET 0×0100 display_mode_set 0x21092c
L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_SYNC 0×0101 display_sync 0×210318
L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_FLIP 0×0102 display_flip 0×210588
Unknown 0×0103 Unknown function, returns LV1_SUCCESS(0) when called with 0,0,0,0 0×210994
Unknown 0×0104 Unknown function, returns LV1_SUCCESS(0) when called with 0,0,0,0 0×210754
Unknown 0×0105 Unknown function, returns LV1_SUCCESS(0) when called with 0,0,0,0 0×210828
Unknown 0×0106 cellGcmFunc4 ? , returns LV1_SUCCESS(0) when called with 0,0,0,0 0x2109ac
Unknown 0×0107 Unknown function, returns LV1_SUCCESS(0) when called with 0,0,0,0 – Doesn’t Exist in the 3.15 HV. N/A
Unknown 0×0108 set interrupt frequency, returns LV1_ILLEGAL_PARAMETER_VALUE(-17) when called with 0,0,0,0 0x21063c
Unknown 0×0109 Unknown function, returns LV1_SUCCESS(0) when called with 0,0,0,0 0x2104e8
Unknown 0x010A init gcm channel, (e.g. (rsx_ctx, 0x10A, 0, 0, 0x80000000, 0)) 0×210888
No Entry 0x010B-0x01FF Not a valid operation, returns LV1_NO_ENTRY (-6)
Unknown 0×0200 Crashes the PS3 when called with 0,0,0,0. See CN2 – Doesn’t exist in 3.15 N/A
Unknown 0×0201 Unknown function, returns LV1_SUCCESS(0) when called with 0,0,0,0 0×210724
Unknown 0×0202 generate rsx graphics error ?, returns LV1_SUCCESS(0) when called with 0,0,0,0. See CN3 0x21083c
No Entry 0×0203-0x02FF Not a valid operation, returns LV1_NO_ENTRY (-6)
Unknown 0×0300 tile, (set invalidate tile, set tile, bind tile, unbind tile) 0x2108c0
Unknown 0×0301 Zcull, (set Zcull, bind Zcull, unbind Zcull) 0x2104bc
Unknown 0×0302 Unknown function. found @ 0x2105E8 in the 3.15 HV 0x2105e8
No Entry 0×0303-0x03FF Not a valid operation, returns LV1_NO_ENTRY (-6)
Unknown 0×0400 Unknown function, returns LV1_SUCCESS(0) when called with 0,0,0,0 0x2109d8
No Entry 0×0401-0x05FF Not a valid operation, returns LV1_NO_ENTRY (-6)
L1GPU_CONTEXT_ATTRIBUTE_FB_SETUP 0×0600 fb_setup 0×210788
L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT 0×0601 fb_blit 0x2107ec
L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT_SYNC 0×0602 fb_blit_sync 0×210964
L1GPU_CONTEXT_ATTRIBUTE_FB_CLOSE 0×0603 Added on FW >= 2.1 and used in recent Linux kernel (called with 0,0,0,0) to undo fb_setup. Not a Valid operation on older firmware. 0×210694
No Entry 0×0604-0x0FFF Not a valid operation, returns LV1_NO_ENTRY (-6)

L1GPU_CONTEXT_ATTRIBUTE_FIFO_SETUP is undocumented and has been discovered by probing.

Notes[edit | edit source]

Probing this call by passing in an unknown operation_code and parameters of 0, seems to return a status of LV1_SUCCESS (0) whereas if the operation is not a valid id, the call returns LV1_NO_ENTRY (-6)

Crash Note 1 (CN1)[edit | edit source]

Symptoms of Crash:

No Video.
Keyboard/Mouse unresponsive.
Green Power Light lit steady.
Requires hard power off to clear (holding power button on front unresponsive).
Crash Note 2 (CN2)[edit | edit source]

Symptoms of Crash:

No Video.
Keyboard/Mouse unresponsive.
Three quick beeps from internal PS3 beeper.
Power Light lit blinks red.
Pressing power Led makes it steady red, pressing again reboots.
Crash Note 3 (CN3)[edit | edit source]

Symptoms of Crash:

Video remains on display (from time preceding call).
All video updates cease.  
Linux Kernel reports repeatedly: "lv1_gpu_context_attribute FB_BLIT failed: status -32768"
Rebooted PS3 to clear using front power button, this did not fix condition.  Hard power reset required to clear.

lv1_gpu_context_attribute:display_mode_set[edit | edit source]

Sets up the display mode? In the 3.15 firmware, this function doesn’t actually do anything. It takes 3 32bit parameters but then doesn’t do anything with them. Always returns 0.

This is a specific operation of the generic operation lv1_gpu_context_attribute(...);

Kernel Call[edit | edit source]
status = lv1_gpu_context_attribute(0x0,L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_MODE_SET,
				   0, 0, 1, 0);
Parameters[edit | edit source]
Inputs
Register Description
R3 ps3fb.context_handle as allocated by lv1_gpu_context_allocate theoretically. The Kernel actually passes 0 for this operation, so it must not be required.
R4 operation_code - L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_MODE_SET (0×100)
R5 p1 - 0 - Unknown.
R6 p2 - 0 - Unknown.
R7 head - 0 = Head A (Unfitted to the Retail PS3), 1 = Head B the active head on the PS3.
R8 p4 - 0 - unused.
Outputs
Register Description
R3 Status - 0 = OK, Other values are unknown, but indicate failure.

lv1_gpu_context_attribute:display_sync[edit | edit source]

Sets up some sort of Display Sync attribute mode.

This is a specific operation of the generic operation lv1_gpu_context_attribute(...);

Kernel Call[edit | edit source]
status = lv1_gpu_context_attribute(0x0,L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_SYNC,
				   head, L1GPU_DISPLAY_SYNC_VSYNC, 0, 0);
Parameters[edit | edit source]
Inputs
Register Description
R3 ps3fb.context_handle as allocated by lv1_gpu_context_allocate theoretically. The Kernel actually passes 0 for this operation, so it must not be required.
R4 operation_code - L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_SYNC (0×101)
R5 head - 0 = Head A (Unfitted to the PC), 1 = Head B the active head on the PS3.
R6 sync_type - L1GPU_DISPLAY_SYNC_VSYNC = Enable VSync?

Possibly also L1GPU_DISPLAY_SYNC_HSYNC = Enable HSync?

R7 p3 - 0 - Unknown, seems unused.
R8 p4 - 0 - Unknown, seems unused.
Outputs
Register Description
R3 Status - 0 = OK, Other values are unknown, but indicate failure.

lv1_gpu_context_attribute:display_flip[edit | edit source]

Set the start of the current video page in video memory.

This is a specific operation of the generic operation lv1_gpu_context_attribute(...);

Kernel Call[edit | edit source]
status = lv1_gpu_context_attribute(ps3fb.context_handle,
			           L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_FLIP,
			           head, offset, 0, 0);
Parameters[edit | edit source]
Inputs
Register Description
R3 ps3fb.context_handle as allocated by lv1_gpu_context_allocate theoretically.
R4 operation_code - L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_FLIP (0×102)
R5 head - 0 = Head A (Unfitted to the PC), 1 = Head B the active head on the PS3.
R6 offset - Offset from start of video memory to set as active displayed memory.
R7 p3 - 0 - Unknown, seems unused.
R8 p4 - 0 - Unknown, seems unused.
Outputs
Register Description
R3 Status - 0 = OK, Other values are unknown, but indicate failure.

lv1_gpu_context_attribute:fb_setup[edit | edit source]

Set the start of the current video page in video memory.

This is a specific operation of the generic operation lv1_gpu_context_attribute(...);

Kernel Call[edit | edit source]
status = lv1_gpu_context_attribute(ps3fb.context_handle,
		L1GPU_CONTEXT_ATTRIBUTE_FB_SETUP,
		xdr_lpar, ps3fb_videomemory.size,
		GPU_IOIF, 0);
Parameters[edit | edit source]
Inputs
Register Description
R3 ps3fb.context_handle as allocated by lv1_gpu_context_allocate theoretically.
R4 operation_code - L1GPU_CONTEXT_ATTRIBUTE_FB_SETUP (0×600)
R5 xdr_lpar - Address of command FIFO
R6 ps3fb_videomemory.size - Size of command FIFO
R7 GPU_IOIF = 0x0d000000UL. - GPU address of command FIFO (was: I dont know what this address is. Maybe its the address of the frame buffers in Video memory???)
R8 p4 - 0 - Unknown, seems unused.
Outputs
Register Description
R3 Status - 0 = OK, Other values are unknown, but indicate failure.

Part of patch to move FIFO from start of video memory to end:

status = lv1_gpu_context_attribute(ps3fb.context_handle,
 					   L1GPU_CONTEXT_ATTRIBUTE_FB_SETUP,
-					   xdr_lpar, ps3fb_videomemory.size,
-					   GPU_IOIF, 0);
+					   xdr_lpar + ps3fb.xdr_size,
+					   GPU_CMD_BUF_SIZE,
+					   GPU_IOIF + ps3fb.xdr_size, 0);

The memory map used to look like:

Address Description
xdr_lpar FIFO region
xdr_lpar + ??? not used
xdr_lpar + ps3fb_videomemory.size - 2 * frame size frame 2
xdr_lpar + ps3fb_videomemory.size - frame size frame 1
xdr_lpar + ps3fb_videomemory.size END

The memory map of ps3fb now looks like this:

Address Description
xdr_lpar frame 1
xdr_lpar + FB_OFF(1) frame 2
xdr_lpar + FB_OFF(2) not used
xdr_lpar + ps3fb_videomemory.size - GPU_CMD_BUF_SIZE FIFO region
xdr_lpar + ps3fb_videomemory.size END

The FIFO section of the memory range is now not mapped into Linux’s address space.

So, from that change we can see that R5 and R7 are moved by the size of the xdr_size (videomemory_size-GPU_CMD_BUF_SIZE) so both refer to the FIFO buffer in different addressing schemes (probably physical memory address and LPAR address)

More discussion on this is at http://forums.ps2dev.org/viewtopic.php?t=8364

lv1_gpu_context_attribute:fb_blit[edit | edit source]

Block Image Transfer from Main memory to GPU memory.

This is a specific operation of the generic operation lv1_gpu_context_attribute(...);

Kernel Call[edit | edit source]
status = lv1_gpu_context_attribute(ps3fb.context_handle,
			           L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT,
				   offset, fb_ioif,
				   L1GPU_FB_BLIT_WAIT_FOR_COMPLETION |
				   (xres << 16) | yres,
				   xres * BPP);	
Parameters[edit | edit source]
Inputs
Register Description
R3 ps3fb.context_handle as allocated by lv1_gpu_context_allocate theoretically.
R4 operation_code - L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT (0×601)
R5 destination GPU address (offset in video RAM).
R6 source GPU address (GPU_IOIF + offset, for system RAM mapped by lv1_gpu_context_iomap).
R7 0×0000 : 0×0000 : xres : yres - x,y size of the blit.
R8 line_length - span, number of bytes in a line. As of Firmware 1.90, lower 32-bit is destination span, upper 32-bit if not null is source span.
Outputs
Register Description
R3 Status - 0 = OK, Other values are unknown, but indicate failure.

lv1_gpu_context_attribute:fb_blit_sync[edit | edit source]

This call is never made by the Kernel

This is a specific operation of the generic operation lv1_gpu_context_attribute(...);

Abstract Call[edit | edit source]
status = lv1_gpu_context_attribute(ps3fb.context_handle,
			           L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT_SYNC,
			           p1, p2, p3, p4);
Parameters[edit | edit source]
Inputs
Register Description
R3 ps3fb.context_handle as allocated by lv1_gpu_context_allocate theoretically.
R4 ooperation_code - L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT_SYNC (0×602)
R5 p1 - Unknown.
R6 p2 - Unknown.
R7 p3 - Unknown.
R8 p4 - Unknown.
Outputs
Register Description
R3 Status - 0 = OK, Other values are unknown, but indicate failure.

I would expect this call to be very similar, if not identical to fb_blit.


lv1_gpu_context_intr[edit | edit source]

Tests the current IRQ state of the GPU

Kernel Call[edit | edit source]
status = lv1_gpu_context_intr(ps3fb.context_handle, &v1);
Parameters[edit | edit source]
Inputs
Register Description
R3 ps3fb.context_handle as allocated by lv1_gpu_context_allocate.
Outputs
Register Description
R3 Status - 0 = OK, Other values are unknown, but indicate failure.
R4 IRQ Bitmap of all pending IRQ’s. This is a bitset.

A bit = 0 means IRQ not pending, 1 = IRQ pending. Bit GPU_INTR_STATUS_VSYNC_0 = 0. IRQ for vsync on head A. Unused by Kernel Bit GPU_INTR_STATUS_VSYNC_1 = 1. IRQ for vsync on head B. Used by Kernel Bit GPU_INTR_STATUS_FLIP_0 = 2. IRQ for flip on head A. Unused by Kernel Bit GPU_INTR_STATUS_FLIP_1 = 3. IRQ for flip on head B. Unused by Kernel Bit GPU_INTR_STATUS_QUEUE_0 = 4. IRQ for queue on head A. Unused by Kernel Bit GPU_INTR_STATUS_QUEUE_1 = 5. IRQ for queue on head B. Unused by Kernel


lv1_gpu_attribute[edit | edit source]

Set a GPU attribute.

kboot Call[edit | edit source]
result = lv1_gpu_attribute( /*IN*/ p1, p2, p3, p4, p5 );
Parameters[edit | edit source]
Inputs
Register Description
R3 p1 - unknown
R4 p2 - unknown
R5 p3 - unknown
R6 p4 - unknown
R7 p5 - unknown
Outputs
Register Description
R3 Status - 0 = OK, Other values are unknown, but indicate failure.

Notes:

Code taken from kboot-10\dl\linux-2.6.16\sound\powerpc\snd_ps3pf.c (kboot-20061208)

ret64 = lv1_gpu_attribute(0x100, 0x007, val, 0, 0);
Test Results[edit | edit source]
p1 p2 p3 p4 p5 Status
0×100 0 0 0 0
0×105 0 0 0 0 0 (LV1_SUCCESS)
0×202 0 0 0 0 0 (LV1_SUCCESS)
0×400 0 0 0 0 0 (LV1_SUCCESS)
0×401 0 0 0 0 0 (LV1_SUCCESS)
0×402 0 0 0 0 0 (LV1_SUCCESS)
0×403 0 0 0 0 0 (LV1_SUCCESS)
other values in 0-0×1000000 0 0 0 0

lv1_undocumented_function_229[edit | edit source]

Existed in PAL 1.7. Returned -17 (LV1_ILLEGAL_PARAMETER_VALUE) when passed 0 in R3 to R10.

Does not exist as of PAL 3.15.


lv1_undocumented_function_230[edit | edit source]

Exists in PAL 3.15. Unknown function; found in 3.15 HV dump.


lv1_undocumented_function_231[edit | edit source]

Exists in PAL 1.7. Returns -17 (LV1_ILLEGAL_PARAMETER_VALUE), 100000000000000h, 9000000000000000h, C000000000537EF8h, F09B89AF5001h, D0000000002B3084h in R3 to R8 when passed 0 in R3 to R10.


lv1_get_rtc[edit | edit source]

Gets the current value of the PS3’s real time clock and time base value.

Kernel Call[edit | edit source]
result = lv1_get_rtc( /*OUT*/ &rtc_val, &tb_val );
Parameters[edit | edit source]
Outputs
Register Description
R3 Status - 0 = OK, Other values are unknown, but indicate failure.
R4 rtc_val - real time clock value
R5 tb_val - time base value

lv1_undocumented_function[edit | edit source]

Exists in PAL 3.15. Unknown function; found in 3.15 HV dump.


lv1_set_ppe_periodic_tracer_frequency[edit | edit source]

Not used in current kernel.

Abstract Call[edit | edit source]
result = lv1_set_ppe_periodic_tracer_frequency( /*IN*/ p1 );
Parameters[edit | edit source]
Inputs
Register Description
R3 p1 - unknown
Outputs
Register Description
R3 Status?

lv1_start_ppe_periodic_tracer[edit | edit source]

Not used in current kernel.

Abstract Call[edit | edit source]
result = lv1_start_ppe_periodic_tracer( /*IN*/ p1, p2, p3, p4, p5 );
Parameters[edit | edit source]
Inputs
Register Description
R3 p1 - unknown
R4 p2 - unknown
R5 p3 - unknown
R6 p4 - unknown
R7 p5 - unknown
Outputs
Register Description
R3 Status?

lv1_stop_ppe_periodic_tracer[edit | edit source]

Not used in current kernel.

Abstract Call[edit | edit source]
result = lv1_stop_ppe_periodic_tracer( /*IN*/ p1, /*OUT*/ &v1 );
Parameters[edit | edit source]
Inputs
Register Description
R3 p1 - unknown
Outputs
Register Description
R3 Status?
R4 v1 - Unknown

lv1_undocumented_function_243[edit | edit source]

Exists in PAL 1.7. Returns -6 (LV1_NO_ENTRY) when passed 0 in R3 to R10.


lv1_undocumented_function_244[edit | edit source]

Exists in PAL 1.7. Returns 0 (LV1_SUCCESS) when passed 0 in R3 to R10.


lv1_storage_read[edit | edit source]

Read a buffer of data from the specified device.

Kernel Call[edit | edit source]
result = lv1_storage_read( /*IN*/ dev_id, region_id, start_sector, sector_count, 0, buffer, /*OUT*/ &lv1_tag );
Parameters[edit | edit source]
Inputs
Register Description
R3 dev_id - device id
R4 region_id - ?
R5 start_sector - start sector of read
R6 sector_count - number of sectors to read
R7 0 - ? comment says /* flags */
R8 buffer - lpar address of buffer
Outputs
Register Description
R3 Status - 0 = OK, Other values are unknown, but indicate failure.
R4 lv1_tag - tag to identify operation?

lv1_storage_write[edit | edit source]

Write a buffer of data to the specified device.

Kernel Call[edit | edit source]
result = lv1_storage_write( /*IN*/ dev_id, region_id, start_sector, sector_count, 0, buffer, /*OUT*/ &lv1_tag );
Parameters[edit | edit source]
Inputs
Register Description
R3 dev_id - device id
R4 region_id - ?
R5 start_sector - start sector of write
R6 sector_count - number of sectors to write
R7 0 - ? comment says /* flags */
R8 buffer - lpar address of buffer
Outputs
Register Description
R3 Status - 0 = OK, Other values are unknown, but indicate failure.
R4 lv1_tag - tag to identify operation?

Notes: The buffer address must be nonzero – even if zero is an otherwise valid address.


lv1_undocumented_function_247[edit | edit source]

Exists in PAL 1.7. Returns -11 (LV1_WRONG_STATE) when passed 0 in R3 to R10. Does not exist as of PAL 3.15.


lv1_storage_send_device_command[edit | edit source]

Send a command to the specified device.

Kernel Call[edit | edit source]
result = lv1_storage_send_device_command( /*IN*/ dev_id, cmd_id, cmd_block, cmd_size, data_buffer, blocks, /*OUT*/ &lv1_tag );
Parameters[edit | edit source]
Inputs
Register Description
R3 dev_id - device id
R4 cmd_id - see notes
R5 cmd_block - lpar address of command block?
R6 cmd_size - size of command block?
R7 data_buffer - lpar address of data buffer?
R8 blocks - number of data blocks?
Outputs
Register Description
R3 Status - 0 = OK, Other values are unknown, but indicate failure.
R4 lv1_tag - tag to identify operation?

Notes:

Command ids specified in ps3_storage.h:

Command cmd_id
LV1_STORAGE_SEND_ATAPI_COMMAND 0x01
LV1_STORAGE_ATA_HDDOUT 0x23

lv1_storage_get_async_status[edit | edit source]

Get status of asynchronous storage operations for the specified device?

Kernel Call[edit | edit source]
result = lv1_storage_get_async_status( /*IN*/ dev_id, /*OUT*/ &lv1_tag, &lv1_status );
Parameters[edit | edit source]
Inputs
Register Description
R3 dev_id - device id
Outputs
Register Description
R3 Status - 0 = OK, Other values are unknown, but indicate failure.
R4 lv1_tag - tag to identify operation?
R5 lv1_status - 0 = OK, else error

lv1_undocumented_function_250[edit | edit source]

Storage device

Exists in PAL 1.7. Returns -11 (LV1_WRONG_STATE) when passed 0 in R3 to R10.


lv1_undocumented_function_251[edit | edit source]

Storage device

Exists in PAL 1.7. Returns -11 (LV1_WRONG_STATE) when passed 0 in R3 to R10.


lv1_undocumented_function_252[edit | edit source]

Storage device

Exists in PAL 1.7. Returns -11 (LV1_WRONG_STATE) when passed 0 in R3 to R10.


lv1_undocumented_function_253[edit | edit source]

Storage device

Exists in PAL 1.7. Returns -11 (LV1_WRONG_STATE) when passed 0 in R3 to R10.


lv1_storage_check_async_status[edit | edit source]

Check status of an asynchronous storage operation on the specified device.

Kernel Call[edit | edit source]
result = lv1_storage_check_async_status( /*IN*/ dev_id, lv1_tag, /*OUT*/ &lv1_status );
Parameters[edit | edit source]
Inputs
Register Description
R3 dev_id - device id
R4 lv1_tag - tag to identify operation?
Outputs
Register Description
R3 Status - 0 = OK, Other values are unknown, but indicate failure.
R4 lv1_status - 0 = OK, else error

lv1_panic[edit | edit source]

Panic! Causes the OtherOS to be halted.

Kernel Call[edit | edit source]
lv1_panic( /*IN*/ reboot );
Parameters[edit | edit source]
Inputs
Register Description
R3 reboot: 0 = power off, 1 = reboot after panic
Outputs
Register Description
It is not expected that this call returns, so no Outputs.

Notes:

This hypervisor call causes the PS3 to shutdown immediately, without performing any cleanup or callbacks. Remember to sync filesystems before calling this function!

It seems that any non-zero value in R3 causes a reboot after panic, rather than just 1.

The code in the kernel does all manner of things to actually reboot, including sending vuart messages to some other process running in a different LPAR. I haven’t investigated enough to see exactly what it does, but calling lv1_panic(0) from my my code in the hypervisor causes a panic with the red light flashing until the power button is pressed whereas the kernel’s shutdown code doesn’t.