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