Loading and launching programs Michal Sojka1 Czech Technical University in Prague, Faculty of Electrical Engineering Email: sojkam1@fel.cvut.cz April 15, 2015 1 Based on exercises by Benjamin Engel from TU Dresden. M. Sojka A3B33OSD, task E3 April 15, 2015 1 / 16 Roadmap Last week I Start hard-coded root task This week I Start arbitrary program as root task I The program is provided in a separate binary I Required memory mapping is read from binary’s header M. Sojka A3B33OSD, task E3 April 15, 2015 2 / 16 Prerequisites I Brief look into program startup assembly and linker script I Multiboot – passing information from bootloader to the OS kernel I ELF binary format M. Sojka A3B33OSD, task E3 April 15, 2015 3 / 16 Program binaries Program binaries I Composed of headers, segments and sections I One segment contains one or more sections I A section may or may not belong to a segment I All of this is controlled by “linker scripts” Linker script – user/src/linker.ld I Program entry point at symbol __start I Two segments: data (rw=6) and text (rx=5) I Put section .text in segment text and sections .data and .bss in segment data I ALIGN stack and text to page boundary (0x1000) M. Sojka A3B33OSD, task E3 April 15, 2015 4 / 16 Program binaries Program startup – user/src/start.S .text .global __start __start: mov $stack_top, %esp call main_func ud2 I Put this into the .text section I Define global symbol __start: I Setup a stack by loading the address of stack_top into esp (stack_top is defined in linker.ld) I Call main_func() M. Sojka A3B33OSD, task E3 April 15, 2015 5 / 16 Program binaries Building and inspecting the user program I Goto user/build and make user binary I Inspect binary by nm -C user.nova.debug 00002004 00002000 0000301 e 00002000 00003000 0000300 c D D T D T T foobar_in_data foobar_in_data2 main_func stack_top __start syscall3 ( unsigned int , unsigned int , un I There are three symbols in the text section (T) and three in data section (D) I Dump the binary: hexdump -C user.nova I Decode headers: objdump -x user.nova M. Sojka A3B33OSD, task E3 April 15, 2015 6 / 16 Bootloader Bootloader I We will use GRUB – standard GNU/Linux bootloader I Among others, it implements multiboot specification I It specifies how does bootloader pass various pieces of information to the OS kernel. I We let the bootloader load not only the kernel (hypervisor) but also the user.nova file: ls boot cat boot/menu.lst M. Sojka # bootloader configuration file A3B33OSD, task E3 April 15, 2015 7 / 16 Bootloader Multiboot information (multiboot.h) https://www.gnu.org/software/grub/manual/multiboot/multiboot.html EBX flags I mem_lower mem_upper Data structure passed by the bootloader to the OS kernel I Flags is required, all the others are optional boot_device I cmdline mods_count If flags:3 (3rd bit) is set, mods_count and mods_addr are valid I mods_addr is the physical address to an mods_addr syms[4] mmap_length mmap_addr ... M. Sojka array of module structs with length mods_count mod_start mod_end string reserved A3B33OSD, task E3 mod_start mod_end string reserved April 15, 2015 ... 8 / 16 Bootloader Accessing data from the bootloader – remapping I I Problem: Multiboot info (mbi) address (in EBX register) and mods_addr are physical addresses We need to (temporarily) map them into the virtual address space. This can be done with the following function: void * Ptab::remap(phys_addr) I It maps the physical memory into “kernel’s remap area” and returns a pointer to it. The previous mapping is replaced, thus returned pointers are remap only usable before the next call to remap! ▼area virtual memory Multi boot info ▼ M. Sojka Kernel physical memory A3B33OSD, task E3 April 15, 2015 9 / 16 Bootloader Task 1 – Find and map the user binary 1. Open kern/src/ec.cc: root_invoke() 2. Ec::current->regs.eax contains mbi pointer (see start.S to understand why) 3. remap Multiboot Info, check flags:3, get mods_addr and count 4. remap Multiboot module structure, print start and end address of user binary 5. remap user binary (it’s an ELF object) 6. see kern/include/multiboot.h and elf.h M. Sojka A3B33OSD, task E3 April 15, 2015 10 / 16 ELF format Executable and Linkable Format (ELF) http://www.sco.com/developers/devspecs/gabi41.pdf, chapter 4 ELF header Program header table I The format of binaries on Unix systems I ELF header contains offset where to find PH table (ph_offset) I Program header table describes the segments to be used at runtime code segment data segment ... M. Sojka A3B33OSD, task E3 April 15, 2015 11 / 16 ELF format ELF header (elf.h) magic: 7f ’E’ ’L’ ’F’ data version padd. padding padding type machine version entry ph_offset sh_offset flags eh_size ph_size ph_count sh_size sh_count strtab class M. Sojka A3B33OSD, task E3 I Check magic, data == 1 and type == 2 I entry – user EIP I ph_count: number of program headers I ph_offset: where within the file the program header table starts April 15, 2015 12 / 16 ELF format Program header table ELF header type file offset virtual address physical address file size mem size flags alignment I If type == PT_LOAD (== 1) load this segment I Flags:2 ⇒ writable I Offset: where this segment starts relative to the beginning of the file I Virtual address: where to map this segment to I File/Mem size: segment size in file and memory type file offset ... M. Sojka A3B33OSD, task E3 April 15, 2015 13 / 16 ELF format Task 2 – Decode the ELF 1. Continue in root_invoke() I user binary is still mapped in 2. Set current->regs.eip to the correct entry point (from ELF header) 3. Remap program header table and iterate over all (two) program segments 3.1 If type != PT_LOAD, ignore this segment 3.2 Print all virt/phys addresses and mem sizes I I I M. Sojka Align them properly to 4k page boundaries phys/virt addresses: align down mem size: align up A3B33OSD, task E3 April 15, 2015 14 / 16 Map and start the program Task 3 – Map and start the program 1. Some sanity checks: I I File size and mem size should be equal Virtual address and file offset should be equal (modulo page size) 2. Add mapping for all pages in all segments: Ptab::insert_mapping (virt, phys, attr) I Inserts a mapping from virtual address virt to physical address phys with attributes attr I If flags & Ph::PF_W ⇒ should be mapped writable, thus attr = 7, otherwise attr = 5 I (See class Ph in kernel/include/elf.h) 3. ret_user_iret() to start user program M. Sojka A3B33OSD, task E3 April 15, 2015 15 / 16 Map and start the program Understanding Ptab::insert_mapping – x86 page tables cr3 pdir addr page directory page table 0x1000 ptab addr ptab addr 31 1 1 1 2 ... .data .stack 0x2000 .text 1 12 20 bit phys addr page addr page addr 1 0 S R P UW P – present (1 : entry valid) R/W – 0 : read only, 1 : writable S/U – 0 : kernel only, 1 : user M. Sojka A3B33OSD, task E3 April 15, 2015 16 / 16
© Copyright 2024