ARM64 Port Status

But clean builds I did after that still loaded the kernel in QEMU, so not sure if QEMU was being nice or something.

2 Likes

That is very interesting! Despite the output you get is different than mine you got to the same point. Happy to see the code works :slight_smile:

Some questions though:

  • Have you applied the “0xFFFFFFFF80000000” suggestion in the linker?
  • Have you enabled as well in the Kernel side? You must have relevant changes in: system/kernel/arch/arm64/arch_debug_console.cpp is it?
3 Likes

Yes, I missed that previously.

Yup, otherwise I wouldn’t have any kernel output.

Though to proceed further I would need to learn more about Haiku and ARMv8 virtual memory, and I’m not sure I want to jump into that rabbit hole at this moment…

2 Likes

About that EL1/2, it’s just that TCR wasn’t configured when booting from EL1, I moved arch_mmu_setup_EL1() to be called in both cases and modified it like that:

	// Possibly inherit TCR from EL2
	uint64 tcr;
	if (arch_exception_level() == 2)
		tcr = READ_SPECIALREG(TCR_EL2);
	else
		tcr = READ_SPECIALREG(TCR_EL1);

Now it works both when booted from EL1 and EL2. (though we probably should write full TCR config there instead of relying on whatever EFI left?)

I hooked up that early page alloc and got a little bit further in boot

gKernelArgs.arch_args.phys_pgdir     = 0x41295000
gKernelArgs.arch_args.vir_pgdir      = 0x00000030
gKernelArgs.arch_args.next_pagetable = 0xbed6b000
Current Exception Level EL1
MMU Enabled, Translation Table @ 47fff000 Granularity 4KB, bits 48
Calling ExitBootServices. So long, EFI!
Boot services terminated.
Configuring TCR_EL1: 580103510
Already at EL1.
phys memory ranges:
    0x40000000-0x41296000, length 0x01296000
    0x43a68000-0x43b00000, length 0x00098000
    0x44000000-0x44020000, length 0x00020000
    0x441f4000-0x474d0000, length 0x032dc000
    0x47560000-0x47570000, length 0x00010000
    0x47690000-0x48000000, length 0x00970000
allocated phys memory ranges:
    0x4128c000-0x43a0f000, length 0x02783000
    0x441f0000-0x441f4000, length 0x00004000
allocated virt memory ranges:
    0xffff000002000000-0xffff00000255b000, length 0x0055b000
    0xffffffff80000000-0xffffffff80222000, length 0x00222000
Entering kernel!
Welcome to kernel debugger output!
Haiku revision: hrev55948+dirty, debug level: 2
INIT: init CPU
INIT: init interrupts
INIT: init VM
vm_init: entry
mark_page_range_in_use(0x0, 0x40000): start page is before free list
reserve_boot_loader_ranges()
reserve_boot_loader_ranges(): Skipping range: 0xffffffff80000000, 2236416
create_anonymous_area [1] page structures: size 0x280000
create_anonymous_area [1] slab area: size 0x800000
PANIC: out of memory
Welcome to Kernel Debugging Land...
Running on CPU 0
Current thread pointer is 0xffffffff801f61c0, which is an address we can't read from.

If nobody else is currently working on hooking up the rest of VM code I might try to do that.

9 Likes

It is confusing that simple change actually worked, that meant you already have as well a MMU configuration… and also implies that it is being changed on the fly :face_with_open_eyes_and_hand_over_mouth:

Changing an active EL1 MMU while in EL1 vs Changing an inactive EL1 MMU configuration while in EL2.

No next step defined from my side, my focus now is to make current changes to the tree.

I would like to have a look on your current changes as well… maybe we could merge your PL011 work with the pending LINFlex to agilize…

If getting inside the kernel please let me remark the following reference:

3 Likes

I don’t have any changes in pl011, just reused things from arch/arm.

I did play around a bit with vm mapping. I will push the code somewhere after I clean it up somewhat.

Calling ExitBootServices. So long, EFI!
Boot services terminated.
Configuring TCR_EL1: 580103510
Already at EL1.
phys memory ranges:
    0x40000000-0x41291000, length 0x01291000
    0x43a68000-0x43b00000, length 0x00098000
    0x44000000-0x44020000, length 0x00020000
    0x441f4000-0x474d0000, length 0x032dc000
    0x47560000-0x47570000, length 0x00010000
    0x47690000-0x48000000, length 0x00970000
allocated phys memory ranges:
    0x41286000-0x43a0f000, length 0x02789000
    0x441f0000-0x441f4000, length 0x00004000
allocated virt memory ranges:
    0xffff000002000000-0xffff00000255d000, length 0x0055d000
    0xffffff0000000000-0xffffff8000000000, length 0x8000000000
    0xffffffff80000000-0xffffffff80225000, length 0x00225000
Entering kernel!
Welcome to kernel debugger output!
Haiku revision: hrev55948+1+dirty, debug level: 2
INIT: init CPU
INIT: init interrupts
INIT: init VM
arch_vm_translation_map_init
vm config: MMFR1: 10211120, TCR: 580103510
TTBR0: 47fff000, TTBR1: 41290000
T0SZ: 16, T1SZ: 16, TG0: 0, TG1: 2, MAIR: ffbb4400
arch_vm_init
pulling page ffffff00441f5000
pulling page ffffff00443f6000
pulling page ffffff00445f7000
pulling page ffffff00447f8000
pulling page ffffff00449f9000
pulling page ffffff0044bfa000
mark_page_range_in_use(0x0, 0x40000): start page is before free list
VMSAv8TranslationMap
reserve_boot_loader_ranges(): Skipping range: 0xffffff0000000000, 549755813888
reserve_boot_loader_ranges(): Skipping range: 0xffffffff80000000, 2248704
arch_vm_translation_map_init_post_area
arch_vm_init_post_area
arch_vm_set_memory_type
INIT: init driver_settings
INIT: init notification services
INIT: init teams
INIT: init ELF loader
INIT: init modules
INIT: init semaphores
INIT: init interrupts post vm
INIT: init system info
INIT: init SMP
INIT: init timer
INIT: init real time clock
allocate_commpage_entry(2, 24) -> 0x0000000000000200
INIT: init condition variables
INIT: init VM semaphores
arch_vm_init_end
arch_vm_translation_map_init_post_sem
INIT: init generic syscall
INIT: init scheduler
scheduler_init: found 1 logical cpu and 0 cache levels
scheduler switches: single core: true, cpu load tracking: false, core load tracking: false
scheduler: switching to low latency mode
INIT: init threads
INIT: init kernel daemons
INIT: init stack protector
INIT: init I/O interrupts
INIT: init VM threads
INIT: init DPC
INIT: init VFS
INIT: init swap support
INIT: init POSIX semaphores
INIT: spawning main2 thread
INIT: waking up AP cpus
INIT: exiting kernel startup
INIT: starting scheduler on cpu 0 and enabling interrupts
12 Likes

I pushed current WIP code there: Commits · Milek7/haiku-work · GitHub
I did not reuse much existing code from efi loader or that linked github earlier, but that’s just because I needed some practice with how it all works, we will need to decide later which approach use for upstreaming.

I run it in qemu like that:

qemu-system-aarch64 -bios /usr/share/edk2/aarch64/QEMU_EFI-pflash.raw -M virt -device ramfb -cpu max -no-acpi -drive file=~/haiku/build/haiku-mmc.image,format=raw,id=d0,if=none -device virtio-blk-device,drive=d0

If you want to try it on different device it needs updating kernel debug serial in arch_debug_console.cpp, currently it’s hardcoded there to pl011@0x9000000. (and likely add appropiate device memory mapping in efi loader, in kernel address space)
In qemu it runs all the way up to PANIC: did not find any boot partitions!, but hardware is less forgiving so I would expect some snags there :wink:

12 Likes

KDL console now works.

36 Likes

Out of curiosity: does the console message “module: Search for bus_managers/pci/x86/v1 failed.” mean the code still uses some x86 specific code?

No. Drivers ask PCI MSI interrupts module that is currently declared as “x86-specific”, but actually it isn’t. MSI interrupt handling is a part of PCI Express specification and available on all hardware that support it including RISC-V and ARM.

3 Likes

Nice work! the UART commit is still pending to be merged

I’ll be incorporating other parts for the next commit on properly dealing with an ongoing MMU in EL1 in EFI.

Let me remark that:

Will fail, as that position is not covered by the MMU, I see in your next commit that you opened the whole kernel virtual range, avoiding the commented fail. Can you explain?

1 Like

64 bit Haiku kernels (x86_64, riscv64) use linear mapping of whole RAM for easy and efficient access to physical memory. So physical RAM addresses can be converted to virtual by adding some fixed offset value.

5 Likes

Why? This is stack top, so only memory below this address should be used. - 8 seems wrong, AAPCS64 ABI requires that stack is 16-byte aligned, and it will probably fault on hardware when SCTLR_EL1.SA bit is set. - 16 would be fine but I don’t see reason for subtracting here.

This is linear mapping that is used by PhysicalPageMapper to access memory directly. (instead of mapping it in-and-out which is necessary on 32-bit platforms, when there isn’t enough virtual address space to cover all memory). Note that mapping everything like that works fine only for qemu, for hardware we also want this linear mapping but it needs to be changed to map only areas covering physical RAM (otherwise speculative access might cause unwanted MMIO reads or bus SError).

3 Likes

As far as I remember:

map 0xffff000002000000 --> 0xf9caf000, len=0x10000, flags=0x7

This was the mapping for the kernel Stack, this involves MMU covers from 0xffff000002000000 to 0xFFFF00000200FFFF.

Writting 0xFFFF000002010000(top+size) to the stack registers provoked an exeception, because that address is already in the next page (not covered by MMU). That is the reason of the substraction.

Alright… hybrid kernels. Maybe is not feasible but I would delay that as much as possible in the progress of the port, to catch as soon a possible unintented acceses & bugs.

Understood, Indeed that mappìng won’t work for me (at physical 0x0 is the mappping of the xSPI controller)

Thank you both!

More icons:

I didn’t push the code yet because it’s too hardcoded.
I’m having trouble with PCI controller discovery because it seems pci_controller_init is getting called at the beginning, but I need information from acpi/devicetree which is only parsed later.

x86 code parses acpi MCFG manually, but that’s not enough here because while it contains config space address, I/O ranges information are accessed through PNP0A03 _CRS method, thus it requires fully parsed acpi namespace.

riscv uses devicetree and binds root module in proper place by filtering in pci_root_supports_device, but I’m not sure how it resolves the problem that by the point this device is discovered pci_controller_init was already called earlier.

25 Likes

If I remember correctly PCI module loading fails if FDT node is not found (not yest registered etc.). So PCI module will be functional if accessed after publishing FDT bus nodes. If it is accessed before, it will load, fail and unload, potentially multiple times.

I think that PCI initialization should be reworked to have initially empty bus with no host controllers and then dynamically register PCI host controllers during ACPI/FDT bus enumeration. Hot pluggable PCI devices also exist.

2 Likes

I think it would make sense to rewrite how ACPI is initialised, it is a bigger task though. ACPI spec expects it to be done very early as well, but we do it quite late in boot.

1 Like

I’m working on this for my (x86_64, boring) laptop.

It is not possible to have the PCI module depend on the ACPI module at the kernel level because the ACPI module depends on the PCI one currently. So the kernel complains about a circular dependency.

What I did so far:

  • Change the support_device function so that the PCI root supports the ACPI PNP0A03 device node, instead of the “root” device node. This is similar to what is done for FDT for RISC-V.

What I did not do yet:

  • In the device initialization, load the ACPI module, use it to call the _CRS method, and parse the result.

I will submit my patch to Gerrit in a few hours when I’m back home.

7 Likes

https://antmicro.com/blog/2022/04/open-source-snapdragon-845-baseboard/

Here you go: https://review.haiku-os.org/c/haiku/+/5182

Hope it helps.

6 Likes