18e670053Srsc // Boot loader. 2f5527388Srsc // 3411ee741Srtm // Part of the boot sector, along with bootasm.S, which calls bootmain(). 4411ee741Srtm // bootasm.S has put the processor into protected 32-bit mode. 5411ee741Srtm // bootmain() loads an ELF kernel image from the disk starting at 6411ee741Srtm // sector 1 and then jumps to the kernel entry routine. 70cfc7290Srsc 80cfc7290Srsc #include "types.h" 90cfc7290Srsc #include "elf.h" 100cfc7290Srsc #include "x86.h" 119aa0337dSFrans Kaashoek #include "memlayout.h" 1255e95b16Srtm 1355e95b16Srtm #define SECTSIZE 512 1455e95b16Srtm 15b7f653dcSrsc void readseg(uchar*, uint, uint); 1655e95b16Srtm 1755e95b16Srtm void 18c35c064eSrsc bootmain(void) 1955e95b16Srtm { 2097ac612fSrsc struct elfhdr *elf; 21b5f17007Srsc struct proghdr *ph, *eph; 2297ac612fSrsc void (*entry)(void); 239aa0337dSFrans Kaashoek uchar* pa; 2455e95b16Srtm 2597ac612fSrsc elf = (struct elfhdr*)0x10000; // scratch space 2655e95b16Srtm 2797ac612fSrsc // Read 1st page off disk 28b7f653dcSrsc readseg((uchar*)elf, 4096, 0); 2997ac612fSrsc 3097ac612fSrsc // Is this an ELF executable? 3197ac612fSrsc if(elf->magic != ELF_MAGIC) 32b7f653dcSrsc return; // let bootasm.S handle error 3355e95b16Srtm 3497ac612fSrsc // Load each program segment (ignores ph flags). 3597ac612fSrsc ph = (struct proghdr*)((uchar*)elf + elf->phoff); 3697ac612fSrsc eph = ph + elf->phnum; 37b7f653dcSrsc for(; ph < eph; ph++){ 38fa81545fSFrans Kaashoek pa = (uchar*)ph->paddr; 39fa81545fSFrans Kaashoek readseg(pa, ph->filesz, ph->off); 40b7f653dcSrsc if(ph->memsz > ph->filesz) 419aa0337dSFrans Kaashoek stosb(pa + ph->filesz, 0, ph->memsz - ph->filesz); 42b7f653dcSrsc } 4355e95b16Srtm 4497ac612fSrsc // Call the entry point from the ELF header. 4597ac612fSrsc // Does not return! 469aa0337dSFrans Kaashoek entry = (void(*)(void))(elf->entry & 0xFFFFFF); 4797ac612fSrsc entry(); 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 76*cd3d739eSFrans Kaashoek // Read 'count' bytes at 'offset' from kernel into physical address 'pa'. 77eaea18cbSrsc // Might copy more than asked. 7855e95b16Srtm void 79*cd3d739eSFrans Kaashoek readseg(uchar* pa, uint count, uint offset) 8055e95b16Srtm { 81*cd3d739eSFrans Kaashoek uchar* epa; 8255e95b16Srtm 83*cd3d739eSFrans Kaashoek epa = pa + count; 8455e95b16Srtm 8597ac612fSrsc // Round down to sector boundary. 86*cd3d739eSFrans Kaashoek pa -= offset % SECTSIZE; 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. 94*cd3d739eSFrans Kaashoek for(; pa < epa; pa += SECTSIZE, offset++) 95*cd3d739eSFrans Kaashoek readsect(pa, offset); 9655e95b16Srtm } 97