1*55e95b16Srtm #include <types.h> 2*55e95b16Srtm #include <elf.h> 3*55e95b16Srtm #include <x86.h> 4*55e95b16Srtm 5*55e95b16Srtm /********************************************************************** 6*55e95b16Srtm * This a dirt simple boot loader, whose sole job is to boot 7*55e95b16Srtm * an elf kernel image from the first IDE hard disk. 8*55e95b16Srtm * 9*55e95b16Srtm * DISK LAYOUT 10*55e95b16Srtm * * This program(boot.S and main.c) is the bootloader. It should 11*55e95b16Srtm * be stored in the first sector of the disk. 12*55e95b16Srtm * 13*55e95b16Srtm * * The 2nd sector onward holds the kernel image. 14*55e95b16Srtm * 15*55e95b16Srtm * * The kernel image must be in ELF format. 16*55e95b16Srtm * 17*55e95b16Srtm * BOOT UP STEPS 18*55e95b16Srtm * * when the CPU boots it loads the BIOS into memory and executes it 19*55e95b16Srtm * 20*55e95b16Srtm * * the BIOS intializes devices, sets of the interrupt routines, and 21*55e95b16Srtm * reads the first sector of the boot device(e.g., hard-drive) 22*55e95b16Srtm * into memory and jumps to it. 23*55e95b16Srtm * 24*55e95b16Srtm * * Assuming this boot loader is stored in the first sector of the 25*55e95b16Srtm * hard-drive, this code takes over... 26*55e95b16Srtm * 27*55e95b16Srtm * * control starts in bootloader.S -- which sets up protected mode, 28*55e95b16Srtm * and a stack so C code then run, then calls cmain() 29*55e95b16Srtm * 30*55e95b16Srtm * * cmain() in this file takes over, reads in the kernel and jumps to it. 31*55e95b16Srtm **********************************************************************/ 32*55e95b16Srtm 33*55e95b16Srtm #define SECTSIZE 512 34*55e95b16Srtm #define ELFHDR ((struct Elf *) 0x10000) // scratch space 35*55e95b16Srtm 36*55e95b16Srtm void readsect(void*, uint32_t); 37*55e95b16Srtm void readseg(uint32_t, uint32_t, uint32_t); 38*55e95b16Srtm 39*55e95b16Srtm void 40*55e95b16Srtm cmain(void) 41*55e95b16Srtm { 42*55e95b16Srtm struct Proghdr *ph, *eph; 43*55e95b16Srtm 44*55e95b16Srtm // read 1st page off disk 45*55e95b16Srtm readseg((uint32_t) ELFHDR, SECTSIZE*8, 0); 46*55e95b16Srtm 47*55e95b16Srtm // is this a valid ELF? 48*55e95b16Srtm if (ELFHDR->e_magic != ELF_MAGIC) 49*55e95b16Srtm goto bad; 50*55e95b16Srtm 51*55e95b16Srtm // load each program segment (ignores ph flags) 52*55e95b16Srtm ph = (struct Proghdr *) ((uint8_t *) ELFHDR + ELFHDR->e_phoff); 53*55e95b16Srtm eph = ph + ELFHDR->e_phnum; 54*55e95b16Srtm for (; ph < eph; ph++) 55*55e95b16Srtm readseg(ph->p_va, ph->p_memsz, ph->p_offset); 56*55e95b16Srtm 57*55e95b16Srtm // call the entry point from the ELF header 58*55e95b16Srtm // note: does not return! 59*55e95b16Srtm ((void (*)(void)) (ELFHDR->e_entry & 0xFFFFFF))(); 60*55e95b16Srtm 61*55e95b16Srtm bad: 62*55e95b16Srtm outw(0x8A00, 0x8A00); 63*55e95b16Srtm outw(0x8A00, 0x8E00); 64*55e95b16Srtm while (1) 65*55e95b16Srtm /* do nothing */; 66*55e95b16Srtm } 67*55e95b16Srtm 68*55e95b16Srtm // Read 'count' bytes at 'offset' from kernel into virtual address 'va'. 69*55e95b16Srtm // Might copy more than asked 70*55e95b16Srtm void 71*55e95b16Srtm readseg(uint32_t va, uint32_t count, uint32_t offset) 72*55e95b16Srtm { 73*55e95b16Srtm uint32_t end_va; 74*55e95b16Srtm 75*55e95b16Srtm va &= 0xFFFFFF; 76*55e95b16Srtm end_va = va + count; 77*55e95b16Srtm 78*55e95b16Srtm // round down to sector boundary 79*55e95b16Srtm va &= ~(SECTSIZE - 1); 80*55e95b16Srtm 81*55e95b16Srtm // translate from bytes to sectors, and kernel starts at sector 1 82*55e95b16Srtm offset = (offset / SECTSIZE) + 1; 83*55e95b16Srtm 84*55e95b16Srtm // If this is too slow, we could read lots of sectors at a time. 85*55e95b16Srtm // We'd write more to memory than asked, but it doesn't matter -- 86*55e95b16Srtm // we load in increasing order. 87*55e95b16Srtm while (va < end_va) { 88*55e95b16Srtm readsect((uint8_t*) va, offset); 89*55e95b16Srtm va += SECTSIZE; 90*55e95b16Srtm offset++; 91*55e95b16Srtm } 92*55e95b16Srtm } 93*55e95b16Srtm 94*55e95b16Srtm void 95*55e95b16Srtm waitdisk(void) 96*55e95b16Srtm { 97*55e95b16Srtm // wait for disk reaady 98*55e95b16Srtm while ((inb(0x1F7) & 0xC0) != 0x40) 99*55e95b16Srtm /* do nothing */; 100*55e95b16Srtm } 101*55e95b16Srtm 102*55e95b16Srtm void 103*55e95b16Srtm readsect(void *dst, uint32_t offset) 104*55e95b16Srtm { 105*55e95b16Srtm // wait for disk to be ready 106*55e95b16Srtm waitdisk(); 107*55e95b16Srtm 108*55e95b16Srtm outb(0x1F2, 1); // count = 1 109*55e95b16Srtm outb(0x1F3, offset); 110*55e95b16Srtm outb(0x1F4, offset >> 8); 111*55e95b16Srtm outb(0x1F5, offset >> 16); 112*55e95b16Srtm outb(0x1F6, (offset >> 24) | 0xE0); 113*55e95b16Srtm outb(0x1F7, 0x20); // cmd 0x20 - read sectors 114*55e95b16Srtm 115*55e95b16Srtm // wait for disk to be ready 116*55e95b16Srtm waitdisk(); 117*55e95b16Srtm 118*55e95b16Srtm // read a sector 119*55e95b16Srtm insl(0x1F0, dst, SECTSIZE/4); 120*55e95b16Srtm } 121*55e95b16Srtm 122