This repository contains a patch for Samsung's official kernel sources that provides KVM support on exynos boards. This can probably be applied to other Samsung exynos kernels with minor changes.
/proc/config.gz
from your device, and unzip to .config
make menuconfig
disable everything about TIMA (?) and RKP under "Boot Options" (they are incompatible with KVM), and enable KVM under "Virtualization".cntfrq_el0
, which the bootloader should have configured, is set to zero. ARM documentation states that is's only writeable from the highest privilege level (i.e.TrustZone), but readable from any privilege level (impossible to trap accesses), and guest OSes will expect it to hold the architected timer frequency (26.0 MHz). There also does not seem to be an smc
call to set this value. This means that guest OSes will need to be patched until a TrustZone exploit is found to initialize the register properly.Normally Linux needs to be booted in EL2 (HYP mode in ARM terminology) to be able to utilize the virtualization extensions. SBOOT boots the Linux kernel in EL1, but fortunately for us they implemented a backdoor in TrustZone to load and execute custom code in EL2. This interface is utilized by init/vmm.c
in Samsung's kernel to load the proprietary RKP hypervisor, and looks as follows:
#define VMM_64BIT_SMC_CALL_MAGIC 0xC2000400
#define VMM_STACK_OFFSET 4096
#define VMM_MODE_AARCH64 1
status = _vmm_goto_EL2(VMM_64BIT_SMC_CALL_MAGIC, entry_point, VMM_STACK_OFFSET, VMM_MODE_AARCH64, vmm, vmm_size);
Here _vmm_goto_EL2
is a simple wrapper around smc #0
, entry_point
is a physical address of the initialization routine, and the last two parameters are passed to it in x0
and x1
registers. To return, the initialization routine calls smc #0
with x0=0xc2000401, x1=status
(the only piece of information that was obtained by disassembling the proprietary hypervisor).
The semantics of this interface are as follows:
x1
(status
) is passed to the kernel as the return value of _vmm_goto_EL2
. If it is nonzero, the firmware resets the HYP state to default, and further hvc
calls result in an exception.sp
is set to bootcore.sp + VMM_STACK_OFFSET * core_index
. The numbering used is the same as in Linux kernel.vbar_el2
at exit from the initialization routine, and restores it to this value at some random (unknown) points. This means that the address of the exception vector can not be changed later by EL2 code.Normal KVM/ARM bootstrap process:
head.S
detects being booted in EL2 and sets the EL2 exception vector to a so-called "HYP stub" (basically a backdoor), and drops to EL1 to continue booting.vbar_el2
to point to the real exception vector.KVM/ARM bootstrap process with this patch:
mm_init()
is called from start_kernel
, a new function preinit_hyp_mode()
is called, that calls the KVM initialization code via the TrustZone backdoor (initialization code itself was also changed to exit via smc #0
instead of eret
). This point is chosen because before that that code would fail on a memory allocation, and if done too late other cores could be already running.arch/arm64/include/asm/virt.h
is replaced with a simple return 1;
What did not work:
arch/arm64/include/asm/virt.h
to fail (boot CPU booted in EL2, others in EL1).vbar_el2
handling, see above.