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