18e670053Srsc // Boot loader. 2f5527388Srsc // 3*411ee741Srtm // Part of the boot sector, along with bootasm.S, which calls bootmain(). 4*411ee741Srtm // bootasm.S has put the processor into protected 32-bit mode. 5*411ee741Srtm // bootmain() loads an ELF kernel image from the disk starting at 6*411ee741Srtm // sector 1 and then jumps to the kernel entry routine. 70cfc7290Srsc 80cfc7290Srsc #include "types.h" 90cfc7290Srsc #include "elf.h" 100cfc7290Srsc #include "x86.h" 1155e95b16Srtm 1255e95b16Srtm #define SECTSIZE 512 1355e95b16Srtm 1429270816Srtm void readseg(uint, uint, uint); 1555e95b16Srtm 1655e95b16Srtm void 17c35c064eSrsc bootmain(void) 1855e95b16Srtm { 1997ac612fSrsc struct elfhdr *elf; 20b5f17007Srsc struct proghdr *ph, *eph; 2197ac612fSrsc void (*entry)(void); 2255e95b16Srtm 2397ac612fSrsc elf = (struct elfhdr*)0x10000; // scratch space 2455e95b16Srtm 2597ac612fSrsc // Read 1st page off disk 2697ac612fSrsc readseg((uint)elf, SECTSIZE*8, 0); 2797ac612fSrsc 2897ac612fSrsc // Is this an ELF executable? 2997ac612fSrsc if(elf->magic != ELF_MAGIC) 3055e95b16Srtm goto bad; 3155e95b16Srtm 3297ac612fSrsc // Load each program segment (ignores ph flags). 3397ac612fSrsc ph = (struct proghdr*)((uchar*)elf + elf->phoff); 3497ac612fSrsc eph = ph + elf->phnum; 3555e95b16Srtm for(; ph < eph; ph++) 36*411ee741Srtm readseg(ph->va & 0xFFFFFF, ph->memsz, ph->offset); 3755e95b16Srtm 3897ac612fSrsc // Call the entry point from the ELF header. 3997ac612fSrsc // Does not return! 4097ac612fSrsc entry = (void(*)(void))(elf->entry & 0xFFFFFF); 4197ac612fSrsc entry(); 4255e95b16Srtm 4355e95b16Srtm bad: 4455e95b16Srtm outw(0x8A00, 0x8A00); 4555e95b16Srtm outw(0x8A00, 0x8E00); 46db8fb62eSrsc for(;;) 47f5527388Srsc ; 4855e95b16Srtm } 4955e95b16Srtm 50eaea18cbSrsc void 51eaea18cbSrsc waitdisk(void) 52eaea18cbSrsc { 5397ac612fSrsc // Wait for disk ready. 54eaea18cbSrsc while((inb(0x1F7) & 0xC0) != 0x40) 55eaea18cbSrsc ; 56eaea18cbSrsc } 57eaea18cbSrsc 58eaea18cbSrsc // Read a single sector at offset into dst. 59eaea18cbSrsc void 60eaea18cbSrsc readsect(void *dst, uint offset) 61eaea18cbSrsc { 6297ac612fSrsc // Issue command. 63eaea18cbSrsc waitdisk(); 64eaea18cbSrsc outb(0x1F2, 1); // count = 1 65eaea18cbSrsc outb(0x1F3, offset); 66eaea18cbSrsc outb(0x1F4, offset >> 8); 67eaea18cbSrsc outb(0x1F5, offset >> 16); 68eaea18cbSrsc outb(0x1F6, (offset >> 24) | 0xE0); 69eaea18cbSrsc outb(0x1F7, 0x20); // cmd 0x20 - read sectors 70eaea18cbSrsc 7197ac612fSrsc // Read data. 72eaea18cbSrsc waitdisk(); 73eaea18cbSrsc insl(0x1F0, dst, SECTSIZE/4); 74eaea18cbSrsc } 75eaea18cbSrsc 7655e95b16Srtm // Read 'count' bytes at 'offset' from kernel into virtual address 'va'. 77eaea18cbSrsc // Might copy more than asked. 7855e95b16Srtm void 7929270816Srtm readseg(uint va, uint count, uint offset) 8055e95b16Srtm { 8197ac612fSrsc uint eva; 8255e95b16Srtm 8397ac612fSrsc eva = va + count; 8455e95b16Srtm 8597ac612fSrsc // Round down to sector boundary. 8655e95b16Srtm va &= ~(SECTSIZE - 1); 8755e95b16Srtm 8897ac612fSrsc // Translate from bytes to sectors; kernel starts at sector 1. 8955e95b16Srtm offset = (offset / SECTSIZE) + 1; 9055e95b16Srtm 9155e95b16Srtm // If this is too slow, we could read lots of sectors at a time. 9255e95b16Srtm // We'd write more to memory than asked, but it doesn't matter -- 9355e95b16Srtm // we load in increasing order. 9497ac612fSrsc for(; va < eva; va += SECTSIZE, offset++) 9529270816Srtm readsect((uchar*)va, offset); 9655e95b16Srtm } 97