OSDev.org https://forum.osdev.org/ |
|
Simple Assembly UEFI Application -- Can't Exit Boot Services https://forum.osdev.org/viewtopic.php?f=1&t=33666 |
Page 1 of 2 |
Author: | charlesap [ Fri Apr 26, 2019 4:18 pm ] |
Post subject: | Simple Assembly UEFI Application -- Can't Exit Boot Services |
I can make a simple pe+ UEFI application with fasm or nasm, I can output text using SIMPLE_TEXT_OUTPUT_INTERFACE, I can get the memory map using EFI_BOOT_SERVICES, I can reset the system using EFI_SYSTEM_TABLE.RuntimeServices but I cannot get EFI_BOOT_SERVICES.ExitBootServices to work. I've searched OSDev and scoured the Internet... I've gotten desperate enough to actually ask a question. Is there something obvious I'm missing? I've put the source assembly and the one assembly include file and build instructions I am following up on https://github.com/charlesap/fasm-uefi in case that's where the real problem is. I expect the following code to use RuntimeServices to reboot after completing ExitBootServices. It just hangs. It will reboot just fine if I comment out the ExitBootServices part. Help? Code: format pe64 dll efi
entry main section '.text' code executable readable include 'efi.inc' main: sub rsp, 4*8 ; reserve space for 4 arguments mov [Handle], rcx ; ImageHandle mov [SystemTable], rdx ; pointer to SystemTable lea rdx, [_hello] mov rcx, [SystemTable] mov rcx, [rcx + EFI_SYSTEM_TABLE.ConOut] call [rcx + SIMPLE_TEXT_OUTPUT_INTERFACE.OutputString] ; get the memory map mov dword [memmapdescsize], 48 lea rcx, [memmapsize] mov qword [rcx], 4096 lea rdx, [memmapbuff] lea r8, [memmapkey] lea r9, [memmapdescsize] lea rax, [memmapdescver] push rax mov rax, [SystemTable] mov rax, [rax + EFI_SYSTEM_TABLE.BootServices] call [rax + EFI_BOOT_SERVICES.GetMemoryMap] pop rcx test rax, rax jnz oops mov rcx, [Handle] mov rdx, [memmapkey] mov rax, [SystemTable] mov rax, [rax + EFI_SYSTEM_TABLE.BootServices] call [rax + EFI_BOOT_SERVICES.ExitBootServices] cmp rax, EFI_SUCCESS je reboot ; if first time fails, second time is supposed to succeed: mov dword [memmapdescsize], 48 lea rcx, [memmapsize] mov qword [rcx], 4096 lea rdx, [memmapbuff] lea r8, [memmapkey] lea r9, [memmapdescsize] lea rax, [memmapdescver] push rax mov rax, [SystemTable] mov rax, [rax + EFI_SYSTEM_TABLE.BootServices] call [rax + EFI_BOOT_SERVICES.GetMemoryMap] pop rcx test rax, rax jnz oops mov rcx, [Handle] mov rdx, [memmapkey] mov rax, [SystemTable] mov rax, [rax + EFI_SYSTEM_TABLE.BootServices] call [rax + EFI_BOOT_SERVICES.ExitBootServices] reboot: mov rax, [SystemTable] mov rax, [rax + EFI_SYSTEM_TABLE.RuntimeServices] mov rcx, EfiResetShutdown mov rdx, EFI_SUCCESS xor r8, r8 xor r9, r9 call [rax + EFI_RUNTIME_SERVICES.ResetSystem] jmp oops oops: lea rdx, [_nok] mov rcx, [SystemTable] mov rcx, [rcx + EFI_SYSTEM_TABLE.ConOut] call [rcx + SIMPLE_TEXT_OUTPUT_INTERFACE.OutputString] jmp $-1 add rsp, 4*8 mov eax, 0 ; was EFI_SUCCESS retn section '.data' data readable writeable memmapbuff: rb 4096 Handle dq 0 SystemTable dq 0 memmapsize: dq 4096 memmapkey: dq 0 memmapdescsize: dq 0 memmapdescver: dq 0 _yok du 'ok.',13,10,0 _nok du 'not ok.',13,10,0 _hello du 'hello world',13,10,0 section '.reloc' fixups data discardable |
Author: | bzt [ Sat Apr 27, 2019 5:07 am ] |
Post subject: | Re: Simple Assembly UEFI Application -- Can't Exit Boot Serv |
Hi, Code: call [rax + EFI_BOOT_SERVICES.GetMemoryMap] It's a miracle if your code does anything at all, the UEFI ABI is not like that. You can only pass 4 arguments in registers, the others must be in stack, and you must preserve space for those 4 arguments. Also you must pass the number of arguments as a first argument on every function call. Therefore the address of the memory key (required by ExitBootServices) is NOT passed in r8.Check out the wiki Uefi.inc. There the uefi_call_wrapper macro counts the arguments and calls uefifunc with SysV-like ABI (passing argument count in AL, and the uefi func in RBX). It worth mentioning that it also calculates function addresses dynamically. Then uefifunc arranges the stack and registers properly and calls the real function using the fastcall-like UEFI ABI. Cheers, bzt |
Author: | charlesap [ Sat Apr 27, 2019 3:09 pm ] |
Post subject: | Re: Simple Assembly UEFI Application -- Can't Exit Boot Serv |
Thanks for the pointer. Perhaps uefi.inc can help... I hope to make raw calls as simply as possible. Clearly I'm missing something! |
Author: | zaval [ Sat Apr 27, 2019 3:55 pm ] |
Post subject: | Re: Simple Assembly UEFI Application -- Can't Exit Boot Serv |
Quote: You can only pass 4 arguments in registers, the others must be in stack he does this. Quote: Also you must pass the number of arguments as a first argument on every function call. WHAT? it's BS. there is no such a thing in the UEFI spec. As of the OP problem, you don't need to call both GetMemoryMap() and ExitBootServices() twice, it's wrong. I mean - testing only for zero (EFI_SUCCESS) after the first call to GetMemoryMap() is not enough. And also wrong to just duplicate code after the fail without any actions. The algorithm for dealing with this pair is like this: Code: /* you first call GetMemoryMap() to learn how big memory map is going to be * passing some reasonable sized buffer */ PVOID Buffer; St = AllocatePool(EfiLoaderData, MemoryMapSize, &Buffer); ... Counter = 1; Addendum = 0x1000; /* modify it if you see, that this is too small and function doesn't succeed quickly */ do{ Status = GetMemoryMap(&MemoryMapSize, (EFI_MEMORY_DESCRIPTOR *)Buffer, &MapKey, &DescriptorSize, &DescriptorVersion); switch(Status){ case EFI_BUFFER_TOO_SMALL: Counter++; FreePool(Buffer); /* or FreePages() depending on what allocation mechanism you were using */ MemoryMapSize += Addendum; St = AllocatePool(EfiLoaderData, MemoryMapSize, &Buffer); if(St != EFI_SUCCESS) Fail("Can't allocate memory for the memory map."); break; case EFI_INVALID_PARAMETER: Fail("My loader has a bug."); } }while(Status == EFI_BUFFER_TOO_SMALL); DebugPrint("GetMemoryMap succeeded from the %d time.", Count); /* for addendum tuning */ Status = ExitBootServices(MyHandle, MapKey); if(Status == EFI_SUCCESS){ /* here, you do your crazy stuff, BUT without relying on Boot Services */ }else{ Fail("I passed a wrong MapKey to ExitBootServices()."); } And yet, may I give an advice? Write in C, don't torturize your 4ss. At least UEFI part; it's specially been done for C writing. Quote: Thanks for the pointer. Perhaps uefi.inc can help... I hope to make raw calls as simply as possible. Clearly I'm missing something! I'd not rely on those pointers, since they are obviously broken, bzt often claims things that are true only for him. |
Author: | kzinti [ Sat Apr 27, 2019 4:42 pm ] |
Post subject: | Re: Simple Assembly UEFI Application -- Can't Exit Boot Serv |
zaval wrote: Quote: Also you must pass the number of arguments as a first argument on every function call. WHAT? it's BS. there is no such a thing in the UEFI spec. I concur. zaval wrote: And yet, may I give an advice? Write in C, don't torturize your 4ss. At least UEFI part; it's specially been done for C writing. I concur. Why torture yourself with assembly when you don't need it. Here is another example from my own code base: https://github.com/kiznit/rainbow-os/bl ... #L146-L184 Code: static EFI_STATUS ExitBootServices()
{ UINTN size = 0; UINTN allocatedSize = 0; EFI_MEMORY_DESCRIPTOR* descriptors = nullptr; UINTN memoryMapKey = 0; UINTN descriptorSize = 0; UINT32 descriptorVersion = 0; // 1) Retrieve the memory map from the firmware EFI_STATUS status; while ((status = BS->GetMemoryMap(&size, descriptors, &memoryMapKey, &descriptorSize, &descriptorVersion)) == EFI_BUFFER_TOO_SMALL) { // Extra space to play safe with "partial shutdown" when calling ExitBootServices(). size += descriptorSize * 10; descriptors = (EFI_MEMORY_DESCRIPTOR*)realloc(descriptors, size); if (!descriptors) { return EFI_OUT_OF_RESOURCES; } allocatedSize = size; } // 2) Exit boot services - it is possible for the firmware to modify the memory map // during a call to ExitBootServices(). A so-called "partial shutdown". // When that happens, ExitBootServices() will return EFI_INVALID_PARAMETER. while ((status = BS->ExitBootServices(g_efiImage, memoryMapKey)) == EFI_INVALID_PARAMETER) { // Memory map changed during ExitBootServices(), the only APIs we are allowed to // call at this point are GetMemoryMap() and ExitBootServices(). size = allocatedSize; status = BS->GetMemoryMap(&size, descriptors, &memoryMapKey, &descriptorSize, &descriptorVersion); if (EFI_ERROR(status)) { return status; } } return status; } |
Author: | charlesap [ Sat Apr 27, 2019 6:22 pm ] |
Post subject: | Re: Simple Assembly UEFI Application -- Can't Exit Boot Serv |
It is my intention to get away from assembly as soon as I can... but my goal is to move to a native Oberon instead of c, which somewhat constrains my toolchain... Also I have banged on the code for long enough that it has started working and now I have to figure out why. I'll post an update. |
Author: | kzinti [ Sat Apr 27, 2019 6:38 pm ] |
Post subject: | Re: Simple Assembly UEFI Application -- Can't Exit Boot Serv |
charlesap wrote: It is my intention to get away from assembly as soon as I can... but my goal is to move to a native Oberon instead of c, which somewhat constrains my toolchain... Surely you can use C to bootstrap your Oberon runtime? charlesap wrote: Also I have banged on the code for long enough that it has started working and now I have to figure out why. Well that's good news (hopefully). Getting UEFI to cooperate is rather painful. |
Author: | charlesap [ Sat Apr 27, 2019 9:26 pm ] |
Post subject: | Re: Simple Assembly UEFI Application -- Can't Exit Boot Serv |
So here's the code that works (successfully calls ExitBootServices and then successfully calls ResetSystem) : Code: format pe64 dll efi entry main section '.text' code executable readable include 'efi.inc' main: sub rsp, 6*8 ; reserve space for 6 arguments mov [Handle], rcx ; ImageHandle mov [SystemTable], rdx ; pointer to SystemTable lea rdx, [_hello] mov rcx, [SystemTable] mov rcx, [rcx + EFI_SYSTEM_TABLE.ConOut] call [rcx + SIMPLE_TEXT_OUTPUT_INTERFACE.OutputString] mov qword [memmapsize], 4096 lea rcx, [memmapsize] lea rdx, [memmap] lea r8, [memmapkey] lea r9, [memmapdescsize] lea r10, [memmapdescver] mov [STK],rsp push r10 sub rsp, 4*8 mov rbx, [SystemTable] mov rbx, [rbx + EFI_SYSTEM_TABLE.BootServices] call [rbx + EFI_BOOT_SERVICES.GetMemoryMap] add rsp, 4*8 pop r10 mov rsp, [STK] cmp rax, EFI_SUCCESS jne oops mov rbx, [memmapkey] push rax push rcx push rdx call printhex pop rdx pop rcx pop rax mov rcx, [Handle] mov rdx, [memmapkey] mov rbx, [SystemTable] mov rbx, [rbx + EFI_SYSTEM_TABLE.BootServices] call [rbx + EFI_BOOT_SERVICES.ExitBootServices] cmp rax, EFI_SUCCESS je reboot ; if first time fails, second time is supposed to succeed: mov qword [memmapsize], 4096 lea rcx, [memmapsize] lea rdx, [memmap] lea r8, [memmapkey] lea r9, [memmapdescsize] lea r10, [memmapdescver] mov [STK],rsp push r10 sub rsp, 4*8 mov rax, 5 mov rbx, [SystemTable] mov rbx, [rbx + EFI_SYSTEM_TABLE.BootServices] call [rbx + EFI_BOOT_SERVICES.GetMemoryMap] add rsp, 4*8 pop r10 mov rsp, [STK] cmp rax, EFI_SUCCESS jne oops mov rbx, [memmapkey] push rax push rcx push rdx call printhex pop rdx pop rcx pop rax mov rcx, [Handle] mov rdx, [memmapkey] mov rbx, [SystemTable] mov rbx, [rbx + EFI_SYSTEM_TABLE.BootServices] call [rbx + EFI_BOOT_SERVICES.ExitBootServices] reboot: mov rbx, [SystemTable] mov rbx, [rbx + EFI_SYSTEM_TABLE.RuntimeServices] mov rcx, EfiResetShutdown mov rdx, EFI_SUCCESS xor r8, r8 call [rbx + EFI_RUNTIME_SERVICES.ResetSystem] jmp oops oops: lea rdx, [_nok] mov rcx, [SystemTable] mov rcx, [rcx + EFI_SYSTEM_TABLE.ConOut] call [rcx + SIMPLE_TEXT_OUTPUT_INTERFACE.OutputString] A: jmp A eek: lea rdx, [_eek] mov rcx, [SystemTable] mov rcx, [rcx + EFI_SYSTEM_TABLE.ConOut] call [rcx + SIMPLE_TEXT_OUTPUT_INTERFACE.OutputString] B: jmp B boop: lea rdx, [_boop] mov rcx, [SystemTable] mov rcx, [rcx + EFI_SYSTEM_TABLE.ConOut] call [rcx + SIMPLE_TEXT_OUTPUT_INTERFACE.OutputString] ret add rsp, 6*8 mov eax, 0 ; was EFI_SUCCESS retn printhex: mov rbp, 16 .loop: rol rbx, 4 mov rax, rbx and rax, 0Fh lea rcx, [_Hex] mov rax, [rax + rcx] mov byte [_Num], al lea rdx, [_Num] mov rcx, [SystemTable] mov rcx, [rcx + EFI_SYSTEM_TABLE.ConOut] call [rcx + SIMPLE_TEXT_OUTPUT_INTERFACE.OutputString] dec rbp jnz .loop lea rdx, [_Nl] mov rcx, [SystemTable] mov rcx, [rcx + EFI_SYSTEM_TABLE.ConOut] call [rcx + SIMPLE_TEXT_OUTPUT_INTERFACE.OutputString] ret section '.data' data readable writeable memmap: times 4096 db 0 Handle dq 0 SystemTable dq 0 ;RTS dq 0 ;BS dq 0 STK dq 0 ptrmemmap: dq 0 memmapsize: dq 0 memmapkey: dq 0 memmapdescsize: dq 0 memmapdescver: dq 0 _yok du 'ok.',13,10,0 _nok du 'not ok.',13,10,0 _eek du 'eek!',13,10,0 _boop du 'boop',13,10,0 _hello du 'hello world',13,10,0 _Hex db '0123456789ABCDEF' _Num dw 0,0 _Nl dw 13,10,0 section '.reloc' fixups data discardable The weird thing is that if I comment out either block where I am using printhex to output the memmapkey, the code hangs inside ExitBootServices. If I don't comment out the printhex calls I can go on with the uefi disabled and I can reboot the system, I can write to the framebuffer, etc. as one would expect. |
Author: | bellezzasolo [ Sun Apr 28, 2019 1:48 am ] |
Post subject: | Re: Simple Assembly UEFI Application -- Can't Exit Boot Serv |
zaval wrote: Quote: You can only pass 4 arguments in registers, the others must be in stack he does this. Quote: Also you must pass the number of arguments as a first argument on every function call. WHAT? it's BS. there is no such a thing in the UEFI spec. It kind of is in the UEFI spec. You need a 16 byte aligned stack, using the "C calling convention" UEFI Spec wrote: The caller passes the first four integer arguments in registers. The integer values are passed from left to right in Rcx, Rdx, R8, and R9 registers. The caller passes arguments five and above onto the stack. All arguments must be right-justified in the register in which they are passed. This ensures the callee can process only the bits in the register that are required. The caller passes arrays and strings via a pointer to memory allocated by the caller. The caller passes structures and unions of size 8, 16, 32, or 64 bits as if they were integers of the same size. The caller is not allowed to pass structures and unions of other than these sizes and must pass these unions and structures via a pointer. The callee must dump the register parameters into their shadow space if required. The most common requirement is to take the address of an argument. This is the MS x64 calling convention - https://docs.microsoft.com/en-us/cpp/build/x64-calling-convention?view=vs-2019 |
Author: | bzt [ Sun Apr 28, 2019 4:02 am ] |
Post subject: | Re: Simple Assembly UEFI Application -- Can't Exit Boot Serv |
charlesap wrote: The weird thing is that if I comment out either block where I am using printhex to output the memmapkey, the code hangs inside ExitBootServices. If I don't comment out the printhex calls I can go on with the uefi disabled and I can reboot the system, I can write to the framebuffer, etc. as one would expect. Keep in mind that print (I mean Simple Text Output protocol) may or may not allocate temporary variables depending on it's arguments. Your memmapkey is only valid if the memory map does not change. Therefore you must avoid calling anything that may allocate or free memory between the GetMemMap and ExitBootServices, otherwise ExitBootServices will always return with an "Invalid key" error.What you wrote seems to be quite the opposite, which is strange. Without digging deep into your code it looks like you pass the wrong argument somehow, and printhex somehow sets it in the correct register too. I would recommend to use a debugger and check the input arguments for ExitBootServices with and without printhex, inputs should be the same. Cheers, bzt |
Author: | MichaelPetch [ Sun Apr 28, 2019 9:35 am ] |
Post subject: | Re: Simple Assembly UEFI Application -- Can't Exit Boot Serv |
Why is it with some EFI calls you allocate the required space (32 bytes) before making a call and other places you don't. You need the shadow space allocated on the stack before each EFI call. Maybe I'm missing something, but most of your calls seem to have this missing. Maybe I have misread your code and you are doing it. |
Author: | charlesap [ Sun Apr 28, 2019 12:26 pm ] |
Post subject: | Re: Simple Assembly UEFI Application -- Can't Exit Boot Serv |
While I do make some room on the stack at the very beginning of my routine (that's the sub rsp, 6*8) I think maybe the garbage in the shadow space may be what is tripping up ExitBootServices. Perhaps. Gonna have to test that. That's the only way I figure the pushes and pops of printhex would make a difference. |
Author: | zaval [ Sun Apr 28, 2019 4:17 pm ] |
Post subject: | Re: Simple Assembly UEFI Application -- Can't Exit Boot Serv |
MichaelPetch wrote: Why is it with some EFI calls you allocate the required space (32 bytes) before making a call and other places you don't. You need the shadow space allocated on the stack before each EFI call. Maybe I'm missing something, but most of your calls seem to have this missing. Maybe I have misread your code and you are doing it. No. Every function needs to do this only once (at its beginning). It allocates at the end of its stack (topmost) the number of slots for parameters. The number of slots is the number of parameters of a function from the set of functions, that this function calls, that has the biggest number of parameters. Say, here, the main function calls several functions, from which GetMemoryMap() has the largest count of parameters - 5. So, the main function allocates 5 slots in its stack frame for the parameters. I looked deeper at the code. It shows not understanding the calling convention. If I remembered x86 asm, I'd write it, but. For example, you don't need all those manipulations with rsp before a function call. A stack frame of a function must be like this: [saved nonvolatile registers] --- highest address [your stack variables] [argN] --- N the biggest number of a parameter from the set of functions this function will call [arg(N-1)] ... [arg5] [r9] --- slot for r9, just have it, not initialize [r8] [rdx] [rcx] --- the lowest address, rsp points here before any function call So when calling GetMemoryMap() and doing: Code: lea r10, [memmapdescver] mov [STK],rsp push r10 you place the 5th parameter in a wrong position. instead, you need: Code: lea r10, [memmapdescver]
mov [rsp + 4*8], r10 ; see scheme above |
Author: | zaval [ Sun Apr 28, 2019 5:24 pm ] |
Post subject: | Re: Simple Assembly UEFI Application -- Can't Exit Boot Serv |
Ok, try this. But remember, I wrote in x86 a long time ago. Code: format pe64 dll efi entry main section '.text' code executable readable include 'efi.inc' main: push rbx push r12 sub rsp, 5 * 8 ; keeping it 16 byte aligned mov [Handle], rcx ; ImageHandle mov rbx, rdx ; SystemTable mov r12, [rdx + EFI_SYSTEM_TABLE.BootServices] lea rdx, [szHello] mov rcx, [rbx + EFI_SYSTEM_TABLE.ConOut] call [rcx + SIMPLE_TEXT_OUTPUT_INTERFACE.OutputString] mov rdx, [memmapsize] a: mov rcx, EfiLoaderData lea r8, [memmap] call [r12 + EFI_BOOT_SERVICES.AllocatePool] cmp rax, EFI_SUCCESS je b ; Fail lea rdx, [szAllocFail] mov rcx, [rbx + EFI_SYSTEM_TABLE.ConOut] call [rcx + SIMPLE_TEXT_OUTPUT_INTERFACE.OutputString] jmp Fail b: lea rcx, [memmapsize] mov rdx, [memmap] lea r8, [memmapkey] lea r9, [memmapdescsize] lea r10, [memmapdescver] mov [rsp + 4 * 8], r10 call [r12 + EFI_BOOT_SERVICES.GetMemoryMap] cmp rax, EFI_SUCCESS je d cmp rax, EFI_BUFFER_TOO_SMALL je c ; Fail lea rdx, [szGetMemMapFail] mov rcx, [rbx + EFI_SYSTEM_TABLE.ConOut] call [rcx + SIMPLE_TEXT_OUTPUT_INTERFACE.OutputString] jmp Fail c: mov rcx, [memmap] call [r12 + EFI_BOOT_SERVICES.FreePool] mov rdx, [memmapsize] add rdx, 400h mov [memmapsize], rdx jmp a d: mov rcx, [Handle] mov rdx, [memmapkey] call [r12 + EFI_BOOT_SERVICES.ExitBootServices] cmp rax, EFI_SUCCESS je reboot ; Fail lea rdx, [szExitBootServFail] mov rcx, [rbx + EFI_SYSTEM_TABLE.ConOut] call [rcx + SIMPLE_TEXT_OUTPUT_INTERFACE.OutputString] jmp Fail reboot: mov rax, [rbx + EFI_SYSTEM_TABLE.RuntimeServices] mov rcx, EfiResetShutdown mov rdx, EFI_SUCCESS xor r8, r8 call [rax + EFI_RUNTIME_SERVICES.ResetSystem] Fail: mov rax, EFI_NOT_READY ; what else? :D add rsp, 5 * 8 pop r12 pop rbx ret section '.data' data readable writeable memmap: dq 0 ; this is a pointer to a buffer for the memory map Handle: dq 0 SystemTable: dq 0 memmapsize: dq 1000h memmapkey: dq 0 memmapdescsize: dq 0 memmapdescver: dq 0 szHello du 'hello, world', 13, 10, 0 szAllocFail du 'allocation failed', 13, 10, 0 szGetMemMapFail du 'getting memory map failed', 13, 10, 0 szExitBootServFail du 'exiting boot services failed', 13, 10, 0 section '.reloc' fixups data discardable Added later. 1. fixed a very unpleasant bug (memmap was db instead of dq). 2. fixed missed return address influence on the stack alignment |
Author: | MichaelPetch [ Mon Apr 29, 2019 2:11 pm ] |
Post subject: | Re: Simple Assembly UEFI Application -- Can't Exit Boot Serv |
A version of the code that handles the stack alignment; moves the saving and restoring of registers into the function print_hex; properly handles the shadow space could look like: Code: bits 64 This code was also fixed so that when the first call to ExitBootServices succeeds it also fills the frame buffer (rather than shutting down). The main entry point should save and restore the volatile registers (and restore them when finished) hoeever given that your code has no path to get to the final `ret` it can be overlooked in this case.
org 0x8000000 section .header DOS: dd 0x00005a4d times 14 dd 0 dd 0x00000080 times 16 dd 0 PECOFF: dd `PE\0\0` ; sig dw 0x8664 ; type dw 3 ; sections dd 0x5cba52f6 ; timestamp dq 0 ; * symbol table + # symbols dw osize ; oheader size dw 0x202e ; characteristics OHEADER: dd 0x0000020b ; oheader + 0000 linker sig dd 8192 ;codesize ; code size dd 8192 ;datasize ; data size dd 0 ; uninitialized data size dd 4096 ; * entry dd 4096 ; * code base dq 0x8000000 ; * image base dd 4096 ; section alignment dd 4096 ; file alignment dq 0 ; os maj, min, image maj, min dq 0 ; subsys maj, min, reserved dd 0x5000 ; image size dd 4096 ; headers size dd 0 ; checksum dd 0x0040000A ; dll characteristics & subsystem dq 0x10000 ; stack reserve size dq 0x10000 ; stack commit size dq 0x10000 ; heap reserve size dq 0 ; heap reserve commit dd 0 ; loader flags dd 0x10 ; rva count DIRS: times 5 dq 0 ; unused dd 0x8005000 ; virtual address .reloc dd 0 ; size .reloc times 10 dq 0 ; unused OEND: osize equ OEND - OHEADER SECTS: .1: dq `.text` ; name dd 8192 ;codesize ; virtual size dd 4096 ; virtual address dd 8192 ; raw data size dd 4096 ; * raw data dq 0 ; * relocations, * line numbers dd 0 ; # relocations, # line numbers dd 0x60000020 ; characteristics .2: dq `.data` dd 8192 ;datasize dd 12288 dd 8192 dd 12288 dq 0 dd 0 dd 0xC0000040 .3: dq `.reloc` dd 0 dd 20480 dd 0 dd 20480 dq 0 dd 0 dd 0x02000040 times 4096 - ($-$$) db 0 ;align the text section on a 4096 byte boundary section .text follows=.header EFI_SUCCESS equ 0 EFI_SYSTEM_TABLE_SIGNATURE equ 0x5453595320494249 EFI_SYSTEM_TABLE_CONOUT equ 64 EFI_SYSTEM_TABLE_RUNTIMESERVICES equ 88 EFI_SYSTEM_TABLE_BOOTSERVICES equ 96 EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL_RESET equ 0 EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL_OUTPUTSTRING equ 8 EFI_BOOT_SERVICES_GETMEMORYMAP equ 56 EFI_BOOT_SERVICES_LOCATEHANDLE equ 176 EFI_BOOT_SERVICES_LOADIMAGE equ 200 EFI_BOOT_SERVICES_EXIT equ 216 EFI_BOOT_SERVICES_EXITBOOTSERVICES equ 232 EFI_BOOT_SERVICES_LOCATEPROTOCOL equ 320 EFI_RUNTIME_SERVICES_RESETSYSTEM equ 104 sub rsp, 6*8+8 ; Stack is misaligned by 8 when control is transferred to ; the EFI entry point. In addition to the shadow space ; (32 bytes) and space for stack based paramaters to be ; saved - we also have to allocate an additional ; 8 bytes to ensure stack alignment on a 16-byte boundary ; 8+(6*8+8)=64, 64 is evenly divisible by 16 at this point mov [Handle], rcx mov [SystemTable], rdx mov rax, [SystemTable] mov rax, [rax + EFI_SYSTEM_TABLE_BOOTSERVICES] mov [BS], rax mov rax, [SystemTable] mov rax, [rax + EFI_SYSTEM_TABLE_RUNTIMESERVICES] mov [RTS], rax lea rdx, [herewego] mov rcx, [SystemTable] mov rcx, [rcx + EFI_SYSTEM_TABLE_CONOUT] call [rcx + EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL_OUTPUTSTRING] ; get the memory map mov qword [memmapsize], 4096 lea rcx, [memmapsize] lea rdx, [memmap] lea r8, [memmapkey] lea r9, [memmapdescsize] lea r10, [memmapdescver] mov [rsp+32], r10 ; Don't push R10 on the stack, move it directly to ; the stack immediately above the shadow space mov rbx, [BS] call [rbx + EFI_BOOT_SERVICES_GETMEMORYMAP] cmp rax, EFI_SUCCESS jne oops ; find the interface to GOP mov rbx, [SystemTable] mov rbx, [rbx + EFI_SYSTEM_TABLE_BOOTSERVICES] mov rcx, _EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID mov rdx, 0 lea r8, [Interface] call [rbx + EFI_BOOT_SERVICES_LOCATEPROTOCOL] cmp rax, EFI_SUCCESS jne oops mov rcx, [Interface] mov rcx, [rcx + 0x18 ] ;EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE mov rbx, [rcx + 0x18 ] ;EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE_FRAMEBUFFERBASE mov [FB], rbx mov rcx, [rcx + 0x20 ] ;EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE_FRAMEBUFFERSIZE mov [FBS], rcx cmp rax, EFI_SUCCESS jne oops mov rbx, [FB] call printhex mov rbx, [FBS] call printhex ; exit boot services mov rcx, [Handle] mov rdx, [memmapkey] mov rbx, [SystemTable] mov rbx, [rbx + EFI_SYSTEM_TABLE_BOOTSERVICES] call [rbx + EFI_BOOT_SERVICES_EXITBOOTSERVICES] cmp rax, EFI_SUCCESS ; je g5 je fillframe mov rbx, [memmapkey] call printhex ; repeat the call to get the memory map mov qword [memmapsize], 4096 lea rcx, [memmapsize] lea rdx, [memmap] lea r8, [memmapkey] lea r9, [memmapdescsize] lea r10, [memmapdescver] mov rbx, [BS] mov [rsp+32], r10 ; Don't push R10 on the stack, move it directly to ; the stack immediately above the shadow space call [rbx + EFI_BOOT_SERVICES_GETMEMORYMAP] cmp rax, EFI_SUCCESS jne oops mov rbx, [memmapkey] call printhex ; exit boot services again mov rcx, [Handle] mov rdx, [memmapkey] xor r8, r8 mov rbx, [SystemTable] mov rbx, [rbx + EFI_SYSTEM_TABLE_BOOTSERVICES] call [rbx + EFI_BOOT_SERVICES_EXITBOOTSERVICES] ;cmp rax, EFI_SUCCESS ;je g5 ;jmp oops fillframe: mov rcx, [FB] mov rax, [FBS] Q: dec rax mov byte[rcx+rax],255 jnz Q W: jmp W g5: mov rcx, 2 ;EfiResetShutdown mov rdx, EFI_SUCCESS mov rax, [SystemTable] mov rax, [rax + EFI_SYSTEM_TABLE_RUNTIMESERVICES] call [rax + EFI_RUNTIME_SERVICES_RESETSYSTEM] oops: lea rdx, [fail] mov rcx, [SystemTable] mov rcx, [rcx + EFI_SYSTEM_TABLE_CONOUT] call [rcx + EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL_OUTPUTSTRING] jmp $ printhex: ; Stack msialigned by 8 at function entry mov rbp, 16 push rax push rcx push rdx ; 3 pushes also align stack on 16 byte boundary ; (8+3*8)=32, 32 evenly divisible by 16 sub rsp, 32 ; Allocate 32 bytes of shadow space .loop: rol rbx, 4 mov rax, rbx and rax, 0Fh lea rcx, [_Hex] mov rax, [rax + rcx] mov byte [_Num], al lea rdx, [_Num] mov rcx, [SystemTable] mov rcx, [rcx + EFI_SYSTEM_TABLE_CONOUT] call [rcx + EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL_OUTPUTSTRING] dec rbp jnz .loop lea rdx, [_Nl] mov rcx, [SystemTable] mov rcx, [rcx + EFI_SYSTEM_TABLE_CONOUT] call [rcx + EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL_OUTPUTSTRING] add rsp, 32 pop rdx pop rcx pop rax ret times 8192-($-$$) db 0 codesize equ $ - $$ section .data follows=.text Handle dq 0 SystemTable dq 0 Interface dq 0 BS dq 0 RTS dq 0 STK dq 0 FB dq 0 FBS dq 0 memmapsize dq 4096 memmapkey dq 0 memmapdescsize dq 48 memmapdescver dq 0 _EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID db 0xde, 0xa9, 0x42, 0x90, 0xdc, 0x23, 0x38, 0x4a db 0x96, 0xfb, 0x7a, 0xde, 0xd0, 0x80, 0x51, 0x6a fail db __utf16__ `fail.\r\n\0` nok db __utf16__ `Not OK.\r\n\0` yok db __utf16__ `OK.\r\n\0` herewego db __utf16__ `here we go\r\n\0` _Hex db '0123456789ABCDEF' _Num dw 0,0 _Nl dw 13,10,0 times 4096-($-$$) db 0 memmap: times 4096 db 0 datasize equ $ - $$ section .reloc follows=.data |
Page 1 of 2 | All times are UTC - 6 hours |
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group http://www.phpbb.com/ |