xref: /xv6-public/bootmain.c (revision b5f17007)
1b53f99d0Srsc #include "types.h"
2b53f99d0Srsc #include "elf.h"
3b53f99d0Srsc #include "x86.h"
455e95b16Srtm 
555e95b16Srtm /**********************************************************************
655e95b16Srtm  * This a dirt simple boot loader, whose sole job is to boot
755e95b16Srtm  * an elf kernel image from the first IDE hard disk.
855e95b16Srtm  *
955e95b16Srtm  * DISK LAYOUT
1055e95b16Srtm  *  * This program(boot.S and main.c) is the bootloader.  It should
1155e95b16Srtm  *    be stored in the first sector of the disk.
1255e95b16Srtm  *
1355e95b16Srtm  *  * The 2nd sector onward holds the kernel image.
1455e95b16Srtm  *
1555e95b16Srtm  *  * The kernel image must be in ELF format.
1655e95b16Srtm  *
1755e95b16Srtm  * BOOT UP STEPS
1855e95b16Srtm  *  * when the CPU boots it loads the BIOS into memory and executes it
1955e95b16Srtm  *
2055e95b16Srtm  *  * the BIOS intializes devices, sets of the interrupt routines, and
2155e95b16Srtm  *    reads the first sector of the boot device(e.g., hard-drive)
2255e95b16Srtm  *    into memory and jumps to it.
2355e95b16Srtm  *
2455e95b16Srtm  *  * Assuming this boot loader is stored in the first sector of the
2555e95b16Srtm  *    hard-drive, this code takes over...
2655e95b16Srtm  *
2755e95b16Srtm  *  * control starts in bootloader.S -- which sets up protected mode,
2855e95b16Srtm  *    and a stack so C code then run, then calls cmain()
2955e95b16Srtm  *
3055e95b16Srtm  *  * cmain() in this file takes over, reads in the kernel and jumps to it.
3155e95b16Srtm  **********************************************************************/
3255e95b16Srtm 
3355e95b16Srtm #define SECTSIZE	512
34*b5f17007Srsc #define ELFHDR		((struct elfhdr *) 0x10000) // scratch space
3555e95b16Srtm 
3655e95b16Srtm void readsect(void*, uint32_t);
3755e95b16Srtm void readseg(uint32_t, uint32_t, uint32_t);
3855e95b16Srtm 
3955e95b16Srtm void
4055e95b16Srtm cmain(void)
4155e95b16Srtm {
42*b5f17007Srsc 	struct proghdr *ph, *eph;
4355e95b16Srtm 
4455e95b16Srtm 	// read 1st page off disk
4555e95b16Srtm 	readseg((uint32_t) ELFHDR, SECTSIZE*8, 0);
4655e95b16Srtm 
4755e95b16Srtm 	// is this a valid ELF?
48ef2bd07aSrsc 	if (ELFHDR->magic != ELF_MAGIC)
4955e95b16Srtm 		goto bad;
5055e95b16Srtm 
5155e95b16Srtm 	// load each program segment (ignores ph flags)
52*b5f17007Srsc 	ph = (struct proghdr *) ((uint8_t *) ELFHDR + ELFHDR->phoff);
53ef2bd07aSrsc 	eph = ph + ELFHDR->phnum;
5455e95b16Srtm 	for (; ph < eph; ph++)
55ef2bd07aSrsc 		readseg(ph->va, ph->memsz, ph->offset);
5655e95b16Srtm 
5755e95b16Srtm 	// call the entry point from the ELF header
5855e95b16Srtm 	// note: does not return!
59ef2bd07aSrsc 	((void (*)(void)) (ELFHDR->entry & 0xFFFFFF))();
6055e95b16Srtm 
6155e95b16Srtm bad:
6255e95b16Srtm 	outw(0x8A00, 0x8A00);
6355e95b16Srtm 	outw(0x8A00, 0x8E00);
6455e95b16Srtm 	while(1)
6555e95b16Srtm 		/* do nothing */;
6655e95b16Srtm }
6755e95b16Srtm 
6855e95b16Srtm // Read 'count' bytes at 'offset' from kernel into virtual address 'va'.
6955e95b16Srtm // Might copy more than asked
7055e95b16Srtm void
7155e95b16Srtm readseg(uint32_t va, uint32_t count, uint32_t offset)
7255e95b16Srtm {
7355e95b16Srtm 	uint32_t end_va;
7455e95b16Srtm 
7555e95b16Srtm 	va &= 0xFFFFFF;
7655e95b16Srtm 	end_va = va + count;
7755e95b16Srtm 
7855e95b16Srtm 	// round down to sector boundary
7955e95b16Srtm 	va &= ~(SECTSIZE - 1);
8055e95b16Srtm 
8155e95b16Srtm 	// translate from bytes to sectors, and kernel starts at sector 1
8255e95b16Srtm 	offset = (offset / SECTSIZE) + 1;
8355e95b16Srtm 
8455e95b16Srtm 	// If this is too slow, we could read lots of sectors at a time.
8555e95b16Srtm 	// We'd write more to memory than asked, but it doesn't matter --
8655e95b16Srtm 	// we load in increasing order.
8755e95b16Srtm 	while (va < end_va) {
8855e95b16Srtm 		readsect((uint8_t*) va, offset);
8955e95b16Srtm 		va += SECTSIZE;
9055e95b16Srtm 		offset++;
9155e95b16Srtm 	}
9255e95b16Srtm }
9355e95b16Srtm 
9455e95b16Srtm void
9555e95b16Srtm waitdisk(void)
9655e95b16Srtm {
9755e95b16Srtm 	// wait for disk reaady
9855e95b16Srtm 	while ((inb(0x1F7) & 0xC0) != 0x40)
9955e95b16Srtm 		/* do nothing */;
10055e95b16Srtm }
10155e95b16Srtm 
10255e95b16Srtm void
10355e95b16Srtm readsect(void *dst, uint32_t offset)
10455e95b16Srtm {
10555e95b16Srtm 	// wait for disk to be ready
10655e95b16Srtm 	waitdisk();
10755e95b16Srtm 
10855e95b16Srtm 	outb(0x1F2, 1);		// count = 1
10955e95b16Srtm 	outb(0x1F3, offset);
11055e95b16Srtm 	outb(0x1F4, offset >> 8);
11155e95b16Srtm 	outb(0x1F5, offset >> 16);
11255e95b16Srtm 	outb(0x1F6, (offset >> 24) | 0xE0);
11355e95b16Srtm 	outb(0x1F7, 0x20);	// cmd 0x20 - read sectors
11455e95b16Srtm 
11555e95b16Srtm 	// wait for disk to be ready
11655e95b16Srtm 	waitdisk();
11755e95b16Srtm 
11855e95b16Srtm 	// read a sector
11955e95b16Srtm 	insl(0x1F0, dst, SECTSIZE/4);
12055e95b16Srtm }
12155e95b16Srtm 
122