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