OPAL: Difference between revisions
[unchecked revision] | [unchecked revision] |
No edit summary |
m (Bot: Replace deprecated source tag with syntaxhighlight) |
||
(3 intermediate revisions by one other user not shown) | |||
Line 10: | Line 10: | ||
The OPAL routines use the [https://refspecs.linuxfoundation.org/ELF/ppc64/PPC-elf64abi.html SysV ABI]. |
The OPAL routines use the [https://refspecs.linuxfoundation.org/ELF/ppc64/PPC-elf64abi.html SysV ABI]. |
||
A really simple example of a trampoline routine and a hello world using it would be: |
|||
<syntaxhighlight lang="asm"> |
|||
.section .text |
|||
.align 2 |
|||
.globl opal_call |
|||
opal_call: |
|||
/* OPAL calls must be in big-endian mode */ |
|||
/* On call, r0, r3 ... should already be set to the desired values*/ |
|||
/* Assume OPAL base is in r13 and the entrypoint in r14 */ |
|||
/* Save current MSR in non-volatile r15 */ |
|||
mfmsr %r15 |
|||
/* Save return address in non-volatile r16 */ |
|||
mflr %r16 |
|||
/* Turn off the LE bit in MSR (ordinarily also do DR, IR and EE) */ |
|||
li %r11, 0x01 |
|||
andc %r11, %r15, %r11 |
|||
/* Get address of trampoline */ |
|||
bl .+4 |
|||
mflr %r12 /* 0 */ |
|||
addi %r12, %r12, 28 /* 32 bytes between the mflr and the return */ |
|||
mtlr %r12 |
|||
/* 12 */ |
|||
/* We need a return trampoline to return to little endian mode */ |
|||
/* Put the trampoline address in LR, OPAL entry in SRR0, MSR in SRR1 */ |
|||
mr %r2, %r13 |
|||
mtsrr0 %r14 |
|||
mtsrr1 %r11 |
|||
/* 24 */ |
|||
/* Do it */ |
|||
rfid |
|||
/* 28 */ |
|||
/* Trampoline here returns us to LE and restores MSR and LR */ |
|||
GO_LITTLE_ENDIAN |
|||
mtmsr %r15 |
|||
mtlr %r16 |
|||
blr |
|||
.align 2 |
|||
.globl main |
|||
main: |
|||
li %r0, 1 /* OPAL_CONSOLE_WRITE */ |
|||
li %r3, 0 /* terminal 0 */ |
|||
addi %r4, %r8, len - here /* ptr to length of string */ |
|||
addi %r5, %r8, str - here /* ptr to string start */ |
|||
bl opal_call |
|||
.section .data |
|||
len: |
|||
/* This value is read by OPAL so it must be big-endian in both modes */ |
|||
.long 0x00 |
|||
/* byte-universal form of BE .long (strend - str) */ |
|||
.byte 0 |
|||
.byte 0 |
|||
.byte 0 |
|||
.byte (strend - str) |
|||
str: |
|||
.string "Hello World!\n" |
|||
strend: |
|||
</syntaxhighlight> |
|||
==Function listing== |
==Function listing== |
||
Line 23: | Line 91: | ||
=== External Links === |
=== External Links === |
||
* [https://github.com/streaksu/microski A complete example of a Hello World OS using OPAL] |
|||
* [https://refspecs.linuxfoundation.org/ELF/ppc64/PPC-elf64abi.html PowerPC64 SysV API] |
* [https://refspecs.linuxfoundation.org/ELF/ppc64/PPC-elf64abi.html PowerPC64 SysV API] |
||
* [https://github.com/open-power/skiboot/tree/master/doc/opal-api 1987 Skiboot's OPAL API documentation] |
* [https://github.com/open-power/skiboot/tree/master/doc/opal-api 1987 Skiboot's OPAL API documentation] |
Latest revision as of 04:35, 9 June 2024
OPAL (OpenPower Abstraction Layer) is an ongoing project created by IBM in an effort of standardizing the boot environment and low-level services available across POWER systems, it was introduced with POWER8.
These low-level services are meant to be used both in boot and runtime, they consist of a series of calls that can be realized for managing different hardware-related and basic Input/Output tasks, all from getting device trees to flashing devices to a console with read/write capabilities.
Calling the functions
To access an OPAL routine, the system is required to be in big endian mode.
Each OPAL routine has a number associated to it, this number is to be loaded in R0, from there only a trampoline has to be calculated using the OPAL base and entrypoint, passed to the loaded payload in R8 and R9 respectively.
The OPAL routines use the SysV ABI.
A really simple example of a trampoline routine and a hello world using it would be:
.section .text
.align 2
.globl opal_call
opal_call:
/* OPAL calls must be in big-endian mode */
/* On call, r0, r3 ... should already be set to the desired values*/
/* Assume OPAL base is in r13 and the entrypoint in r14 */
/* Save current MSR in non-volatile r15 */
mfmsr %r15
/* Save return address in non-volatile r16 */
mflr %r16
/* Turn off the LE bit in MSR (ordinarily also do DR, IR and EE) */
li %r11, 0x01
andc %r11, %r15, %r11
/* Get address of trampoline */
bl .+4
mflr %r12 /* 0 */
addi %r12, %r12, 28 /* 32 bytes between the mflr and the return */
mtlr %r12
/* 12 */
/* We need a return trampoline to return to little endian mode */
/* Put the trampoline address in LR, OPAL entry in SRR0, MSR in SRR1 */
mr %r2, %r13
mtsrr0 %r14
mtsrr1 %r11
/* 24 */
/* Do it */
rfid
/* 28 */
/* Trampoline here returns us to LE and restores MSR and LR */
GO_LITTLE_ENDIAN
mtmsr %r15
mtlr %r16
blr
.align 2
.globl main
main:
li %r0, 1 /* OPAL_CONSOLE_WRITE */
li %r3, 0 /* terminal 0 */
addi %r4, %r8, len - here /* ptr to length of string */
addi %r5, %r8, str - here /* ptr to string start */
bl opal_call
.section .data
len:
/* This value is read by OPAL so it must be big-endian in both modes */
.long 0x00
/* byte-universal form of BE .long (strend - str) */
.byte 0
.byte 0
.byte 0
.byte (strend - str)
str:
.string "Hello World!\n"
strend:
Function listing
A complete listing can be found here, but this is a list of the most useful functions.
- OPAL_CEC_POWER_DOWN - Powers down the system.
- OPAL_CONSOLE_WRITE, OPAL_CONSOLE_READ, OPAL_CONSOLE_FLUSH, OPAL_CONSOLE_WRITE_BUFFER_SPACE - Console management, from printing to reading.
- OPAL_GET_DEVICE_TREE - Fetching a flattened device tree (FDT) for kernel use.
- OPAL_START_CPU and OPAL_RETURN_CPU - Secondary CPU management.