diff options
Diffstat (limited to 'documentation')
-rw-r--r-- | documentation/DEBUG statement | 10 | ||||
-rw-r--r-- | documentation/Debugging in Qemu | 41 | ||||
-rw-r--r-- | documentation/GDB commands | 139 | ||||
-rw-r--r-- | documentation/GNU-efi | 299 | ||||
-rw-r--r-- | documentation/QEMU Monitor Commands | 39 | ||||
-rw-r--r-- | documentation/debug statement | 1 | ||||
-rw-r--r-- | documentation/debugcon | 11 | ||||
-rw-r--r-- | documentation/gdb commands | 19 | ||||
-rw-r--r-- | documentation/gdb with efi application | 0 | ||||
-rw-r--r-- | documentation/memtest86_build_process/24_08_22_memtest_build_process | 244 | ||||
-rw-r--r-- | documentation/todo | 12 |
11 files changed, 783 insertions, 32 deletions
diff --git a/documentation/DEBUG statement b/documentation/DEBUG statement new file mode 100644 index 0000000..eb110ff --- /dev/null +++ b/documentation/DEBUG statement @@ -0,0 +1,10 @@ + +Library to include: +#include "Library/DebugLib.h" + +DEBUG (("%a: %d\n", _FUNCTION_, _LINE_)); + +example: + +DEBUG((EFI_D_INFO, "My Entry Point: 0x%08x\r\n",(CHAR16*)UefiMain)); + diff --git a/documentation/Debugging in Qemu b/documentation/Debugging in Qemu new file mode 100644 index 0000000..6d43b3e --- /dev/null +++ b/documentation/Debugging in Qemu @@ -0,0 +1,41 @@ +######################################### +# # +# Ways to debug in Qemu # +# # +######################################### + +DEBUGCON +############### + +-debugcon file:debug.log -global isa-debugcon.iobase=0x402 + +SERIAL +############### + +-serial stdio + redirects the virtual serial port to the host's terminal i/o + +TRACE +############### + +-D ./qemu_log.txt +-d guest_errors, nochain, exec, in_asm, out_asm, op, op_opt, op_ind, int, cpu, mmu, pcall, cpu_reset, unimp, page + +--trace "memory_region*" + +MONITOR +############### + +-monitor stdio + +or + +Ctrl + Alt + 2 (Exit with Ctrl + Alt + 1) + +GDB - GNU DEBUGGER +##################### + +-s -S (when starting qemu) + +(gdb) target remote localhost:1234 +(gdb) c diff --git a/documentation/GDB commands b/documentation/GDB commands new file mode 100644 index 0000000..8411f19 --- /dev/null +++ b/documentation/GDB commands @@ -0,0 +1,139 @@ +################################################################### +###################### ############################# +### GDB COMMANDS ### +###################### ############################# +################################################################### + +QEMU CONFIGURATION + + qemu must be started with "-s" option + (shorthand for "-gdb tcp::1234") + +# +# GDB PART +# + +SYMBOL FILES + add-symbol-file /path/to/Hello.debug 0x... -s .data 0x... + + +CONNECTION + - source gdbscript + (if a gdbscript is created, which contains + add-symbol-file commandos) + + - target remote localhost:1234 + +DISCONNECTION + - detach + break connection with target, target resumes execution + GDB Target + (RSP Client) (RSP Server) + D + O------------------------------>O + O RSP exchange + O<------------------------------O + OK + -disconnect + Simply break connection. Target stays at the point where execution terminated previously + Reconnection(target remote): resume debugging at the point where the previous connection was broken + +BREAKPOINTS + + - b CoreHandleProtocol || or OutputString + - break *0x65fe447 || set breakpoint at address + - delete 2 || delete breakpoint no 2 + - break sampleApp.c:nn=LineNumber + + +INFORMATION + + - info + address SYM || Get address for symbol SYM + symbol ADDR || Show symbol at specified address + + all-registers || all registers & their contents + + breakpoints + + files || get Entry point + sections + files || Names of targets & files being debugged + + functions || all function names in Program + functions UefiMain || show where this function occurs + + line + + types [regex] || list all types or with regex + + args || Argument variables of current stack frame + locals || local variables of current stack frame + variables || all gloabl & static variables + + +CONTROL FLOW + + - c || continue + - next || move only one step forward + - bt || print back_trace of all stack frames + - stop || stop program until it reaches a different source line + +FILES (perhaps not applicable when debugging with QEMU) + + - file MemtestEfi.efi || load file ...no debugging symbols found...done + - file || unload files + +LIST + + - list || list specified function or line + +gdb --tui + - layout asm + - layout reg + - layout src + + - tui enable + - tui disable + + - next + + - ctrl+x o || change active window + + - ctrl+x 1 || use TUI layout with one window + - ctrl+x 2 || use TUI layout with two windows + + - PgUp || scroll the active window one page up + - PgDn || scroll the active window one page down + + - Up || scroll the active window one line up + - Down || scroll the active window one lin down + - Right + - Left + + - C+L || refresh the screen + +VARIABLES + info locals + info variables + info args + + || Set is the same as print except that the expression's value is not printed + || and is not put in the value history. + || if your program has a variable width, you get an error if you try to set + || a new value with just ‘set width=13’, because GDB has the command set width + || To avoid to set silently general variables to invalid values, ALWAYS use + || set var x=4 + print x=4 + set x=4 or set variable x=4 + whatis x -> type = double + +DISSASEMBLE BINARIES + gdb -batch -ex 'file /bin/ls' -ex 'disassemble main' + Also, -ex 'set disassembly-flavor intel' before other -exs will result in Intel assembly syntax + + gcc -O0 -ggdb3 -std=c99 -Wall -Wextra -pedantic -o main.out main.c + gdb -batch -ex "disassemble/rs myfunc" main.out + + + + diff --git a/documentation/GNU-efi b/documentation/GNU-efi new file mode 100644 index 0000000..40cd91f --- /dev/null +++ b/documentation/GNU-efi @@ -0,0 +1,299 @@ +################################################################################## +## ## +## BUILDING HELLOWORLD.EFI WIH GNU-EFI ## +## ## +################################################################################## + +################################################################################# +# SUMMARY # +################################################################################# + +Minimal working example: + + hello.c +--------------------------------------------------------------------------------- +#include <efi.h> +#include <efilib.h> + +EFI_STATUS +EFIAPI +efi_main (EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) { + + InitializeLib(ImageHandle, SystemTable); + Print(L"Hello, world!\n"); + + return EFI_SUCCESS; +} + + +Makefile +-------------------------------------------------------------------------------- +ARCH = $(shell uname -m | sed s,i[3456789]86,ia32,) + +OBJS = hello.o +TARGET = hello.efi + +EFIINC = /usr/include/efi +EFFINCS = -I$(EFIINC) -I$(EFIINC)/$(ARCH) -I$(EFIINC)/protocol +EFILIB = /usr/lib +EFI_CRT_OBJS = $(EFILIB)/crt0-efi-$(ARCH).o +EFI_LDS = $(EFILIB)/elf_$(ARCH)_efi.lds + +CFLAGS = $(EFFINCS) -fno-stack-protector -fpic \ + -fshort-wchar -mno-red-zone -Wall + +ifeq ($(ARCH),x86_64) + CFLAGS += -DEFI_FUNCTION_WRAPPER +endif + +LDFLAGS = -nostdlib -znocombreloc -T $(EFI_LDS) -shared \ + -Bsymbolic -L $(EFILIB) $(EFI_CRT_OBJS) + +all: $(TARGET) + +hello.so: $(OBJS) + ld $(LDFLAGS) $(OBJS) -o $@ -lefi -lgnuefi + +%.efi: %.so + objcopy -j .text -j .sdata -j .data -j .dynamic \ + -j .dynsym -j .rel -j .rela -j .reloc \ + --target=efi-app-$(ARCH) $^ $@ + +----- +Now expanded version in git + +Get ImageBase: + Run ./test.sh and then hello.efi...this prints ImageBase + +Get Offsets: + GDB + file hello.efi + -> get text and data offset + file + add-symbol-file hello.efi (ImageBase+text-off) -s .data (ImageBase+data-off) + + +################################################################################# +# https://wiki.osdev.org/GNU-EFI # +################################################################################# + +GNU-EFI is a very lightweight developing environment to create UEFI applications. +It is a set of libraries and headers for compiling UEFI applications with a +system's native GCC. + +You can use host native compiler, then convert resulting ELF into UEFI-compatible +PE. + OR +Use GCC Cross-Compiler generating PE directly. + +********************************************************************************* +* $ git clone https://git.code.sf.net/p/gnu-efi/code gnu-efi * +* $ cd gnu-efi * +* $ make * +********************************************************************************* + +This should create +* crt0-efi-x86_64.o: + A CRT0 (C runtime initialization code) that will call the + "efi_main" function + +* libgnuefi.a: + A library containing a single function (_relocate) + that is used by the CRT0 + +* (optional) libefi.a: + A library containing convenience functions like CRC computation, string + length calculation, and easy text printing + +HEADERS can be used from: +* /usr/include/efi (updated to the latest) +* from EDK2 package +* Or from gnu-efi/inc + +LINKER SCRIPT: +* gnu-efi/gnuefi/elf_x86_64_efi.lds + OR +* /usr/lib/elf_x86_64_efi.lds + +COMPILATION: +$ gcc + -Ignu-efi-dir/inc || set this to the efi headers directory + + -fpic || UEFI PE executable must be relocatable + + -ffreestanding || there's no hosted gcc environment, + we don't have libc + -fno-stack-protector = + -fno-stack-check || stack must be strictly used, + || no additional canaries or + || pre-allocated local variable + || space allowed + -mno-red-zone = + + -fshort-wchar || It is very important that UEFI + || uses 16bit characters + || (wide-characters or wchar_t, + || defined as CHAR16 in efi headers + + -maccumulate-outgoing-args || function calls must include the + || number of argumnets passed to the + || functions + + -c main.c -o main.o + +LINKING: +$ ld -shared -Bsymbolic -Lgnu-efi-dir/x86_64/lib -Lgnu-efi-dir/x86_64/gnuefi \ + -Tgnu-efi-dir/gnuefi/elf_x86_64_efi.lds \ + gnu-efi-dir/x86_64/gnuefi/crt0-efi-x86_64.o \ + main.o -o main.so -lgnuefi -lefi + + -shared -Bsymbolic || tell GNU ld to create so (shared library) + + -L and -T || Where to find the static GNU-EFI libraries + || (.a) and the linker script + + .o || it is important to specify crt0 as the + || first. Should work as the last too, but + || some had problems + + -l || linking with gnuefi is a must, as that + || contains the relocation code. Linking + || with efi is optional, but recommended + +CONVERT CHARED OBJECT TO EFI EXECUTABLE +$ objcopy -j .text -j .sdata -j .data -j .dynamic -j .dynsym -j .rel -j .rela -j .rel.* + -j .rela.* -j .reloc --target efi-app-x86_64 --subsystem=10 main.so main.efi + + -j || which sections to keep during convertion + + --target efi-app-x86_64 || tells objcop to generate a PE32+ format, + || with architecture code 0x8664 + + --subsystem=10: || most important. Sets file type to UEFI + || executable in the PE header + +Now you can copy main.efi to your EFI System Partition, and after boot run it +from the EFI Shell. Or you can rename it to EFI\BOOT\BOOTX64.EFI and it should +be executed automatically on boot. + + +LIBEFI.A + +Has wrappers for the most common UEFI functions, but you might need to call +something not covered. For completeness, it provides: + +uefi_call_wrapper(func, numarg, ...); + +For example, the "Print" function used in our main.c and which accepts printf +compatible arguments, is under the hood nothing else than a call to: + +uefi_call_wrapper(ST->ConOut->OutputString, 2, ST->ConOut, buffer); + +The biggest advantage of 'uefi_call_wrapper_ is that doesn't matter what ABI +your gcc is using, it will always correctly translate thet into UEFI ABI. If, +and only if you've used the correct gcc options, then you should be able to +make the same call as: + +ST->ConOut->OutputString(ST->ConOut, buffer); + + +################################################################################# +# https://wiki.osdev.org/Debugging_UEFI_applications_with_GDB # +################################################################################# + +Makefile at: +https://sourceforge.net/p/ast-phoenix/code/ci/master/tree/kernel/boot/Makefile#l72 + +EFI firmware is unable to launch binaries with debug sections. What you need is +to create two EFI binaries - one with only required sections to upload it to +target system and another one with debug symbols to use with GDB. Actually you +just need to run objcopy utility twice with different set of sections to copy and +different output files. (See Makefile example) + +To load image with symbols to relocated addresses for .text and .data sections, +you need to add ImageBase address to their offsets: + +********************************************************************************* +* # gdb hello.efi * +* (gdb) info files * +* ... * +* Entry point: 0x3000 * +* 3000 - ... is .text * +* c00 - ... is .data * +* (gdb) file || unload file * +* add-symbol-file hello.efi (ImageBase+text-off) -s .data (ImageBase+data-off) * +********************************************************************************* + +################################################################################# +# https://www.rodsbooks.com/efi-programming/hello.html # +################################################################################# + +You should not normally include regular C header files, such as stdlib.h, +because most of these header files define data types and functions that are used +by the C library. This library is not available in EFI. + +************************************ +* efi.h and efilib.h always needed * +************************************ + +Entry point: efi_main() in GNU-efi + +CFLAGS: +* -fno-stack-protector: + Stack protection isn't suppoerted by EFI, so there's no point in + building a binary with this feature active. + +* -fpic: + EFI requires that code be position-independet, hence the use + of this option. + +* -fshort-wchar: + GCC defines the wchar_t type to be 32 bits by default, but EFI requires + it to be 16 bits for 16-bit strings to work correctly. + +* fmno-red-zone: + On x86-64 systems, the red zone is an area that follows the stack pointer + that can be used for temporary variables. The EFI may modify this area, + though, so it's not safe to use, and you must compile EFI binaries with + this option. + +* -Wall: + When developing EFI applications, you might want to pay extra attention to + compiler warnings, and this switch (which causes warnings to be treated as + errors) can help. + +* -DEFI_FUNCTION_WRAPPER: + This option is required on the x86_64 platform, but is not defined on the + 32-bit x86 platform. It relates to th calling conventions for EFI functions, + described on the Using EFI Services page. + +LDFLAGS: +* -nostdlib: + An EFI application should not be linked against standard libraries, and this + argument accomplishes this goal. + +* -nocombreloc: + This argument causes the linker to not combine relocation sections. + +* -T $(EFI_LDS): + To create an EFI binary, a non-standard linker script must be used, and this + option tells ld where to find it. + +* -shared: + Even with GNU-EFI's new linker script, ld can't create the final executable. + Instead, it creates a shared library, which is subsequently + turned into the final binary. + +* -Bsymbolic: + This option causes references to global symbols to be bound to the + definitions within the shared library. + + + + + + + + + + diff --git a/documentation/QEMU Monitor Commands b/documentation/QEMU Monitor Commands new file mode 100644 index 0000000..bae7cf7 --- /dev/null +++ b/documentation/QEMU Monitor Commands @@ -0,0 +1,39 @@ +#################################################################### +#################### ################### +### QEMU MONITOR COMMANDS ### +#################### ################### +#################################################################### + +1. START QEMU MONITOR + + - within viewer: + Ctrl + Alt + 2 + exit with Ctrl + Alt + 1 + + - as QEMU parameter to get monitor in terminal: + -monitor stdio + +2. GET HELP + + help + help info + help list + +3. SCROLL + + Ctrl + PgUp/PgDown + +4. GDBSERVER + + starts a remote session for the GNU debugger (gdb) + To connect to it from the host machine, + $gdb qemuKernelFile + target remote localhost:1234 + +5. SHOW REGISTERS + + info registers + + eax = 32bit + rax = 64bit + rip = memory address of the next instruction to execute diff --git a/documentation/debug statement b/documentation/debug statement deleted file mode 100644 index a8e192c..0000000 --- a/documentation/debug statement +++ /dev/null @@ -1 +0,0 @@ -DEBUG (("%a: %d\n", _FUNCTION_, _LINE_)); diff --git a/documentation/debugcon b/documentation/debugcon new file mode 100644 index 0000000..5d914f5 --- /dev/null +++ b/documentation/debugcon @@ -0,0 +1,11 @@ +######################### +# # +# DEBUGCON # +# # +######################### + +for debug already in early bootphases +One can connect the I/O port to either a file or a device, like /dev/stdout + - debugcon /dev/stdout (terminal that started Qemu process) + - debugcon file:qemu/debug.log (or other file name) + diff --git a/documentation/gdb commands b/documentation/gdb commands deleted file mode 100644 index 85bf88e..0000000 --- a/documentation/gdb commands +++ /dev/null @@ -1,19 +0,0 @@ -GDB COMMANDS -============ - -qemu must be started with "-s" option (shorthand for "-gdb tcp::1234") - -source gdbscript - -file MemtestEfi.efi || load file -info files || get Entry point + sections -file || unload files - -b CoreHandleProtocol | or OutputString - -target remote localhost:1234 - -c -bt || print back_trace of all stack frames -stop || stop program until it reaches a different source line -list || list specified function or line diff --git a/documentation/gdb with efi application b/documentation/gdb with efi application deleted file mode 100644 index e69de29..0000000 --- a/documentation/gdb with efi application +++ /dev/null diff --git a/documentation/memtest86_build_process/24_08_22_memtest_build_process b/documentation/memtest86_build_process/24_08_22_memtest_build_process new file mode 100644 index 0000000..fc8f33c --- /dev/null +++ b/documentation/memtest86_build_process/24_08_22_memtest_build_process @@ -0,0 +1,244 @@ + +Linker scripts: + memtest_shared.lds + memtest_efi.lds +boot/ + header.S || The standard EFI header + setup.S + efisetup.c || Macros + private functions + || Only for 32-bit boot entry point??? + startup64.S + +*.c files in app/, lib/, system/, tests/ + +########################################################################## +## ## +## MEMTEST LINKING PART 1 - MEMTEST_SHARED ## +## ## +########################################################################## + +# +# memtest_shared.lds +# + +OUTPUT_FORMAT("elf64-x86-64") + +ENTRY(startup64); <--------- in startup64.S + +SECTIONS { + .text : { + _start = .; <---------- First section in memtest_shared-.text + *(.text) + *(.text.*) + ... + + .rodata + .dynsym + .dynstr + .hash + .gnu.hash + .dynamic + + .rela.text + .rela.rodata + .rela.data + .rela.got + .rela.plt + + .data + .got + .bss + +# +# startup64.S +# +118: .globl startup64 +119: startup64: +120: cld +121: cli + + # Save the boot params pointer +125: movq %rsi, boot_params_addr(%rip) + +127: jmp startup + +143: .globl startup +144: startup: + Use startup stack until we pick a correct one + Pick the correct stack + Initialize the pml4 and pdp tables + Set the page directory base address + Initialise the GDT and the segment registers + Load the GDT and the segment registers + Initialise the IDT + Initialise the IDT descriptor + Zero the BSS (if first boot) + Initialise the FPU + Enable SSE + Call the dynamic linker to fix up the addresses in the GOT + +268: call reloc <---------------- system/reloc64.c:151 + get_load_address() + get_dynamic_section_offset() + get_dynamic_info() + do_relocations + +276: call main <---------------- app/main.c:499 # main entry point called from the startup code + +# +# Analysis of the binary +# + +* objdump -h memtest_shared + .text ... File off Algn + 00200000 2**4 + +* objdump -g memtest_shared | grep efi_setup # check for occurences + | grep efi_handover + +* readelf -h memtest_shared + ELF Header: + Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 + Class: ELF64 + Data: 2's complement, little endian + Version: 1 (current) + OS/ABI: UNIX - System V + ABI Version: 0 + Type: DYN (Shared object file) + Machine: Advanced Micro Devices X86-64 + Version: 0x1 + Entry point address: 0x200 <-----------------That's startup64 !!! + Start of program headers: 64 (bytes into file) + Start of section headers: 2821656 (bytes into file) + Flags: 0x0 + Size of this header: 64 (bytes) + Size of program headers: 56 (bytes) + Number of program headers: 3 + Size of section headers: 64 (bytes) + Number of section headers: 26 + Section header string table index: 25 + +* objdump -d memtest_shared + memtest_shared: file format elf64-x86-64 + + Disassembly of section .text: + + 0000000000000000 <_start>: + 0: cld + 1: cli + + 9f: ljmp *-0x6(%rsp) + + 00000000000001e0 <efi_boot>: + + 1ed: jmp 210 <efi_handover> + + 0000000000000200 <startup64>: + + 202: mov %rsi,0x23df7(%rip) # 2400 <boot_params_addr> + 209: jmp 220 <startup> + + 0000000000000210 <efi_handover>: + + 214: callq 68f <efi_setup> + 219: mov %rax,0x23de0(%rip) # 2400 <boot_params_addr> + + 0000000000000220 <startup>: + + 2ce: ljmp *-0x6(%rsp) + + + +########################################################################## +## ## +## MEMTEST LINKING PART 2 - MEMTEST.EFI ## +## ## +########################################################################## + +# +# memtest_efi.lds +# +OUTPUT_FORMAT("binary") + +ENTRY(boot); <----- in boot/header.S:36 + +SECTIONS { + .header : { <----- boot/header.S + *(.header) + } + .setup : { <----- boot/setup.S + *(.setup) + } + .text : { + _text_start = .; + *(.data) <----- !!! NO .text !!!! + ... + +# +# header.S +# +The EFI loader loads the header at ImageBase, so we have to locate the main program +after that. This means we can't load the main program at HIGH_LOAD_ADDR. Pick a load +address well away from HIGH_LOAD_ADDR, to avoid overlap when relocating code. + +. # define IMAGE_BASE 0x200000 +. # define BASE_OF_CODE 0x1000 <- where do these values come from????? + + .section ".header", "ax", @progbits + .code16 + + .globl boot + +boot: + "MZ", the MS-DOS header signature + .byte 0x4d + .byte 0x5a + +pe_header: + +coff_header: + +... + +# +# setup.S +# +Collects memory map information from the BIOS, disables APM, enables A20 and performs +the switch from real mode to protected mode before jumping to the main program entry +point. + +The memory map information is stored in the 4KB block of memory immediately following +the setup code. The layout of the information matches the Linux boot_params struct. +A pointer to this block is passed to the main program, for compatibility with the Linux +32-bit boot protocol. + +. # define BOOT_PARAMS_START (SETUP_SECS * 512) || SETUP_SEC is defined in boot.h +. # define BOOT_PARAMS_END (BOOT_PARAMS_START + 4096) <--- here are the 4K + + .section ".setup", "ax", @progbits + .code16 + +Emulate the Linux boot header, to allow loading by other boot loaders. Indicate that the +main program code should be loaded in high memory. + + .globl setup +setup: jmp do_setup + +101: do_setup: + Reload the segment registers, except for the stack + Get the memory map and disable APM + Disable interrupts + Enable A20 + ... + +179: flush: + Reload the segment registers and jump to the main test program <------------!!!! + + ... +188: jump: + data32 ljmp $KERNEL_CS, $0 + + + +389: Pad to the declared size + .org (ESTUP_SECS*512) diff --git a/documentation/todo b/documentation/todo deleted file mode 100644 index 5238731..0000000 --- a/documentation/todo +++ /dev/null @@ -1,12 +0,0 @@ - -- gdb breakpoint - -- debug Symbole Memtest - -- AddressSanitizer - -- make vs make run - -- plugin to handle lto object - -- debug information by DEBUG ((---)) |