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 // 1520365348Srtm // * the BIOS intializes devices, sets up 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 28eaea18cbSrsc //PAGEBREAK! 290cfc7290Srsc #include "types.h" 300cfc7290Srsc #include "elf.h" 310cfc7290Srsc #include "x86.h" 3255e95b16Srtm 3355e95b16Srtm #define SECTSIZE 512 3455e95b16Srtm 3529270816Srtm void readseg(uint, uint, uint); 3655e95b16Srtm 3755e95b16Srtm void 3855e95b16Srtm cmain(void) 3955e95b16Srtm { 40*97ac612fSrsc struct elfhdr *elf; 41b5f17007Srsc struct proghdr *ph, *eph; 42*97ac612fSrsc void (*entry)(void); 4355e95b16Srtm 44*97ac612fSrsc elf = (struct elfhdr*)0x10000; // scratch space 4555e95b16Srtm 46*97ac612fSrsc // Read 1st page off disk 47*97ac612fSrsc readseg((uint)elf, SECTSIZE*8, 0); 48*97ac612fSrsc 49*97ac612fSrsc // Is this an ELF executable? 50*97ac612fSrsc if(elf->magic != ELF_MAGIC) 5155e95b16Srtm goto bad; 5255e95b16Srtm 53*97ac612fSrsc // Load each program segment (ignores ph flags). 54*97ac612fSrsc ph = (struct proghdr*)((uchar*)elf + elf->phoff); 55*97ac612fSrsc eph = ph + elf->phnum; 5655e95b16Srtm for(; ph < eph; ph++) 57ef2bd07aSrsc readseg(ph->va, ph->memsz, ph->offset); 5855e95b16Srtm 59*97ac612fSrsc // Call the entry point from the ELF header. 60*97ac612fSrsc // Does not return! 61*97ac612fSrsc entry = (void(*)(void))(elf->entry & 0xFFFFFF); 62*97ac612fSrsc entry(); 6355e95b16Srtm 6455e95b16Srtm bad: 6555e95b16Srtm outw(0x8A00, 0x8A00); 6655e95b16Srtm outw(0x8A00, 0x8E00); 67db8fb62eSrsc for(;;) 68f5527388Srsc ; 6955e95b16Srtm } 7055e95b16Srtm 71eaea18cbSrsc void 72eaea18cbSrsc waitdisk(void) 73eaea18cbSrsc { 74*97ac612fSrsc // Wait for disk ready. 75eaea18cbSrsc while((inb(0x1F7) & 0xC0) != 0x40) 76eaea18cbSrsc ; 77eaea18cbSrsc } 78eaea18cbSrsc 79eaea18cbSrsc // Read a single sector at offset into dst. 80eaea18cbSrsc void 81eaea18cbSrsc readsect(void *dst, uint offset) 82eaea18cbSrsc { 83*97ac612fSrsc // Issue command. 84eaea18cbSrsc waitdisk(); 85eaea18cbSrsc outb(0x1F2, 1); // count = 1 86eaea18cbSrsc outb(0x1F3, offset); 87eaea18cbSrsc outb(0x1F4, offset >> 8); 88eaea18cbSrsc outb(0x1F5, offset >> 16); 89eaea18cbSrsc outb(0x1F6, (offset >> 24) | 0xE0); 90eaea18cbSrsc outb(0x1F7, 0x20); // cmd 0x20 - read sectors 91eaea18cbSrsc 92*97ac612fSrsc // Read data. 93eaea18cbSrsc waitdisk(); 94eaea18cbSrsc insl(0x1F0, dst, SECTSIZE/4); 95eaea18cbSrsc } 96eaea18cbSrsc 9755e95b16Srtm // Read 'count' bytes at 'offset' from kernel into virtual address 'va'. 98eaea18cbSrsc // Might copy more than asked. 9955e95b16Srtm void 10029270816Srtm readseg(uint va, uint count, uint offset) 10155e95b16Srtm { 102*97ac612fSrsc uint eva; 10355e95b16Srtm 10455e95b16Srtm va &= 0xFFFFFF; 105*97ac612fSrsc eva = va + count; 10655e95b16Srtm 107*97ac612fSrsc // Round down to sector boundary. 10855e95b16Srtm va &= ~(SECTSIZE - 1); 10955e95b16Srtm 110*97ac612fSrsc // Translate from bytes to sectors; kernel starts at sector 1. 11155e95b16Srtm offset = (offset / SECTSIZE) + 1; 11255e95b16Srtm 11355e95b16Srtm // If this is too slow, we could read lots of sectors at a time. 11455e95b16Srtm // We'd write more to memory than asked, but it doesn't matter -- 11555e95b16Srtm // we load in increasing order. 116*97ac612fSrsc for(; va < eva; va += SECTSIZE, offset++) 11729270816Srtm readsect((uchar*)va, offset); 11855e95b16Srtm } 119