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