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