trying to clean up the memory map but still getting crashes/reboots, mostly in _MapChunk. probably something’s getting overwritten…
it seems that the early paging setup relies on some quirky assumptions around the memory layout and physical-virtual mapping.
is there a document describing the kernel’s memory map and requirements on initial page tables and how arch_args shall be filled in? (e.g. i just noticed that num_pgtables and pgtables[] are not referenced in any file in src/system/kernel/ subtree. i also suspect there are some further assumptions around how the early page tables are allocated in MapEarly)
for anyone interested:
my development branch can be found on github here
perhaps my build dir was stale… after redoing my dev branch, now the bootup reaches the 4th icon and stops there, apparently waiting for the ATA interface. (no crashes or restarts any more, so maybe I was able to compose a better memory map. or I’m just lucky that none of the kernel gets overwritten )
number of disk systems: 20
KDiskDeviceManager::_Scan(/dev/disk)
PCI-ATA: Controller in legacy mode: cmd 0x1f0, ctrl 0x3f6, irq 14
PCI-ATA: init channel...
PCI-ATA: channel index 0
PCI-ATA: bus master base 0xc040
PCI-ATA: init channel done
At least for RISC-V there are no assumptions about kernel memory layout. Kernel itself is loaded at dynamically allocated address. But some x86-specific assumptions may exist.
nope, but actually it was not a driver issue. I still had come garbage in the page tables. Once I clean that up, I’m able to get a boot to desktop with qemu + edk2-ovmf-ia32 + 32-bit Haiku UEFI loader.
Most of the SMP stuff was also quite easy, msotly copy-paste from 64-bit. (good candidate for a refactor)
I still have some limitations on the memory layout though, as I see we currently rely on identity mapping for a few things related to kernel startup:
trampoline code
kernel_args
initial GDT
So it probably still causes some trouble with >2G RAM… maybe I’ll just copy them to lower 1M. Or perhaps EFI allocate_pages with EFI_ALLOCATE_MAX_ADDRESS.
It should be possible, we already do this with the bios loader which is also 32 bit code, IIRC that is the reason that the buildtools include a 32bit targeting gcc aswell.
yes, that should be possible… but first I’m trying to solve the simpler task of loading the 32-bit kernel using 32-bit UEFI loader.
the BIOS loader already works this way, i.e. there’s a single BIOS loader that can load either 32-bit or 64-bit kernel
the 64-bit EFI loader is able to load only 64-bit kernel
my initial code for 32-bit EFI loader works with 32-bit kernel, the “hybrid mode” can be a next step.
some code cleanup and refactoring stil to be done.
Great work and I think this is something that could make it into a blog post? I’d love to read how it all works internally for a wider audience Thanks!
Code cleanup mostly done, I’ve uploaded the code for gerrit review.
One thing remaining, the SMP startup - the code is ready just I have to do some more formatting to align with the coding standards.
There’s also a regression that I’m still trying to track down: depending on memory size, sometimes I get a panic during kernel loading:
That’s what I was suspecting, but then it turned out to be a sign extension issue.
When converting from void* to phys_addr_t ( = uint64), the upper bits are repeated.
e.g. 0xb0000000 → 0xffffffffb0000000 etc.
If I convert from void* to addr_t and then to phys_addr_t then I get better results.
e.g.
phys_addr_t addr = (phys_addr_t)(addr_t)address;
There’s still an issue with PAE though. If there’s any physical memory region above 4G, the kernel initialization crashes with a KDL when trying to parse the ACPI tables. (no problem with ACPI table init if we have <=4G mem)