github.com/jspc/eggos@v0.5.1-0.20221028160421-556c75c878a5/boot/multiboot.c (about) 1 // According to the multiboot specification, 2 // the multiboot header must appear in the first 8192 bytes of the kernel image, 3 // and the go image is often megabytes in size. 4 // 5 // Therefore, we first write the elf loader in C language, 6 // and then load the kernel image in go language. 7 // 8 // https://www.gnu.org/software/grub/manual/multiboot/multiboot.html#OS-image-format 9 10 typedef unsigned char uint8; 11 typedef unsigned short uint16; 12 typedef unsigned int uint32; 13 typedef unsigned long long uint64; 14 15 #include "elf.h" 16 #include "multiboot.h" 17 18 extern char _binary_boot64_elf_start[]; 19 20 void memcpy(char *dst, char *src, int count); 21 void memset(char *addr, char data, int cnt); 22 uint64 loadelf(char *image); 23 uint64 loadKernelElf(multiboot_info_t *info); 24 typedef void (*boot64_entry_t)(uint32, uint32, uint32); 25 26 void multibootmain(unsigned long magic, multiboot_info_t *mbi) 27 { 28 uint64 entry_addr = 0; 29 boot64_entry_t boot64_entry; 30 31 entry_addr = loadelf(_binary_boot64_elf_start); 32 if (entry_addr == 0) 33 { 34 return; 35 } 36 boot64_entry = (boot64_entry_t)((uint32)entry_addr); 37 38 entry_addr = loadKernelElf(mbi); 39 if (entry_addr == 0) 40 { 41 return; 42 } 43 boot64_entry((uint32)entry_addr, (uint32)magic, (uint32)mbi); 44 } 45 46 uint64 loadelf(char *image) 47 { 48 struct elfhdr *elf; 49 struct proghdr *ph, *eph; 50 char *pa; 51 52 elf = (struct elfhdr *)(image); 53 54 // Is this an ELF executable? 55 if (elf->magic != ELF_MAGIC) 56 return 0; 57 58 // Load each program segment (ignores ph flags). 59 ph = (struct proghdr *)((uint8 *)elf + elf->phoff); 60 eph = ph + elf->phnum; 61 for (; ph < eph; ph++) 62 { 63 pa = (char *)(uint32)(ph->paddr); 64 memcpy(pa, image + ph->off, ph->filesz); 65 if (ph->memsz > ph->filesz) 66 { 67 memset((char *)(pa + ph->filesz), 0, ph->memsz - ph->filesz); 68 } 69 } 70 return elf->entry; 71 } 72 73 uint64 loadKernelElf(multiboot_info_t *info) 74 { 75 if (info->mods_count < 1) 76 { 77 return 0; 78 } 79 multiboot_module_t *mod = (multiboot_module_t *)(info->mods_addr); 80 char *new_addr = (char *)(100 << 20); // 100 MB 81 memcpy(new_addr, (char *)(mod->mod_start), mod->mod_end - mod->mod_start + 1); 82 return loadelf(new_addr); 83 } 84 85 void memcpy(char *dst, char *src, int count) 86 { 87 int i = 0; 88 for (; i < count; i++) 89 { 90 *dst++ = *src++; 91 } 92 } 93 94 void memset(char *addr, char data, int count) 95 { 96 int i = 0; 97 for (; i < count; i++) 98 { 99 *addr++ = data; 100 } 101 }