My Haiku ARM (UEFI) port progress

Recently I am working on making Haiku ARM port step progress. I am trying to use all my knowledge and experience about arm, because it’s China here, maybe I can’t report imediately.

Today After some debug about mmu and dcache and icache, I got our pl011 driver show some string. My work as below:

  1. Disable mmu and dcache & icache when platform init.

    arch_platform_init(struct kernel_args *kernelArgs)
    // NOTE: dprintf() is off-limits here, too early…

    return B_OK;

  2. Some Hack to our pl011 driver when conscructing.

    void ArchUARTPL011::Init(addr_t base, int64 clock)
    DebugUART::Init(base, clock);


Now we could see the serial output “EA” .

Issues we have:

static char buffer[sizeof(ArchUARTPL011)];

ArchUARTPL011 *arch_get_uart_pl011(addr_t base, int64 clock)
   ArchUARTPL011 *uart = new(&buffer) ArchUARTPL011(base, clock);
   // the referrence to this instance will cause exception 
   uart->Init(base, clock);

when the issue happened, the uefi firmware will show message as below:

add-symbol-file /home/abuild/rpmbuild/BUILD/edk2-edk2-stable202102/Build/ArmVirtQemu-ARM/DEBUG_GCC5/ARM/ArmPlatformPkg/PrePeiCore/PrePeiCoreUniCore/DEBUG/ArmPlatformPrePeiCore.dll 0x1220
add-symbol-file /home/abuild/rpmbuild/BUILD/edk2-edk2-stable202102/Build/ArmVirtQemu-ARM/DEBUG_GCC5/ARM/MdeModulePkg/Core/Pei/PeiMain/DEBUG/PeiCore.dll 0x5220
Register PPI Notify: DCD0BE23-9586-40F4-B643-06522CED4EDE
Install PPI: 8C8CE578-8A3D-4F1C-9935-896185C32DD3
Install PPI: 5473C07A-3DCB-4DCA-BD6F-1E9689E7349A
The 0th FV start address is 0x00000001000, size is 0x001FF000, handle is 0x1000
Register PPI Notify: 49EDB1C1-BF21-4761-BB12-EB0031AABB39
Register PPI Notify: EA7CA24B-DED5-4DAD-A389-BF827E8F9B38
Install PPI: B9E0ABFE-5979-4914-977F-6DEE78C278A6
Install PPI: DBE23AA9-A345-4B97-85B6-B226F1617389
Install PPI: 6847CC74-E9EC-4F8F-A29D-AB44E754A8FC
DiscoverPeimsAndOrderWithApriori(): Found 0x7 PEI FFS files in the 0th FV
Loading PEIM 9B3ADA4F-AE56-4C24-8DEA-F03B7558AE50
add-symbol-file /home/abuild/rpmbuild/BUILD/edk2-edk2-stable202102/Build/ArmVirtQemu-ARM/DEBUG_GCC5/ARM/MdeModulePkg/Universal/PCD/Pei/Pcd/DEBUG/PcdPeim.dll 0x1A220
Loading PEIM at 0x0000001A150 EntryPoint=0x0000001C675 PcdPeim.efi
Install PPI: 06E81C58-4AD7-44BC-8390-F10265F72480
Install PPI: 01F34D25-4DE2-23AD-3FF3-36353FF323F1
Install PPI: 4D8B155B-C059-4C8F-8926-06FD4331DB8A
Install PPI: A60C6B59-E459-425D-9C69-0BCC9CB27D81
Register PPI Notify: 605EA650-C65C-42E1-BA80-91A52AB618C6
Loading PEIM C61EF796-B50D-4F98-9F78-4F6F79D800D5
add-symbol-file /home/abuild/rpmbuild/BUILD/edk2-edk2-stable202102/Build/ArmVirtQemu-ARM/DEBUG_GCC5/ARM/ArmPlatformPkg/MemoryInitPei/MemoryInitPeim/DEBUG/MemoryInit.dll 0x13220
Loading PEIM at 0x00000013150 EntryPoint=0x000000142E5 MemoryInit.efi
QemuVirtMemInfoPeiLibConstructor: System RAM @ 0x40000000 - 0xBFFFFFFF
Memory Init PEIM Loaded
PeiInstallPeiMemory MemoryBegin 0xBC000000, MemoryLength 0x4000000
ArmVirtGetMemoryMap: Dumping System DRAM Memory Map:
	PhysicalBase: 0x40000000
	VirtualBase: 0x40000000
	Length: 0x80000000
DataAbort Exception at 0x9DA6

You can also see my implementation of software text mode over framebuffer: It can be easily ported.

1 Like

@X512 your console is really nice, and for arm platform, it’s nearly close for debug. :wink:

the only problem is why the reference to uart instance will break down.

I feel that working with bare virtual hardware is easier and productive than fightning with firmware.

I give an idea:


.global _start
    ldr x5, =STACK_TOP
    mov sp,x5
    bl start
    b 1b
.size _start, . - _start


#include <stdint.h>
#include <stddef.h>

#define UART0_BASE 0x09000000

void WriteChar(char ch)
	*(volatile uint32_t *)(UART0_BASE) = ch;

void WriteString(const char *str)
	for (const char *ch = str; *ch != '\0'; ch++)

void WriteLn()

void WriteInt(int64_t val)
	if (val == -9223372036854775807LL - 1) WriteString("-9223372036854775808");
	else if (val < 0) {WriteString("-"); WriteInt(-val);}
	else {
		if (val > 9) WriteInt(val/10);
		WriteChar(val%10 + '0');

void WriteHex(uint64_t val, int n)
	if (n > 1 || val > 0xf) WriteHex(val/0x10, n - 1);
	val = val%0x10;
	if (val <= 9) WriteChar(val + '0');
	else WriteChar(val - 10 + 'A');

void Recursion(int n)
	WriteString("+"); WriteInt(n); WriteLn();
	if (n > 0) Recursion(n - 1);
	WriteString("-"); WriteInt(n); WriteLn();

void start(void *fdt) {
	WriteString("This is a test\n");

	WriteHex(0x12345678, 8); WriteLn();
	WriteHex(0x87654321, 8); WriteLn();
	WriteInt(-123456789); WriteLn();

	WriteString("fdt: "); WriteHex((size_t)fdt, 8); WriteLn();
	WriteString("fdt[0]: "); WriteHex(*((uint32_t*)fdt + 0), 8); WriteLn();
	WriteString("fdt[1]: "); WriteHex(*((uint32_t*)fdt + 1), 8); WriteLn();

	for (;;) {}


   . = 0x40000000;
    /* Make sure our entry stub goes first */
    .stub   : { _start.o(.text) }
    .text   : { *(.text) }
    .rodata : { *(.rodata) }
    .data   : { *(.data) }
    .bss    : { *(.bss COMMON) }
    STACK_BASE = .;
    . += 0x10000;
    STACK_TOP = .;

Build with following commands:

clang --target=aarch64-linux-gnu -ffreestanding -fpic -c _start.S
clang --target=aarch64-linux-gnu -ffreestanding -fpic -c start.c
ld.lld -T linker.ld _start.o start.o -o start
llvm-objcopy -O binary start start.bin

Run with:

qemu-system-aarch64 -M virt -cpu cortex-a57 -kernel start.bin -nographic


This is a test
fdt: 44000000
fdt[0]: EDFE0DD0
fdt[1]: 00001000

All operations can be done from Haiku.


After the previous hacking, I found the code blow will have different results

// we can only display 'H' char.
int32 ii = 0;
char gd[20] = "HACB\n";
while (ii<6) {

// we will got all char displayed.
ii = 0;
char gc[20] = {‘H’, ‘A’, ‘C’, ‘B’, ‘\n’};
while (ii<6) {

All the difference of upper code is where we put the string:

  1. “HACB” will be packed to bss field or data field?
  2. the array will be filled in function processed.

I wonder there is something wrong with kernel.ld, or missed parsing elf in efi loader.

1 Like

Do you run this code in kernel, not haiku_loader? I had similar issue. -fpic -shared is needed for compiling kernel. You can disassemble kernel binary and look how constants and global variables are compiled. Also take a look at relocations. Check that required relocations are implemented here.

1 Like

Yes, these code is running in kernel mode, I am not sure what’s the problem, although it will break when accessing static struct variable .

As you can see, ELF relocations are currently not implemented for ARM64, you need to implement it. Sorry, if you are working on 32 bit ARM, relocation resolving is here.

it’s arm 32bit, but it can’t explain. I am not very familiar with elf referring things. :frowning:

Can you upload kernel binary somewhere so it contains writing of string constant data, so I can analyze it?

1 Like

The test kernel binary is

kernel_arm have no relocations and use absolute addressing with load address 0x80000000. Is it really loaded at 0x80000000?

I missed something, I forget to recover the kernel link script.

This kernel_arm binary (provided by) is linked with the kernel.ld from riscv64 :frowning: I will rebuild another with it’s original kernel.ld .

Also where your test code is located? In _start or in some other function?

I have update the hack code to github

1 Like

how are things progressing? :slight_smile:

1 Like

Have you you switsh to ARM now? :wink:

Not yet. Posted to wrong topic.


I have tried use -fpic and -fshared to build arm kernel, but bootloader will parse kernel fail with “Couldn’t found both text and data segment”.


On other architectures there were some problems with the kernel linker scripts. The bootloader expects the text and data sections to be each in a separate segment, but some of the linker scripts are not doing this correctly.

I think you can compare the linker script with other architectures and see if the segments are defined correctly.