Replace the default hyp fw with UEFI on HDK855

本文最后更新于 2026年2月22日 凌晨

Brief

The hyp partition stores firmware named hyp.mbn. It is Qualcomm’s hypervisor implementation for its ARM chips, also known as QHEE (Qualcomm Hypervisor Execution Environment). QHEE provides functions such as PIL, an SMMU driver, and SMC routing. The PIL (Peripheral Image Loader) service is very important to HLOS. It helps authenticate and load subsystem images like DSPs and other firmware.

Sadly, on LA platforms, QHEE does not provide a way to replace itself, but Linux needs EL2 to set up KVM, and Windows needs EL2 to start Hyper-V. QHEE limits us from unlocking the full functionality of the chip. Thankfully, the hyp image is not signed by QTI, so we can patch it freely on unfused devices (this no longer works since 8350). I know Linaro made a U-Boot hyp image for SM8250, but I do not really like U-Boot :/. So I replaced hyp with a UEFI bootloader.

Build UEFI

mu_aloha_platforms is a UEFI repository for Qualcomm devices. It collects drivers from stock firmware and rebuilds UEFI with extra drivers for booting Windows or other OSes. HDK855 is one of the supported devices.
In the Brief section, I mentioned the PIL service. It will not work if we take over QHEE, so I removed the PIL driver in HDK855’s DXE.inc. To enable UART output, I also enabled USE_UART_GENI_FOR_SERIAL_OUTPUT in SurfaceDuo1NoSb.dsc.
Then build a DEBUG UEFI image for testing. If the build succeeds, we get an Android boot image. What we need is the kernel in that boot image. Unpacking it with MagiskBoot is a good option.

Build HYP

The default hyp image is an ELF executable file. To inspect the segments in the ELF, we can use readelf:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
> readelf -l hyp.img
Elf file type is EXEC (Executable file)
Entry point 0x85710000
There are 4 program headers, starting at offset 64

Program Headers:
Type Offset VirtAddr PhysAddr
FileSiz MemSiz Flags Align
# Signature Stuff
NULL 0x0000000000000000 0x0000000000000000 0x0000000000000000
0x0000000000000120 0x0000000000000000 0x0
NULL 0x0000000000001000 0x000000008595f000 0x000000008595f000
0x0000000000001a68 0x0000000000002000 0x1000
# useless header
LOAD 0x0000000000002000 0x0000000000000000 0x0000000000000000
0x0000000000000000 0x0000000000000000 0x1000
# The real HYP/QHEE
LOAD 0x0000000000003000 0x0000000085710000 0x0000000085710000
0x0000000000071188 0x000000000024f000 RWE 0x1000

The load address should be the same when we build our own hyp.elf. The UEFI image we built is a raw binary, so some conversion is needed. First, convert it to a linkable ELF:

1
aarch64-linux-gnu-objcopy -I binary -B aarch64 -O elf64-littleaarch64 kernel uefi.o

A linker script is needed to link it and output a statically linked ELF:

1
2
3
4
5
6
7
8
9
10
11
12
ENTRY(ELFENTRY)
PHDRS
{
data PT_LOAD FLAGS(7);
}
SECTIONS
{
. = ELFENTRY;
.data : {
*(.data*)
} : data
}

Link:

1
aarch64-linux-gnu-ld -T hyp.lds -EL --defsym=ELFENTRY=0x85710000 -Ttext=0x85710000 -z common-page-size=0x1000 -z max-page-size=0x1000 uefi.o -o uefi4hyp.elf

Check the output image with readelf:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
> readelf -l uefi4hyp.elf

Elf file type is EXEC (Executable file)
Entry point 0x85710000
There is 1 program header, starting at offset 64

Program Headers:
Type Offset VirtAddr PhysAddr
FileSiz MemSiz Flags Align
LOAD 0x0000000000001000 0x0000000085710000 0x0000000085710000
0x0000000000300070 0x0000000000300070 RWE 0x1000

Section to Segment mapping:
Segment Sections...
00 .data

Sign HYP

qtestsign is a useful tool for signing firmware with a test signature. Sign uefi4hyp.elf with the v6 + hyp command:

1
python qtestsign.py -v6 hyp -o uefi4hyp_signed.elf uefi4hyp.elf

Test UEFI

Flash the hyp firmware into the hyp partition with fastboot. After rebooting, UEFI loads successfully:
UEFI loaded as HYP

After the noisy logs, we can enter the UEFI shell:
UEFI Shell

That now looks like a normal UEFI environment! Sadly, UFS no longer works, and I have not figured out why. Thankfully, at least the SD card and USB still work.

KVM

KVM is a type-2 hypervisor solution in the Linux kernel. It is automatically initialized in EL2 when the kernel boots from EL2. Now we can try booting a Linux kernel because uefi4hyp is a bootloader that runs in EL2. The kernel also boots from EL2 after UEFI loads it.
I made an ESP partition on my SD card with a simple initrd by BigfootACA. Insert the card and press the power button!
KVM
KVM initialized successfully! Let’s check /dev too…
Check system info
Nice, it contains the KVM character device. The mini initrd does not contain QEMU, so I did not test running anything on it.

Hyper-V

Due to the lack of a working UFS driver in the UEFI environment, I cannot test Hyper-V on it. Many drivers from the WOA Project also no longer work because of the broken PIL service. Perhaps I’ll investigate the reason and update this section someday…

References


Replace the default hyp fw with UEFI on HDK855
https://kancy.life/2026/02/21/QheeReplace/
作者
Kancy Joe
发布于
2026年2月21日
许可协议