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