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