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