Page 1 of 2
UEFI in assembler
Posted: Sun May 02, 2021 5:57 am
by newosdeveloper2021
Where do I learn about UEFI (the spec is very complex), because the bare bones tutorials talk about the text mode buffer(very old), and I want to learn to UEFI in-depth, because tutorials tell you some offsets and little else.. I can only find crap tutorials
Re: UEFI in assembler
Posted: Sun May 02, 2021 10:34 pm
by nullplan
Well, which is it? Do you want to learn in depth or do you want a tutorial. We have a UEFI tutorial in the Wiki for you to peruse at your leisure, and if you want to go in-depth, there is the UEFI specification. It's not very complicated. UEFI works with PE DLLs (essentially; you have to make sure your code is position independent). Chapter 4 of the spec tells you what your entry point looks like and most of the remaining chapters are a reference for all the services you can call. But just like you don't need to have all of Ralf Brown's Interrupt List memorized when creating a legacy bootloader, you don't need to know all of the UEFI spec to write a UEFI bootloader.
Unsurprisingly, the job of a bootloader (to load a file into memory) largely remains the same, but with UEFI you no longer have to limit yourself to 512 bytes.
Re: UEFI in assembler
Posted: Sun May 02, 2021 11:06 pm
by zaval
you just need to conform to the calling convention for the particular architecture, there is nothing special in interfacing your loader, written in assembly, with UEFI, that provides the C language specified interface. just like any other C and assembly interaction. if you want to learn deep UEFI, then the only way is studying its specification. And I second, it's absolutely not complex. especially shouldn't be for one, who wants to write in assembly.
nullplan confused something, telling you need your code to be position independent, it absolutely doesn't, rather opposite - your loader is a PE image and it will be loaded at some base, maybe that, you specify, if it's free. You need your assembler to be able to generate PE images.
Re: UEFI in assembler
Posted: Mon May 03, 2021 5:40 am
by bzt
newosdeveloper2021 wrote:Where do I learn about UEFI (the spec is very complex), because the bare bones tutorials talk about the text mode buffer(very old), and I want to learn to UEFI in-depth, because tutorials tell you some offsets and little else.. I can only find crap tutorials
The easiest would be with
fasm (it has very good macro capabilities to use ABI wrappers and can generate PE executable with configurable subsystem). You'll need a function that converts standard calls to UEFI ABI, and then use the UEFI spec to figure out the parameters to each calls.
Both can be found on the
wiki, the macro "uefi_call_wrapper" provides the ABI wrapper, and there are examples on how to read sectors, set screen resolution etc.
Cheers,
bzt
Re: UEFI in assembler
Posted: Mon May 03, 2021 7:03 am
by Korona
What others have said so far is correct. But let me ask for the "why?".
Using UEFI from assembler has zero benefits over using it from C. You mention that you want to learn UEFI in-depth but calling it from assembly will mainly teach you how to fight calling conventions and PIC idiosyncrasies and not really what UEFI is about. My 2¢: if you want to learn it in-depth, learn how it use it in C.
Re: UEFI in assembler
Posted: Mon May 03, 2021 12:15 pm
by nullplan
zaval wrote:nullplan confused something, telling you need your code to be position independent, it absolutely doesn't, rather opposite - your loader is a PE image and it will be loaded at some base, maybe that, you specify, if it's free. You need your assembler to be able to generate PE images.
I was under the impression the image had to be position independent, or else the UEFI would refuse to load it. Besides, I don't know ahead of time what addresses will be free, and having a PIC PE image will allow the UEFI to relocate the image properly wherever is space.
Korona wrote:What others have said so far is correct. But let me ask for the "why?".
Well, the wisdom of doing any osdev at all can be disputed, but yeah, seconded.
https://www.youtube.com/watch?v=wJ81MZUlrDo
That said, only the title of the thread talks about assembler, and the actual question is silent on the subject.
Re: UEFI in assembler
Posted: Mon May 03, 2021 12:52 pm
by kzinti
newosdeveloper2021 wrote:Where do I learn about UEFI (the spec is very complex), because the bare bones tutorials talk about the text mode buffer(very old), and I want to learn to UEFI in-depth, because tutorials tell you some offsets and little else.. I can only find crap tutorials
See
https://mjg59.dreamwidth.org/18773.html?thread=1003605 as a starting point.
nullplan wrote:I was under the impression the image had to be position independent, or else the UEFI would refuse to load it. Besides, I don't know ahead of time what addresses will be free, and having a PIC PE image will allow the UEFI to relocate the image properly wherever is space.
This is correct. The UEFI executable needs to be position independent. UEFI can relocate your code anywhere.
nullplan wrote:That said, only the title of the thread talks about assembler, and the actual question is silent on the subject.
Very few people are masochist enough to write a UEFI bootloader in assembly. It is unlikely that many people will be willing to take the time to help with this.
Re: UEFI in assembler
Posted: Mon May 03, 2021 1:32 pm
by vvaltchev
Korona wrote:What others have said so far is correct. But let me ask for the "why?".
Using UEFI from assembler has zero benefits over using it from C. You mention that you want to learn UEFI in-depth but calling it from assembly will mainly teach you how to fight calling conventions and PIC idiosyncrasies and not really what UEFI is about. My 2¢: if you want to learn it in-depth, learn how it use it in C.
I totally agree with that.
Also:
newosdeveloper2021 wrote: Where do I learn about UEFI (the spec is very complex), because the bare bones tutorials talk about the text mode buffer(very old), and I want to learn to UEFI in-depth, because tutorials tell you some offsets and little else.. I can only find crap tutorials.
If you really wanna avoid "crappy" tutorials, then read the spec, seriously. But, don't be scared: you won't need to read the WHOLE spec. Just some parts of it. If you find it too difficult, maybe you need to learn more about the theory behind operating systems and bootloaders in general. Also, you need to have some understanding about how C code gets compiled and linked, along with calling conventions etc. To build a UEFI application knowing what's going on, without blindly copy-pasting stuff from tutorials, you need to have some amount of knowledge and experience.
Could you be more specific and explain what do you find super-hard to understand in the UEFI spec?
Re: UEFI in assembler
Posted: Mon May 03, 2021 1:47 pm
by rdos
When I started with UEFI, the biggest problem was an environment that could create EFI files. I'm not on Linux, and I don't have M$ compilers, only OpenWatcom. However, I solved it by installing cygwin, both the 32-bit and the 64-bit version (on different computers) and downloaded GCC.
I actually was pondering to use assembly too, so I could avoid cygwin / Linux dependencies in my project. I eventually solved it by checking in the efi-executables into my SVN so I don't have to build them.
Re: UEFI in assembler
Posted: Mon May 03, 2021 2:09 pm
by Octocontrabass
nullplan wrote:I was under the impression the image had to be position independent, or else the UEFI would refuse to load it.
EFI binaries are supposed to be relocatable, which is almost the same as position-independent. I don't think the UEFI spec says anything about what will happen if your binary isn't relocatable. (OVMF will load it anyway, which makes it difficult to tell if your linker options are correct.)
Re: UEFI in assembler
Posted: Mon May 03, 2021 2:40 pm
by zaval
kzinti wrote:
This is correct. The UEFI executable needs to be position independent. UEFI can relocate your code anywhere.
relocating means fixing absolute addresses used inside instructions and data (pointers). It is NOT PIC. PE is not PIC by the nature.
nullplan wrote:
I was under the impression the image had to be position independent, or else the UEFI would refuse to load it. Besides, I don't know ahead of time what addresses will be free, and having a PIC PE image will allow the UEFI to relocate the image properly wherever is space.
You don't have to know free addresses, your PE image uses some as a base, it may be even 0; then the FW, when loading the image, looks if it can place it at this address, if it can, then that's all, if not, it relocates the image, fixing (changing) all the references to the absolute addresses, both in code and data. That's why it's not PIC, because PIC means no references to absolute addresses at all, all references are relative, for example, to the program counter. Then putting an image somewhere else wouldn't require fixing anything, since for example a reference "load word into reg R from the memory, that is N bytes above program counter" remains the same. Position dependent then would be "load word into reg R from the memory at the address A0". That's exactly what PE uses. if the image has been put not at the preferred base, then A0 needs to be changed to A1, before the image starts execution. It applies both to exes and dlls. loaders are exes. dlls would be something that imports/exports from/to other images. unfortunately, UEFI doesn't make use this feature (for example exporting Boot Services/Runtime Services is an obvious case, but they decided to invent almost the same instead, resulting in an uglier code).
EFI binaries are supposed to be relocatable, which is almost the same as position-independent. I don't think the UEFI spec says anything about what will happen if your binary isn't relocatable. (OVMF will load it anyway, which makes it difficult to tell if your linker options are correct.)
The only way to make a PE image non-relocatable is to strip relocation information. If you do this and the image really has a non empty .reloc section and the preferred base, the image has been linked to isn't available, the FW has zero chances to start it. Unless it includes instruction decoder and some euristic to guess if these data (in the data sections) are pointers or something else.
Re: UEFI in assembler
Posted: Mon May 03, 2021 7:05 pm
by kzinti
zaval wrote:
relocating means fixing absolute addresses used inside instructions and data (pointers). It is NOT PIC. PE is not PIC by the nature.
I understand the difference. You still need to compile your UEFI bootloader as PIC and link it as PIE. At least you do when using GCC. Do you have a different experience?
If I remove either -fpic or -pie, my bootloader stops working.
Every source I can find says that EFI needs position-independant code (i.e. -fpic). This appears to be the way you tell GCC to build a relocatable binary.
Re: UEFI in assembler
Posted: Mon May 03, 2021 7:43 pm
by zaval
kzinti wrote:zaval wrote:
relocating means fixing absolute addresses used inside instructions and data (pointers). It is NOT PIC. PE is not PIC by the nature.
I understand the difference. You still need to compile your UEFI bootloader as PIC and link it as PIE. At least you do when using GCC. Do you have a different experience?
If I remove either -fpic or -pie, my bootloader stops working.
That's the weirdness of GCC (or even that gnu-efi cruft), that has nothing to do with either the PE image format or UEFI. I don't use GCC.
Every source I can find says that EFI needs position-independant code (i.e. -fpic). This appears to be the way you tell GCC to build a relocatable binary.
for some incomprehensible reasons, this way, they produce an ELF shared object (that needs to be PIC) and wrap it into PE, instead of targetting PE directly... It's just, the right tool needs to be used, a normal PE generating compiler toolset, in this case. If you can't use MSVC, then Clang maybe? But anyway, that -fpic option for building an UEFI application is a useless artifact, forced on you by the strange attitude of gnu/folks. Still I believe, that mingw thing should be free of this nonsense (given gnu-efi is ditched as well, of course).
Re: UEFI in assembler
Posted: Mon May 03, 2021 8:04 pm
by kzinti
I have used mingw in the past and it is much easier to build an UEFI app with it (you don't need any of the gnu-efi trickeries).
That said, mingw actually forces fpic on you. It doesn't magically disappear. Here is what happens if you specify "-fpic" on the command line with mingw:
Code: Select all
foo.c:1:0: warning: -fPIC ignored for target (all code is position independent) [enabled by default]
So yeah... If you use mingw, you are actually generating position-independent code.
You are also right that PE doesn't require it.
Ah the joys of computer programming.
Re: UEFI in assembler
Posted: Mon May 03, 2021 10:27 pm
by Octocontrabass
kzinti wrote:So yeah... If you use mingw, you are actually generating position-independent code.
Despite the warning, GCC is generating the right code.
PE does require RIP-relative addressing if the executable might be loaded above 2GB. That's probably the reason why PIC is always enabled for 64-bit Windows targets.