github.com/icexin/eggos@v0.4.2-0.20220216025428-78b167e4f349/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  }