1b53f99d0Srsc #include "types.h" 2b53f99d0Srsc #include "elf.h" 3b53f99d0Srsc #include "x86.h" 455e95b16Srtm 555e95b16Srtm /********************************************************************** 655e95b16Srtm * This a dirt simple boot loader, whose sole job is to boot 755e95b16Srtm * an elf kernel image from the first IDE hard disk. 855e95b16Srtm * 955e95b16Srtm * DISK LAYOUT 1055e95b16Srtm * * This program(boot.S and main.c) is the bootloader. It should 1155e95b16Srtm * be stored in the first sector of the disk. 1255e95b16Srtm * 1355e95b16Srtm * * The 2nd sector onward holds the kernel image. 1455e95b16Srtm * 1555e95b16Srtm * * The kernel image must be in ELF format. 1655e95b16Srtm * 1755e95b16Srtm * BOOT UP STEPS 1855e95b16Srtm * * when the CPU boots it loads the BIOS into memory and executes it 1955e95b16Srtm * 2055e95b16Srtm * * the BIOS intializes devices, sets of the interrupt routines, and 2155e95b16Srtm * reads the first sector of the boot device(e.g., hard-drive) 2255e95b16Srtm * into memory and jumps to it. 2355e95b16Srtm * 2455e95b16Srtm * * Assuming this boot loader is stored in the first sector of the 2555e95b16Srtm * hard-drive, this code takes over... 2655e95b16Srtm * 2755e95b16Srtm * * control starts in bootloader.S -- which sets up protected mode, 2855e95b16Srtm * and a stack so C code then run, then calls cmain() 2955e95b16Srtm * 3055e95b16Srtm * * cmain() in this file takes over, reads in the kernel and jumps to it. 3155e95b16Srtm **********************************************************************/ 3255e95b16Srtm 3355e95b16Srtm #define SECTSIZE 512 34*b5f17007Srsc #define ELFHDR ((struct elfhdr *) 0x10000) // scratch space 3555e95b16Srtm 3655e95b16Srtm void readsect(void*, uint32_t); 3755e95b16Srtm void readseg(uint32_t, uint32_t, uint32_t); 3855e95b16Srtm 3955e95b16Srtm void 4055e95b16Srtm cmain(void) 4155e95b16Srtm { 42*b5f17007Srsc struct proghdr *ph, *eph; 4355e95b16Srtm 4455e95b16Srtm // read 1st page off disk 4555e95b16Srtm readseg((uint32_t) ELFHDR, SECTSIZE*8, 0); 4655e95b16Srtm 4755e95b16Srtm // is this a valid ELF? 48ef2bd07aSrsc if (ELFHDR->magic != ELF_MAGIC) 4955e95b16Srtm goto bad; 5055e95b16Srtm 5155e95b16Srtm // load each program segment (ignores ph flags) 52*b5f17007Srsc ph = (struct proghdr *) ((uint8_t *) ELFHDR + ELFHDR->phoff); 53ef2bd07aSrsc eph = ph + ELFHDR->phnum; 5455e95b16Srtm for (; ph < eph; ph++) 55ef2bd07aSrsc readseg(ph->va, ph->memsz, ph->offset); 5655e95b16Srtm 5755e95b16Srtm // call the entry point from the ELF header 5855e95b16Srtm // note: does not return! 59ef2bd07aSrsc ((void (*)(void)) (ELFHDR->entry & 0xFFFFFF))(); 6055e95b16Srtm 6155e95b16Srtm bad: 6255e95b16Srtm outw(0x8A00, 0x8A00); 6355e95b16Srtm outw(0x8A00, 0x8E00); 6455e95b16Srtm while(1) 6555e95b16Srtm /* do nothing */; 6655e95b16Srtm } 6755e95b16Srtm 6855e95b16Srtm // Read 'count' bytes at 'offset' from kernel into virtual address 'va'. 6955e95b16Srtm // Might copy more than asked 7055e95b16Srtm void 7155e95b16Srtm readseg(uint32_t va, uint32_t count, uint32_t offset) 7255e95b16Srtm { 7355e95b16Srtm uint32_t end_va; 7455e95b16Srtm 7555e95b16Srtm va &= 0xFFFFFF; 7655e95b16Srtm end_va = va + count; 7755e95b16Srtm 7855e95b16Srtm // round down to sector boundary 7955e95b16Srtm va &= ~(SECTSIZE - 1); 8055e95b16Srtm 8155e95b16Srtm // translate from bytes to sectors, and kernel starts at sector 1 8255e95b16Srtm offset = (offset / SECTSIZE) + 1; 8355e95b16Srtm 8455e95b16Srtm // If this is too slow, we could read lots of sectors at a time. 8555e95b16Srtm // We'd write more to memory than asked, but it doesn't matter -- 8655e95b16Srtm // we load in increasing order. 8755e95b16Srtm while (va < end_va) { 8855e95b16Srtm readsect((uint8_t*) va, offset); 8955e95b16Srtm va += SECTSIZE; 9055e95b16Srtm offset++; 9155e95b16Srtm } 9255e95b16Srtm } 9355e95b16Srtm 9455e95b16Srtm void 9555e95b16Srtm waitdisk(void) 9655e95b16Srtm { 9755e95b16Srtm // wait for disk reaady 9855e95b16Srtm while ((inb(0x1F7) & 0xC0) != 0x40) 9955e95b16Srtm /* do nothing */; 10055e95b16Srtm } 10155e95b16Srtm 10255e95b16Srtm void 10355e95b16Srtm readsect(void *dst, uint32_t offset) 10455e95b16Srtm { 10555e95b16Srtm // wait for disk to be ready 10655e95b16Srtm waitdisk(); 10755e95b16Srtm 10855e95b16Srtm outb(0x1F2, 1); // count = 1 10955e95b16Srtm outb(0x1F3, offset); 11055e95b16Srtm outb(0x1F4, offset >> 8); 11155e95b16Srtm outb(0x1F5, offset >> 16); 11255e95b16Srtm outb(0x1F6, (offset >> 24) | 0xE0); 11355e95b16Srtm outb(0x1F7, 0x20); // cmd 0x20 - read sectors 11455e95b16Srtm 11555e95b16Srtm // wait for disk to be ready 11655e95b16Srtm waitdisk(); 11755e95b16Srtm 11855e95b16Srtm // read a sector 11955e95b16Srtm insl(0x1F0, dst, SECTSIZE/4); 12055e95b16Srtm } 12155e95b16Srtm 122