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