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