Editing HV Syscall Reference

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

The edit can be undone. Please check the comparison below to verify that this is what you want to do, and then publish the changes below to finish undoing the edit.

Latest revision Your text
Line 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 236: Line 227:
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 785: Line 775:
=== lv1_detect_pending_interrupts ===
=== lv1_detect_pending_interrupts ===


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


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


Notes:<br>
Notes:
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,274: Line 1,263:
|}
|}
----
----
=== 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,655: Line 1,636:
----
----
=== 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,928: Line 1,906:
|00000000000000 (0)
|00000000000000 (0)
|00000000000000 (0)
|00000000000000 (0)
|System Debug Flag
|
|-
|-
|sys.flash.boot.#0
|sys.flash.boot.#0
Line 2,036: Line 2,014:
|}
|}
----
----
=== lv1_modify_repository_node_value ===
=== lv1_modify_repository_node_value ===


Line 2,174: Line 2,151:
=== lv1_set_dabr ===
=== lv1_set_dabr ===


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


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


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


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


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


*DABRX
DABR_KERNEL and DABR_USER are defined in “setup.c” as follows
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,263: Line 2,224:
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.


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.
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.


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,273: Line 2,234:
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,307: Line 2,267:
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_authenticate_program_segment ===
=== lv1_undocumented_function_99 ===
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 ===
=== 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.
Exists in PAL 1.7; Returned 0 (LV1_SUCCESS) and R4 = 0x692F5D1E7h when passed 0 in R3 to R10.
----
----
=== lv1_get_total_execution_time ===
=== lv1_get_total_execution_time ===


Line 2,382: Line 2,335:
Exists in PAL 1.7. Returns the same as [[HV_Syscall_Reference#lv1_undocumented_function_105|lv1_undocumented_function_105]].
Exists in PAL 1.7. Returns the same as [[HV_Syscall_Reference#lv1_undocumented_function_105|lv1_undocumented_function_105]].
----
----
=== lv1_read_remote_file ===
=== lv1_undocumented_function_110 ===
 
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_111 ===
 
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_112 ===


===== Parameters =====
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]].
{| class="wikitable"
----
|-
=== lv1_undocumented_function_114 ===
! colspan="2" | Inputs
 
|-
Exists in PAL 1.7. Returns -17 (LV1_ILLEGAL_PARAMETER_VALUE) in R3, 0 in R4-R10. Passed 0 in R3 to R10.
!Register
----
!Description
=== lv1_undocumented_function_115 ===
|-
 
Exists in PAL 1.7. Returns -8 (LV1_TYPE_MISMATCH) in R3, 0 in R4-R10. Passed 0 in R3 to R10.
----
=== 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
|R3
|u32 type
|ioas_id - io address space id
|-
|-
|R4
|R4
|u32 *path
|segment_size - io segment size
|-
|-
|R5
|R5
|u64 offset
|io_page_size - io page size, 0xC, 0×10, 0×14
|-
|R6
|u32 *buf
|-
|R7
|u64 size
|-
|-
! colspan="2" | Outputs
! colspan="2" | Outputs
Line 2,413: Line 2,386:
|-
|-
|R3
|R3
|status - 0 = OK, LV1_TYPE_MISMATCH when type is not 1. Other values are unknown but indicate failure.
|Status - 0 = OK, Other values are unknown, but indicate failure.
|-
|-
|R4
|R4
|n_read
|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 =====


=== lv1_write_remote_file ===
result = lv1_release_io_segment( /*IN*/ ioas_id, ioif_addr );


===== Parameters =====
===== Parameters =====
Line 2,432: Line 2,418:
|-
|-
|R3
|R3
|u32 type
|ioas_id - io address space id
|-
|-
|R4
|R4
|u32 *path
|ioif_addr - io interface address
|-
|-
|R5
! colspan="2" | Outputs
|u64 offset
|-
|-
|R6
!Register
|u32 *buf
|-
|R7
|u64 size
|-
! colspan="2" | Outputs
|-
!Register
!Description
!Description
|-
|-
|R3
|R3
|status
|Status - 0 = OK, Other values are unknown, but indicate failure.
|-
|R4
|n_write
|-
|-
|}
|}
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_get_remote_file_size ===
=== lv1_allocate_ioid ===
 
Not used in current kernel.
 
===== Abstract Call =====
 
result = lv1_allocate_ioid( /*IN*/ p1, /*OUT*/ &v1 );


===== Parameters =====
===== Parameters =====
Line 2,470: Line 2,456:
|-
|-
|R3
|R3
|u32 type
|SBZ
|-
|R4
|u32 *path
|-
|-
! colspan="2" | Outputs
! colspan="2" | Outputs
Line 2,481: Line 2,464:
|-
|-
|R3
|R3
|status
|Status?
|-
|-
|R4
|R4
|file_size
|the ioid
|-
|-
|}----
|}
=== lv1_map_physical_address_region ===
 
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 =====
===== Parameters =====
Line 2,498: Line 2,492:
|-
|-
|R3
|R3
|start -  
|p1 - Unknown
|-
|-
|R4
|R4
|page_size -
|p2 - Unknown
|-
|R5
|size -  
|-
|-
! colspan="2" | Outputs
! colspan="2" | Outputs
Line 2,512: Line 2,503:
|-
|-
|R3
|R3
|Status - 0 = OK, Other values are unknown, but indicate failure.
|Status?
|-
|R4
|lpar_addr -
|-
|-
|}
|}


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


=== lv1_unmap_physical_address_region ===
Construct an outlet for a non-virtualized device interrupt.
 
===== Kernel Call =====
 
result = lv1_construct_io_irq_outlet( /*IN*/ interrupt_id, /*OUT*/ &outlet );


===== Parameters =====
===== Parameters =====
Line 2,532: Line 2,528:
|-
|-
|R3
|R3
|lpar_addr -  
|interrupt_id - interrupt id
|-
|-
! colspan="2" | Outputs
! colspan="2" | Outputs
Line 2,541: Line 2,537:
|R3
|R3
|Status - 0 = OK, Other values are unknown, but indicate failure.
|Status - 0 = OK, Other values are unknown, but indicate failure.
|-
|R4
|outlet - interrupt outlet
|-
|-
|}
|}
----
----
=== lv1_destruct_io_irq_outlet ===


=== lv1_allocate_io_segment ===
Destruct a previously constructed device interrupt outlet.


Allocate an io segment.
===== Kernel Call =====


===== kboot Call =====
  result = lv1_destruct_io_irq_outlet( /*IN*/ outlet );
 
  result = lv1_allocate_io_segment( /*IN*/ ioas_id, segment_size, io_page_size, /*OUT*/ &ioif_addr );


===== Parameters =====
===== Parameters =====
Line 2,564: Line 2,560:
|-
|-
|R3
|R3
|ioas_id - io address space id
|outlet - interrupt outlet
|-
|R4
|segment_size - io segment size
|-
|R5
|io_page_size - io page size, 0xC, 0×10, 0×14
|-
|-
! colspan="2" | Outputs
! colspan="2" | Outputs
Line 2,579: Line 2,569:
|R3
|R3
|Status - 0 = OK, Other values are unknown, but indicate failure.
|Status - 0 = OK, Other values are unknown, but indicate failure.
|-
|R4
|ioif_addr - io interface address
|-
|}
|}
----
=== lv1_map_htab ===


Notes:
Map the hash page table.


Code taken from kboot-10\dl\linux-2.6.16\sound\powerpc\snd_ps3pf.c (kboot-20061208)
===== Kernel Call =====
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.
  result = lv1_map_htab( /*IN*/ 0, /*OUT*/ &htab_addr );
 
===== kboot Call =====
 
  result = lv1_release_io_segment( /*IN*/ ioas_id, ioif_addr );


===== Parameters =====
===== Parameters =====
Line 2,610: Line 2,588:
|-
|-
|R3
|R3
|ioas_id - io address space id
|0 - Unknown (lpid?)
|-
|R4
|ioif_addr - io interface address
|-
|-
! colspan="2" | Outputs
! colspan="2" | Outputs
Line 2,621: Line 2,596:
|-
|-
|R3
|R3
|Status - 0 = OK, Other values are unknown, but indicate failure.
|Status?
|-
|-
|R4
|htab_addr - hash page table address
|}
|}


Notes:
Notes:


Code taken from kboot-10\dl\linux-2.6.16\sound\powerpc\snd_ps3pf.c (kboot-20061208)
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
ret64 = lv1_release_io_segment(0, /* io space */
    ioif_map_info_array[current_segment].ioif_addr);
----
----
=== lv1_allocate_ioid ===
=== lv1_unmap_htab ===


Not used in current kernel.
Unmap the hash page table.


===== Abstract Call =====
===== Kernel Call =====


  result = lv1_allocate_ioid( /*IN*/ p1, /*OUT*/ &v1 );
  lv1_unmap_htab( /*IN*/ htab_addr );


===== Parameters =====
===== Parameters =====
Line 2,648: Line 2,623:
|-
|-
|R3
|R3
|SBZ
|htab_addr - hash page table address
|-
|-
! colspan="2" | Outputs
! colspan="2" | Outputs
Line 2,657: Line 2,632:
|R3
|R3
|Status?
|Status?
|-
|R4
|the ioid
|-
|}
|}
----
=== lv1_undocumented_function_124 ===
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_125 ===


Notes:
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_126 ===


Info taken from kboot-10\dl\linux-2.6.16\include\asm-powerpc\lv1calltab.h (kboot-20061208)
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_release_ioid ===
=== lv1_get_version_info ===


Not used in current Kernel.
Returns PS3 firmware version information.


===== Abstract Call =====
===== Kernel Call =====


  result = lv1_release_ioid( /*IN*/ p1, p2 );
  result = lv1_get_version_info( /*OUT*/ &raw );


===== Parameters =====
===== Parameters =====
{| class="wikitable"
{| class="wikitable"
|-
|-
! colspan="2" | Inputs
! colspan="2" | Outputs
|-
|-
!Register
!Register
Line 2,684: Line 2,663:
|-
|-
|R3
|R3
|p1 - Unknown
|Status - 0 = OK, Other values are unknown, but indicate failure.
|-
|-
|R4
|R4
|p2 - Unknown
|raw - firmware data (see notes)
|-
! colspan="2" | Outputs
|-
!Register
!Description
|-
|R3
|Status?
|-
|}
|}


Notes:
Notes:


Info taken from kboot-10\dl\linux-2.6.16\include\asm-powerpc\lv1calltab.h (kboot-20061208)
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_construct_io_irq_outlet ===
=== lv1_undocumented_function_135 ===


Construct an outlet for a non-virtualized device interrupt.
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 ===


===== Kernel Call =====
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 ===


result = lv1_construct_io_irq_outlet( /*IN*/ interrupt_id, /*OUT*/ &outlet );
Exists in PAL 1.7. Returns -4 (LV1_DENIED_BY_POLICY) when passed 0 in R3-R10.
----
=== lv1_undocumented_function_138 ===


===== Parameters =====
Exists in PAL 1.7. Returns -4 (LV1_DENIED_BY_POLICY) when passed 0 in R3-R10.
{| class="wikitable"
----
|-
=== lv1_construct_lpm ===
! colspan="2" | Inputs
 
|-
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
!Register
!Description
!Description
|-
|-
|R3
|R3
|interrupt_id - interrupt id
|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
! colspan="2" | Outputs
Line 2,728: Line 2,742:
|-
|-
|R3
|R3
|Status - 0 = OK, Other values are unknown, but indicate failure.
|Status
|-
|-
|R4
|R4
|outlet - interrupt outlet
|v1 - lpm_id
|-
|R5
|v2 - outlet_id
|-
|R6
|v3 - tb_size
|-
|-
|}
|}
----
----
=== lv1_destruct_io_irq_outlet ===
=== lv1_destruct_lpm ===


Destruct a previously constructed device interrupt outlet.
Not used in current kernel.


===== Kernel Call =====
===== Abstract Call =====


  result = lv1_destruct_io_irq_outlet( /*IN*/ outlet );
  result = lv1_destruct_lpm( /*IN*/ p1 );


===== Parameters =====
===== Parameters =====
Line 2,752: Line 2,772:
|-
|-
|R3
|R3
|outlet - interrupt outlet
|p1 - lpm_id
|-
|-
! colspan="2" | Outputs
! colspan="2" | Outputs
Line 2,760: Line 2,780:
|-
|-
|R3
|R3
|Status - 0 = OK, Other values are unknown, but indicate failure.
|Status?
|-
|}
|}
----
----
=== lv1_map_htab ===
=== lv1_start_lpm ===


Map the hash page table.
Not used in current kernel.


===== Kernel Call =====
===== Abstract Call =====


  result = lv1_map_htab( /*IN*/ 0, /*OUT*/ &htab_addr );
  result = lv1_start_lpm( /*IN*/ p1 );


===== Parameters =====
===== Parameters =====
Line 2,780: Line 2,801:
|-
|-
|R3
|R3
|0 - Unknown (lpid?)
|p1 - lpm_id
|-
|-
! colspan="2" | Outputs
! colspan="2" | Outputs
Line 2,790: Line 2,811:
|Status?
|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 ===
=== lv1_stop_lpm ===


Unmap the hash page table.
Not used in current kernel.


===== Kernel Call =====
===== Abstract Call =====


  lv1_unmap_htab( /*IN*/ htab_addr );
  result = lv1_stop_lpm( /*IN*/ p1, /*OUT*/ &v1 );


===== Parameters =====
===== Parameters =====
Line 2,815: Line 2,830:
|-
|-
|R3
|R3
|htab_addr - hash page table address
|p1 - Unknown
|-
|-
! colspan="2" | Outputs
! colspan="2" | Outputs
Line 2,824: Line 2,839:
|R3
|R3
|Status?
|Status?
|-
|R4
|v1 - Unknown
|-
|}
|}
----
----
=== lv1_read_remote_file_long_name ===
=== 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 =====
===== Parameters =====
Line 2,837: Line 2,862:
|-
|-
|R3
|R3
|u32 type
|p1 - lpm_id
|-
|-
|R4
|R3
|u32 *path
|p2 - offset
|-
|-
|R5
|R3
|u32 path_len
|p3 - request
|-
|R6
|u64 offset
|-
|R7
|u32 *buf
|-
|R8
|u64 size
|-
|-
! colspan="2" | Outputs
! colspan="2" | Outputs
Line 2,860: Line 2,876:
|-
|-
|R3
|R3
|status
|Status
|-
|-
|R4
|R4
|n_read
|v1 - tmp
|-
|-
|}
|}
----
----
=== lv1_write_remote_file_long_name ===
=== lv1_add_lpm_event_bookmark ===
 
Not in current kernel.
 
===== Abstract Call =====
 
result = lv1_add_lpm_event_bookmark( /*IN*/ p1, p2, p3, p4, p5 );


===== Parameters =====
===== Parameters =====
Line 2,878: Line 2,900:
|-
|-
|R3
|R3
|u32 type
|p1 - Unknown
|-
|-
|R4
|R3
|u32 *path
|p2 - Unknown
|-
|-
|R5
|R3
|u32 path_len
|p3 - Unknown
|-
|-
|R6
|R6
|u64 offset
|p4 - Unknown
|-
|-
|R7
|R7
|u32 *buf
|p5 - Unknown
|-
|R8
|u64 size
|-
|-
! colspan="2" | Outputs
! colspan="2" | Outputs
Line 2,901: Line 2,920:
|-
|-
|R3
|R3
|status
|Status?
|-
|R4
|n_write
|-
|-
|}
|}
----
----
=== lv1_get_remote_file_size_long_name ===
=== lv1_delete_lpm_event_bookmark ===
 
Not used in current kernel.
 
===== Abstract Call =====
 
result = lv1_delete_lpm_event_bookmark( /*IN*/ p1, p2, p3 );


===== Parameters =====
===== Parameters =====
Line 2,919: Line 2,941:
|-
|-
|R3
|R3
|u32 type
|p1 - Unknown
|-
|-
|R4
|R3
|u32 *path
|p2 - Unknown
|-
|-
|R5
|R3
|u32 path_len
|p3 - Unknown
|-
|-
! colspan="2" | Outputs
! colspan="2" | Outputs
Line 2,933: Line 2,955:
|-
|-
|R3
|R3
|status
|Status?
|-
|R4
|file_size
|-
|-
|}
|}
----
----
=== lv1_get_version_info ===
=== lv1_set_lpm_interrupt_mask ===


Returns PS3 firmware version information.
Not used in current kernel.


===== Kernel Call =====
===== Abstract Call =====


  result = lv1_get_version_info( /*OUT*/ &raw );
  result = lv1_set_lpm_interrupt_mask( /*IN*/ p1, p2, p3, /*OUT*/ &v1 );


===== Parameters =====
===== Parameters =====
{| class="wikitable"
{| class="wikitable"
|-
! colspan="2" | Inputs
|-
!Register
!Description
|-
|R3
|p1 - Unknown
|-
|R3
|p2 - Unknown
|-
|R3
|p3 - Unknown
|-
|-
! colspan="2" | Outputs
! colspan="2" | Outputs
Line 2,957: Line 2,990:
|-
|-
|R3
|R3
|Status - 0 = OK, Other values are unknown, but indicate failure.
|Status?
|-
|-
|R4
|R4
|raw - firmware data (see notes)
|v1 - Unknown
|-
|}
|}
----
=== lv1_get_lpm_interrupt_status ===


Notes:
Not used in current kernel.


The firmware information is accessed using the following union:
===== Abstract Call =====
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.
result = lv1_get_lpm_interrupt_status( /*IN*/ p1, /*OUT*/ &v1 );
----
=== 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]].
===== Parameters =====
----
{| class="wikitable"
=== lv1_undocumented_function_136 ===
|-
 
! colspan="2" | Inputs
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]].
|-
!Register
!Description
|-
|R3
|p1 - Unknown
|-
! colspan="2" | Outputs
|-
!Register
!Description
|-
|R3
|Status?
|-
|R4
|v1 - Unknown
|-
|}
----
----
=== lv1_undocumented_function_137 ===
=== lv1_set_lpm_general_control ===
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.
Not used in current kernel.
Line 3,006: Line 3,035:
===== Abstract Call =====
===== Abstract Call =====


  result = lv1_construct_lpm( /*IN*/ p1, p2, p3, p4, p5, p6, /*OUT*/ &v1, &v2, &v3 );
  result = lv1_set_lpm_general_control( /*IN*/ p1, p2, p3, p4, p5, /*OUT*/ &v1, &v2 );


===== Parameters =====
===== Parameters =====
Line 3,017: Line 3,046:
|-
|-
|R3
|R3
|p1 - node_id, this is the node id of the processor, 0 is only valid value
|p1 - Unknown
|-
|-
|R4
|R4
|p2 - tb_type, 0 is none, 1 is internal
|p2 - Unknown
|-
|-
|R5
|R5
|p3 - Unknown, is 0
|p3 - Unknown
|-
|-
|R6
|R6
|p4 - Unknown, is 0
|p4 - Unknown
|-
|-
|R7
|R7
|p5 - tb_cache in lpar, 128 byte aligned
|p5 - Unknown
|-
|-
|R8
! colspan="2" | Outputs
|p6 - tb_cache_size
|-
! colspan="2" | Outputs
|-
|-
!Register
!Register
Line 3,040: Line 3,066:
|-
|-
|R3
|R3
|Status
|Status?
|-
|-
|R4
|R4
|v1 - lpm_id
|v1 - Unknown
|-
|-
|R5
|R5
|v2 - outlet_id
|v2 - Unknown
|-
|R6
|v3 - tb_size
|-
|-
|}
|}
----
----
=== lv1_destruct_lpm ===
=== lv1_set_lpm_interval ===


Not used in current kernel.
Not used in current kernel.
Line 3,059: Line 3,082:
===== Abstract Call =====
===== Abstract Call =====


  result = lv1_destruct_lpm( /*IN*/ p1 );
  result = lv1_set_lpm_interval( /*IN*/ p1, p2, p3, /*OUT*/ &v1 );


===== Parameters =====
===== Parameters =====
Line 3,070: Line 3,093:
|-
|-
|R3
|R3
|p1 - lpm_id
|p1 - Unknown
|-
|R4
|p2 - Unknown
|-
|R5
|p3 - Unknown
|-
|-
! colspan="2" | Outputs
! colspan="2" | Outputs
Line 3,079: Line 3,108:
|R3
|R3
|Status?
|Status?
|-
|R4
|v1 - Unknown
|-
|-
|}
|}
----
----
=== lv1_start_lpm ===
=== lv1_set_lpm_trigger_control ===


Not used in current kernel.
Not used in current kernel.
Line 3,088: Line 3,120:
===== Abstract Call =====
===== Abstract Call =====


  result = lv1_start_lpm( /*IN*/ p1 );
  result = lv1_set_lpm_trigger_control( /*IN*/ p1, p2, p3, /*OUT*/ &v1 );


===== Parameters =====
===== Parameters =====
Line 3,099: Line 3,131:
|-
|-
|R3
|R3
|p1 - lpm_id
|p1 - Unknown
|-
|R4
|p2 - Unknown
|-
|R5
|p3 - Unknown
|-
|-
! colspan="2" | Outputs
! colspan="2" | Outputs
Line 3,108: Line 3,146:
|R3
|R3
|Status?
|Status?
|-
|R4
|v1 - Unknown
|-
|-
|}
|}
----
----
=== lv1_stop_lpm ===
=== lv1_set_lpm_counter_control ===


Not used in current kernel.
Not used in current kernel.
Line 3,117: Line 3,158:
===== Abstract Call =====
===== Abstract Call =====


  result = lv1_stop_lpm( /*IN*/ p1, /*OUT*/ &v1 );
  result = lv1_set_lpm_counter_control( /*IN*/ p1, p2, p3, p4, /*OUT*/ &v1 );


===== Parameters =====
===== Parameters =====
Line 3,130: Line 3,171:
|p1 - Unknown
|p1 - Unknown
|-
|-
! colspan="2" | Outputs
|R4
|p2 - Unknown
|-
|R5
|p3 - Unknown
|-
|R6
|p4 - Unknown
|-
! colspan="2" | Outputs
|-
|-
!Register
!Register
Line 3,143: Line 3,193:
|}
|}
----
----
=== lv1_copy_lpm_trace_buffer ===
=== lv1_set_lpm_group_control ===


Not used in current kernel.
Not used in current kernel.
Line 3,149: Line 3,199:
===== Abstract Call =====
===== Abstract Call =====


  result = lv1_copy_lpm_trace_buffer( /*IN*/ p1, p2, p3 /*OUT*/ &v1 );
  result = lv1_set_lpm_group_control( /*IN*/ p1, p2, p3, /*OUT*/ &v1 );


===== Parameters =====
===== Parameters =====
Line 3,160: Line 3,210:
|-
|-
|R3
|R3
|p1 - lpm_id
|p1 - Unknown
|-
|-
|R3
|R4
|p2 - offset
|p2 - Unknown
|-
|-
|R3
|R5
|p3 - request
|p3 - Unknown
|-
|-
! colspan="2" | Outputs
! colspan="2" | Outputs
Line 3,174: Line 3,224:
|-
|-
|R3
|R3
|Status
|Status?
|-
|-
|R4
|R4
|v1 - tmp
|v1 - Unknown
|-
|-
|}
|}
----
----
=== lv1_add_lpm_event_bookmark ===
=== lv1_set_lpm_debug_bus_control ===


Not in current kernel.
Not used in current kernel.


===== Abstract Call =====
===== Abstract Call =====


  result = lv1_add_lpm_event_bookmark( /*IN*/ p1, p2, p3, p4, p5 );
  result = lv1_set_lpm_debug_bus_control( /*IN*/ p1, p2, p3, /*OUT*/ &v1 );


===== Parameters =====
===== Parameters =====
Line 3,200: Line 3,250:
|p1 - Unknown
|p1 - Unknown
|-
|-
|R3
|R4
|p2 - Unknown
|p2 - Unknown
|-
|-
|R3
|R5
|p3 - Unknown
|p3 - Unknown
|-
|R6
|p4 - Unknown
|-
|R7
|p5 - Unknown
|-
|-
! colspan="2" | Outputs
! colspan="2" | Outputs
Line 3,219: Line 3,263:
|R3
|R3
|Status?
|Status?
|-
|R4
|v1 - Unknown
|-
|-
|}
|}
----
----
=== lv1_delete_lpm_event_bookmark ===
=== lv1_set_lpm_counter ===


Not used in current kernel.
Not used in current kernel.
Line 3,228: Line 3,275:
===== Abstract Call =====
===== Abstract Call =====


  result = lv1_delete_lpm_event_bookmark( /*IN*/ p1, p2, p3 );
  result = lv1_set_lpm_counter( /*IN*/ p1, p2, p3, p4, p5, /*OUT*/ &v1, &v2 );


===== Parameters =====
===== Parameters =====
Line 3,241: Line 3,288:
|p1 - Unknown
|p1 - Unknown
|-
|-
|R3
|R4
|p2 - Unknown
|p2 - Unknown
|-
|-
|R3
|R5
|p3 - Unknown
|p3 - Unknown
|-
|R6
|p4 - Unknown
|-
|R7
|p5 - Unknown
|-
|-
! colspan="2" | Outputs
! colspan="2" | Outputs
Line 3,254: Line 3,307:
|R3
|R3
|Status?
|Status?
|-
|R4
|v1 - Unknown
|-
|R5
|v2 - Unknown
|-
|-
|}
|}
----
----
=== lv1_set_lpm_interrupt_mask ===
=== lv1_set_lpm_signal ===


Not used in current kernel.
Not used in current kernel.
Line 3,263: Line 3,322:
===== Abstract Call =====
===== Abstract Call =====


  result = lv1_set_lpm_interrupt_mask( /*IN*/ p1, p2, p3, /*OUT*/ &v1 );
  result = lv1_set_lpm_signal( /*IN*/ p1, p2, p3, p4, p5, p6, p7 );


===== Parameters =====
===== Parameters =====
Line 3,276: Line 3,335:
|p1 - Unknown
|p1 - Unknown
|-
|-
|R3
|R4
|p2 - Unknown
|p2 - Unknown
|-
|-
|R3
|R5
|p3 - Unknown
|p3 - Unknown
|-
|R6
|p4 - Unknown
|-
|R7
|p5 - Unknown
|-
|R8
|p6 - Unknown
|-
|R9
|p7 - Unknown
|-
|-
! colspan="2" | Outputs
! colspan="2" | Outputs
Line 3,289: Line 3,360:
|R3
|R3
|Status?
|Status?
|-
|R4
|v1 - Unknown
|-
|-
|}
|}
----
----
=== lv1_get_lpm_interrupt_status ===
=== lv1_set_lpm_spr_trigger ===


Not used in current kernel.
Not used in current kernel.
Line 3,301: Line 3,369:
===== Abstract Call =====
===== Abstract Call =====


  result = lv1_get_lpm_interrupt_status( /*IN*/ p1, /*OUT*/ &v1 );
  result = lv1_set_lpm_spr_trigger( /*IN*/ p1, p2 );


===== Parameters =====
===== Parameters =====
Line 3,313: Line 3,381:
|R3
|R3
|p1 - Unknown
|p1 - Unknown
|-
|R4
|p2 - Unknown
|-
|-
! colspan="2" | Outputs
! colspan="2" | Outputs
Line 3,322: Line 3,393:
|Status?
|Status?
|-
|-
|R4
|}
|v1 - Unknown
|-
|}
----
----
=== lv1_set_lpm_general_control ===
=== lv1_insert_htab_entry ===


Not used in current kernel.
Used in current kernel.


===== Abstract Call =====
===== Kernel Call =====


  result = lv1_set_lpm_general_control( /*IN*/ p1, p2, p3, p4, p5, /*OUT*/ &v1, &v2 );
  result = lv1_insert_htab_entry( /*IN*/ p1, p2, p3, p4, p5, p6, /*OUT*/ &v1, &v2, &v3 );


===== Parameters =====
===== Parameters =====
Line 3,344: Line 3,412:
|-
|-
|R3
|R3
|p1 - Unknown
|p1 - htab ID, 0 or returns -6
|-
|-
|R4
|R4
|p2 - Unknown
|p2 - hpte_group, 0 or returns -17
|-
|-
|R5
|R5
|p3 - Unknown
|p3 - hpte_v
|-
|-
|R6
|R6
|p4 - Unknown
|p4 - hpte_r
|-
|-
|R7
|R7
|p5 - Unknown
|p5 - Bolted flag
|-
|R8
|p6 - flags?
|-
|-
! colspan="2" | Outputs
! colspan="2" | Outputs
Line 3,367: Line 3,438:
|-
|-
|R4
|R4
|v1 - Unknown
|v1 - inserted_index
|-
|-
|R5
|R5
|v2 - Unknown
|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_set_lpm_interval ===
=== lv1_read_virtual_uart ===


Not used in current kernel.
Read data from a VUART port into a provided buffer.


===== Abstract Call =====
===== Kernel Call =====


  result = lv1_set_lpm_interval( /*IN*/ p1, p2, p3, /*OUT*/ &v1 );
  result = lv1_read_virtual_uart( /*IN*/ port_number, buffer, bytes, /*OUT*/ bytes_read );


===== Parameters =====
===== Parameters =====
Line 3,391: Line 3,472:
|-
|-
|R3
|R3
|p1 - Unknown
|port_number - VUART port number
|-
|-
|R4
|R4
|p2 - Unknown
|buffer - pointer to buffer (must be address in lpar)
|-
|-
|R5
|R5
|p3 - Unknown
|bytes - buffer size?
|-
|-
! colspan="2" | Outputs
! colspan="2" | Outputs
Line 3,405: Line 3,486:
|-
|-
|R3
|R3
|Status?
|Status - 0 = OK, Other values are unknown, but indicate failure.
|-
|-
|R4
|R4
|v1 - Unknown
|bytes_read - number of bytes read into buffer
|-
|-
|}
|}
----
----
=== lv1_set_lpm_trigger_control ===
=== lv1_write_virtual_uart ===


Not used in current kernel.
Write a buffer of data to a VUART port.


===== Abstract Call =====
===== Kernel Call =====


  result = lv1_set_lpm_trigger_control( /*IN*/ p1, p2, p3, /*OUT*/ &v1 );
  result = lv1_write_virtual_uart( /*IN*/ port_number, buffer, bytes, /*OUT*/ bytes_written );


===== Parameters =====
===== Parameters =====
Line 3,429: Line 3,510:
|-
|-
|R3
|R3
|p1 - Unknown
|port_number - VUART port number
|-
|-
|R4
|R4
|p2 - Unknown
|buffer - pointer to buffer (must be address in lpar)
|-
|-
|R5
|R5
|p3 - Unknown
|bytes - buffer size?
|-
|-
! colspan="2" | Outputs
! colspan="2" | Outputs
Line 3,443: Line 3,524:
|-
|-
|R3
|R3
|Status?
|Status - 0 = OK, Other values are unknown, but indicate failure.
|-
|-
|R4
|R4
|v1 - Unknown
|bytes_written - number of bytes written to VUART
|-
|-
|}
|}
----
----
=== lv1_set_lpm_counter_control ===
=== lv1_set_virtual_uart_param ===


Not used in current kernel.
Set a parameter for a port on the VUART.


===== Abstract Call =====
===== Kernel Call =====


  result = lv1_set_lpm_counter_control( /*IN*/ p1, p2, p3, p4, /*OUT*/ &v1 );
  result = lv1_set_virtual_uart_param( /*IN*/ port_number, param_id, param_value );


===== Parameters =====
===== Parameters =====
Line 3,467: Line 3,548:
|-
|-
|R3
|R3
|p1 - Unknown
|port_number - VUART port number
|-
|-
|R4
|R4
|p2 - Unknown
|param_id - id of parameter to set (see notes)
|-
|-
|R5
|R5
|p3 - Unknown
|param_value - parameter value
|-
|R6
|p4 - Unknown
|-
|-
! colspan="2" | Outputs
! colspan="2" | Outputs
Line 3,484: Line 3,562:
|-
|-
|R3
|R3
|Status?
|Status - 0 = OK, Other values are unknown, but indicate failure.
|-
|R4
|v1 - Unknown
|-
|-
|}
|}
See [[HV_Syscall_Reference#lv1_get_virtual_uart_param|lv1_get_virtual_uart_param]] for parameter information.
----
----
=== lv1_set_lpm_group_control ===
=== lv1_get_virtual_uart_param ===


Not used in current kernel.
Get a parameter for a port on the VUART.


===== Abstract Call =====
===== Kernel Call =====


  result = lv1_set_lpm_group_control( /*IN*/ p1, p2, p3, /*OUT*/ &v1 );
  result = lv1_get_virtual_uart_param( /*IN*/ port_number, param_id, /*OUT*/ &param_value );


===== Parameters =====
===== Parameters =====
Line 3,508: Line 3,585:
|-
|-
|R3
|R3
|p1 - Unknown
|port_number - VUART port number
|-
|-
|R4
|R4
|p2 - Unknown
|param_id - id of parameter to set (see notes)
|-
|R5
|p3 - Unknown
|-
|-
! colspan="2" | Outputs
! colspan="2" | Outputs
Line 3,522: Line 3,596:
|-
|-
|R3
|R3
|Status?
|Status - 0 = OK, Other values are unknown, but indicate failure.
|-
|-
|R4
|R4
|v1 - Unknown
|param_value - parameter value
|-
|-
|}
|}
----
=== lv1_set_lpm_debug_bus_control ===


Not used in current kernel.
VUART parameters defined in vuart.c:
 
===== Abstract Call =====
 
result = lv1_set_lpm_debug_bus_control( /*IN*/ p1, p2, p3, /*OUT*/ &v1 );
 
===== Parameters =====
{| class="wikitable"
{| class="wikitable"
|-
|-
! colspan="2" | Inputs
!Parameter
!param_id
!Notes
|-
|-
!Register
|PARAM_TX_TRIGGER
!Description
|0
|
|-
|-
|R3
|PARAM_RX_TRIGGER
|p1 - Unknown
|1
|
|-
|-
|R4
|PARAM_INTERRUPT_MASK
|p2 - Unknown
|2
|
|-
|-
|R5
|PARAM_RX_BUF_SIZE
|p3 - Unknown
|3
|read only
|-
|-
! colspan="2" | Outputs
|PARAM_RX_BYTES
|4
|read only
|-
|-
!Register
|PARAM_TX_BUF_SIZE
!Description
|5
|read only, not referenced in current Kernel
|-
|-
|R3
|PARAM_TX_BYTES
|Status?
|6
|read only, not referenced in current Kernel
|-
|-
|R4
|PARAM_INTERRUPT_STATUS
|v1 - Unknown
|7
|read only
|-
|-
|}
|}
----
----
=== lv1_set_lpm_counter ===
=== lv1_configure_virtual_uart_irq ===


Not used in current kernel.
Configure the VUART IRQ.


===== Abstract Call =====
===== Kernel Call =====


  result = lv1_set_lpm_counter( /*IN*/ p1, p2, p3, p4, p5, /*OUT*/ &v1, &v2 );
  result = lv1_configure_virtual_uart_irq( /*IN*/ lpar_addr, /*OUT*/ &outlet );


===== Parameters =====
===== Parameters =====
Line 3,584: Line 3,661:
|-
|-
|R3
|R3
|p1 - Unknown
|lpar_addr - logical partition address of virtual uart interrupt bitmap
|-
|R4
|p2 - Unknown
|-
|R5
|p3 - Unknown
|-
|R6
|p4 - Unknown
|-
|R7
|p5 - Unknown
|-
|-
! colspan="2" | Outputs
! colspan="2" | Outputs
Line 3,604: Line 3,669:
|-
|-
|R3
|R3
|Status?
|Status - 0 = OK, Other values are unknown, but indicate failure.
|-
|-
|R4
|R4
|v1 - Unknown
|outlet - irq outlet
|-
|R5
|v2 - Unknown
|-
|-
|}
|}
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_set_lpm_signal ===
=== lv1_undocumented_function_167 ===
 
Exists on PAL 1.7. Returns -4 (LV1_DENIED_BY_POLICY) when passed 0 in R3 to R10.
----
=== lv1_undocumented_function_168 ===
 
Exists on PAL 1.7. Returns -4 (LV1_DENIED_BY_POLICY) when passed 0 in R3 to R10.
----
=== lv1_open_device ===


Not used in current kernel.
Open the device for a given bus and device id.


===== Abstract Call =====
===== Kernel Call =====


  result = lv1_set_lpm_signal( /*IN*/ p1, p2, p3, p4, p5, p6, p7 );
  result = lv1_open_device( /*IN*/ bus_id, dev_id, 0 );


===== Parameters =====
===== Parameters =====
Line 3,631: Line 3,709:
|-
|-
|R3
|R3
|p1 - Unknown
|bus_id - bus id
|-
|-
|R4
|R4
|p2 - Unknown
|dev_id - device id
|-
|-
|R5
|R5
|p3 - Unknown
|0 - Unknown
|-
|R6
|p4 - Unknown
|-
|R7
|p5 - Unknown
|-
|R8
|p6 - Unknown
|-
|R9
|p7 - Unknown
|-
|-
! colspan="2" | Outputs
! colspan="2" | Outputs
Line 3,657: Line 3,723:
|-
|-
|R3
|R3
|Status?
|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_set_lpm_spr_trigger ===
=== lv1_close_device ===


Not used in current kernel.
Close the device for a given bus and device id.


===== Abstract Call =====
===== Kernel Call =====


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


===== Parameters =====
===== Parameters =====
Line 3,678: Line 3,755:
|-
|-
|R3
|R3
|p1 - Unknown
|bus_id - bus id
|-
|-
|R4
|R4
|p2 - Unknown
|dev_id - device id
|-
|-
! colspan="2" | Outputs
! colspan="2" | Outputs
Line 3,689: Line 3,766:
|-
|-
|R3
|R3
|Status?
|Status - 0 = OK, Other values are unknown, but indicate failure.
|-
|-
|}
|}
----
----
=== lv1_insert_htab_entry ===
=== lv1_map_device_mmio_region ===


Used in current kernel.
Map an MMIO region to the specified device.


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


  result = lv1_insert_htab_entry( /*IN*/ p1, p2, p3, p4, p5, p6, /*OUT*/ &v1, &v2, &v3 );
  result = lv1_map_device_mmio_region( /*IN*/ bus_id, dev_id, bus_addr, size, page_size, /*OUT*/ &lpar_addr );


===== Parameters =====
===== Parameters =====
Line 3,710: Line 3,787:
|-
|-
|R3
|R3
|p1 - htab ID, 0 or returns -6
|bus_id - bus id
|-
|-
|R4
|R4
|p2 - hpte_group, 0 or returns -17
|dev_id - device id
|-
|-
|R5
|R5
|p3 - hpte_v
|bus_addr - address of the region
|-
|-
|R6
|R6
|p4 - hpte_r
|size - size of the region
|-
|-
|R7
|R7
|p5 - Bolted flag
|page_size - page size of the region
|-
|R8
|p6 - flags?
|-
|-
! colspan="2" | Outputs
! colspan="2" | Outputs
Line 3,733: Line 3,807:
|-
|-
|R3
|R3
|Status?
|Status - 0 = OK, Other values are unknown, but indicate failure.
|-
|-
|R4
|R4
|v1 - inserted_index
|lpar_addr - logical partition address of the mapped region
|-
|-
|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 ===
=== lv1_unmap_device_mmio_region ===


Read data from a VUART port into a provided buffer.
Unmap an MMIO region from the specified device.


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


  result = lv1_read_virtual_uart( /*IN*/ port_number, buffer, bytes, /*OUT*/ bytes_read );
  result = lv1_unmap_device_mmio_region( /*IN*/ bus_id, dev_id, lpar_addr );


===== Parameters =====
===== Parameters =====
Line 3,770: Line 3,831:
|-
|-
|R3
|R3
|port_number - VUART port number
|bus_id - bus id
|-
|-
|R4
|R4
|buffer - pointer to buffer (must be address in lpar)
|dev_id - device id
|-
|-
|R5
|R5
|bytes - buffer size?
|lpar_addr - logical partition address of the mapped region
|-
|-
! colspan="2" | Outputs
! colspan="2" | Outputs
Line 3,785: Line 3,846:
|R3
|R3
|Status - 0 = OK, Other values are unknown, but indicate failure.
|Status - 0 = OK, Other values are unknown, but indicate failure.
|-
|R4
|bytes_read - number of bytes read into buffer
|-
|-
|}
|}
----
----
=== lv1_write_virtual_uart ===
=== lv1_allocate_device_dma_region ===


Write a buffer of data to a VUART port.
Allocate a DMA region for the specified device.


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


  result = lv1_write_virtual_uart( /*IN*/ port_number, buffer, bytes, /*OUT*/ bytes_written );
  result = lv1_allocate_device_dma_region( /*IN*/ bus_id, dev_id, io_size, io_pagesize, flag, &dma_region );


===== Parameters =====
===== Parameters =====
Line 3,808: Line 3,866:
|-
|-
|R3
|R3
|port_number - VUART port number
|bus_id - bus id
|-
|-
|R4
|R4
|buffer - pointer to buffer (must be address in lpar)
|dev_id - device id
|-
|-
|R5
|R5
|bytes - buffer size?
|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
! colspan="2" | Outputs
Line 3,825: Line 3,889:
|-
|-
|R4
|R4
|bytes_written - number of bytes written to VUART
|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_set_virtual_uart_param ===
=== lv1_free_device_dma_region ===


Set a parameter for a port on the VUART.
Free a previously allocated DMA region for the specified device.


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


  result = lv1_set_virtual_uart_param( /*IN*/ port_number, param_id, param_value );
  lv1_free_device_dma_region( /*IN*/ bus_id, dev_id, dma_region );


===== Parameters =====
===== Parameters =====
Line 3,846: Line 3,912:
|-
|-
|R3
|R3
|port_number - VUART port number
|bus_id - bus id
|-
|-
|R4
|R4
|param_id - id of parameter to set (see notes)
|dev_id - device id
|-
|-
|R5
|R5
|param_value - parameter value
|dma_region - dma region address
|-
|-
! colspan="2" | Outputs
! colspan="2" | Outputs
Line 3,860: Line 3,926:
|-
|-
|R3
|R3
|Status - 0 = OK, Other values are unknown, but indicate failure.
|Status?
|-
|-
|}
|}
See [[HV_Syscall_Reference#lv1_get_virtual_uart_param|lv1_get_virtual_uart_param]] for parameter information.
----
----
=== lv1_get_virtual_uart_param ===
=== lv1_map_device_dma_region ===


Get a parameter for a port on the VUART.
Map a DMA region for the specified device.


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


  result = lv1_get_virtual_uart_param( /*IN*/ port_number, param_id, /*OUT*/ &param_value );
  result = lv1_map_device_dma_region( /*IN*/ bus_id, dev_id, lpar_addr, dma_region, size, flags );


===== Parameters =====
===== Parameters =====
Line 3,883: Line 3,947:
|-
|-
|R3
|R3
|port_number - VUART port number
|bus_id - bus id
|-
|-
|R4
|R4
|param_id - id of parameter to set (see notes)
|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
! colspan="2" | Outputs
Line 3,895: Line 3,971:
|R3
|R3
|Status - 0 = OK, Other values are unknown, but indicate failure.
|Status - 0 = OK, Other values are unknown, but indicate failure.
|-
|R4
|param_value - parameter value
|-
|-
|}
|}


VUART parameters defined in vuart.c:
Notes:
{| class="wikitable"
 
|-
In “mm.c” and “ps3_storage.c”, flags parameter is always specified as 0xf800000000000000UL. They are the same flags as the IOPTE entry ones.
!Parameter
----
!param_id
=== lv1_unmap_device_dma_region ===
!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.
Unmap a DMA region for the specified device.


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


  result = lv1_configure_virtual_uart_irq( /*IN*/ lpar_addr, /*OUT*/ &outlet );
  result = lv1_unmap_device_dma_region( /*IN*/ bus_id, dev_id, dma_region, size );


===== Parameters =====
===== Parameters =====
Line 3,959: Line 3,995:
|-
|-
|R3
|R3
|lpar_addr - logical partition address of virtual uart interrupt bitmap
|bus_id - bus id
|-
|-
! colspan="2" | Outputs
|R4
|dev_id - device id
|-
|R5
|dma_region - dma region address
|-
|R6
|size - region size
|-
! colspan="2" | Outputs
|-
|-
!Register
!Register
Line 3,968: Line 4,013:
|R3
|R3
|Status - 0 = OK, Other values are unknown, but indicate failure.
|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 ===
=== lv1_read_pci_config ===
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.
Read external PCI config. ''PS3tool only?''
----


=== lv1_undocumented_function_168 ===
===== kboot Call =====
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.
  result = lv1_read_pci_config( /*IN*/ bus_id, pci_bus_id, dev_id, func_id, offset, size, /*OUT*/ &config_data );
----
 
=== 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 =====
===== Parameters =====
Line 4,011: Line 4,033:
|-
|-
|R3
|R3
|bus_id - bus id
|bus_id - ps3 bus id
|-
|-
|R4
|R4
|dev_id - device id
|pci_bus_id - pci bus id
|-
|-
|R5
|R5
|0 - Unknown
|dev_id - pci device id
|-
|-
! colspan="2" | Outputs
|R6
|func_id - pci function
|-
|-
!Register
|R7
|offset - offset to store data within config_data
|-
|R8
|size - size of config_data
|-
! colspan="2" | Outputs
|-
!Register
!Description
!Description
|-
|-
|R3
|R3
|Status: LV1_SUCCESS (0) - OK
|Status - 0 = OK, Other values are unknown, but indicate failure.
LV1_NO_ENTRY (-6) - invalid dev_id
|-
LV1_BUSY (-9) - device already open
|R4
LV1_ILLEGAL_PARAMETER_VALUE (-17) - invalid bus_id
|config_data - pci config data
|-
|-
|}
|}
Line 4,034: Line 4,065:
Notes:
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]]).
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,
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.
(uint64_t)offset, size, &data);
 
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 ===
=== lv1_write_pci_config ===


Close the device for a given bus and device id.
Write external PCI config. ''PS3tool only?''


===== Kernel Call =====
===== kboot Call =====


result = lv1_close_device( /*IN*/ bus_id, dev_id );
result = lv1_write_pci_config( /*IN*/ bus_id, pci_bus_id, dev_id, func_id, offset, size, config_data );


===== Parameters =====
===== Parameters =====
Line 4,057: Line 4,086:
|-
|-
|R3
|R3
|bus_id - bus id
|bus_id - ps3 bus id
|-
|-
|R4
|R4
|dev_id - device id
|pci_bus_id - pci bus id
|-
|-
! colspan="2" | Outputs
|R5
|dev_id - pci device id
|-
|-
!Register
|R6
!Description
|func_id - pci function
|-
|-
|R3
|R7
|Status - 0 = OK, Other values are unknown, but indicate failure.
|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_map_device_mmio_region ===
=== lv1_read_pci_io ===


Map an MMIO region to the specified device.
Not used in current kernel.


===== Kernel Call =====
===== Abstract Call =====


  result = lv1_map_device_mmio_region( /*IN*/ bus_id, dev_id, bus_addr, size, page_size, /*OUT*/ &lpar_addr );
  result = lv1_read_pci_io( /*IN*/ p1, p2, p3, p4, /*OUT*/ &v1 );


===== Parameters =====
===== Parameters =====
Line 4,089: Line 4,142:
|-
|-
|R3
|R3
|bus_id - bus id
|p1 - Unknown
|-
|-
|R4
|R4
|dev_id - device id
|p2 - Unknown
|-
|-
|R5
|R5
|bus_addr - address of the region
|p3 - Unknown
|-
|-
|R6
|R6
|size - size of the region
|p4 - Unknown
|-
|R7
|page_size - page size of the region
|-
|-
! colspan="2" | Outputs
! colspan="2" | Outputs
Line 4,109: Line 4,159:
|-
|-
|R3
|R3
|Status - 0 = OK, Other values are unknown, but indicate failure.
|Status?
|-
|-
|R4
|R4
|lpar_addr - logical partition address of the mapped region
|v1 - Unknown
|-
|-
|}
|}
----
=== lv1_unmap_device_mmio_region ===


Unmap an MMIO region from the specified device.
Notes:


===== Kernel Call =====
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_unmap_device_mmio_region( /*IN*/ bus_id, dev_id, lpar_addr );
  result = lv1_write_pci_io( /*IN*/ p1, p2, p3, p4, p5 );


===== Parameters =====
===== Parameters =====
Line 4,133: Line 4,187:
|-
|-
|R3
|R3
|bus_id - bus id
|p1 - Unknown
|-
|-
|R4
|R4
|dev_id - device id
|p2 - Unknown
|-
|-
|R5
|R5
|lpar_addr - logical partition address of the mapped region
|p3 - Unknown
|-
|R6
|p4 - Unknown
|-
|-
! colspan="2" | Outputs
! colspan="2" | Outputs
Line 4,147: Line 4,204:
|-
|-
|R3
|R3
|Status - 0 = OK, Other values are unknown, but indicate failure.
|Status?
|-
|-
|}
|}
Notes:
Info taken from kboot-10\dl\linux-2.6.16\include\asm-powerpc\lv1calltab.h (kboot-20061208)
----
----
=== lv1_allocate_device_dma_region ===
=== 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 ===


Allocate a DMA region for the specified device.
Add multicast address to the specified network device.


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


  result = lv1_allocate_device_dma_region( /*IN*/ bus_id, dev_id, io_size, io_pagesize, flag, /*OUT*/ &dma_region );
  result = lv1_net_add_multicast_address( /*IN*/ bus_id, dev_id, addr, flag );


===== Parameters =====
===== Parameters =====
Line 4,174: Line 4,245:
|-
|-
|R5
|R5
|io_size - region size
|addr - see notes
|-
|-
|R6
|R6
|io_pagesize - specified as a PAGE_SHIFT (i.e. n where pagesize = 2^n)
|flag - see notes
|-
|R7
|flag - 0=32 bit mode, 2=8 bit mode
|-
|-
! colspan="2" | Outputs
! colspan="2" | Outputs
Line 4,190: Line 4,258:
|Status - 0 = OK, Other values are unknown, but indicate failure.
|Status - 0 = OK, Other values are unknown, but indicate failure.
|-
|-
|R4
|}
|dma_region - dma region address
 
|-
Notes:
|}


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.
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 ===


=== lv1_free_device_dma_region ===
Remove multicast address on the specified network device.
 
Free a previously allocated DMA region for the specified device.


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


  lv1_free_device_dma_region( /*IN*/ bus_id, dev_id, dma_region );
  result = lv1_net_remove_multicast_address( /*IN*/ bus_id, dev_id, 0, 1 );


===== Parameters =====
===== Parameters =====
Line 4,221: Line 4,287:
|-
|-
|R5
|R5
|dma_region - dma region address
|0 - Unknown
|-
|R6
|1 - Unknown
|-
|-
! colspan="2" | Outputs
! colspan="2" | Outputs
Line 4,229: Line 4,298:
|-
|-
|R3
|R3
|Status?
|Status - 0 = OK, Other values are unknown, but indicate failure.
|-
|-
|}
|}
----
----
=== lv1_map_device_dma_region ===
=== lv1_net_start_tx_dma ===


Map a DMA region for the specified device.
Start DMA transmit on the specified network device.


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


  result = lv1_map_device_dma_region( /*IN*/ bus_id, dev_id, lpar_addr, dma_region, size, flags );
  result = lv1_net_start_tx_dma( /*IN*/ bus_id, dev_id, bus_addr, 0 );


===== Parameters =====
===== Parameters =====
Line 4,256: Line 4,325:
|-
|-
|R5
|R5
|lpar_addr - logical partition address
|bus_addr - dma address?
|-
|-
|R6
|R6
|dma_region - dma region address
|0 - Unknown
|-
|R7
|size - region size
|-
|R8
|flags - see notes
|-
|-
! colspan="2" | Outputs
! colspan="2" | Outputs
Line 4,276: Line 4,339:
|-
|-
|}
|}
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 ===
=== lv1_net_stop_tx_dma ===


Unmap a DMA region for the specified device.
Stop DMA transmit on the specified network device.


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


  result = lv1_unmap_device_dma_region( /*IN*/ bus_id, dev_id, dma_region, size );
  result = lv1_net_stop_tx_dma( /*IN*/ bus_id, dev_id, 0 );


===== Parameters =====
===== Parameters =====
Line 4,304: Line 4,363:
|-
|-
|R5
|R5
|dma_region - dma region address
|0 - Unknown
|-
|R6
|size - region size
|-
|-
! colspan="2" | Outputs
! colspan="2" | Outputs
Line 4,319: Line 4,375:
|}
|}
----
----
=== lv1_read_pci_config ===
=== lv1_net_start_rx_dma ===


Read external PCI config. ''PS3tool only?''
Start DMA receive on the specified network device.


===== kboot Call =====
===== Kernel Call =====


  result = lv1_read_pci_config( /*IN*/ bus_id, pci_bus_id, dev_id, func_id, offset, size, /*OUT*/ &config_data );
  result = lv1_net_start_rx_dma( /*IN*/ bus_id, dev_id, bus_addr, 0 );


===== Parameters =====
===== Parameters =====
Line 4,336: Line 4,392:
|-
|-
|R3
|R3
|bus_id - ps3 bus id
|bus_id - bus id
|-
|-
|R4
|R4
|pci_bus_id - pci bus id
|dev_id - device id
|-
|-
|R5
|R5
|dev_id - pci device id
|bus_addr - dma address?
|-
|-
|R6
|R6
|func_id - pci function
|0 - Unknown
|-
|R7
|offset - offset to store data within config_data
|-
|R8
|size - size of config_data
|-
|-
! colspan="2" | Outputs
! colspan="2" | Outputs
Line 4,360: Line 4,410:
|R3
|R3
|Status - 0 = OK, Other values are unknown, but indicate failure.
|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 ===
=== lv1_net_stop_rx_dma ===


Write external PCI config. ''PS3tool only?''
Stop DMA receive on the specified network device.


===== kboot Call =====
===== Kernel Call =====


  result = lv1_write_pci_config( /*IN*/ bus_id, pci_bus_id, dev_id, func_id, offset, size, config_data );
  result = lv1_net_stop_rx_dma( /*IN*/ bus_id, dev_id, 0 );


===== Parameters =====
===== Parameters =====
Line 4,389: Line 4,430:
|-
|-
|R3
|R3
|bus_id - ps3 bus id
|bus_id - bus id
|-
|-
|R4
|R4
|pci_bus_id - pci bus id
|dev_id - device id
|-
|-
|R5
|R5
|dev_id - pci device id
|0 - Unknown
|-
|-
|R6
! colspan="2" | Outputs
|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
!Register
Line 4,418: Line 4,447:
|-
|-
|}
|}
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 ===
=== lv1_net_set_interrupt_status_indicator  ===


Not used in current kernel.
Set the interrupt status indicator for the specified network device.


===== Abstract Call =====
===== Kernel Call =====


  result = lv1_read_pci_io( /*IN*/ p1, p2, p3, p4, /*OUT*/ &v1 );
  result = lv1_net_set_interrupt_status_indicator( /*IN*/ bus_id, dev_id, irq_status_addr, 0 );


===== Parameters =====
===== Parameters =====
Line 4,445: Line 4,465:
|-
|-
|R3
|R3
|p1 - Unknown
|bus_id - bus id
|-
|-
|R4
|R4
|p2 - Unknown
|dev_id - device id
|-
|-
|R5
|R5
|p3 - Unknown
|irq_status_addr - lpar address of the irq status indicator
|-
|-
|R6
|R6
|p4 - Unknown
|0 - Unknown
|-
|-
! colspan="2" | Outputs
! colspan="2" | Outputs
Line 4,462: Line 4,482:
|-
|-
|R3
|R3
|Status?
|Status - 0 = OK, Other values are unknown, but indicate failure.
|-
|R4
|v1 - Unknown
|-
|-
|}
|}
----
=== lv1_net_set_interrupt_mask ===


Notes:
Sets the interrupt mask for specified network device.


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


Not used in current kernel.
  result = lv1_net_set_interrupt_mask( /*IN*/ bus_id, dev_id, mask, 0 );
 
===== Abstract Call =====
 
  result = lv1_write_pci_io( /*IN*/ p1, p2, p3, p4, p5 );


===== Parameters =====
===== Parameters =====
Line 4,490: Line 4,503:
|-
|-
|R3
|R3
|p1 - Unknown
|bus_id - bus id
|-
|-
|R4
|R4
|p2 - Unknown
|dev_id - device id
|-
|-
|R5
|R5
|p3 - Unknown
|mask - interrupt mask
|-
|-
|R6
|R6
|p4 - Unknown
|0 - Unknown
|-
|-
! colspan="2" | Outputs
! colspan="2" | Outputs
Line 4,507: Line 4,520:
|-
|-
|R3
|R3
|Status?
|Status - 0 = OK, Other values are unknown, but indicate failure.
|-
|-
|}
|}
Notes:
Info taken from kboot-10\dl\linux-2.6.16\include\asm-powerpc\lv1calltab.h (kboot-20061208)
----
----
=== lv1_undocumented_function_182 ===
=== lv1_net_control ===


Exists in PAL 3.15. Nothing known so far.
Send a control command to the specified network device.
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 =====
===== Kernel Call =====


  result = lv1_net_add_multicast_address( /*IN*/ bus_id, dev_id, addr, flag );
  result = lv1_net_control( /*IN*/ bus_id, dev_id, p1, p2, p3, p4, /*OUT*/ &v1, &v2 );


===== Parameters =====
===== Parameters =====
Line 4,548: Line 4,547:
|-
|-
|R5
|R5
|addr - see notes
|p1 - command dependent input parameter
|-
|-
|R6
|R6
|flag - see notes
|p2 - command dependent input parameter
|-
|R7
|p3 - command dependent input parameter
|-
|R8
|p4 - command dependent input parameter
|-
|-
! colspan="2" | Outputs
! colspan="2" | Outputs
Line 4,560: Line 4,565:
|R3
|R3
|Status - 0 = OK, Other values are unknown, but indicate failure.
|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 ===


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


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.
Exists in PAL 1.7. Returns -3 (LV1_NO_PRIVILEGE) when passed 0 in R3 to R10.
----
----
=== lv1_net_remove_multicast_address ===
=== lv1_connect_interrupt_event_receive_port ===


Remove multicast address on the specified network device.
Assign a virtual interrupt to a system bus device.


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


  result = lv1_net_remove_multicast_address( /*IN*/ bus_id, dev_id, 0, 1 );
  result = lv1_connect_interrupt_event_receive_port( /*IN*/ bus_id, dev_id, outlet, interrupt_id );


===== Parameters =====
===== Parameters =====
Line 4,584: Line 4,599:
|-
|-
|R3
|R3
|bus_id - bus id
|bus_id - device bus id
|-
|-
|R4
|R4
Line 4,590: Line 4,605:
|-
|-
|R5
|R5
|0 - Unknown
|outlet - interrupt outlet
|-
|-
|R6
|R6
|1 - Unknown
|interrupt_id - interrupt id
|-
|-
! colspan="2" | Outputs
! colspan="2" | Outputs
Line 4,605: Line 4,620:
|}
|}
----
----
=== lv1_net_start_tx_dma ===
=== lv1_disconnect_interrupt_event_receive_port ===


Start DMA transmit on the specified network device.
Disconnect a virtual interrupt from a system bus device.


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


  result = lv1_net_start_tx_dma( /*IN*/ bus_id, dev_id, bus_addr, 0 );
  result = lv1_disconnect_interrupt_event_receive_port( /*IN*/ bus_id, dev_id, outlet, interrupt_id );


===== Parameters =====
===== Parameters =====
Line 4,622: Line 4,637:
|-
|-
|R3
|R3
|bus_id - bus id
|bus_id - device bus id
|-
|-
|R4
|R4
Line 4,628: Line 4,643:
|-
|-
|R5
|R5
|bus_addr - dma address?
|outlet - interrupt outlet
|-
|-
|R6
|R6
|0 - Unknown
|interrupt_id - interrupt id
|-
|-
! colspan="2" | Outputs
! colspan="2" | Outputs
Line 4,643: Line 4,658:
|}
|}
----
----
=== lv1_net_stop_tx_dma ===
=== lv1_get_spe_all_interrupt_statuses ===


Stop DMA transmit on the specified network device.
Not used in current kernel.


===== Kernel Call =====
===== Abstract Call =====


  result = lv1_net_stop_tx_dma( /*IN*/ bus_id, dev_id, 0 );
  result = lv1_get_spe_all_interrupt_statuses( /*IN*/ p1, /*OUT*/ &v1 );


===== Parameters =====
===== Parameters =====
Line 4,660: Line 4,675:
|-
|-
|R3
|R3
|bus_id - bus id
|p1 - Unknown
|-
|-
|R4
! colspan="2" | Outputs
|dev_id - device id
|-
|R5
|0 - Unknown
|-
! colspan="2" | Outputs
|-
|-
!Register
!Register
Line 4,674: Line 4,683:
|-
|-
|R3
|R3
|Status - 0 = OK, Other values are unknown, but indicate failure.
|Status?
|-
|R4
|v1 - Unknown
|-
|-
|}
|}
----
----
=== lv1_net_start_rx_dma ===
=== lv1_undocumented_function_200 ===
 
Exists in PAL 1.7. Returns -4 (LV1_DENIED_BY_POLICY) when passed 0 in R3 to R10.
----
=== lv1_undocumented_function_201 ===
 
Exists in PAL 1.7. Returns -4 (LV1_DENIED_BY_POLICY) when passed 0 in R3 to R10.
----
=== lv1_deconfigure_virtual_uart_irq ===


Start DMA receive on the specified network device.
Deconfigure the VUART IRQ.


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


  result = lv1_net_start_rx_dma( /*IN*/ bus_id, dev_id, bus_addr, 0 );
  result = lv1_deconfigure_virtual_uart_irq();


===== Parameters =====
===== Parameters =====
{| class="wikitable"
{| 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
! colspan="2" | Outputs
Line 4,716: Line 4,719:
|}
|}
----
----
=== lv1_net_stop_rx_dma ===
=== lv1_enable_logical_spe ===


Stop DMA receive on the specified network device.
Enables a logical SPE.


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


  result = lv1_net_stop_rx_dma( /*IN*/ bus_id, dev_id, 0 );
  status = lv1_enable_logical_spe( /*IN*/ spe_id, resource_id );


===== Parameters =====
===== Parameters =====
Line 4,733: Line 4,736:
|-
|-
|R3
|R3
|bus_id - bus id
|spe_id - logical spe id
|-
|-
|R4
|R4
|dev_id - device id
|resource_id - spe resource id (prevously retrieved from Kernel repository)
|-
|R5
|0 - Unknown
|-
|-
! colspan="2" | Outputs
! colspan="2" | Outputs
Line 4,751: Line 4,751:
|}
|}
----
----
=== lv1_net_set_interrupt_status_indicator  ===
=== lv1_undocumented_function_209 ===
 
Exists in PAL 1.7. Returns -4 (LV1_DENIED_BY_POLICY) when passed 0 in R3 to R10.
----
=== lv1_gpu_open ===


Set the interrupt status indicator for the specified network device.
Open the GPU. Call [[HV_Syscall_Reference#lv1_gpu_close|lv1_gpu_close]] to close the GPU.


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


  result = lv1_net_set_interrupt_status_indicator( /*IN*/ bus_id, dev_id, irq_status_addr, 0 );
  status = lv1_gpu_open( /*IN*/ p1 );


===== Parameters =====
===== Parameters =====
Line 4,768: Line 4,772:
|-
|-
|R3
|R3
|bus_id - bus id
|p1 - Unknown, Kernel only ever passes 0, though other randomly chosen values seem to succeed.
|-
|R4
|dev_id - device id
|-
|R5
|irq_status_addr - lpar address of the irq status indicator
|-
|R6
|0 - Unknown
|-
|-
! colspan="2" | Outputs
! colspan="2" | Outputs
Line 4,785: Line 4,780:
|-
|-
|R3
|R3
|Status - 0 = OK, Other values are unknown, but indicate failure.
|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_net_set_interrupt_mask ===
=== lv1_gpu_close ===


Sets the interrupt mask for specified network device.
Closes the GPU. Must be called once for every call to [[HV_Syscall_Reference#lv1_gpu_open|lv1_gpu_open]].


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


  result = lv1_net_set_interrupt_mask( /*IN*/ bus_id, dev_id, mask, 0 );
  status = lv1_gpu_close();


===== Parameters =====
===== Parameters =====
{| class="wikitable"
{| class="wikitable"
|-
|-
! colspan="2" | Inputs
! colspan="2" | Outputs
|-
|-
!Register
!Register
Line 4,806: Line 4,805:
|-
|-
|R3
|R3
|bus_id - bus id
|Status - 0 = OK, Other values are unknown, but indicate failure.
|-
|-
|R4
|}
|dev_id - device id
----
|-
=== lv1_gpu_device_map ===
|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.
Map a device into logical address space. Address needs to be ioremapped before use.


===== Kernel Call =====
===== kboot Call =====


  result = lv1_net_control( /*IN*/ bus_id, dev_id, p1, p2, p3, p4, /*OUT*/ &v1, &v2 );
  result = lv1_gpu_device_map( /*IN*/ dev_id, /*OUT*/ &lpar_addr, &lpar_size );


===== Parameters =====
===== Parameters =====
Line 4,844: Line 4,826:
|-
|-
|R3
|R3
|bus_id - bus id
|dev_id - device id (see notes)
|-
|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
! colspan="2" | Outputs
Line 4,870: Line 4,837:
|-
|-
|R4
|R4
|v1 - command dependent output parameter
|lpar_addr - logical partition address of device block
|-
|-
|R5
|R5
|v2 - command dependent output parameter
|lpar_size - size of device block
|-
|-
|}
|}
----
=== lv1_undocumented_function_195 ===
WLAN Gelic device


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


=== lv1_undocumented_function_196 ===
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).
WLAN Gelic device


Exists in PAL 1.7. Returns -3 (LV1_NO_PRIVILEGE) when passed 0 in R3 to R10.
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.
----


=== lv1_connect_interrupt_event_receive_port ===
===== Test Results =====
 
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"
{| class="wikitable"
|-
|-
! colspan="2" | Inputs
! colspan="5" | lv1_gpu_device_map
|-
|-
!Register
!dev_id
!Description
!result
!lpar_addr
!lpar_size
!Comment
|-
|-
|R3
|0
|bus_id - device bus id
|ffffffffffffffef
|98d2f7d44da1ceae
|0100000000000000
|result = LV1_ILLEGAL_PARAMETER_VALUE
|-
|-
|R4
|1
|dev_id - device id
|0000000000000000
|0000300000022000
|0000000000001000
|Audio IRQ Outlet (map1_dump)
|-
|-
|R5
|2
|outlet - interrupt outlet
|0000000000000000
|00003c0000128000
|0000000000008000
|Audio_Registers (map2_dump)
|-
|-
|R6
|3
|interrupt_id - interrupt id
|0000000000000000
|0000300000026000
|0000000000001000
|??? - Any attempt to dereference this lpar_addr locks up the PS3
|-
|-
! colspan="2" | Outputs
|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)
|-
|-
!Register
|8
!Description
|0000000000000000
|000030000002B000
|0000000000001000
|video RAM at offset 0x0ff10000- (map8_dump)
|-
|-
|R3
|9-255
|Status - 0 = OK, Other values are unknown, but indicate failure.
| -20
|???
|???
|result = LV1_NOT_IMPLEMENTED
|-
|-
|}
|}
----
=== lv1_disconnect_interrupt_event_receive_port ===


Disconnect a virtual interrupt from a system bus device.
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)


===== Kernel Call =====
===== 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.


  result = lv1_disconnect_interrupt_event_receive_port( /*IN*/ bus_id, dev_id, outlet, interrupt_id );
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 =====
===== Parameters =====
Line 4,944: Line 4,959:
|-
|-
|R3
|R3
|bus_id - device bus id
|dev_id - device id (see [[HV_Syscall_Reference#lv1_gpu_device_map|lv1_gpu_device_map]])
|-
|R4
|dev_id - device id
|-
|R5
|outlet - interrupt outlet
|-
|R6
|interrupt_id - interrupt id
|-
|-
! colspan="2" | Outputs
! colspan="2" | Outputs
Line 4,961: Line 4,967:
|-
|-
|R3
|R3
|Status - 0 = OK, Other values are unknown, but indicate failure.
|Status?
|-
|-
|}
|}
Notes:
Info taken from kboot-10\dl\linux-2.6.16\sound\powerpc\snd_ps3pf.c (kboot-20061208)
----
----
=== lv1_get_spe_all_interrupt_statuses ===
=== lv1_gpu_memory_allocate ===


Not used in current kernel.
Allocate GPU memory.


===== Abstract Call =====
===== Kernel Call =====


  result = lv1_get_spe_all_interrupt_statuses( /*IN*/ p1, /*OUT*/ &v1 );
  status = lv1_gpu_memory_allocate(ddr_size, 0, 0, 0, 0, &memory_handle, &ddr_lpar);


===== Parameters =====
===== Parameters =====
Line 4,982: Line 4,992:
|-
|-
|R3
|R3
|p1 - Unknown
|ddr_size - amount of DDR to reserve? (see notes)
|-
|R4
|0 - Unknown. Max value 512*1024.
|-
|R5
|0 - Unknown. Max value 3075*1024.
|-
|R6
|0 - Unknown. Max value 15.
|-
|R7
|0 - Unknown. Max value 8.
|-
|-
! colspan="2" | Outputs
! colspan="2" | Outputs
Line 4,990: Line 5,012:
|-
|-
|R3
|R3
|Status?
|status: 0 = LV1_SUCCESS, -17 = LV1_ILLEGAL_PARAMETER_VALUE
|-
|-
|R4
|R4
|v1 - Unknown
|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.
|-
|-
|}
|}
----
=== lv1_undocumented_function_200 ===
SPE (isolation)


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


=== lv1_undocumented_function_201 ===
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]
SPE (isolation)


Exists in PAL 1.7. Returns -4 (LV1_DENIED_BY_POLICY) when passed 0 in R3 to R10.
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.
----


=== lv1_deconfigure_virtual_uart_irq ===
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.


Deconfigure the VUART IRQ.
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.


===== Kernel Call =====
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).


result = lv1_deconfigure_virtual_uart_irq();
===== Test Results =====
 
===== Parameters =====
{| class="wikitable"
{| class="wikitable"
|-
! colspan="2" | Outputs
|-
|-
!Register
!Register
!Description
!Hex
!Decimal
!Comments
|-
|-
|R3
|R3
|Status - 0 = OK, Other values are unknown, but indicate failure.
|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_enable_logical_spe ===
=== lv1_gpu_memory_free ===


Enables a logical SPE.
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 =====
===== Kernel Call =====


  status = lv1_enable_logical_spe( /*IN*/ spe_id, resource_id );
  status = lv1_gpu_memory_free(ps3fb.memory_handle);


===== Parameters =====
===== Parameters =====
Line 5,047: Line 5,105:
|-
|-
|R3
|R3
|spe_id - logical spe id
|Memory handle returned by [[HV_Syscall_Reference#lv1_gpu_memory_allocate|lv1_gpu_memory_allocate]]
|-
|R4
|resource_id - spe resource id (prevously retrieved from Kernel repository)
|-
|-
! colspan="2" | Outputs
! colspan="2" | Outputs
Line 5,062: Line 5,117:
|}
|}
----
----
=== lv1_undocumented_function_209 ===
=== lv1_gpu_context_iomap ===
SPE (isolation)


Exists in PAL 1.7. Returns -4 (LV1_DENIED_BY_POLICY) when passed 0 in R3 to R10.
Map system RAM address to GPU through the Cell FlexIO interface.
----
 
=== lv1_gpu_open ===
 
Open the GPU. Call [[HV_Syscall_Reference#lv1_gpu_close|lv1_gpu_close]] to close the GPU.


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


  status = lv1_gpu_open( /*IN*/ p1 );
  status = lv1_gpu_context_iomap(ps3fb.context_handle, GPU_IOIF,
      xdr_lpar, ps3fb_videomemory.size, 0);


===== Parameters =====
===== Parameters =====
Line 5,085: Line 5,135:
|-
|-
|R3
|R3
|p1 - Unknown, Kernel only ever passes 0, though other randomly chosen values seem to succeed.
|ps3fb.context_handle as allocated by [[HV_Syscall_Reference#lv1_gpu_context_allocate|lv1_gpu_context_allocate]]
|-
|-
! colspan="2" | Outputs
|R4
|GPU_IOIF = 0x0d000000UL - GPU address where the system RAM virtual framebuffer is remapped
|-
|-
!Register
|R5
!Description
|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)
|-
|-
|R3
|R6
|Status: 0 = LV1_SUCCESS, -6 = LV1_NO_ENTRY
|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
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
! colspan="2" | Outputs
Line 5,118: Line 5,155:
|-
|-
|R3
|R3
|Status - 0 = OK, Other values are unknown, but indicate failure.
|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
|-
|-
|}
|}
----
=== lv1_gpu_device_map ===


Map a device into logical address space. Address needs to be ioremapped before use.
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.


===== kboot Call =====
Comments:


  result = lv1_gpu_device_map( /*IN*/ dev_id, /*OUT*/ &lpar_addr, &lpar_size );
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 =====
===== Parameters =====
Line 5,139: Line 5,207:
|-
|-
|R3
|R3
|dev_id - device id (see notes)
|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
|R4
|lpar_addr - logical partition address of device block
|operation_code - The code of the operation to perform.
|-
|-
|R5
|R5
|lpar_size - size of device block
|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.
|-
|-
|}
|}


Notes:
===== Operations =====


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).
The operation code can be one of the following:
 
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"
{| class="wikitable"
|-
|-
! colspan="5" | lv1_gpu_device_map
!Operation
!Code
!Details
!Address in 3.15
|-
|-
!dev_id
|No Entry
!result
|0×0000
!lpar_addr
|Not a valid operation, returns LV1_NO_ENTRY (-6)
!lpar_size
|
!Comment
|-
|-
|0
|L1GPU_CONTEXT_ATTRIBUTE_FIFO_SETUP
|ffffffffffffffef
|0×0001
|98d2f7d44da1ceae
|fifo_setup
|0100000000000000
|0×210910
|result = LV1_ILLEGAL_PARAMETER_VALUE
|-
|-
|1
|Unknown
|0000000000000000
|0×0002
|0000300000022000
|Unknown function, returns LV1_SUCCESS(0) when called with 0,0,0,0
|0000000000001000
|0x2108ec
|Audio IRQ Outlet (map1_dump)
|-
|-
|2
|Unknown
|0000000000000000
|0×0003
|00003c0000128000
|Unknown function, returns LV1_SUCCESS(0) when called with 0,0,0,0
|0000000000008000
|0x2107c0
|Audio_Registers (map2_dump)
|-
|-
|3
|No Entry
|0000000000000000
|0×0004-0x00FF
|0000300000026000
|Not a valid operation, returns LV1_NO_ENTRY (-6)
|0000000000001000
|
|??? - Any attempt to dereference this lpar_addr locks up the PS3
|-
|-
|4
|L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_MODE_SET
|ffffffffffffffef
|0×0100
|0000300000026000
|display_mode_set
|0000000000001000
|0x21092c
|result = LV1_ILLEGAL_PARAMETER_VALUE
|-
|-
|5
|L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_SYNC
|0000000000000000
|0×0101
|0000300000028000
|display_sync
|0000000000001000
|0×210318
|??? - (map5_dump)
|-
|-
|6
|L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_FLIP
|0000000000000000
|0×0102
|0000300000029000
|display_flip
|0000000000001000
|0×210588
|??? - (map6_dump)
|-
|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
|-
|-
|7
|Unknown
|0000000000000000
|0×0105
|00003000002A0000
|Unknown function, returns LV1_SUCCESS(0) when called with 0,0,0,0
|0000000000010000
|0×210828
|??? - (map7_dump)
|-
|-
|8
|Unknown
|0000000000000000
|0×0106
|000030000002B000
|Unknown function, returns LV1_SUCCESS(0) when called with 0,0,0,0
|0000000000001000
|0x2109ac
|video RAM at offset 0x0ff10000- (map8_dump)
|-
|-
|9-255
|Unknown
| -20
|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
|result = LV1_NOT_IMPLEMENTED
|-
|-
|}
|Unknown
 
|0×0108
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)
|Unknown function, returns LV1_ILLEGAL_PARAMETER_VALUE(-17) when called with 0,0,0,0
 
|0x21063c
===== 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
|Unknown
|0×0109
|Unknown function, returns LV1_SUCCESS(0) when called with 0,0,0,0
|0x2104e8
|-
|-
!Register
|Unknown
!Description
|0x010A
|Unknown function, returns LV1_SUCCESS(0) when called with 0,0,0,0
|0×210888
|-
|-
|R3
|No Entry
|dev_id - device id (see [[HV_Syscall_Reference#lv1_gpu_device_map|lv1_gpu_device_map]])
|0x010B-0x01FF
|Not a valid operation, returns LV1_NO_ENTRY (-6)
|
|-
|-
! colspan="2" | Outputs
|Unknown
|0×0200
|Crashes the PS3 when called with 0,0,0,0. See CN2 – Doesn’t exist in 3.15
|N/A
|-
|-
!Register
|Unknown
!Description
|0×0201
|Unknown function, returns LV1_SUCCESS(0) when called with 0,0,0,0
|0×210724
|-
|-
|R3
|Unknown
|Status?
|0×0202
|Unknown function, returns LV1_SUCCESS(0) when called with 0,0,0,0. See CN3
|0x21083c
|-
|-
|}
|No Entry
 
|0×0203-0x02FF
Notes:
|Not a valid operation, returns LV1_NO_ENTRY (-6)
 
|
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
|Unknown
|0×0300
|Unknown function, returns LV1_ILLEGAL_PARAMETER_VALUE(-17) when called with 0,0,0,0
|0x2108c0
|-
|-
!Register
|Unknown
!Description
|0×0301
|Unknown function, returns LV1_ILLEGAL_PARAMETER_VALUE(-17) when called with 0,0,0,0
|0x2104bc
|-
|-
|R3
|Unknown
|ddr_size - amount of DDR to reserve? (see notes)
|0×0302
|Unknown function. found @ 0x2105E8 in the 3.15 HV
|0x2105e8
|-
|-
|R4
|No Entry
|tile_max_size in bytes. Max value 512*1024.
|0×0303-0x03FF
|Not a valid operation, returns LV1_NO_ENTRY (-6)
|
|-
|-
|R5
|Unknown
|zcull_max_size in bytes. Max value 3075*1024.
|0×0400
|Unknown function, returns LV1_SUCCESS(0) when called with 0,0,0,0
|0x2109d8
|-
|-
|R6
|No Entry
|tile_max_areas. Max value 15.
|0×0401-0x05FF
|Not a valid operation, returns LV1_NO_ENTRY (-6)
|
|-
|-
|R7
|L1GPU_CONTEXT_ATTRIBUTE_FB_SETUP
|zcull_max_areas. Max value 8.
|0×0600
|fb_setup
|0×210788
|-
|-
! colspan="2" | Outputs
|L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT
|0×0601
|fb_blit
|0x2107ec
|-
|-
!Register
|L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT_SYNC
!Description
|0×0602
|fb_blit_sync
|0×210964
|-
|-
|R3
|L1GPU_CONTEXT_ATTRIBUTE_FB_CLOSE
|status: 0 = LV1_SUCCESS, -17 = LV1_ILLEGAL_PARAMETER_VALUE
|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
|-
|-
|R4
|No Entry
|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]]??
|0×0604-0x0FFF
|-
|Not a valid operation, returns LV1_NO_ENTRY (-6)
|R5
|
|ddr_lpar - remappable address of allocated video memory, unused by Kernel.
|-
|-
|}
|}


Notes:
L1GPU_CONTEXT_ATTRIBUTE_FIFO_SETUP is undocumented and has been discovered by probing.


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]
===== Notes =====


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.
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)


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.
====== 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).


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.
====== 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 =====


To make use of the allocated DDR ddr_lpar needs to be transformed into a usable address using:
  status = lv1_gpu_context_attribute(0x0,L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_MODE_SET,
  ddr_address = ioremap_flags(ddr_lpar, ddr_size, _PAGE_NO_CACHE);
  0, 0, 1, 0);
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 =====
===== Parameters =====
{| class="wikitable"
{| class="wikitable"
|-
! colspan="2" | Inputs
|-
|-
!Register
!Register
!Hex
!Description
!Decimal
!Comments
|-
|-
|R3
|R3
|0x000000000fc00000
|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.
|(264241152)
|252 MB
|-
|-
|R4
|R4
|0×0000000000000000
|operation_code - L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_MODE_SET (0×100)
|(0)
|-
|
|-
|R5
|R5
|0×0000000000000000
|p1 - 0 - Unknown.
|(0)
|
|-
|-
|R6
|R6
|0×0000000000000000
|p2 - 0 - Unknown.
|(0)
|
|-
|-
|R7
|R7
|0×0000000000000000
|head - 0 = Head A (Unfitted to the Retail PS3), 1 = Head B the active head on the PS3.
|(0)
|
|-
|-
! colspan="4" | Outputs
|R8
|p4 - 0 - unused.
|-
|-
|R3
! colspan="2" | Outputs
|0×0000000000000000
|(0)
|LV1_SUCCESS
|-
|-
|R4
!Register
|0x000000005a5a5a5b
!Description
|(...)
|memory handle
|-
|-
|R5
|R3
|0x00007001a0000000
|Status - 0 = OK, Other values are unknown, but indicate failure.
|(...)
|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]].
==== 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 =====
===== Kernel Call =====


  status = lv1_gpu_memory_free(ps3fb.memory_handle);
  status = lv1_gpu_context_attribute(0x0,L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_SYNC,
  head, L1GPU_DISPLAY_SYNC_VSYNC, 0, 0);


===== Parameters =====
===== Parameters =====
Line 5,418: Line 5,503:
|-
|-
|R3
|R3
|Memory handle returned by [[HV_Syscall_Reference#lv1_gpu_memory_allocate|lv1_gpu_memory_allocate]]
|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
! colspan="2" | Outputs
Line 5,429: Line 5,530:
|-
|-
|}
|}
----
=== lv1_gpu_context_iomap ===


Map system RAM address to GPU through the Cell FlexIO interface.
==== 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 =====
===== Kernel Call =====


  status = lv1_gpu_context_iomap(ps3fb.context_handle, GPU_IOIF,  
  status = lv1_gpu_context_attribute(ps3fb.context_handle,
      xdr_lpar, ps3fb_videomemory.size, 0);
          L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_FLIP,
          head, offset, 0, 0);


===== Parameters =====
===== Parameters =====
Line 5,448: Line 5,552:
|-
|-
|R3
|R3
|ps3fb.context_handle as allocated by [[HV_Syscall_Reference#lv1_gpu_context_allocate|lv1_gpu_context_allocate]]
|ps3fb.context_handle as allocated by [[HV_Syscall_Reference#lv1_gpu_context_allocate|lv1_gpu_context_allocate]] theoretically.
|-
|-
|R4
|R4
|GPU_IOIF = 0x0d000000UL - GPU address where the system RAM virtual framebuffer is remapped
|operation_code - L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_FLIP (0×102)
|-
|-
|R5
|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)
|head - 0 = Head A (Unfitted to the PC), 1 = Head B the active head on the PS3.
|-
|-
|R6
|R6
|ps3fb_videomemory.size = The size of the virtual frame buffer
|offset - Offset from start of video memory to set as active displayed memory.
|-
|-
|R7
|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
|p3 - 0 - Unknown, seems unused.
|-
|R8
|p4 - 0 - Unknown, seems unused.
|-
|-
! colspan="2" | Outputs
! colspan="2" | Outputs
Line 5,468: Line 5,575:
|-
|-
|R3
|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
|Status - 0 = OK, Other values are unknown, but indicate failure.
|-
|-
|}
|}


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.
==== lv1_gpu_context_attribute:fb_setup ====


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


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.]
This is a specific operation of the generic operation [[HV_Syscall_Reference#lv1_gpu_context_attribute|lv1_gpu_context_attribute]](...);


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)
===== Kernel Call =====


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.
  status = lv1_gpu_context_attribute(ps3fb.context_handle,
 
L1GPU_CONTEXT_ATTRIBUTE_FB_SETUP,
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]]:
xdr_lpar, ps3fb_videomemory.size,
 
GPU_IOIF, 0);
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 =====
===== Parameters =====
Line 5,520: Line 5,601:
|-
|-
|R3
|R3
|ps3fb.context_handle as allocated by [[HV_Syscall_Reference#lv1_gpu_context_allocate|lv1_gpu_context_allocate]]
|ps3fb.context_handle as allocated by [[HV_Syscall_Reference#lv1_gpu_context_allocate|lv1_gpu_context_allocate]] theoretically.
|-
|-
|R4
|R4
|operation_code - The code of the operation to perform.
|operation_code - L1GPU_CONTEXT_ATTRIBUTE_FB_SETUP (0×600)
|-
|-
|R5
|R5
|p1 - Parameter 1 to the operation
|xdr_lpar - Address of command FIFO
|-
|-
|R6
|R6
|p2 - Parameter 2 to the operation
|ps3fb_videomemory.size - Size of command FIFO
|-
|-
|R7
|R7
|p3 - Parameter 3 to the operation
|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
|R8
|p4 - Parameter 4 to the operation
|p4 - 0 - Unknown, seems unused.
|-
|-
! colspan="2" | Outputs
! colspan="2" | Outputs
Line 5,547: Line 5,628:
|}
|}


===== Operations =====
Part of patch to move FIFO from start of video memory to end:
 
status = lv1_gpu_context_attribute(ps3fb.context_handle,
The operation code can be one of the following:
    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"
{| class="wikitable"
|-
|-
!Operation
!Address
!Code
!Description
!Details
!Address in 3.15
|-
|-
|No Entry
|xdr_lpar
|0×0000
|FIFO region
|Not a valid operation, returns LV1_NO_ENTRY (-6)
|
|-
|-
|L1GPU_CONTEXT_ATTRIBUTE_FIFO_SETUP
|xdr_lpar + ???
|0×0001
|not used
|fifo_setup
|0×210910
|-
|-
|Unknown
|xdr_lpar + ps3fb_videomemory.size - 2 * frame size
|0×0002
|frame 2
|fifo_pause, (rsx_ctx, 2, 0, 0, 0, 0)
|0x2108ec
|-
|-
|Unknown
|xdr_lpar + ps3fb_videomemory.size - frame size
|0×0003
|frame 1
|fifo_continue,  (rsx_ctx, 3, 0, 0, 0, 0)
|0x2107c0
|-
|-
|No Entry
|xdr_lpar + ps3fb_videomemory.size
|0×0004-0x00FF
|END
|Not a valid operation, returns LV1_NO_ENTRY (-6)
|
|-
|-
|L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_MODE_SET
|}
|0×0100
 
|display_mode_set
The memory map of ps3fb now looks like this:
|0x21092c
{| class="wikitable"
|-
|-
|L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_SYNC
!Address
|0×0101
!Description
|display_sync
|0×210318
|-
|-
|L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_FLIP
|xdr_lpar
|0×0102
|frame 1
|display_flip
|0×210588
|-
|-
|Unknown
|xdr_lpar + FB_OFF(1)
|0×0103
|frame 2
|Unknown function, returns LV1_SUCCESS(0) when called with 0,0,0,0
|0×210994
|-
|-
|Unknown
|xdr_lpar + FB_OFF(2)
|0×0104
|not used
|Unknown function, returns LV1_SUCCESS(0) when called with 0,0,0,0
|0×210754
|-
|-
|Unknown
|xdr_lpar + ps3fb_videomemory.size - GPU_CMD_BUF_SIZE
|0×0105
|FIFO region
|Unknown function, returns LV1_SUCCESS(0) when called with 0,0,0,0
|0×210828
|-
|-
|Unknown
|xdr_lpar + ps3fb_videomemory.size
|0×0106
|END
|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.
The FIFO section of the memory range is now not mapped into Linux’s address space.
|N/A
 
|-
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)
|Unknown
 
|0×0108
More discussion on this is at http://forums.ps2dev.org/viewtopic.php?t=8364
|set interrupt frequency, returns LV1_ILLEGAL_PARAMETER_VALUE(-17) when called with 0,0,0,0
 
|0x21063c
==== 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"
|-
|-
|Unknown
! colspan="2" | Inputs
|0×0109
|Unknown function, returns LV1_SUCCESS(0) when called with 0,0,0,0
|0x2104e8
|-
|-
|Unknown
!Register
|0x010A
!Description
|init gcm channel, (e.g. (rsx_ctx, 0x10A, 0, 0, 0x80000000, 0))
|0×210888
|-
|-
|No Entry
|R3
|0x010B-0x01FF
|ps3fb.context_handle as allocated by [[HV_Syscall_Reference#lv1_gpu_context_allocate|lv1_gpu_context_allocate]] theoretically.
|Not a valid operation, returns LV1_NO_ENTRY (-6)
|
|-
|-
|Unknown
|R4
|0×0200
|operation_code - L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT (0×601)
|Crashes the PS3 when called with 0,0,0,0. See CN2 – Doesn’t exist in 3.15
|N/A
|-
|-
|Unknown
|R5
|0×0201
|destination GPU address (offset in video RAM).
|Unknown function, returns LV1_SUCCESS(0) when called with 0,0,0,0
|0×210724
|-
|-
|Unknown
|R6
|0×0202
|source GPU address (GPU_IOIF + offset, for system RAM mapped by [[HV_Syscall_Reference#lv1_gpu_context_iomap|lv1_gpu_context_iomap]]).
|generate rsx graphics error ?, returns LV1_SUCCESS(0) when called with 0,0,0,0. See CN3
|0x21083c
|-
|-
|No Entry
|R7
|0×0203-0x02FF
|0×0000 : 0×0000 : xres : yres - x,y size of the blit.
|Not a valid operation, returns LV1_NO_ENTRY (-6)
|
|-
|-
|Unknown
|R8
|0×0300
|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.
|tile, (set invalidate tile, set tile, bind tile, unbind tile)
|0x2108c0
|-
|-
|Unknown
! colspan="2" | Outputs
|0×0301
|Zcull, (set Zcull, bind Zcull, unbind Zcull)
|0x2104bc
|-
|-
|Unknown
!Register
|0×0302
!Description
|Unknown function. found @ 0x2105E8 in the 3.15 HV
|0x2105e8
|-
|-
|No Entry
|R3
|0×0303-0x03FF
|Status - 0 = OK, Other values are unknown, but indicate failure.
|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
==== lv1_gpu_context_attribute:fb_blit_sync  ====
|0x2109d8
 
|-
This call is never made by the Kernel
|No Entry
 
|0×0401-0x05FF
This is a specific operation of the generic operation [[HV_Syscall_Reference#lv1_gpu_context_attribute|lv1_gpu_context_attribute]](...);
|Not a valid operation, returns LV1_NO_ENTRY (-6)
 
|
===== 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
|-
|-
|L1GPU_CONTEXT_ATTRIBUTE_FB_SETUP
!Register
|0×0600
!Description
|fb_setup
|0×210788
|-
|-
|L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT
|R3
|0×0601
|ps3fb.context_handle as allocated by [[HV_Syscall_Reference#lv1_gpu_context_allocate|lv1_gpu_context_allocate]] theoretically.
|fb_blit
|0x2107ec
|-
|-
|L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT_SYNC
|R4
|0×0602
|ooperation_code - L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT_SYNC (0×602)
|fb_blit_sync
|0×210964
|-
|-
|L1GPU_CONTEXT_ATTRIBUTE_FB_CLOSE
|R5
|0×0603
|p1 - Unknown.
|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
|R6
|0×0604-0x0FFF
|p2 - Unknown.
|Not a valid operation, returns LV1_NO_ENTRY (-6)
|
|-
|-
|}
|R7
 
|p3 - Unknown.
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
|R8
|-
|p4 - Unknown.
!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.
0 = IRQ not pending, 1 = IRQ pending.
Bit GPU_INTR_STATUS_VSYNC_0 = 0x01. IRQ for vsync on head A.
Bit GPU_INTR_STATUS_VSYNC_1 = 0x02. IRQ for vsync on head B.
Bit GPU_INTR_UNK            = 0x04. Unknown, PS2 emulators panic when bit is set.
Bit GPU_INTR_STATUS_FLIP_0  = 0x08. IRQ for flip on head A.
Bit GPU_INTR_STATUS_FLIP_1  = 0x10. IRQ for flip on head B.
Bit GPU_INTR_STATUS_QUEUE_0 = 0x20. IRQ for queue on head A.
Bit GPU_INTR_STATUS_QUEUE_1 = 0x40. IRQ for queue on head B.
All bits are unused by kernel but used by PS2 emulators, additionally GPU_INTR_STATUS_VSYNC_1 and GPU_INTR_STATUS_FLIP_1 are used in Linux RSX driver.
|-
|}
----
 
=== 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
! colspan="2" | Outputs
Line 6,666: Line 5,785:
|R3
|R3
|Status - 0 = OK, Other values are unknown, but indicate failure.
|Status - 0 = OK, Other values are unknown, but indicate failure.
|-
|R4
|lv1_status - 0 = OK, else error
|-
|-
|}
|}
I would expect this call to be very similar, if not identical to fb_blit.
----
----
=== 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>
Please note that all contributions to PS3 Developer wiki are considered to be released under the GNU Free Documentation License 1.2 (see PS3 Developer wiki:Copyrights for details). If you do not want your writing to be edited mercilessly and redistributed at will, then do not submit it here.
You are also promising us that you wrote this yourself, or copied it from a public domain or similar free resource. Do not submit copyrighted work without permission!

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

Cancel Editing help (opens in new window)