1*8e670053Srsc // Boot loader. 2f5527388Srsc // 3*8e670053Srsc // The BIOS loads boot sector (bootasm.S) from sector 1 of the disk 4*8e670053Srsc // into memory and executes it. The boot sector puts the processor 5*8e670053Srsc // in 32-bit mode and calls cmain below, which loads an ELF kernel 6*8e670053Srsc // image from the disk starting at sector 2 and then jumps to the 7*8e670053Srsc // kernel entry routine. 80cfc7290Srsc 90cfc7290Srsc #include "types.h" 100cfc7290Srsc #include "elf.h" 110cfc7290Srsc #include "x86.h" 1255e95b16Srtm 1355e95b16Srtm #define SECTSIZE 512 1455e95b16Srtm 1529270816Srtm void readseg(uint, uint, uint); 1655e95b16Srtm 1755e95b16Srtm void 1855e95b16Srtm cmain(void) 1955e95b16Srtm { 2097ac612fSrsc struct elfhdr *elf; 21b5f17007Srsc struct proghdr *ph, *eph; 2297ac612fSrsc void (*entry)(void); 2355e95b16Srtm 2497ac612fSrsc elf = (struct elfhdr*)0x10000; // scratch space 2555e95b16Srtm 2697ac612fSrsc // Read 1st page off disk 2797ac612fSrsc readseg((uint)elf, SECTSIZE*8, 0); 2897ac612fSrsc 2997ac612fSrsc // Is this an ELF executable? 3097ac612fSrsc if(elf->magic != ELF_MAGIC) 3155e95b16Srtm goto bad; 3255e95b16Srtm 3397ac612fSrsc // Load each program segment (ignores ph flags). 3497ac612fSrsc ph = (struct proghdr*)((uchar*)elf + elf->phoff); 3597ac612fSrsc eph = ph + elf->phnum; 3655e95b16Srtm for(; ph < eph; ph++) 37ef2bd07aSrsc readseg(ph->va, ph->memsz, ph->offset); 3855e95b16Srtm 3997ac612fSrsc // Call the entry point from the ELF header. 4097ac612fSrsc // Does not return! 4197ac612fSrsc entry = (void(*)(void))(elf->entry & 0xFFFFFF); 4297ac612fSrsc entry(); 4355e95b16Srtm 4455e95b16Srtm bad: 4555e95b16Srtm outw(0x8A00, 0x8A00); 4655e95b16Srtm outw(0x8A00, 0x8E00); 47db8fb62eSrsc for(;;) 48f5527388Srsc ; 4955e95b16Srtm } 5055e95b16Srtm 51eaea18cbSrsc void 52eaea18cbSrsc waitdisk(void) 53eaea18cbSrsc { 5497ac612fSrsc // Wait for disk ready. 55eaea18cbSrsc while((inb(0x1F7) & 0xC0) != 0x40) 56eaea18cbSrsc ; 57eaea18cbSrsc } 58eaea18cbSrsc 59eaea18cbSrsc // Read a single sector at offset into dst. 60eaea18cbSrsc void 61eaea18cbSrsc readsect(void *dst, uint offset) 62eaea18cbSrsc { 6397ac612fSrsc // Issue command. 64eaea18cbSrsc waitdisk(); 65eaea18cbSrsc outb(0x1F2, 1); // count = 1 66eaea18cbSrsc outb(0x1F3, offset); 67eaea18cbSrsc outb(0x1F4, offset >> 8); 68eaea18cbSrsc outb(0x1F5, offset >> 16); 69eaea18cbSrsc outb(0x1F6, (offset >> 24) | 0xE0); 70eaea18cbSrsc outb(0x1F7, 0x20); // cmd 0x20 - read sectors 71eaea18cbSrsc 7297ac612fSrsc // Read data. 73eaea18cbSrsc waitdisk(); 74eaea18cbSrsc insl(0x1F0, dst, SECTSIZE/4); 75eaea18cbSrsc } 76eaea18cbSrsc 7755e95b16Srtm // Read 'count' bytes at 'offset' from kernel into virtual address 'va'. 78eaea18cbSrsc // Might copy more than asked. 7955e95b16Srtm void 8029270816Srtm readseg(uint va, uint count, uint offset) 8155e95b16Srtm { 8297ac612fSrsc uint eva; 8355e95b16Srtm 8455e95b16Srtm va &= 0xFFFFFF; 8597ac612fSrsc eva = va + count; 8655e95b16Srtm 8797ac612fSrsc // Round down to sector boundary. 8855e95b16Srtm va &= ~(SECTSIZE - 1); 8955e95b16Srtm 9097ac612fSrsc // Translate from bytes to sectors; kernel starts at sector 1. 9155e95b16Srtm offset = (offset / SECTSIZE) + 1; 9255e95b16Srtm 9355e95b16Srtm // If this is too slow, we could read lots of sectors at a time. 9455e95b16Srtm // We'd write more to memory than asked, but it doesn't matter -- 9555e95b16Srtm // we load in increasing order. 9697ac612fSrsc for(; va < eva; va += SECTSIZE, offset++) 9729270816Srtm readsect((uchar*)va, offset); 9855e95b16Srtm } 99