Skip to main content

Userspace Interaction with the Hypervisor

OS-Independent Breakpoints

Sometimes it's desirable to break into the kernel debugger from user software running in EL0. Inserting a BRK opcode usually results in it being intercepted by the operating system kernel. But if you want to end up directly in the kernel debugger instead, you can use the following opcode sequence:

EL1 (64-bit)

hvc #0x7242

iOS EL0 (64-bit)

mrs xzr, cntpct_el0
hvc #0x7242

Linux EL0 (64-bit), Android EL0 (64-bit)

mrs xzr, pmcr_el0
hvc #0x7242

Linux EL0 (32-bit), Android EL0 (32-bit)

mrc p15,#0,r0,c9,c12,#0
hvc #0x7242

After running this code, the device will enter a paused state. If a debugger is attached, this will result in the debugger registering a debug event (similar to a breakpoint).

Console Output from Anywhere in the VM

Sometimes, when writing patches to kernel or user applications, it's nice to be able to print output without having to ask the operating system to do so. In fact, it can be fairly hard to get to debug output from some places, such as EL0 software that has no standard output and disabled debugging calls.

This feature helps you get debug output from patches, shellcodes or maybe just helper programs without having to deal with operating system constraints.

Both EL0 and EL1 code can print directly to device console via a special HVC (hypervisor call). The form of the HVC itself depends on the environment:

EL1 (64-bit)

hvc #0x6C43

ciOS EL0 (64-bit)

mrs xzr, cntpct_el0
hvc #0x6C43

Linux EL0 (64-bit), Android EL0 (64-bit)

mrs xzr, pmcr_el0
hvc #0x6C43

Linux EL0 (32-bit), Android EL0 (32-bit)

mrc p15,#0,r0,c9,c12,#0
hvc #0x6C43

To use the HVC, set registers x0 .. x2 (or r0 .. r2 for 32-bit code) to the following values:

CONSLOG_REQ_STR:

prints a zero-terminated (C) string

x0 = 0xFFFF0000
x1 = pointer to string

CONSLOG_REQ_U64:

prints a number as hex

x0 = 0xFFFF0001
x1 = number

CONSLOG_REQ_S64:

prints a number as signed decimal

x0 = 0xFFFF0002
x1 = number

CONSLOG_REQ_HEX:

prints a buffer as hex dump

x0 = 0xFFFF0003
x1 = pointer to buffer
x2 = size in bytes

The memory printing calls (CONSLOG_REQ_STR and CONSLOG_REQ_HEX) return status in x0; if negative, the call failed. If non-negative, returns number of bytes retrieved from the buffer (or string). The other calls simply return zero in x0.

Text printed through this output path will show up in the device console, in cyan color using ANSI control characters.

An example for the string printing function, including handling EL0 page faults, is in the Corellium GitHub repository at guest-tools - the conslog program will echo its standard input to VM console (in the highly visible cyan color of hypervisor messages).