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 up 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 //PAGEBREAK! 29 #include "types.h" 30 #include "elf.h" 31 #include "x86.h" 32 33 #define SECTSIZE 512 34 #define ELFHDR ((struct elfhdr*) 0x10000) // scratch space 35 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 void 68 waitdisk(void) 69 { 70 // wait for disk reaady 71 while((inb(0x1F7) & 0xC0) != 0x40) 72 ; 73 } 74 75 // Read a single sector at offset into dst. 76 void 77 readsect(void *dst, uint offset) 78 { 79 // wait for disk to be ready 80 waitdisk(); 81 82 outb(0x1F2, 1); // count = 1 83 outb(0x1F3, offset); 84 outb(0x1F4, offset >> 8); 85 outb(0x1F5, offset >> 16); 86 outb(0x1F6, (offset >> 24) | 0xE0); 87 outb(0x1F7, 0x20); // cmd 0x20 - read sectors 88 89 // wait for disk to be ready 90 waitdisk(); 91 92 // read a sector 93 insl(0x1F0, dst, SECTSIZE/4); 94 } 95 96 // Read 'count' bytes at 'offset' from kernel into virtual address 'va'. 97 // Might copy more than asked. 98 void 99 readseg(uint va, uint count, uint offset) 100 { 101 uint end_va; 102 103 va &= 0xFFFFFF; 104 end_va = va + count; 105 106 // round down to sector boundary 107 va &= ~(SECTSIZE - 1); 108 109 // translate from bytes to sectors, and kernel starts at sector 1 110 offset = (offset / SECTSIZE) + 1; 111 112 // If this is too slow, we could read lots of sectors at a time. 113 // We'd write more to memory than asked, but it doesn't matter -- 114 // we load in increasing order. 115 while(va < end_va) { 116 readsect((uchar*) va, offset); 117 va += SECTSIZE; 118 offset++; 119 } 120 } 121 122