Usefulness of UEFI

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
kzinti
Member
Member
Posts: 898
Joined: Mon Feb 02, 2015 7:11 pm

Re: Usefulness of UEFI

Post by kzinti »

quirck wrote:That quote effectively allows UEFI to make any mappings of EfiConventionalMemory (readonly, no-execute, etc), it may even not map it at all. So the first thing to do after ExitBootServices is to switch to known good page tables.

Consider loaders written prior to introduction of 5-level paging. They might just construct PML4 and point CR3 to that, unaware that CPU can treat it as PML5. This isn't going to work, that code needs to be rewritten. Even if an OS isn't going to support 57-bit linear addresses, it still needs to be aware of it.
You are right.
quirck wrote:Consider another approach when we just want to disable paging altogether. "MOV to CR0 causes a general-protection exception if it would clear CR0.PG to 0 while CR4.PCIDE = 1", for example.
You cannot disable paging in long mode. So I am not sure what your scenario is here.
quirck wrote:Again, if we know about this bit, we can clear it in advance and disable paging afterwards. But how should we handle bits that are reserved now? Is there a safe path if at some time in future our code reads them as 1?
If history is any lesson, I think it is pretty safe to assume that no UEFI will enable 5-level paging by default. Otherwise it would indeed break existing bootloaders / kernels. This is the reason why the processor starts without 5-level paging enabled: backward compatibility. So if your bootloader is not aware of PML5, things continue working. If it is, it can setup a PML5 if desired.

But this has nothing to do with UEFI: the same problem would exist with any firmware that runs in long mode. If anything, UEFI got it right by being non-specific about what the mapping is so that you don't assume anything about it. Backward compatibility is then in the end of manufacturers and that gives them maximum flexibility.
quirck
Member
Member
Posts: 42
Joined: Sun Nov 23, 2008 5:56 am
Location: Russia, Saint-Petersburg

Re: Usefulness of UEFI

Post by quirck »

kzinti wrote:
quirck wrote:Consider another approach when we just want to disable paging altogether. "MOV to CR0 causes a general-protection exception if it would clear CR0.PG to 0 while CR4.PCIDE = 1", for example.
You cannot disable paging in long mode. So I am not sure what your scenario is here.
I just omitted some details. Of course, first, we need to make sure UEFI loaded us under 4G. Otherwise, we need to relocate some code below 4G. I assume EfiLoaderCode memory type is needed in this case so that we actually can write our code there and execute it afterwards. Next, prepare GDT so that we know what selector to use to switch to compatibility mode. ExitBootServices. Jump to compatibility mode. Turn off CR0.PG. This will effectively put us in protected mode, there we can adjust CR4.PA57, switch CR3, and turn CR0.PG back on. Jump to appropriate code segment and return to long mode. That's the plan. Maybe there is a better way.

If there was no way to switch between 4-level and 5-level paging, that would mean that UEFI chooses which type to use. I'd say it is an OS that should make such decision, not UEFI.
kzinti wrote:
quirck wrote:Again, if we know about this bit, we can clear it in advance and disable paging afterwards. But how should we handle bits that are reserved now? Is there a safe path if at some time in future our code reads them as 1?
If history is any lesson, I think it is pretty safe to assume that no UEFI will enable 5-level paging by default. Otherwise it would indeed break existing bootloaders / kernels. This is the reason why the processor starts without 5-level paging enabled: backward compatibility.
Yes, that's what I hope for. But, "never make assumptions".
kzinti
Member
Member
Posts: 898
Joined: Mon Feb 02, 2015 7:11 pm

Re: Usefulness of UEFI

Post by kzinti »

quirck wrote:I just omitted some details. Of course, first, we need to make sure UEFI loaded us under 4G. Otherwise, we need to relocate some code below 4G. I assume EfiLoaderCode memory type is needed in this case so that we actually can write our code there and execute it afterwards. Next, prepare GDT so that we know what selector to use to switch to compatibility mode. ExitBootServices. Jump to compatibility mode. Turn off CR0.PG. This will effectively put us in protected mode, there we can adjust CR4.PA57, switch CR3, and turn CR0.PG back on. Jump to appropriate code segment and return to long mode. That's the plan. Maybe there is a better way.
That sounds very painful. I haven't looked at this PA57 business... But I would expect that setting that bit to actually do nothing until you reload CR3 (I am just guessing here, I don't know anything). I am not willing to believe that you need to go back to protected/compatibility mode just to enable PML5.
quirck wrote:If there was no way to switch between 4-level and 5-level paging, that would mean that UEFI chooses which type to use. I'd say it is an OS that should make such decision, not UEFI.
I think it's pretty safe to assume no UEFI will enable 5 levels as that would break existing bootloaders, including all the Windows and Linux machines out there. I agree the OS should make that decision.
quirck wrote:Yes, that's what I hope for. But, "never make assumptions".
Certainly, but one cannot predict the future either.
quirck
Member
Member
Posts: 42
Joined: Sun Nov 23, 2008 5:56 am
Location: Russia, Saint-Petersburg

Re: Usefulness of UEFI

Post by quirck »

Oops, I meant LA57, not PA57 :)
Intel SDM (2020) wrote:Software cannot transition directly between 4-level paging (or 5-level paging) and any of other paging mode. It must first disable paging (by clearing CR0.PG with MOV to CR0), then set CR4.PAE, IA32_EFER.LME, and CR4.LA57 to the desired values (with MOV to CR4 and WRMSR), and then re-enable paging (by setting CR0.PG with MOV to CR0). As noted earlier, an attempt to modify CR4.PAE, IA32_EFER.LME, or CR.LA57 while 4-level paging or 5-level paging is enabled causes a general-protection exception (#GP(0)).
rdos
Member
Member
Posts: 3351
Joined: Wed Oct 01, 2008 1:55 pm

Re: Usefulness of UEFI

Post by rdos »

quirck wrote:I just omitted some details. Of course, first, we need to make sure UEFI loaded us under 4G. Otherwise, we need to relocate some code below 4G. I assume EfiLoaderCode memory type is needed in this case so that we actually can write our code there and execute it afterwards. Next, prepare GDT so that we know what selector to use to switch to compatibility mode. ExitBootServices. Jump to compatibility mode. Turn off CR0.PG. This will effectively put us in protected mode, there we can adjust CR4.PA57, switch CR3, and turn CR0.PG back on. Jump to appropriate code segment and return to long mode. That's the plan. Maybe there is a better way.

If there was no way to switch between 4-level and 5-level paging, that would mean that UEFI chooses which type to use. I'd say it is an OS that should make such decision, not UEFI.
Exactly. This includes which mode it should leave the CPU in too. Maybe the OS doesn't use long mode, and wants to boot up in protected mode? Then it would need two different loaders, one for 32-bit mode that turns off paging to get back to a known mode and one for 64-bit mode which switches to compatibility mode, disables long mode and paging. It would have been a whole lot better if UEFI always handed over control in protected mode with paging disabled.
User avatar
bzt
Member
Member
Posts: 1584
Joined: Thu Oct 13, 2016 4:55 pm
Contact:

Re: Usefulness of UEFI

Post by bzt »

Gigasoft wrote:That's just silly.
Address complaints to SCO UNIX, not to me. I didn't designed ELF.
Gigasoft wrote:The very first thing you'll likely do is to set up yourself an initial paging structure
If we have to do this ourselves, then how exactly is UEFI helpful? I thought you were saying UEFI is good because it does these kinds of things for you, so you don't have to... Oh wait, you have to anyway!
Gigasoft wrote:are you saying that you can't live with having this simple and tiny piece of code be position independent?
The fact that you think that's easy and PIC would solve your issue indicates that you have no experience on this topic. Writing a relocatable kernel is not as simple as you suggest, besides of position independent code that would also require a dynamic loader that applies relocations and fills up the GOT. I've already did that, I know exactly how much work that means. (And then we haven't talked about the differences in linkers, because LLVM lld and GNU ld generates different relocation records and relocatable instructions; plus there's the fact that some put all records in one table, while others generate two tables, one with code relocs and one with data relocs... Writing a PIC kernel loader IS NOT EASY. 300-400 SLoC at a minimum, compared to that 8 SLoC that tutorial has right now. If you think 300 and 8 are the same magnitude, then I really can't help you.)
Gigasoft wrote:Likewise, this should be a straightforward piece of code. Disable NMI, disabling paging, load new IDTR, CR3 and TR, enable long mode, enable paging, enable NMI. Why does this function need to reside at a fixed address?
Maybe straightforward, but not for you. Your first mistake was that APs start in real-mode, not in long-mode. Your second mistake was that you cannot disable paging in long mode. Your third mistake was that both LIDT and MOV CR3 instructions require absolute, relocated addresses (yes, that means fixed addresses in lack of a dynamic linker). Fourth mistake not knowing that SIPI needs a fixed segment to jump to. Straightforward, you say?

Plus yes, you could write a real-mode prot-mode long-mode instruction relocating code yourself, but that's extremely problematic because you cannot rely on the compiler generating relocation records for you (PE file cannot store relocations for different operating modes in the same file). You have to do everything manually, including constructing a list of relocations for the trampoline code in compile-time as well as applying those relocations in run-time according to that table. It is everything but not straightforward!

Cheers,
bzt
Last edited by bzt on Wed Mar 03, 2021 5:59 pm, edited 1 time in total.
Ethin
Member
Member
Posts: 625
Joined: Sun Jun 23, 2019 5:36 pm
Location: North Dakota, United States

Re: Usefulness of UEFI

Post by Ethin »

Why would you ever want to make an OS that's only 32-bit and then want to use it on UEFI? UEFI is meant for the future, so its unsurprising it would boot the processor directly into long mode and forget about protected mode. And, as others have said, I doubt UEFI will use 5-level paging unless its been confirmed that all the major bootloaders support it first. Though I don't know why what paging UEFI uses would matter at all since you'll be swapping in your own page tables anyway...
User avatar
bzt
Member
Member
Posts: 1584
Joined: Thu Oct 13, 2016 4:55 pm
Contact:

Re: Usefulness of UEFI

Post by bzt »

Ethin wrote:its unsurprising it would boot the processor directly into long mode
The problem is, UEFI spec does not specify the details how long mode is set up on the BSP. Plus UEFI does not boot the APs into long-mode, as I've already said, but they still start in real-mode, meaning you'll need that trampoline code anyway on SMP systems. It would be different if you could start APs with UEFI into long-mode, but you can't, because the spec is badly designed. It is pretty annoying to know that UEFI must include all the necessary code (for MP Services), but you just can't use that, so you have to reimplement everything yourself... This is what we call "failure by design", and it isn't helpful at all.

Cheers,
bzt
Ethin
Member
Member
Posts: 625
Joined: Sun Jun 23, 2019 5:36 pm
Location: North Dakota, United States

Re: Usefulness of UEFI

Post by Ethin »

bzt wrote:
Ethin wrote:its unsurprising it would boot the processor directly into long mode
The problem is, UEFI spec does not specify the details how long mode is set up on the BSP. Plus UEFI does not boot the APs into long-mode, as I've already said, but they still start in real-mode, meaning you'll need that trampoline code anyway on SMP systems. It would be different if you could start APs with UEFI into long-mode, but you can't, because the spec is badly designed. It is pretty annoying to know that UEFI must include all the necessary code (for MP Services), but you just can't use that, so you have to reimplement everything yourself... This is what we call "failure by design", and it isn't helpful at all.

Cheers,
bzt
Oh, would you quit with this tripe? UEFI doesn't need to specify how the BSP is set up in long mode because its completely unnecessary. As soon as you call ExitBootServices() the boot environment is gone, so its completely irrelevant to OS development. You'll be overriding the page tables anyway so there's no reason for them to discuss it in depth. Yes, it doesn't boot the APs in long mode because that would most likely break all the OSes out there that use SMP, so that's entirely unsurprising. The spec is not "badly designed" with SMP. It provides MP services so long as you continue using the boot services because UEFI has full control over the hardware. Until you call ExitBootServices(), UEFI is the one in charge, not you. Your free to initialize the APs like you'd normally do after the boot environment is gone. There's no reason to boot them in long mode, because the firmware would need to return them to real mode anyway. Its not a failure by design.
I don't mean to be antagonistic but this is getting ridiculous. You don't need to know the hardware state because you'll literally need to replace it with your own anyway. The bootloader will give you some information but your still going to need to implement PCIe. Your still going to need to implement an ACPI parser. Your still going to need to implement storage drivers, network drivers and so on. And your still going to need to write a memory allocator and your still going to need to replace whatever is in CR3 with your own page tables because you'll want your kernel to run in a sane environment. As soon as processors with 5-level paging come out and the major bootloaders get support for them, I'm pretty sure they'll include a way of telling you that 5-level table paging is required. And if they don't, then you can always check the appropriate control and model-specific registers yourself. You don't need to care about the preboot environment unless your writing software explicitly designed to only run in the preboot environment, and a bootloader only runs in that environment until it loads your kernel. Then it loads it, terminates the boot services, and jumps to your kernel. Your kernels job is to then set up a sane environment for itself.
I imagine that the reason UEFI doesn't boot APs into long mode is because of compatibility. If they did that, every OS would need to have two SMP trampolines -- one for BIOS systems and one for UEFI systems. At least UEFI has an actual specification and we can guarantee that every UEFI implementation always operates the same way regarding lots of things. The BIOS didn't even have that.
Last edited by Ethin on Wed Mar 03, 2021 8:27 pm, edited 1 time in total.
Gigasoft
Member
Member
Posts: 858
Joined: Sat Nov 21, 2009 5:11 pm

Re: Usefulness of UEFI

Post by Gigasoft »

If we have to do this ourselves, then how exactly is UEFI helpful? I thought you were saying UEFI is good because it does these kinds of things for you, so you don't have to... Oh wait, you have to anyway!
What? No. No one said that.
The fact that you think that's easy and PIC would solve your issue indicates that you have no experience on this topic.
Funny how everyone but you manages it perfectly, then.
Writing a relocatable kernel is not as simple as you suggest, besides of position independent code that would also require a dynamic loader that applies relocations and fills up the GOT.
I didn't say you should make the whole kernel position independent. We're talking about a simple function that sets up page table mappings for the kernel image. You must be doing something really wrong to have the compiler emit GOT relocations, especially since you're in 64 bit mode.
Maybe straightforward, but not for you. Your first mistake was that APs start in real-mode, not in long-mode. Your second mistake was that you cannot disable paging in long mode. [...] Fourth mistake not knowing that SIPI needs a fixed segment to jump to. Straightforward, you say?
Did you even read the post I replied to? He's talking about switching from protected mode to long mode, not the AP trampoline.
Your third mistake was that both LIDT and MOV CR3 instructions require absolute, relocated addresses (yes, that means fixed addresses in lack of a dynamic linker).
What on earth have you been smoking? Of course, LIDT can use any memory addressing mode, and MOV CR3 can use any addressing mode.
You have to do everything manually, including constructing a list of relocations for the trampoline code in compile-time as well as applying those relocations in run-time according to that table. It is everything but not straightforward!
And what would this code be doing that requires all these relocations? Mine certainly doesn't.
Ethin
Member
Member
Posts: 625
Joined: Sun Jun 23, 2019 5:36 pm
Location: North Dakota, United States

Re: Usefulness of UEFI

Post by Ethin »

Gigasoft wrote:
If we have to do this ourselves, then how exactly is UEFI helpful? I thought you were saying UEFI is good because it does these kinds of things for you, so you don't have to... Oh wait, you have to anyway!
What? No. No one said that.
The fact that you think that's easy and PIC would solve your issue indicates that you have no experience on this topic.
Funny how everyone but you manages it perfectly, then.
Writing a relocatable kernel is not as simple as you suggest, besides of position independent code that would also require a dynamic loader that applies relocations and fills up the GOT.
I didn't say you should make the whole kernel position independent. We're talking about a simple function that sets up page table mappings for the kernel image. You must be doing something really wrong to have the compiler emit GOT relocations, especially since you're in 64 bit mode.
Maybe straightforward, but not for you. Your first mistake was that APs start in real-mode, not in long-mode. Your second mistake was that you cannot disable paging in long mode. [...] Fourth mistake not knowing that SIPI needs a fixed segment to jump to. Straightforward, you say?
Did you even read the post I replied to? He's talking about switching from protected mode to long mode, not the AP trampoline.
Your third mistake was that both LIDT and MOV CR3 instructions require absolute, relocated addresses (yes, that means fixed addresses in lack of a dynamic linker).
What on earth have you been smoking? Of course, LIDT can use any memory addressing mode, and MOV CR3 can use any addressing mode.
You have to do everything manually, including constructing a list of relocations for the trampoline code in compile-time as well as applying those relocations in run-time according to that table. It is everything but not straightforward!
And what would this code be doing that requires all these relocations? Mine certainly doesn't.
You know, I've wanted to make my kernel generate the SMP trampoline at runtime. I'm still trying to figure out the assembler syntax -> library usage conversion, but I'm pretty positive that once I can figure that out it'll work just fine. But eh, that's for when I need SMP, and I don't need that quite yet. It'll be fun seeing if I can actually get it to do it though!
rdos
Member
Member
Posts: 3351
Joined: Wed Oct 01, 2008 1:55 pm

Re: Usefulness of UEFI

Post by rdos »

Ethin wrote:Why would you ever want to make an OS that's only 32-bit and then want to use it on UEFI? UEFI is meant for the future, so its unsurprising it would boot the processor directly into long mode and forget about protected mode. And, as others have said, I doubt UEFI will use 5-level paging unless its been confirmed that all the major bootloaders support it first. Though I don't know why what paging UEFI uses would matter at all since you'll be swapping in your own page tables anyway...
Why? Because the segmented memory model is so superior to long mode, and you really don't need 64-bit addressing anyway. Long mode doesn't even have a full 64-bit address space, and also uses 32-bit relative addressing unless you load 48-bit addresses using constants.

The question is more why anybody would want to use long mode at all.
rdos
Member
Member
Posts: 3351
Joined: Wed Oct 01, 2008 1:55 pm

Re: Usefulness of UEFI

Post by rdos »

Ethin wrote: Oh, would you quit with this tripe? UEFI doesn't need to specify how the BSP is set up in long mode because its completely unnecessary. As soon as you call ExitBootServices() the boot environment is gone, so its completely irrelevant to OS development. You'll be overriding the page tables anyway so there's no reason for them to discuss it in depth.
Exactly, which is why entering the OS loader with paging is enabled is completely useless.
Ethin wrote: Yes, it doesn't boot the APs in long mode because that would most likely break all the OSes out there that use SMP, so that's entirely unsurprising. The spec is not "badly designed" with SMP. It provides MP services so long as you continue using the boot services because UEFI has full control over the hardware. Until you call ExitBootServices(), UEFI is the one in charge, not you. Your free to initialize the APs like you'd normally do after the boot environment is gone. There's no reason to boot them in long mode, because the firmware would need to return them to real mode anyway. Its not a failure by design.
Intel & AMD would have made it much easier to remove real mode in future processors if they added it to UEFI so OSes written today didn't rely on real mode. However, they failed to and so they cannot remove real mode anytime soon. Actually, they cannot remove protected mode either for the same reason.
Ethin
Member
Member
Posts: 625
Joined: Sun Jun 23, 2019 5:36 pm
Location: North Dakota, United States

Re: Usefulness of UEFI

Post by Ethin »

I very much disagree. How exactly is segmented memory superior to paging? (Also, x86 may only have 48-bit to 57-bit memory addresses, but other architectures like RISC-V do not have that limitation but employ paging.) If segmented memory was so superior as you claim, every other architecture would use it. Clearly, that isn't the case at all.
rdos
Member
Member
Posts: 3351
Joined: Wed Oct 01, 2008 1:55 pm

Re: Usefulness of UEFI

Post by rdos »

Ethin wrote:I very much disagree. How exactly is segmented memory superior to paging? (Also, x86 may only have 48-bit to 57-bit memory addresses, but other architectures like RISC-V do not have that limitation but employ paging.) If segmented memory was so superior as you claim, every other architecture would use it. Clearly, that isn't the case at all.
It's C compilers that cannot handle segmentation properly, something that goes back to poorly designed memory models in the days of 16-bit code.

Segmentation is superior since with a good design you can protect different parts of the kernel from each other, something that is impossible with flat memory models unless you go microkernel, and then you have huge inter-process communication delays instead.

Paging, in the absence of process isolation, doesn't solve the problems with flat memory models. Paging has too poor granularity and is per process, not per memory object as segmentation is. In a typical monolithic kernel, per-process means per-system since kernel memory is mapped in every process.
Post Reply