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