xref: /xv6-public/bootmain.c (revision 1a81e38b)
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 an ELF 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 "elf.h"
10 #include "x86.h"
11 
12 #define SECTSIZE  512
13 
14 void readseg(uchar*, uint, uint);
15 
16 void
17 bootmain(void)
18 {
19   struct elfhdr *elf;
20   struct proghdr *ph, *eph;
21   void (*entry)(void);
22   uchar* va;
23 
24   elf = (struct elfhdr*)0x10000;  // scratch space
25 
26   // Read 1st page off disk
27   readseg((uchar*)elf, 4096, 0);
28 
29   // Is this an ELF executable?
30   if(elf->magic != ELF_MAGIC)
31     return;  // let bootasm.S handle error
32 
33   // Load each program segment (ignores ph flags).
34   ph = (struct proghdr*)((uchar*)elf + elf->phoff);
35   eph = ph + elf->phnum;
36   for(; ph < eph; ph++){
37     va = (uchar*)ph->va;
38     readseg(va, ph->filesz, ph->offset);
39     if(ph->memsz > ph->filesz)
40       stosb(va + ph->filesz, 0, ph->memsz - ph->filesz);
41   }
42 
43   // Call the entry point from the ELF header.
44   // Does not return!
45   entry = (void(*)(void))(elf->entry);
46   entry();
47 }
48 
49 void
50 waitdisk(void)
51 {
52   // Wait for disk ready.
53   while((inb(0x1F7) & 0xC0) != 0x40)
54     ;
55 }
56 
57 // Read a single sector at offset into dst.
58 void
59 readsect(void *dst, uint offset)
60 {
61   // Issue command.
62   waitdisk();
63   outb(0x1F2, 1);   // count = 1
64   outb(0x1F3, offset);
65   outb(0x1F4, offset >> 8);
66   outb(0x1F5, offset >> 16);
67   outb(0x1F6, (offset >> 24) | 0xE0);
68   outb(0x1F7, 0x20);  // cmd 0x20 - read sectors
69 
70   // Read data.
71   waitdisk();
72   insl(0x1F0, dst, SECTSIZE/4);
73 }
74 
75 // Read 'count' bytes at 'offset' from kernel into virtual address 'va'.
76 // Might copy more than asked.
77 void
78 readseg(uchar* va, uint count, uint offset)
79 {
80   uchar* eva;
81 
82   eva = va + count;
83 
84   // Round down to sector boundary.
85   va -= offset % SECTSIZE;
86 
87   // Translate from bytes to sectors; kernel starts at sector 1.
88   offset = (offset / SECTSIZE) + 1;
89 
90   // If this is too slow, we could read lots of sectors at a time.
91   // We'd write more to memory than asked, but it doesn't matter --
92   // we load in increasing order.
93   for(; va < eva; va += SECTSIZE, offset++)
94     readsect(va, offset);
95 }
96