1f5527388Srsc // This a dirt simple boot loader, whose sole job is to boot 2f5527388Srsc // an elf kernel image from the first IDE hard disk. 3f5527388Srsc // 4f5527388Srsc // DISK LAYOUT 5f5527388Srsc // * This program(boot.S and main.c) is the bootloader. It should 6f5527388Srsc // be stored in the first sector of the disk. 7f5527388Srsc // 8f5527388Srsc // * The 2nd sector onward holds the kernel image. 9f5527388Srsc // 10f5527388Srsc // * The kernel image must be in ELF format. 11f5527388Srsc // 12f5527388Srsc // BOOT UP STEPS 13f5527388Srsc // * when the CPU boots it loads the BIOS into memory and executes it 14f5527388Srsc // 15f5527388Srsc // * the BIOS intializes devices, sets of the interrupt routines, and 16f5527388Srsc // reads the first sector of the boot device(e.g., hard-drive) 17f5527388Srsc // into memory and jumps to it. 18f5527388Srsc // 19f5527388Srsc // * Assuming this boot loader is stored in the first sector of the 20f5527388Srsc // hard-drive, this code takes over... 21f5527388Srsc // 22f5527388Srsc // * control starts in bootloader.S -- which sets up protected mode, 23f5527388Srsc // and a stack so C code then run, then calls cmain() 24f5527388Srsc // 25*0cfc7290Srsc // * cmain() in this file takes over, 26*0cfc7290Srsc // reads in the kernel and jumps to it. 27*0cfc7290Srsc 28*0cfc7290Srsc #include "types.h" 29*0cfc7290Srsc #include "elf.h" 30*0cfc7290Srsc #include "x86.h" 3155e95b16Srtm 3255e95b16Srtm #define SECTSIZE 512 33b5f17007Srsc #define ELFHDR ((struct elfhdr*) 0x10000) // scratch space 3455e95b16Srtm 3529270816Srtm void readsect(void*, uint); 3629270816Srtm void readseg(uint, uint, uint); 3755e95b16Srtm 3855e95b16Srtm void 3955e95b16Srtm cmain(void) 4055e95b16Srtm { 41b5f17007Srsc struct proghdr *ph, *eph; 4255e95b16Srtm 4355e95b16Srtm // read 1st page off disk 4429270816Srtm readseg((uint) ELFHDR, SECTSIZE*8, 0); 4555e95b16Srtm 4655e95b16Srtm // is this a valid ELF? 47ef2bd07aSrsc if(ELFHDR->magic != ELF_MAGIC) 4855e95b16Srtm goto bad; 4955e95b16Srtm 5055e95b16Srtm // load each program segment (ignores ph flags) 5129270816Srtm ph = (struct proghdr*) ((uchar*) ELFHDR + ELFHDR->phoff); 52ef2bd07aSrsc eph = ph + ELFHDR->phnum; 5355e95b16Srtm for(; ph < eph; ph++) 54ef2bd07aSrsc readseg(ph->va, ph->memsz, ph->offset); 5555e95b16Srtm 5655e95b16Srtm // call the entry point from the ELF header 5755e95b16Srtm // note: does not return! 58ef2bd07aSrsc ((void(*)(void)) (ELFHDR->entry & 0xFFFFFF))(); 5955e95b16Srtm 6055e95b16Srtm bad: 6155e95b16Srtm outw(0x8A00, 0x8A00); 6255e95b16Srtm outw(0x8A00, 0x8E00); 63db8fb62eSrsc for(;;) 64f5527388Srsc ; 6555e95b16Srtm } 6655e95b16Srtm 6755e95b16Srtm // Read 'count' bytes at 'offset' from kernel into virtual address 'va'. 6855e95b16Srtm // Might copy more than asked 6955e95b16Srtm void 7029270816Srtm readseg(uint va, uint count, uint offset) 7155e95b16Srtm { 7229270816Srtm uint end_va; 7355e95b16Srtm 7455e95b16Srtm va &= 0xFFFFFF; 7555e95b16Srtm end_va = va + count; 7655e95b16Srtm 7755e95b16Srtm // round down to sector boundary 7855e95b16Srtm va &= ~(SECTSIZE - 1); 7955e95b16Srtm 8055e95b16Srtm // translate from bytes to sectors, and kernel starts at sector 1 8155e95b16Srtm offset = (offset / SECTSIZE) + 1; 8255e95b16Srtm 8355e95b16Srtm // If this is too slow, we could read lots of sectors at a time. 8455e95b16Srtm // We'd write more to memory than asked, but it doesn't matter -- 8555e95b16Srtm // we load in increasing order. 8655e95b16Srtm while(va < end_va) { 8729270816Srtm readsect((uchar*) va, offset); 8855e95b16Srtm va += SECTSIZE; 8955e95b16Srtm offset++; 9055e95b16Srtm } 9155e95b16Srtm } 9255e95b16Srtm 9355e95b16Srtm void 9455e95b16Srtm waitdisk(void) 9555e95b16Srtm { 9655e95b16Srtm // wait for disk reaady 9755e95b16Srtm while((inb(0x1F7) & 0xC0) != 0x40) 98f5527388Srsc ; 9955e95b16Srtm } 10055e95b16Srtm 10155e95b16Srtm void 10229270816Srtm readsect(void *dst, uint offset) 10355e95b16Srtm { 10455e95b16Srtm // wait for disk to be ready 10555e95b16Srtm waitdisk(); 10655e95b16Srtm 10755e95b16Srtm outb(0x1F2, 1); // count = 1 10855e95b16Srtm outb(0x1F3, offset); 10955e95b16Srtm outb(0x1F4, offset >> 8); 11055e95b16Srtm outb(0x1F5, offset >> 16); 11155e95b16Srtm outb(0x1F6, (offset >> 24) | 0xE0); 11255e95b16Srtm outb(0x1F7, 0x20); // cmd 0x20 - read sectors 11355e95b16Srtm 11455e95b16Srtm // wait for disk to be ready 11555e95b16Srtm waitdisk(); 11655e95b16Srtm 11755e95b16Srtm // read a sector 11855e95b16Srtm insl(0x1F0, dst, SECTSIZE/4); 11955e95b16Srtm } 12055e95b16Srtm 121