xref: /xv6-public/bootmain.c (revision 97ac612f)
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 //
1520365348Srtm //  * the BIOS intializes devices, sets up 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 //
250cfc7290Srsc //  * cmain() in this file takes over,
260cfc7290Srsc //    reads in the kernel and jumps to it.
270cfc7290Srsc 
28eaea18cbSrsc //PAGEBREAK!
290cfc7290Srsc #include "types.h"
300cfc7290Srsc #include "elf.h"
310cfc7290Srsc #include "x86.h"
3255e95b16Srtm 
3355e95b16Srtm #define SECTSIZE  512
3455e95b16Srtm 
3529270816Srtm void readseg(uint, uint, uint);
3655e95b16Srtm 
3755e95b16Srtm void
3855e95b16Srtm cmain(void)
3955e95b16Srtm {
40*97ac612fSrsc   struct elfhdr *elf;
41b5f17007Srsc   struct proghdr *ph, *eph;
42*97ac612fSrsc   void (*entry)(void);
4355e95b16Srtm 
44*97ac612fSrsc   elf = (struct elfhdr*)0x10000;  // scratch space
4555e95b16Srtm 
46*97ac612fSrsc   // Read 1st page off disk
47*97ac612fSrsc   readseg((uint)elf, SECTSIZE*8, 0);
48*97ac612fSrsc 
49*97ac612fSrsc   // Is this an ELF executable?
50*97ac612fSrsc   if(elf->magic != ELF_MAGIC)
5155e95b16Srtm     goto bad;
5255e95b16Srtm 
53*97ac612fSrsc   // Load each program segment (ignores ph flags).
54*97ac612fSrsc   ph = (struct proghdr*)((uchar*)elf + elf->phoff);
55*97ac612fSrsc   eph = ph + elf->phnum;
5655e95b16Srtm   for(; ph < eph; ph++)
57ef2bd07aSrsc     readseg(ph->va, ph->memsz, ph->offset);
5855e95b16Srtm 
59*97ac612fSrsc   // Call the entry point from the ELF header.
60*97ac612fSrsc   // Does not return!
61*97ac612fSrsc   entry = (void(*)(void))(elf->entry & 0xFFFFFF);
62*97ac612fSrsc   entry();
6355e95b16Srtm 
6455e95b16Srtm bad:
6555e95b16Srtm   outw(0x8A00, 0x8A00);
6655e95b16Srtm   outw(0x8A00, 0x8E00);
67db8fb62eSrsc   for(;;)
68f5527388Srsc     ;
6955e95b16Srtm }
7055e95b16Srtm 
71eaea18cbSrsc void
72eaea18cbSrsc waitdisk(void)
73eaea18cbSrsc {
74*97ac612fSrsc   // Wait for disk ready.
75eaea18cbSrsc   while((inb(0x1F7) & 0xC0) != 0x40)
76eaea18cbSrsc     ;
77eaea18cbSrsc }
78eaea18cbSrsc 
79eaea18cbSrsc // Read a single sector at offset into dst.
80eaea18cbSrsc void
81eaea18cbSrsc readsect(void *dst, uint offset)
82eaea18cbSrsc {
83*97ac612fSrsc   // Issue command.
84eaea18cbSrsc   waitdisk();
85eaea18cbSrsc   outb(0x1F2, 1);   // count = 1
86eaea18cbSrsc   outb(0x1F3, offset);
87eaea18cbSrsc   outb(0x1F4, offset >> 8);
88eaea18cbSrsc   outb(0x1F5, offset >> 16);
89eaea18cbSrsc   outb(0x1F6, (offset >> 24) | 0xE0);
90eaea18cbSrsc   outb(0x1F7, 0x20);  // cmd 0x20 - read sectors
91eaea18cbSrsc 
92*97ac612fSrsc   // Read data.
93eaea18cbSrsc   waitdisk();
94eaea18cbSrsc   insl(0x1F0, dst, SECTSIZE/4);
95eaea18cbSrsc }
96eaea18cbSrsc 
9755e95b16Srtm // Read 'count' bytes at 'offset' from kernel into virtual address 'va'.
98eaea18cbSrsc // Might copy more than asked.
9955e95b16Srtm void
10029270816Srtm readseg(uint va, uint count, uint offset)
10155e95b16Srtm {
102*97ac612fSrsc   uint eva;
10355e95b16Srtm 
10455e95b16Srtm   va &= 0xFFFFFF;
105*97ac612fSrsc   eva = va + count;
10655e95b16Srtm 
107*97ac612fSrsc   // Round down to sector boundary.
10855e95b16Srtm   va &= ~(SECTSIZE - 1);
10955e95b16Srtm 
110*97ac612fSrsc   // Translate from bytes to sectors; kernel starts at sector 1.
11155e95b16Srtm   offset = (offset / SECTSIZE) + 1;
11255e95b16Srtm 
11355e95b16Srtm   // If this is too slow, we could read lots of sectors at a time.
11455e95b16Srtm   // We'd write more to memory than asked, but it doesn't matter --
11555e95b16Srtm   // we load in increasing order.
116*97ac612fSrsc   for(; va < eva; va += SECTSIZE, offset++)
11729270816Srtm     readsect((uchar*)va, offset);
11855e95b16Srtm }
119