Hello,
Is it common practice for a UEFI OS loader to allocate memory of type EfiLoaderData when loading the entire kernel into memory?
The UEFI specs says that - in general - UEFI OS loaders should allocate memory of type EfiLoaderData, and also all the information on the web I've come across on loading your own kernel into memory use this type of memory and everything seems to be working just fine. Probably because the execute permission bit is set for EfiLoaderData pages, but is this guaranteed to always be the case though?
Wouldn't it be better to only load the data part of your kernel into memory of type EfiLoaderData and the executable part of your kernel into memory of type EfiLoaderCode, just to ensure that it can always be executed on different platforms?
Loading your kernel, EfiLoaderData?
-
- Posts: 14
- Joined: Wed Jun 12, 2024 5:32 am
Re: Loading your kernel, EfiLoaderData?
No, you load the entire kernel as EfiLoaderData, and when you hand the memory map to the kernel, you tell it where the kernel is (given that you cannot know in advance). Or at least, that's what I do. I have to reformat the memory map to my bespoke format anyway, may as well reserve the kernel pages while I'm at it.
For the loader, the kernel is just data. It becomes code only once the kernel is executed, but then we are no longer in the loader phase.
For the loader, the kernel is just data. It becomes code only once the kernel is executed, but then we are no longer in the loader phase.
Carpe diem!
-
- Posts: 14
- Joined: Wed Jun 12, 2024 5:32 am
Re: Loading your kernel, EfiLoaderData?
Allright, loading the entire kernel as EfiLoaderData it is. Thanks nullplan!
Re: Loading your kernel, EfiLoaderData?
Such a bit is not set for this type at all nor does it matter.Probably because the execute permission bit is set for EfiLoaderData pages
You should get one thing: outside of UEFI running time, UEFI memory types are meant just for recognizing what to do with these pages next: whether it's free memory or it's firmware reserved, for ACPI or for run time services. And that's all of the purpose. You don't use these types for setting up attributes for pages where you put the kernel. You set up those attributes on your own, what exactly you need, in the page tables, built up by you. UEFI and its memory types have nothing to with that. EfiLoaderData for such allocations is used because it's all needed. For UEFI, it's really loader data. Those pages become code or data after your loader takes control over the map.
-
- Posts: 14
- Joined: Wed Jun 12, 2024 5:32 am
Re: Loading your kernel, EfiLoaderData?
Yes, I think I understand. After loading the kernel into memory as EfiLoaderData, I can set up my own page tables, map the loaded kernel, set the appropriate attributes, and then jump to the kernel's main entry point and go from there.
However, rather than placing the page table creation code inside the OS loader, I would prefer to include it in the kernel's init function. But jumping to the kernel's init code might not work if the execution of code in EfiLoaderData is not allowed by the page tables created by the firmware. That's why I was wondering if it's ok for an OS loader to load the executable part of the kernel as EfiLoaderCode.
But looking at nullplan's post, we probably should only use EfiLoaderData.
In any case, thanks for your reply zaval. Much appreciated.
However, rather than placing the page table creation code inside the OS loader, I would prefer to include it in the kernel's init function. But jumping to the kernel's init code might not work if the execution of code in EfiLoaderData is not allowed by the page tables created by the firmware. That's why I was wondering if it's ok for an OS loader to load the executable part of the kernel as EfiLoaderCode.
But looking at nullplan's post, we probably should only use EfiLoaderData.
In any case, thanks for your reply zaval. Much appreciated.
Re: Loading your kernel, EfiLoaderData?
I don't know your reason for that preference, but that would only mean, that you postponed one of the main loader's task to the kernel function (2 in fact: building up the mapping and trampoline (jumping from UEFI space to the kernel one)). That function then would have to start in the UEFI (identity mapped) address space, build up its page table structure and switch to its own address space. Meaning you would need to ExitBootServices() from the kernel, rather from the loader, as normally is being done. If you ExitBootServices() in the loader, but without your own page tables built up yet, that would be a massive mess, - you would need then to add to that yet one page allocator, page table building requires pages for itself... but, it's up to the designer.However, rather than placing the page table creation code inside the OS loader, I would prefer to include it in the kernel's init function. But jumping to the kernel's init code might not work if the execution of code in EfiLoaderData is not allowed by the page tables created by the firmware.
Marking memory as EfiLoaderCode is used by UEFI internally for its payload's code section pages. It's for .efi files, intended for running in the UEFI environment.
-
- Posts: 14
- Joined: Wed Jun 12, 2024 5:32 am
Re: Loading your kernel, EfiLoaderData?
Interesting. I was under the impression that a UEFI OS loader's job was to do just these two things: 1) gather system information that needs to be passed to the kernel, and 2) load the kernel into memory, get the memory map, call ExitBootServices, and finally hand off control to the loaded kernel image. The loaded kernel image would then enter an initialization stage in which it would create the PML4 page table and set up the necessary system tables, such as the GDT and IDT. I didn’t realize that these tasks were supposed to be part of the OS loader. To me, it felt like they needed to be part of the kernel's initialization process, but perhaps you are right, and it’s bad design. I’ll give it some more thought. Thank you.