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