* more re-work
[mascara-docs.git] / i386 / junos / standford / 2004 / src / lab2 / boot / main.c
blobbdad3fe9302510ad4ab1b3476f7a9f42edc3c855
2 #include <inc/x86.h>
3 #include <inc/elf.h>
5 /**********************************************************************
6 * This a dirt simple boot loader, whose sole job is to boot
7 * an elf kernel image from the first IDE hard disk.
9 * DISK LAYOUT
10 * * This program(boot.S and main.c) is the bootloader. It should
11 * be stored in the first sector of the disk.
13 * * The 2nd sector onward holds the kernel image.
15 * * The kernel image must be in ELF format.
17 * BOOT UP STEPS
18 * * when the CPU boots it loads the BIOS into memory and executes it
20 * * the BIOS intializes devices, sets of the interrupt routines, and
21 * reads the first sector of the boot device(e.g., hard-drive)
22 * into memory and jumps to it.
24 * * Assuming this boot loader is stored in the first sector of the
25 * hard-drive, this code takes over...
27 * * control starts in bootloader.S -- which sets up protected mode,
28 * and a stack so C code then run, then calls cmain()
30 * * cmain() in this file takes over, reads in the kernel and jumps to it.
31 **********************************************************************/
33 #define SECTOR_SIZE 512
35 static u_char *sect = (u_char*)0x10000; // scratch space
37 void readsect(u_char*, u_int, u_int);
38 void readseg(u_int, u_int, u_int);
40 void
41 cmain(void)
43 u_int entry, i;
44 struct Elf *elf;
45 struct Proghdr *ph;
47 // read 1st page off disk
48 readsect(sect, 8, 1);
50 if(*(u_int*)sect != 0x464C457F) // \x7F ELF in little endian
51 goto bad;
53 // look at ELF header - ignores ph flags
54 elf = (struct Elf*)sect;
55 entry = elf->e_entry;
56 ph = (struct Proghdr*)(sect+elf->e_phoff);
57 for(i=0; i<elf->e_phnum; i++, ph++)
58 readseg(ph->p_va, ph->p_memsz, ph->p_offset);
60 entry &= 0xFFFFFF;
61 ((void(*)(void))entry)();
62 /* DOES NOT RETURN */
64 bad:
65 outw(0x8A00, 0x8A00);
66 outw(0x8A00, 0x8E00);
67 for(;;);
71 // read count bytes at offset from kernel into addr dst
72 // might copy more than asked
73 void
74 readseg(u_int va, u_int count, u_int offset)
76 u_int i;
78 va &= 0xFFFFFF;
80 // round down to sector boundary; offset will round later
81 i = va&511;
82 count += i;
83 va -= i;
85 // translate from bytes to sectors
86 offset /= 512;
87 count = (count+511)/512;
89 // kernel starts at sector 1
90 offset++;
92 // if this is too slow, we could read lots of sectors at a time.
93 // we'd write more to memory than asked, but it doesn't matter --
94 // we load in increasing order.
95 for(i=0; i<count; i++){
96 readsect((u_char*)va, 1, offset+i);
97 va += 512;
101 void
102 notbusy(void)
104 while(inb(0x1F7) & 0x80); // wait for disk not busy
107 void
108 readsect(u_char *dst, u_int count, u_int offset)
110 notbusy();
112 outb(0x1F2, count);
113 outb(0x1F3, offset);
114 outb(0x1F4, offset>>8);
115 outb(0x1F5, offset>>16);
116 outb(0x1F6, (offset>>24)|0xE0);
117 outb(0x1F7, 0x20); // cmd 0x20 - read sectors
119 notbusy();
121 insl(0x1F0, dst, count*512/4);