1 #include "types.h" 2 #include "elf.h" 3 #include "x86.h" 4 5 /********************************************************************** 6 * This a dirt simple boot loader, whose sole job is to boot 7 * an elf kernel image from the first IDE hard disk. 8 * 9 * DISK LAYOUT 10 * * This program(boot.S and main.c) is the bootloader. It should 11 * be stored in the first sector of the disk. 12 * 13 * * The 2nd sector onward holds the kernel image. 14 * 15 * * The kernel image must be in ELF format. 16 * 17 * BOOT UP STEPS 18 * * when the CPU boots it loads the BIOS into memory and executes it 19 * 20 * * the BIOS intializes devices, sets of the interrupt routines, and 21 * reads the first sector of the boot device(e.g., hard-drive) 22 * into memory and jumps to it. 23 * 24 * * Assuming this boot loader is stored in the first sector of the 25 * hard-drive, this code takes over... 26 * 27 * * control starts in bootloader.S -- which sets up protected mode, 28 * and a stack so C code then run, then calls cmain() 29 * 30 * * cmain() in this file takes over, reads in the kernel and jumps to it. 31 **********************************************************************/ 32 33 #define SECTSIZE 512 34 #define ELFHDR ((struct elfhdr *) 0x10000) // scratch space 35 36 void readsect(void*, uint32_t); 37 void readseg(uint32_t, uint32_t, uint32_t); 38 39 void 40 cmain(void) 41 { 42 struct proghdr *ph, *eph; 43 44 // read 1st page off disk 45 readseg((uint32_t) ELFHDR, SECTSIZE*8, 0); 46 47 // is this a valid ELF? 48 if (ELFHDR->magic != ELF_MAGIC) 49 goto bad; 50 51 // load each program segment (ignores ph flags) 52 ph = (struct proghdr *) ((uint8_t *) ELFHDR + ELFHDR->phoff); 53 eph = ph + ELFHDR->phnum; 54 for (; ph < eph; ph++) 55 readseg(ph->va, ph->memsz, ph->offset); 56 57 // call the entry point from the ELF header 58 // note: does not return! 59 ((void (*)(void)) (ELFHDR->entry & 0xFFFFFF))(); 60 61 bad: 62 outw(0x8A00, 0x8A00); 63 outw(0x8A00, 0x8E00); 64 while(1) 65 /* do nothing */; 66 } 67 68 // Read 'count' bytes at 'offset' from kernel into virtual address 'va'. 69 // Might copy more than asked 70 void 71 readseg(uint32_t va, uint32_t count, uint32_t offset) 72 { 73 uint32_t end_va; 74 75 va &= 0xFFFFFF; 76 end_va = va + count; 77 78 // round down to sector boundary 79 va &= ~(SECTSIZE - 1); 80 81 // translate from bytes to sectors, and kernel starts at sector 1 82 offset = (offset / SECTSIZE) + 1; 83 84 // If this is too slow, we could read lots of sectors at a time. 85 // We'd write more to memory than asked, but it doesn't matter -- 86 // we load in increasing order. 87 while (va < end_va) { 88 readsect((uint8_t*) va, offset); 89 va += SECTSIZE; 90 offset++; 91 } 92 } 93 94 void 95 waitdisk(void) 96 { 97 // wait for disk reaady 98 while ((inb(0x1F7) & 0xC0) != 0x40) 99 /* do nothing */; 100 } 101 102 void 103 readsect(void *dst, uint32_t offset) 104 { 105 // wait for disk to be ready 106 waitdisk(); 107 108 outb(0x1F2, 1); // count = 1 109 outb(0x1F3, offset); 110 outb(0x1F4, offset >> 8); 111 outb(0x1F5, offset >> 16); 112 outb(0x1F6, (offset >> 24) | 0xE0); 113 outb(0x1F7, 0x20); // cmd 0x20 - read sectors 114 115 // wait for disk to be ready 116 waitdisk(); 117 118 // read a sector 119 insl(0x1F0, dst, SECTSIZE/4); 120 } 121 122