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