bootmain.c (2719B)
1 // Boot loader. 2 // 3 // Part of the boot sector, along with bootasm.S, which calls bootmain(). 4 // bootasm.S has put the processor into protected 32-bit mode. 5 // bootmain() loads a multiboot kernel image from the disk starting at 6 // sector 1 and then jumps to the kernel entry routine. 7 8 #include "types.h" 9 #include "x86.h" 10 #include "memlayout.h" 11 12 #define SECTSIZE 512 13 14 struct mbheader { 15 uint32 magic; 16 uint32 flags; 17 uint32 checksum; 18 uint32 header_addr; 19 uint32 load_addr; 20 uint32 load_end_addr; 21 uint32 bss_end_addr; 22 uint32 entry_addr; 23 }; 24 25 void readseg(uchar*, uint, uint); 26 27 void 28 bootmain(void) 29 { 30 struct mbheader *hdr; 31 void (*entry)(void); 32 uint32 *x; 33 uint n; 34 35 x = (uint32*) 0x10000; // scratch space 36 37 // multiboot header must be in the first 8192 bytes 38 readseg((uchar*)x, 8192, 0); 39 40 for (n = 0; n < 8192/4; n++) 41 if (x[n] == 0x1BADB002) 42 if ((x[n] + x[n+1] + x[n+2]) == 0) 43 goto found_it; 44 45 // failure 46 return; 47 48 found_it: 49 hdr = (struct mbheader *) (x + n); 50 51 if (!(hdr->flags & 0x10000)) 52 return; // does not have load_* fields, cannot proceed 53 if (hdr->load_addr > hdr->header_addr) 54 return; // invalid; 55 if (hdr->load_end_addr < hdr->load_addr) 56 return; // no idea how much to load 57 58 readseg((uchar*) hdr->load_addr, 59 (hdr->load_end_addr - hdr->load_addr), 60 (n * 4) - (hdr->header_addr - hdr->load_addr)); 61 62 if (hdr->bss_end_addr > hdr->load_end_addr) 63 stosb((void*) hdr->load_end_addr, 0, 64 hdr->bss_end_addr - hdr->load_end_addr); 65 66 // Call the entry point from the multiboot header. 67 // Does not return! 68 entry = (void(*)(void))(hdr->entry_addr); 69 entry(); 70 } 71 72 void 73 waitdisk(void) 74 { 75 // Wait for disk ready. 76 while((inb(0x1F7) & 0xC0) != 0x40) 77 ; 78 } 79 80 // Read a single sector at offset into dst. 81 void 82 readsect(void *dst, uint offset) 83 { 84 // Issue command. 85 waitdisk(); 86 outb(0x1F2, 1); // count = 1 87 outb(0x1F3, offset); 88 outb(0x1F4, offset >> 8); 89 outb(0x1F5, offset >> 16); 90 outb(0x1F6, (offset >> 24) | 0xE0); 91 outb(0x1F7, 0x20); // cmd 0x20 - read sectors 92 93 // Read data. 94 waitdisk(); 95 insl(0x1F0, dst, SECTSIZE/4); 96 } 97 98 // Read 'count' bytes at 'offset' from kernel into physical address 'pa'. 99 // Might copy more than asked. 100 void 101 readseg(uchar* pa, uint count, uint offset) 102 { 103 uchar* epa; 104 105 epa = pa + count; 106 107 // Round down to sector boundary. 108 pa -= offset % SECTSIZE; 109 110 // Translate from bytes to sectors; kernel starts at sector 1. 111 offset = (offset / SECTSIZE) + 1; 112 113 // If this is too slow, we could read lots of sectors at a time. 114 // We'd write more to memory than asked, but it doesn't matter -- 115 // we load in increasing order. 116 for(; pa < epa; pa += SECTSIZE, offset++) 117 readsect(pa, offset); 118 }