xv6

port of xv6 to x86-64
git clone http://frotz.net/git/xv6.git
Log | Files | Refs | README | LICENSE

bootmain.c (2719B)


      1 // Boot loader.
      2 // 
      3 // Part of the boot sector, along with bootasm.S, which calls bootmain().
      4 // bootasm.S has put the processor into protected 32-bit mode.
      5 // bootmain() loads a multiboot kernel image from the disk starting at
      6 // sector 1 and then jumps to the kernel entry routine.
      7 
      8 #include "types.h"
      9 #include "x86.h"
     10 #include "memlayout.h"
     11 
     12 #define SECTSIZE  512
     13 
     14 struct mbheader {
     15   uint32 magic;
     16   uint32 flags;
     17   uint32 checksum;
     18   uint32 header_addr;
     19   uint32 load_addr;
     20   uint32 load_end_addr;
     21   uint32 bss_end_addr;
     22   uint32 entry_addr;
     23 };
     24 
     25 void readseg(uchar*, uint, uint);
     26 
     27 void
     28 bootmain(void)
     29 {
     30   struct mbheader *hdr;
     31   void (*entry)(void);
     32   uint32 *x;
     33   uint n;
     34 
     35   x = (uint32*) 0x10000; // scratch space
     36 
     37   // multiboot header must be in the first 8192 bytes
     38   readseg((uchar*)x, 8192, 0);
     39 
     40   for (n = 0; n < 8192/4; n++)
     41     if (x[n] == 0x1BADB002)
     42       if ((x[n] + x[n+1] + x[n+2]) == 0)
     43         goto found_it;
     44 
     45   // failure
     46   return;
     47 
     48 found_it:
     49   hdr = (struct mbheader *) (x + n);
     50 
     51   if (!(hdr->flags & 0x10000))
     52     return; // does not have load_* fields, cannot proceed
     53   if (hdr->load_addr > hdr->header_addr)
     54     return; // invalid;
     55   if (hdr->load_end_addr < hdr->load_addr)
     56     return; // no idea how much to load
     57 
     58   readseg((uchar*) hdr->load_addr,
     59     (hdr->load_end_addr - hdr->load_addr),
     60     (n * 4) - (hdr->header_addr - hdr->load_addr));
     61 
     62   if (hdr->bss_end_addr > hdr->load_end_addr)
     63     stosb((void*) hdr->load_end_addr, 0,
     64       hdr->bss_end_addr - hdr->load_end_addr);
     65 
     66   // Call the entry point from the multiboot header.
     67   // Does not return!
     68   entry = (void(*)(void))(hdr->entry_addr);
     69   entry();
     70 }
     71 
     72 void
     73 waitdisk(void)
     74 {
     75   // Wait for disk ready.
     76   while((inb(0x1F7) & 0xC0) != 0x40)
     77     ;
     78 }
     79 
     80 // Read a single sector at offset into dst.
     81 void
     82 readsect(void *dst, uint offset)
     83 {
     84   // Issue command.
     85   waitdisk();
     86   outb(0x1F2, 1);   // count = 1
     87   outb(0x1F3, offset);
     88   outb(0x1F4, offset >> 8);
     89   outb(0x1F5, offset >> 16);
     90   outb(0x1F6, (offset >> 24) | 0xE0);
     91   outb(0x1F7, 0x20);  // cmd 0x20 - read sectors
     92 
     93   // Read data.
     94   waitdisk();
     95   insl(0x1F0, dst, SECTSIZE/4);
     96 }
     97 
     98 // Read 'count' bytes at 'offset' from kernel into physical address 'pa'.
     99 // Might copy more than asked.
    100 void
    101 readseg(uchar* pa, uint count, uint offset)
    102 {
    103   uchar* epa;
    104 
    105   epa = pa + count;
    106 
    107   // Round down to sector boundary.
    108   pa -= offset % SECTSIZE;
    109 
    110   // Translate from bytes to sectors; kernel starts at sector 1.
    111   offset = (offset / SECTSIZE) + 1;
    112 
    113   // If this is too slow, we could read lots of sectors at a time.
    114   // We'd write more to memory than asked, but it doesn't matter --
    115   // we load in increasing order.
    116   for(; pa < epa; pa += SECTSIZE, offset++)
    117     readsect(pa, offset);
    118 }