1 // Boot loader. 2 // 3 // Part of the boot sector, along with bootasm.S, which calls bootmain(). 4 // bootasm.S has put the processor into protected 32-bit mode. 5 // bootmain() loads an ELF kernel image from the disk starting at 6 // sector 1 and then jumps to the kernel entry routine. 7 8 #include "types.h" 9 #include "elf.h" 10 #include "x86.h" 11 #include "memlayout.h" 12 13 #define SECTSIZE 512 14 15 void readseg(uchar*, uint, uint); 16 17 void 18 bootmain(void) 19 { 20 struct elfhdr *elf; 21 struct proghdr *ph, *eph; 22 void (*entry)(void); 23 uchar* pa; 24 25 elf = (struct elfhdr*)0x10000; // scratch space 26 27 // Read 1st page off disk 28 readseg((uchar*)elf, 4096, 0); 29 30 // Is this an ELF executable? 31 if(elf->magic != ELF_MAGIC) 32 return; // let bootasm.S handle error 33 34 // Load each program segment (ignores ph flags). 35 ph = (struct proghdr*)((uchar*)elf + elf->phoff); 36 eph = ph + elf->phnum; 37 for(; ph < eph; ph++){ 38 pa = (uchar*)ph->pa; 39 readseg(pa, ph->filesz, ph->offset); 40 if(ph->memsz > ph->filesz) 41 stosb(pa + ph->filesz, 0, ph->memsz - ph->filesz); 42 } 43 44 // Call the entry point from the ELF header. 45 // Does not return! 46 entry = (void(*)(void))(elf->entry & 0xFFFFFF); 47 entry(); 48 } 49 50 void 51 waitdisk(void) 52 { 53 // Wait for disk ready. 54 while((inb(0x1F7) & 0xC0) != 0x40) 55 ; 56 } 57 58 // Read a single sector at offset into dst. 59 void 60 readsect(void *dst, uint offset) 61 { 62 // Issue command. 63 waitdisk(); 64 outb(0x1F2, 1); // count = 1 65 outb(0x1F3, offset); 66 outb(0x1F4, offset >> 8); 67 outb(0x1F5, offset >> 16); 68 outb(0x1F6, (offset >> 24) | 0xE0); 69 outb(0x1F7, 0x20); // cmd 0x20 - read sectors 70 71 // Read data. 72 waitdisk(); 73 insl(0x1F0, dst, SECTSIZE/4); 74 } 75 76 // Read 'count' bytes at 'offset' from kernel into virtual address 'va'. 77 // Might copy more than asked. 78 void 79 readseg(uchar* va, uint count, uint offset) 80 { 81 uchar* eva; 82 83 eva = va + count; 84 85 // Round down to sector boundary. 86 va -= offset % SECTSIZE; 87 88 // Translate from bytes to sectors; kernel starts at sector 1. 89 offset = (offset / SECTSIZE) + 1; 90 91 // If this is too slow, we could read lots of sectors at a time. 92 // We'd write more to memory than asked, but it doesn't matter -- 93 // we load in increasing order. 94 for(; va < eva; va += SECTSIZE, offset++) 95 readsect(va, offset); 96 } 97