Skip to content

gonefunctor/ariel

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

37 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

ariel

AArch64 EL2 hypervisor for QEMU virt that boots at EL2, sets up exception vectors, writes a stage 2 guest IPA space and loads a bundled EL1 diagnostic guest/an external linux image and traps privileged guest activity as well as applying compiled policy tables and exposes a UART monitor over QEMU stdio

Build/Run

make clean
make
make run

Equivalent QEMU shape

qemu-system-aarch64 \
  -M virt,virtualization=on,gic-version=3 \
  -cpu cortex-a57 \
  -m 1G \
  -nographic \
  -serial mon:stdio \
  -kernel build/hypervisor.elf

Run a Linux arm64 Image with a QEMU virt DTB

make run-linux \
  LINUX_IMAGE=/path/Image \
  LINUX_DTB=/path/qemu-virt.dtb

Or just do it with an initrd

make run-linux \
  LINUX_IMAGE=/path/Image \
  LINUX_DTB=/path/qemu-virt.dtb \
  LINUX_INITRD=/path/initrd.gz

Fetch the tested Debian installer artifacts and smoke test the Linux path

make test-linux-smoke

and complete the local gate

make test
make release

Memory

hypervisor link PA       0x40080000
guest IPA base           0x40000000
guest backing PA         0x42000000
guest RAM size           0x30000000  768 MiB
diagnostic entry IPA     0x40000000
diagnostic stack top     0x40100000
Linux Image load PA      0x42000000
Linux Image entry IPA    Image text_offset + 0x40000000
Linux initrd PA          0x46000000
Linux initrd IPA         0x44000000
Linux DTB PA             0x71e00000
Linux DTB IPA            0x6fe00000
PL011 UART PA            0x09000000
GICD PA                  0x08000000
GICR PA                  0x080a0000

S2 uses 2 MiB block mappings for guest RAM. The guest sees the IPA range 0x40000000..0x70000000 which EL2 maps onto the PA range 0x42000000..0x72000000. MMIO isn't passed through by default andkKnown device ranges are handled through policy or emulation layers

Trap Path

EL1 traps enter the EL2 vector table and the assembly path saves general registers and exception state into struct trap_frame

x0-x30
sp_el0
sp_el1
elr_el2
spsr_el2
esr_el2
far_el2
hpfar_el2

Hypercalls

enum {
    HVC_GET_HV_ID = 0,
    HVC_DUMP_LOG = 1,
    HVC_GET_STATUS = 2,
    HVC_PAUSE = 3,
    HVC_GUEST_CONSOLE_WRITE = 4,
    HVC_REPORT_EXCEPTION = 5,
};

Guest side call pattern

static inline unsigned long hvc(unsigned long op,
                                unsigned long a1,
                                unsigned long a2,
                                unsigned long a3)
{
    register unsigned long x0 asm("x0") = op;
    register unsigned long x1 asm("x1") = a1;
    register unsigned long x2 asm("x2") = a2;
    register unsigned long x3 asm("x3") = a3;

    asm volatile("hvc #0"
                 : "+r"(x0)
                 : "r"(x1), "r"(x2), "r"(x3)
                 : "memory");
    return x0;
}

Console write from guest IPA memory

const char msg[] = "guest online";
hvc(HVC_GUEST_CONSOLE_WRITE, (unsigned long)msg, sizeof(msg) - 1, 0);

Pause into the EL2 monitor:

hvc(HVC_PAUSE, 0, 0, 0);

Logs

make run 2>&1 | tee uart.log
python3 tools/log_decode.py --summary < uart.log

About

AArch64 EL2 hypervisor for QEMU virt that boots at EL2

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors