flat assembler
Message board for the users of flat assembler.
 Home   FAQ   Search   Register 
 Profile   Log in to check your private messages   Log in 
flat assembler > Main > UEFI questions

Goto page 1, 2, 3  Next
Author
Thread Post new topic Reply to topic
MrFox



Joined: 17 Aug 2016
Posts: 52
Location: Russia
UEFI questions
Hello, I've been trying to figure out how to start coding with UEFI in assembler.
I found a few examples of very basic programs from osdev in fasm, tried them and yay, they worked.

Since I'm new to UEFI in asm I have a couple of questions. The one to start off with:

1. Why do we have to save ebp on entry and restore it before exit?


Code:
include 'efi.inc'

main:
        push ebp; !!!!!!!!!!!!!!!!!!!!!!!! ---- Saving
        mov ebpesp

        ...
        blah blah blah
        ...

        mov ecx, [edx + 4]
        mov eaxEFI_SYSTEM_TABLE_SIGNATURE2
        cmp eaxecx
        jne error

        ...
        blah blah blah
        ...

success:
        mov eaxEFI_SUCCESS
        pop ebp ; !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! --- Restoring
        retn

error:
        mov eax1
        pop ebp ; !!!!!!!!!!!!!!!!!!!!!!!!!!! --- And once again
        retn


Post 17 Aug 2016, 20:38
View user's profile Send private message Reply with quote
Trinitek



Joined: 06 Nov 2011
Posts: 257
UEFI on x86-64 platforms uses Microsoft's x64 calling convention. You would see the same saving and restoring procedure when entering and leaving a 64-bit function in userspace code on Windows as well.
Post 17 Aug 2016, 22:51
View user's profile Send private message Reply with quote
MrFox



Joined: 17 Aug 2016
Posts: 52
Location: Russia
Thank you Trinitec.
I looked that up, so very interesting thing to read.
Post 18 Aug 2016, 06:56
View user's profile Send private message Reply with quote
Trinitek



Joined: 06 Nov 2011
Posts: 257
Actually, since that's 32-bit code, that would be the cdecl calling convention, but the saving/restoring procedure is the same. Not sure why I didn't catch that.
Post 18 Aug 2016, 12:46
View user's profile Send private message Reply with quote
JohnFound



Joined: 16 Jun 2003
Posts: 3436
Location: Bulgaria
ebp is used for comfortable access to the arguments and local variables, both located on the stack.
Of course, you can access these variables using esp directly, but if you push/pop some values in the stack, esp will change and the offset to the variables will change as well. This will make the code much less readable and the risk of bugs increases. In the same time, once, esp is copied to ebp, you can use ebp with constant offset to every local variable (function argument).

So, this way, If you don't use local variables or procedure arguments and don't change ebp, there is no need to save it.
Post 18 Aug 2016, 13:20
View user's profile Send private message Visit poster's website ICQ Number Reply with quote
MrFox



Joined: 17 Aug 2016
Posts: 52
Location: Russia
Umm I've read there about preserving registers, calling conventions, shadow space in the stack... Do I have to adhere to all that within my code as well or does it only refer to external calls and rets (apart from readability issues)?
Post 19 Aug 2016, 06:34
View user's profile Send private message Reply with quote
Trinitek



Joined: 06 Nov 2011
Posts: 257

MrFox wrote:
Umm I've read there about preserving registers, calling conventions, shadow space in the stack... Do I have to adhere to all that within my code as well or does it only refer to external calls and rets (apart from readability issues)?

It's absolutely required that you adhere to the convention when calling external functions. You can do whatever you want with internal functions, however. I think that you should be aware that there are macros available that allow you to define and call functions of a particular convention, so you do not have to write the entry and exit procedures yourself.
Post 19 Aug 2016, 06:55
View user's profile Send private message Reply with quote
MrFox



Joined: 17 Aug 2016
Posts: 52
Location: Russia
Thanks, Trinitec, that's what I needed to know.
AFAIK, there are not only macros but even special x86 assembly instructions created especially to do such things.
Enter and Leave: http://stackoverflow.com/questions/5858996/enter-and-leave-in-assembly
does FASM support them?

Question #2
I'm wracking my brains around the http://wiki.osdev.org/Uefi.inc and can't figure out why on earth the guy needed all those bells and whistles with redefining data types and structures (see efi.inc titled "The include file" at the middle of the page).

Namely, I can't get why he needed all those:

Code:
...

struc int64 {
  align 8
  . dq ?
}

...

macro struct name
{
  virtual at 0
    name name
  end virtual
}

...

struc EFI_TABLE_HEADER {
 .Signature             int64
 .Revision              int32
 .HeaderSize            int32
 .CRC32                 int32
 .Reserved              int32
}
struct EFI_TABLE_HEADER

struc EFI_SYSTEM_TABLE {
 .Hdr                   EFI_TABLE_HEADER
 .FirmwareVendor        dptr
 .FirmwareRevision      int32
 .ConsoleInHandle       dptr
 .ConIn                 dptr
 .ConsoleOutHandle      dptr
 .ConOut                dptr
 .StandardErrorHandle   dptr
 .StdErr                dptr
 .RuntimeServices       dptr
 .BootServices          dptr
 .NumberOfTableEntries  intn
 .ConfigurationTable    dptr
}
struct EFI_SYSTEM_TABLE
...



why don't we just use:


Code:
struc EFI_TABLE_HEADER
{virtual at 0
;----------------------
 .Signature             dq ?
 .Revision              dd ?
 .HeaderSize            dd ?
 .CRC32                 dd ?
 .Reserved              dd ?
;----------------------
 end virtual}

Post 24 Aug 2016, 18:02
View user's profile Send private message Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 15086
Location: The Unicomplex
When you put "virtual at 0" inside the struc definition then you won't be able to instantiate the structure into any memory address other than 0. So probably not a good idea unless you know that you never need anything else.

For "enter" and "leave", yes fasm supports them. But most people don't use them because of concerns about performance. But you are free to use them if you wish to.
Post 24 Aug 2016, 18:14
View user's profile Send private message Visit poster's website Reply with quote
MrFox



Joined: 17 Aug 2016
Posts: 52
Location: Russia
Oh, thanks. What do you mean by performance? Any issues using them?

If I understood that code correctly, that guy uses the structures to only provide offsets, like this:

Code:
mov edxdword [rax+EFI_BLOCK_IO_MEDIA.MediaId]


or this:

Code:
clear:
        mov eaxEFI_SYSTEM_TABLE.ConOut
        mov ecx, [SystemTable]
        add ecxeax
        mov ecx, [ecx]

        mov edxecx
        mov eaxSIMPLE_TEXT_OUTPUT_INTERFACE.ClearScreen
        add edxeax

        push ecx                                ; [arg] SystemTable.ConOut

        mov edx, [edx]
        call edx
        add esp4


I guess my interpretation of his code will work exactly the same way, won't it?
Post 24 Aug 2016, 18:28
View user's profile Send private message Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 15086
Location: The Unicomplex
By performance, this is how other people view them. Other people think that enter/leave are slow so they avoid them. Sometimes this makes sense, sometimes it doesn't matter. It depends upon what you are doing and where you use them.

If you only ever reference the struc in the way you show then it makes no difference. But you still need to initialise the values by instantiating the struc somewhere, you can't escape this requirement. Merely declaring the struc will not define the value of EFI_TABLE_HEADER.Signature. So you lose some flexibility without any gain in simplicity IMO.
Post 24 Aug 2016, 18:38
View user's profile Send private message Visit poster's website Reply with quote
Tomasz Grysztar
Assembly Artist


Joined: 16 Jun 2003
Posts: 6509
Location: Kraków, Poland

revolution wrote:
If you only ever reference the struc in the way you show then it makes no difference. But you still need to initialise the values by instantiating the struc somewhere, you can't escape this requirement. Merely declaring the struc will not define the value of EFI_TABLE_HEADER.Signature. So you lose some flexibility without any gain in simplicity IMO.

It could be a little bit simpler if "struc" was not used at all:

Code:
virtual at 0 
 EFI_TABLE_HEADER:
 .Signature             dq ? 
 .Revision              dd ? 
 .HeaderSize            dd ? 
 .CRC32                 dd ? 
 .Reserved              dd ? 
end virtual

This is how structure offsets used to be defined before fasm had "struc" implemented.
Post 24 Aug 2016, 19:01
View user's profile Send private message Visit poster's website Reply with quote
MrFox



Joined: 17 Aug 2016
Posts: 52
Location: Russia
Ok, I got it. Thanks.
The thing is, we do not initialize any of these tables or handles. They all already reside in memory when our UEFI app (they call it 'Image') starts and we only need these structures to address offsets within those tables. The app gains System_Table pointer and Loaded_Image handle pointer through stack when it's loaded and all the other references are being made relative to these pointers, 'browsing' the existing tree of structs and handles. That's why I think (as of now, at least) I'll never have to initialize those structures, only to map them on existing addresses. I may be mistaken though as I'm a lil noobie. Smile

Would you recommend that I stick to his way of declaration when introducing other structures from UEFI spec (there are tons of them) into that file?

---------------

Added: Thanks, Tomasz!!! Simplicity is what I need as these are my 'first steps' at fasm.
Post 24 Aug 2016, 19:07
View user's profile Send private message Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 15086
Location: The Unicomplex

MrFox wrote:
Would you recommend that I stick to his way of declaration when introducing other structures from UEFI spec (there are tons of them) into that file?

It is just personal preference. I would suggest that you do what makes sense to you, not necessarily what gives the most flexibility, or whatever other metric, if it confuses you. But it is nice to be able to understand the various methods and know that you can use them when you might need the extra flexibility in the future.
Post 24 Aug 2016, 19:13
View user's profile Send private message Visit poster's website Reply with quote
MrFox



Joined: 17 Aug 2016
Posts: 52
Location: Russia
Okay, as of now, I think I'll do what suits me best, i.e. put it as Tomasz suggested, because I hate it when there are pieces in MY code that I don't 100% understand (even if they are technically more correct).

And of course, I'll be 'reading the source' in order to improve my personal understanding of fasm syntax and working principles to get that extra flexibility in the future.

Thanks, guys, you rock!
Post 24 Aug 2016, 19:24
View user's profile Send private message Reply with quote
MrFox



Joined: 17 Aug 2016
Posts: 52
Location: Russia

Code:
virtual at 0 
 EFI_TABLE_HEADER:
 .Signature             dq ? 
 .Revision              dd ? 
 .HeaderSize            dd ? 
 .CRC32                 dd ? 
 .Reserved              dd ? 
end virtual


How can I implement nested structures?

I need something like this:

Code:
struc EFI_SYSTEM_TABLE {
 .Hdr                           EFI_TABLE_HEADER
 .FirmwareVendor                dptr
 .FirmwareRevision              int32
 .ConsoleInHandle               dptr
 .ConIn                         dptr
 .ConsoleOutHandle              dptr
 .ConOut                        dptr
 .StandardErrorHandle           dptr
 .StdErr                        dptr
 .RuntimeServices               dptr
 .BootServices                  dptr
 .NumberOfTableEntries          intn
 .ConfigurationTable            dptr
}

Post 25 Aug 2016, 05:53
View user's profile Send private message Reply with quote
Tomasz Grysztar
Assembly Artist


Joined: 16 Jun 2003
Posts: 6509
Location: Kraków, Poland
For this you need "struc", because you need to instantiate the same structure in different places. Simplified variant is not your friend in such case.
Post 25 Aug 2016, 07:08
View user's profile Send private message Visit poster's website Reply with quote
MrFox



Joined: 17 Aug 2016
Posts: 52
Location: Russia
Thanks!

I have a question regarding programming technique.

The task is to browse through the system table and its subtables. They contain values and pointers. This man uses different registers to move along the table and jump to pointers:


Code:
clear:
        mov eaxEFI_SYSTEM_TABLE.ConOut
        mov ecx, [SystemTable]
        add ecxeax
        mov ecx, [ecx]

        mov edxecx
        mov eaxSIMPLE_TEXT_OUTPUT_INTERFACE.ClearScreen
        add edxeax

        push ecx                                ; [arg] SystemTable.ConOut

        mov edx, [edx]
        call edx
        add esp4
        ret




Why don't we just use one register for all that? Would it be faster or slower?


Code:
clear:
        mov eax, [SystemTable]
        add eaxEFI_SYSTEM_TABLE.ConOut
        mov eax, [eax]
        push eax                                ; [arg] SystemTable.ConOut

        add eaxSIMPLE_TEXT_OUTPUT_INTERFACE.ClearScreen
        mov eax, [eax]
        call eax
        add esp4

        ret

Post 25 Aug 2016, 11:16
View user's profile Send private message Reply with quote
MrFox



Joined: 17 Aug 2016
Posts: 52
Location: Russia
Afterthought: maybe that's done this way to prevent local overheating EAX cpu cirquitry?
Post 25 Aug 2016, 11:32
View user's profile Send private message Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 15086
Location: The Unicomplex
Don't worry about "overheating" any particular part of the CPU. Use whatever registers you want.

And besides, modern CPUs use register renaming so such a thing isn't possible even if you tried to do it deliberately.
Post 26 Aug 2016, 07:51
View user's profile Send private message Visit poster's website Reply with quote
Display posts from previous:
Post new topic Reply to topic

Jump to:  
Goto page 1, 2, 3  Next

< Last Thread | Next Thread >

Forum Rules:
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Powered by phpBB © 2001-2005 phpBB Group.

Main index   Download   Documentation   Examples   Message board
Copyright © 2004-2016, Tomasz Grysztar.