Pokazywanie postów oznaczonych etykietą uefi. Pokaż wszystkie posty
Pokazywanie postów oznaczonych etykietą uefi. Pokaż wszystkie posty

wtorek, 1 listopada 2016

openSUSE Tumbleweed - grub2 installed in non-EFI mode

Last time after I've installed openSUSE Tumbleweed, I've got incorrect grub2 installation (but system instalation was successful). Instead of using EFI my grub2 was configured to run in the classic mode. After reboot I was able to see only the grub2 command line.

Here is the solution:

First we need to find our grub config file. We can do it using:
 > search.file /boot/grub2/grub.cfg
We should get something like:
 (hd1,gpt6)
Now load that config:
 > configfile (hd1,gpt6)/boot/grub2/grub.cfg
The grub menu should appear. Unfortunately entries were incorrect because of using e.g. "linux" command instead of "linuxefi". We have to change that, so press "e" to edit your entry. Next, change "linux" to "linuxefi" and "initrd" to "initrdefi".
To boot press F10.
After your OS is loaded open YaST, then go to Bootloader settings and change mode to "GRUB2 EFI". Done!

poniedziałek, 22 lutego 2016

EDKII and QEMU - remote debugging with gdb

While working with UEFI debugger can be very helpful. I was using EDKII project to write my UEFI applications and I was testing it with QEMU. I added my application information file to the OvmfPkg module information and this let me to running my program using existing script.
To build OvmfPkg and run QEMU run (in the OvmfPkg folder):
 ./build.sh -A IA32 qemu -s -monitor stdio -debugcon file:debug.log -global isa-debugcon.iobase=0x402  
After start debug.log file will be created where you can read output from UEFI.
We need to know where your application will be loaded (memory address). Run your application in QEMU:
 Shell> fs0:  
 fs0:\> MyApp.efi  
Open debug.log file (in the EDKII directory), and find line with name of your loaded application. You should get something like this:
 Loading driver at 0x00006B75000 EntryPoint=0x00006B75220 MyApp.efi  
And this is our address:
 EntryPoint=0x00006B75220  
Now open second terminal, open directory with your application's debugging symbols and efi file (for me: Build/OvmfIa32/DEBUG_GCC48/IA32/MyApp.debug) and run gdb:
 gdb --tui  
We need to know where particular sections are located. Load efi file and enter info files:
 (gdb) file MyApp.efi  
 Reading symbols from MyApp.efi...(no debugging symbols found)...done.  
 (gdb) info files  
 Symbols from ".../edk2/Build/OvmfIa32/DEBUG_GCC48/IA32/MyApp.efi".  
 Local exec file:  
     `.../Build/OvmfIa32/DEBUG_GCC48/IA32/MyApp.efi', file type pei-i386.  
     Entry point: 0x220  
     0x00000220 - 0x00003a40 is .text  
     0x00003a40 - 0x00004320 is .data  
     0x00004320 - 0x00004520 is .reloc  
We need to calculate our addresses for text and data section. Application is loaded under 0x00006B75220 (entry point) and we know text and data offsets.
text = 0x06B75220
data = 0x06B75220 + 0x00003a40 = 0x06B78C60

Now unload efi file:
 (gdb) file  
 No executable file now.  
 No symbol file now.  
Load symbols:
 (gdb) add-symbol-file MyApp.debug 0x06B75220 -s .data 0x06B78C60
add symbol table from file "MyApp.debug" at
        .text_addr = 0x6b75220
        .data_addr = 0x6b78c60
(y or n) y
Reading symbols from MyApp.debug...done.
You can add some breakpoints, for example:
 break UefiMain  
And attach debugger to the QEMU:
 target remote localhost:1234  
And run QEMU:
 ./build.sh -A IA32 qemu -s -monitor stdio -debugcon file:debug.log -global isa-debugcon.iobase=0x402  
Machine will be paused, type "continue", load your application. Done!



Links:
http://osdevnotes.blogspot.com/2011/05/using-gdb-to-debug-uefi.html
http://wiki.osdev.org/Debugging_UEFI_applications_with_GDB
http://comments.gmane.org/gmane.comp.bios.tianocore.devel/6777

niedziela, 7 lutego 2016

UEFI programming using pure assembler (32bit mode)

I was writing some small UEFI applications. UEFI is a powerful BIOS successor, which introduces a lot of features. Unfortunately not every implementations on real hardware supports all these things. I neeed only basic functionality like writing some text for test purposes and wrote small test programs using pure assembler.

In the internet you can easily find an asm code for 64 bit architecture but not for 32 bit. I shared my translated code https://github.com/eszkadev/UEFI-32bit-asm-examples

Most important file is efi.inc which describes EFI structures:
 ;  
 ; EFI.inc  
 ; Based on: http://wiki.osdev.org/Uefi.inc  
 ; 2015 Szymon Kłos  
 ;  
   
 struc int8 {  
  . db ?  
 }  
   
 struc int16 {  
  align 2  
  . dw ?  
 }  
   
 struc int32 {  
  align 4  
  . dd ?  
 }  
   
 struc int64 {  
  align 8  
  . dq ?  
 }  
   
 struc intn {  
  align 4  
  . dd ?  
 }  
   
 struc dptr {  
  align 4  
  . dd ?  
 }  
   
  ; symbols  
   
 EFI_SUCCESS                       equ    0  
   
 EFI_SYSTEM_TABLE_SIGNATURE        equ    20494249h  
 EFI_SYSTEM_TABLE_SIGNATURE2       equ    54535953h  
 EFI_RUNTIME_SERVICES_SIGNATURE    equ    544e5552h  
 EFI_RUNTIME_SERVICES_SIGNATURE2   equ    56524553h  
   
  ; helper macro for definition of relative structure member offsets  
   
 macro struct name  
 {  
  virtual at 0  
   name name  
  end virtual  
 }  
   
  ; structures  
   
 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  
   
 struc SIMPLE_TEXT_OUTPUT_INTERFACE {  
  .Reset                      dptr  
  .OutputString               dptr  
  .TestString                 dptr  
  .QueryMode                  dptr  
  .SetMode                    dptr  
  .SetAttribute               dptr  
  .ClearScreen                dptr  
  .SetCursorPosition          dptr  
  .EnableCursor               dptr  
  .Mode                       dptr  
 }  
 struct SIMPLE_TEXT_OUTPUT_INTERFACE  
   
 struc EFI_SIMPLE_TEXT_INPUT_PROTOCOL {  
  .Reset                      dptr  
  .ReadKeyStroke              dptr  
  .WaitForKey                 dptr  
 }  
 struct EFI_SIMPLE_TEXT_INPUT_PROTOCOL  
   
 struc EFI_INPUT_KEY {  
  .ScanCode                   int16  
  .UnicodeChar                int16  
 }  
 struct EFI_INPUT_KEY  
   
 struc EFI_RUNTIME_SERVICES {  
  .Hdr                        EFI_TABLE_HEADER  
  .GetTime                    dptr  
  .SetTime                    dptr  
  .GetWakeUpTime              dptr  
  .SetWakeUpTime              dptr  
  .SetVirtualAddressMap       dptr  
  .ConvertPointer             dptr  
  .GetVariable                dptr  
  .GetNextVariableName        dptr  
  .SetVariable                dptr  
  .GetNextHighMonotonicCount  dptr  
  .ResetSystem                dptr  
 }  
 struct EFI_RUNTIME_SERVICES  
   
 struc EFI_TIME {  
  .Year                       int16  
  .Month                      int8  
  .Day                        int8  
  .Hour                       int8  
  .Minute                     int8  
  .Second                     int8  
  .Pad1                       int8  
  .Nanosecond                 int32  
  .TimeZone                   int16  
  .Daylight                   int8  
  .Pad2                       int8  
  .sizeof                     rb 1  
 }  
 struct EFI_TIME  

Pointer to the EFI_SYSTEM_TABLE structure is passed to your entry function. EFI uses C calling convention and you can get it from the stack:

 format pe dll efi  
 entry main  
   
 section '.text' code executable readable  
   
 include 'efi.inc'  
   
 main:  
     push ebp  
     mov ebp, esp  
   
  ; get args ( ImageHandle and SystemTable pointer )  
   
     mov ecx, [ebp+8]  
     mov [ImageHandle], ecx  
     mov edx, [ebp+12]  
     mov [SystemTable], edx  
   
  ; ... YOUR CODE  
   
     mov eax, EFI_SUCCESS  
   
     pop ebp  
     retn  
   
 section '.data' data readable writeable  
   
 ImageHandle        dd        ?  
 SystemTable        dd        ?  
   
 section '.reloc' fixups data discardable  

Simple HelloWorld: https://github.com/eszkadev/UEFI-32bit-asm-examples/blob/master/HelloWorld.asm

EFI application binary must be in a PE format. You can compile this code with fasm. Then place it on your disc and run from UEFI Shell (for example using Virtualbox).

Links:
http://wiki.osdev.org/Uefi.inc
http://x86asm.net/articles/uefi-programming-first-steps/index.html