xref: /xv6-public/bootmain.c (revision 0cfc7290)
1f5527388Srsc // This a dirt simple boot loader, whose sole job is to boot
2f5527388Srsc // an elf kernel image from the first IDE hard disk.
3f5527388Srsc //
4f5527388Srsc // DISK LAYOUT
5f5527388Srsc //  * This program(boot.S and main.c) is the bootloader.  It should
6f5527388Srsc //    be stored in the first sector of the disk.
7f5527388Srsc //
8f5527388Srsc //  * The 2nd sector onward holds the kernel image.
9f5527388Srsc //
10f5527388Srsc //  * The kernel image must be in ELF format.
11f5527388Srsc //
12f5527388Srsc // BOOT UP STEPS
13f5527388Srsc //  * when the CPU boots it loads the BIOS into memory and executes it
14f5527388Srsc //
15f5527388Srsc //  * the BIOS intializes devices, sets of the interrupt routines, and
16f5527388Srsc //    reads the first sector of the boot device(e.g., hard-drive)
17f5527388Srsc //    into memory and jumps to it.
18f5527388Srsc //
19f5527388Srsc //  * Assuming this boot loader is stored in the first sector of the
20f5527388Srsc //    hard-drive, this code takes over...
21f5527388Srsc //
22f5527388Srsc //  * control starts in bootloader.S -- which sets up protected mode,
23f5527388Srsc //    and a stack so C code then run, then calls cmain()
24f5527388Srsc //
25*0cfc7290Srsc //  * cmain() in this file takes over,
26*0cfc7290Srsc //    reads in the kernel and jumps to it.
27*0cfc7290Srsc 
28*0cfc7290Srsc #include "types.h"
29*0cfc7290Srsc #include "elf.h"
30*0cfc7290Srsc #include "x86.h"
3155e95b16Srtm 
3255e95b16Srtm #define SECTSIZE  512
33b5f17007Srsc #define ELFHDR    ((struct elfhdr*) 0x10000) // scratch space
3455e95b16Srtm 
3529270816Srtm void readsect(void*, uint);
3629270816Srtm void readseg(uint, uint, uint);
3755e95b16Srtm 
3855e95b16Srtm void
3955e95b16Srtm cmain(void)
4055e95b16Srtm {
41b5f17007Srsc   struct proghdr *ph, *eph;
4255e95b16Srtm 
4355e95b16Srtm   // read 1st page off disk
4429270816Srtm   readseg((uint) ELFHDR, SECTSIZE*8, 0);
4555e95b16Srtm 
4655e95b16Srtm   // is this a valid ELF?
47ef2bd07aSrsc   if(ELFHDR->magic != ELF_MAGIC)
4855e95b16Srtm     goto bad;
4955e95b16Srtm 
5055e95b16Srtm   // load each program segment (ignores ph flags)
5129270816Srtm   ph = (struct proghdr*) ((uchar*) ELFHDR + ELFHDR->phoff);
52ef2bd07aSrsc   eph = ph + ELFHDR->phnum;
5355e95b16Srtm   for(; ph < eph; ph++)
54ef2bd07aSrsc     readseg(ph->va, ph->memsz, ph->offset);
5555e95b16Srtm 
5655e95b16Srtm   // call the entry point from the ELF header
5755e95b16Srtm   // note: does not return!
58ef2bd07aSrsc   ((void(*)(void)) (ELFHDR->entry & 0xFFFFFF))();
5955e95b16Srtm 
6055e95b16Srtm bad:
6155e95b16Srtm   outw(0x8A00, 0x8A00);
6255e95b16Srtm   outw(0x8A00, 0x8E00);
63db8fb62eSrsc   for(;;)
64f5527388Srsc     ;
6555e95b16Srtm }
6655e95b16Srtm 
6755e95b16Srtm // Read 'count' bytes at 'offset' from kernel into virtual address 'va'.
6855e95b16Srtm // Might copy more than asked
6955e95b16Srtm void
7029270816Srtm readseg(uint va, uint count, uint offset)
7155e95b16Srtm {
7229270816Srtm   uint end_va;
7355e95b16Srtm 
7455e95b16Srtm   va &= 0xFFFFFF;
7555e95b16Srtm   end_va = va + count;
7655e95b16Srtm 
7755e95b16Srtm   // round down to sector boundary
7855e95b16Srtm   va &= ~(SECTSIZE - 1);
7955e95b16Srtm 
8055e95b16Srtm   // translate from bytes to sectors, and kernel starts at sector 1
8155e95b16Srtm   offset = (offset / SECTSIZE) + 1;
8255e95b16Srtm 
8355e95b16Srtm   // If this is too slow, we could read lots of sectors at a time.
8455e95b16Srtm   // We'd write more to memory than asked, but it doesn't matter --
8555e95b16Srtm   // we load in increasing order.
8655e95b16Srtm   while(va < end_va) {
8729270816Srtm     readsect((uchar*) va, offset);
8855e95b16Srtm     va += SECTSIZE;
8955e95b16Srtm     offset++;
9055e95b16Srtm   }
9155e95b16Srtm }
9255e95b16Srtm 
9355e95b16Srtm void
9455e95b16Srtm waitdisk(void)
9555e95b16Srtm {
9655e95b16Srtm   // wait for disk reaady
9755e95b16Srtm   while((inb(0x1F7) & 0xC0) != 0x40)
98f5527388Srsc     ;
9955e95b16Srtm }
10055e95b16Srtm 
10155e95b16Srtm void
10229270816Srtm readsect(void *dst, uint offset)
10355e95b16Srtm {
10455e95b16Srtm   // wait for disk to be ready
10555e95b16Srtm   waitdisk();
10655e95b16Srtm 
10755e95b16Srtm   outb(0x1F2, 1);   // count = 1
10855e95b16Srtm   outb(0x1F3, offset);
10955e95b16Srtm   outb(0x1F4, offset >> 8);
11055e95b16Srtm   outb(0x1F5, offset >> 16);
11155e95b16Srtm   outb(0x1F6, (offset >> 24) | 0xE0);
11255e95b16Srtm   outb(0x1F7, 0x20);  // cmd 0x20 - read sectors
11355e95b16Srtm 
11455e95b16Srtm   // wait for disk to be ready
11555e95b16Srtm   waitdisk();
11655e95b16Srtm 
11755e95b16Srtm   // read a sector
11855e95b16Srtm   insl(0x1F0, dst, SECTSIZE/4);
11955e95b16Srtm }
12055e95b16Srtm 
121