One thing I could never find a satisfactory answer to is where is UEFI allowed to load your bootloader in memory. Clearly a PE file can be relocated and I have tested that this is the case on 3 computers + QEMU. In all cases, by 0-based image gets relocated "somewhere" that is different on each machine.
I do load my kernel from the bootloader and setup virtual memory space so that my kernel is at 0xF0000000. If for any reason UEFI decided to load my bootloader at or above 0xF0000000, this would be a problem: turning on virtual memory would crash the bootloader. That's the 32 bits world. So as previously mentioned you can just ignore UEFI on ia32. But what about other 32-bits platforms?
As for the 64 bits world, I am less worried because I find it even less likely for something like this to happen. But still. I am surprised by the lack of information / clarity about this issue.
Now it so happened that Windows and Linux and any other sane OS probably wants to be at the end of the address space, but I don't know that's always true especially on non-PC platforms.
One could detect this and relocate some trampoline code out of the way, but that's pain I'd rather avoid if it is not necessary.
UEFI Bare Bones
Re: UEFI Bare Bones
Yep, that is the entire definition you get. UEFI will put your bootloader anywhere in memory. The only guarantees you have are that physical address == virtual address.kzinti wrote:One thing I could never find a satisfactory answer to is where is UEFI allowed to load your bootloader in memory. Clearly a PE file can be relocated and I have tested that this is the case on 3 computers + QEMU. In all cases, by 0-based image gets relocated "somewhere" that is different on each machine.
What Linux does to work around this is to relocate. It is normal now to have a compressed kernel (in fact, building an uncompressed kernel with UEFI stub is unsupported right now). Compressed kernels work by having a decompressor unpack the raw kernel image. The decompressor is mostly position independent (unlike the rest of the kernel). It will detect if it is in the way of the uncompressed kernel and relocate itself elsewhere if so.
On PowerPC, every operating system wants to be loaded at the start of physical address space. This is because all exceptions disable paging there, and then jump to predetermined addresses in the first 12kB of address space (unless a certain bit is set in the MSR, in which case the exception vectors are in the first 12kB of the last megabyte of address space). Therefore most OSes have a 12kB block of exception handlers at the start, to be copied to the start of address space, which is easiest if the entire kernel image is just loaded there. I am, however, unaware of a UEFI implementation for PowerPC.kzinti wrote:Now it so happened that Windows and Linux and any other sane OS probably wants to be at the end of the address space, but I don't know that's always true especially on non-PC platforms.
Back to the PC: My kernel does not care where it is loaded in physical memory, or even if it is contiguous. The bootloader gives a list of reserved physical memory ranges to the kernel, and the kernel only knows that those ranges are unavailable, for whatever reason. Since in my case, the bootloader turns on the virtual memory (that is, it switches over to my kernel's paging scheme), the kernel itself does not have to know.
Oh, come on, it is not that painful. My bootloader turns on virtual memory as the very last thing before invoking the kernel. Therefore the code that does that is mostly self-contained. So why not just compile the trampoline code into a raw binary, then tack that binary into the bootloader as data? Then you can just copy it always. You need to know where the trampoline will end up, anyway, for the identity-map. So instead of putting it in a constant address, you use as base address whatever the allocator returns to you. Copy, set function pointer, call, done.kzinti wrote:One could detect this and relocate some trampoline code out of the way, but that's pain I'd rather avoid if it is not necessary.
Carpe diem!
Re: UEFI Bare Bones
Lol. Fair enough. I'll just get it done .nullplan wrote:Oh, come on, it is not that painful.
Yes I do the same thing. I basically don't care where my kernel is loaded. I identity map everything from 0 to 0xEFFFFFFF and map the kernel to 0xF0000000. The very last bit I do is set CR3 and jump to the entry point (>= 0xF0000000). This will only fail if this last bit of code is not below 0xF0000000. I think I'll just dynamically generate the trampoline code out of the way and use that.nullplan wrote:My bootloader turns on virtual memory as the very last thing before invoking the kernel.
Thanks for your comments.
Re: UEFI Bare Bones
Personally, I'm happy to see another UEFI article.
I am not quite so happy to see yet another article featuring that worst of all compilers to cross-compile with, but it won't actually affect me because I don't like C.
I would like clarification regarding the 32-bit issue because if you can boot 32-bit UEFI binaries on 64-bit UEFI machines, it would save me some work in the short term.
I am not quite so happy to see yet another article featuring that worst of all compilers to cross-compile with, but it won't actually affect me because I don't like C.
I would like clarification regarding the 32-bit issue because if you can boot 32-bit UEFI binaries on 64-bit UEFI machines, it would save me some work in the short term.
Kaph — a modular OS intended to be easy and fun to administer and code for.
"May wisdom, fun, and the greater good shine forth in all your work." — Leo Brodie
"May wisdom, fun, and the greater good shine forth in all your work." — Leo Brodie
Re: UEFI Bare Bones
That's not possible. But once your UEFI binary is loaded, you can do whatever you want including switching from 64 bits to 32 bits or vice-versa.eekee wrote:(...) if you can boot 32-bit UEFI binaries on 64-bit UEFI machines, it would save me some work in the short term.
So if your UEFI app is a 64 bits bootloader, it can load and setup a 32 bits kernel. But UEFI won't be of any help here (well except for loading the kernel, of course).
- xenos
- Member
- Posts: 1118
- Joined: Thu Aug 11, 2005 11:00 pm
- Libera.chat IRC: xenos1984
- Location: Tartu, Estonia
- Contact:
Re: UEFI Bare Bones
In the meantime I had a look at the GCC sources to figure out the implications of using a Windows (MinGW or Cygwin) targeted compiler vs. the ELF approach I used here. After all, I think the "cleanest" approach with GCC would be adding another target to GCC, something like i686-efi / x86_64-efi, which generates PE / PE+ executables with the proper subsystem and relocations, without pulling in any Cygwin / MinGW specific dependencies. This requires modifying the GCC sources, which I am not (yet) very familiar with. But maybe it's worth a shot.
Also I tried out Clang / LLVM and managed to compile some working examples with the i686-unknown-windows / x86_64-unknown-windows targets, but I also had to modify the sources a bit. I will update the wiki article once I have cleaned up things a bit. The result is definitely "better" / "cleaner" since it uses neither PIC nor ELF as an intermediate step, but directly yields a PE / PE+ executable with proper relocations. I'll take a look at the sources as well, to see whether also here one could add some *-efi target, and what is actually implied by targeting *-windows.
Speaking of relocations - one thing I'll try to investigate is where the file is loaded by different UEFI implementations and how relocations are handled there.
Finally, I still intend to extend this work to AArch32 / AArch64
Also I tried out Clang / LLVM and managed to compile some working examples with the i686-unknown-windows / x86_64-unknown-windows targets, but I also had to modify the sources a bit. I will update the wiki article once I have cleaned up things a bit. The result is definitely "better" / "cleaner" since it uses neither PIC nor ELF as an intermediate step, but directly yields a PE / PE+ executable with proper relocations. I'll take a look at the sources as well, to see whether also here one could add some *-efi target, and what is actually implied by targeting *-windows.
Speaking of relocations - one thing I'll try to investigate is where the file is loaded by different UEFI implementations and how relocations are handled there.
Finally, I still intend to extend this work to AArch32 / AArch64
Re: UEFI Bare Bones
Thanks. I think I'll put the work in to convert this "Plain English" compiler to 64-bits. It'll be about as easy as such a conversion could be right now, and will familiarize me with the parts I'd need for porting it to other architectures.kzinti wrote:That's not possible. But once your UEFI binary is loaded, you can do whatever you want including switching from 64 bits to 32 bits or vice-versa.eekee wrote:(...) if you can boot 32-bit UEFI binaries on 64-bit UEFI machines, it would save me some work in the short term.
Kaph — a modular OS intended to be easy and fun to administer and code for.
"May wisdom, fun, and the greater good shine forth in all your work." — Leo Brodie
"May wisdom, fun, and the greater good shine forth in all your work." — Leo Brodie