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 // 250cfc7290Srsc // * cmain() in this file takes over, 260cfc7290Srsc // reads in the kernel and jumps to it. 270cfc7290Srsc 28*eaea18cbSrsc //PAGEBREAK! 290cfc7290Srsc #include "types.h" 300cfc7290Srsc #include "elf.h" 310cfc7290Srsc #include "x86.h" 3255e95b16Srtm 3355e95b16Srtm #define SECTSIZE 512 34b5f17007Srsc #define ELFHDR ((struct elfhdr*) 0x10000) // scratch space 3555e95b16Srtm 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 67*eaea18cbSrsc void 68*eaea18cbSrsc waitdisk(void) 69*eaea18cbSrsc { 70*eaea18cbSrsc // wait for disk reaady 71*eaea18cbSrsc while((inb(0x1F7) & 0xC0) != 0x40) 72*eaea18cbSrsc ; 73*eaea18cbSrsc } 74*eaea18cbSrsc 75*eaea18cbSrsc // Read a single sector at offset into dst. 76*eaea18cbSrsc void 77*eaea18cbSrsc readsect(void *dst, uint offset) 78*eaea18cbSrsc { 79*eaea18cbSrsc // wait for disk to be ready 80*eaea18cbSrsc waitdisk(); 81*eaea18cbSrsc 82*eaea18cbSrsc outb(0x1F2, 1); // count = 1 83*eaea18cbSrsc outb(0x1F3, offset); 84*eaea18cbSrsc outb(0x1F4, offset >> 8); 85*eaea18cbSrsc outb(0x1F5, offset >> 16); 86*eaea18cbSrsc outb(0x1F6, (offset >> 24) | 0xE0); 87*eaea18cbSrsc outb(0x1F7, 0x20); // cmd 0x20 - read sectors 88*eaea18cbSrsc 89*eaea18cbSrsc // wait for disk to be ready 90*eaea18cbSrsc waitdisk(); 91*eaea18cbSrsc 92*eaea18cbSrsc // read a sector 93*eaea18cbSrsc insl(0x1F0, dst, SECTSIZE/4); 94*eaea18cbSrsc } 95*eaea18cbSrsc 9655e95b16Srtm // Read 'count' bytes at 'offset' from kernel into virtual address 'va'. 97*eaea18cbSrsc // Might copy more than asked. 9855e95b16Srtm void 9929270816Srtm readseg(uint va, uint count, uint offset) 10055e95b16Srtm { 10129270816Srtm uint end_va; 10255e95b16Srtm 10355e95b16Srtm va &= 0xFFFFFF; 10455e95b16Srtm end_va = va + count; 10555e95b16Srtm 10655e95b16Srtm // round down to sector boundary 10755e95b16Srtm va &= ~(SECTSIZE - 1); 10855e95b16Srtm 10955e95b16Srtm // translate from bytes to sectors, and kernel starts at sector 1 11055e95b16Srtm offset = (offset / SECTSIZE) + 1; 11155e95b16Srtm 11255e95b16Srtm // If this is too slow, we could read lots of sectors at a time. 11355e95b16Srtm // We'd write more to memory than asked, but it doesn't matter -- 11455e95b16Srtm // we load in increasing order. 11555e95b16Srtm while(va < end_va) { 11629270816Srtm readsect((uchar*) va, offset); 11755e95b16Srtm va += SECTSIZE; 11855e95b16Srtm offset++; 11955e95b16Srtm } 12055e95b16Srtm } 12155e95b16Srtm 122