Another of those "can't enter long mode" post...
Posted: Fri Feb 08, 2019 12:46 am
First some background about my project setup...
- I have an EFI bootloader implementation that loads the kernel (an elf file), setups page mapping and then jump to the kernel. I support both ia32 and x86_64 targets. Everything is working fine here.
- I implemented a multiboot bootloader (loaded by Grub) that uses much of the same code because I want to be able to run my kernel in Bochs. This bootloader is always ia32 code but can load both an ia32 and x86_64 kernel, because why not.
- The multiboot loader shares the same code as the EFI bootloader for page mapping, elf parsing and so on.
So in theory, all I need is some custom code to jump from the ia32 bootloader to the x86_64 kernel. Lucky me I have implemented this in a previous OS project so I just copied the code over and it should just work right? Well it does, on Bochs at least. But on QEMU and real hardware, it fails miserably.
- Works with EFI bootloader
- Works with BIOS under Bochs (both ia32 and x86_64)
- Works with BIOS under QMU and hardware for ia32
- Does not work with BIOS under QEMU or hardware for x86_64
It fails when I enable paging. Boom. So two possibilities comes to mind:
1) My page tables are not setup properly. But they are exactly the same ones I use with x86_64 EFI. I went through the pain of printing them all out and comparing them. They look the same.
2) My code that jumps from 32 to 64 bits code has a bug. I've been checking and rechecking these ~20 lines of code over and over against my old OS project and documentation on the wiki, other places on the internets and Intel reference manuals. I can't find anything wrong with it.
Clearly I am missing something, but after days of banging my head on the wall, I am looking for a saviour to help me.
Here is the function I use to jump to long mode (it crashes on line 171 when I try to enable paging):
https://github.com/kiznit/rainbow-os/bl ... try.S#L156
The page table setup is here:
https://github.com/kiznit/rainbow-os/bl ... x86_64.hpp
The way it works is:
1) I call init() to identity map the first 4 GB - https://github.com/kiznit/rainbow-os/bl ... ot.cpp#L72
2) The elf loading code calls map() to map the kernel in high memory - https://github.com/kiznit/rainbow-os/bl ... r.cpp#L388
3) enable() is called to set cr3 before I call jumpToKernel64() - https://github.com/kiznit/rainbow-os/bl ... t.cpp#L150
Any help much appreciated, this is driving me nuts.
- I have an EFI bootloader implementation that loads the kernel (an elf file), setups page mapping and then jump to the kernel. I support both ia32 and x86_64 targets. Everything is working fine here.
- I implemented a multiboot bootloader (loaded by Grub) that uses much of the same code because I want to be able to run my kernel in Bochs. This bootloader is always ia32 code but can load both an ia32 and x86_64 kernel, because why not.
- The multiboot loader shares the same code as the EFI bootloader for page mapping, elf parsing and so on.
So in theory, all I need is some custom code to jump from the ia32 bootloader to the x86_64 kernel. Lucky me I have implemented this in a previous OS project so I just copied the code over and it should just work right? Well it does, on Bochs at least. But on QEMU and real hardware, it fails miserably.
- Works with EFI bootloader
- Works with BIOS under Bochs (both ia32 and x86_64)
- Works with BIOS under QMU and hardware for ia32
- Does not work with BIOS under QEMU or hardware for x86_64
It fails when I enable paging. Boom. So two possibilities comes to mind:
1) My page tables are not setup properly. But they are exactly the same ones I use with x86_64 EFI. I went through the pain of printing them all out and comparing them. They look the same.
2) My code that jumps from 32 to 64 bits code has a bug. I've been checking and rechecking these ~20 lines of code over and over against my old OS project and documentation on the wiki, other places on the internets and Intel reference manuals. I can't find anything wrong with it.
Clearly I am missing something, but after days of banging my head on the wall, I am looking for a saviour to help me.
Here is the function I use to jump to long mode (it crashes on line 171 when I try to enable paging):
https://github.com/kiznit/rainbow-os/bl ... try.S#L156
The page table setup is here:
https://github.com/kiznit/rainbow-os/bl ... x86_64.hpp
The way it works is:
1) I call init() to identity map the first 4 GB - https://github.com/kiznit/rainbow-os/bl ... ot.cpp#L72
2) The elf loading code calls map() to map the kernel in high memory - https://github.com/kiznit/rainbow-os/bl ... r.cpp#L388
3) enable() is called to set cr3 before I call jumpToKernel64() - https://github.com/kiznit/rainbow-os/bl ... t.cpp#L150
Any help much appreciated, this is driving me nuts.