1// Simple boot-loader. 2// 3// This code is only intended for use on M5 where it is started via 4// molly_boot.S which runs on Core 0. The simulator starts Core 0 5// in 64-bit mode already, so typical initialization code is not 6// needed. 7 8#include <assert.h> 9#include <stdio.h> 10#include <stdint.h> 11#include <stddef.h> 12#include <string.h> 13#include <barrelfish_kpi/types.h> 14#include <errors/errno.h> 15#include <elf/elf.h> 16#include <multiboot.h> 17 18// Prototypes for functions from molly_boot.S: 19extern void molly_to_kernel_transition(void *entry_addr, 20 uint64_t RAX, 21 uint64_t RBX); 22 23// Prototypes for functions from m5_kernel.c: 24extern struct multiboot_info *molly_get_mbi(void); 25//struct multiboot_info *molly_get_mbi(void) { return NULL; } 26 27// Prototypes for symbols declared via linker script: 28extern void *_start_img; 29extern void *_end_img; 30 31//...................................................................... 32// 33// Basic debugging output functions. These assume M5 with the serial 34// port already initialized, and with flow control unnecessary. 35 36static inline void outb(int port, char data) 37{ 38 __asm __volatile("outb %0,%%dx" : : "a" (data), "d" (port)); 39} 40 41static int serial_portbase = 0x3f8; // COM1 42 43static void serial_putchar(char c) 44{ 45 outb(serial_portbase, c); 46} 47 48static void putstr(const char *cp) { 49 char c; 50 while ((c=*(cp++))) { 51 serial_putchar(c); 52 } 53} 54 55static const char hexdigits[] = "0123456789abcdef"; 56 57static void puthex64(unsigned long long x) { 58 putstr("0x"); 59 unsigned long long mask = 0xf000000000000000; 60 int s = 60; 61 do { 62 unsigned int idx = (x & mask) >> s; 63 serial_putchar(hexdigits[idx]); 64 s -= 4; 65 mask >>= 4; 66 } while (s >= 0); 67} 68 69static void puthex32(uint32_t x) { 70 putstr("0x"); 71 uint32_t mask = 0xf0000000; 72 int s = 28; 73 do { 74 unsigned int idx = (x & mask) >> s; 75 serial_putchar(hexdigits[idx]); 76 s -= 4; 77 mask >>= 4; 78 } while (s >= 0); 79} 80 81static void puthex8(uint32_t x) { 82 uint32_t mask = 0xf0; 83 int s = 4; 84 do { 85 unsigned int idx = (x & mask) >> s; 86 serial_putchar(hexdigits[idx]); 87 s -= 4; 88 mask >>= 4; 89 } while (s >= 0); 90} 91 92static void putptr64(void *ptr) { 93 puthex64((unsigned long long)ptr); 94} 95 96static void putstrptr64(char *str, void *ptr) { 97 putstr(str); 98 putptr64(ptr); 99 putstr("\n"); 100} 101 102 103//...................................................................... 104// 105// Basic libc functionality needed 106 107void __assert(const char *exp, const char *file, const char *func, int line) 108{ 109 putstr("Assertion failure: "); 110 putstr(exp); 111 putstr(" "); 112 putstr(file); 113 putstr(" "); 114 putstr(func); 115 putstr(" "); 116 puthex32(line); 117 putstr("\n"); 118 while(1){} 119} 120 121int printf(const char *fmt, ...) 122{ 123 putstr(fmt); 124} 125 126void * 127memset (void *s, int c, size_t n) 128{ 129 uint8_t *p = (uint8_t *)s; 130 for (size_t m = 0; m < n; m++) { 131 *p++ = c; 132 } 133 return s; 134} 135 136void * 137memcpy(void *dst, const void *src, size_t len) 138{ 139 char *d = dst; 140 const char *s = src; 141 142 /* check that we don't overlap (should use memmove()) */ 143 assert((src < dst && src + len <= dst) || (dst < src && dst + len <= src)); 144 145 while (len--) 146 *d++ = *s++; 147 148 return dst; 149} 150 151char * 152strrchr(const char *s, int c) 153{ 154 unsigned int i; 155 156 if(strlen(s) == 0) 157 return NULL; 158 159 for(i = strlen(s) - 1; i >= 0; i--) { 160 if(s[i] == c) 161 return (char *)&s[i]; 162 } 163 164 return NULL; 165} 166 167int 168strncmp(const char *s1, const char *s2, size_t n) 169{ 170 int result; 171 172 for(unsigned int i = 0; i < n; i++) { 173 if((result = s2[i] - s1[i]) != 0) { 174 return result; 175 } 176 177 if(s1[i] == '\0' || s2[i] == '\0') { 178 break; 179 } 180 } 181 182 return 0; 183} 184 185size_t 186strlen(const char *s) 187{ 188 size_t i = 0; 189 190 while (*s != '\0') { 191 i++; 192 s++; 193 } 194 195 return i; 196} 197 198int 199strcmp(const char* a, const char* b) 200{ 201 while (*a == *b && *a != '\0') 202 { 203 a++; 204 b++; 205 } 206 207 return *a - *b; 208} 209 210//...................................................................... 211// 212// Allocation function used from the ELF loader 213 214#define BASE_PAGE_SIZE 4096 215 216// Round up n to the next multiple of size 217#define ROUND_UP(n, size) ((((n) + (size) - 1)) & (~((size) - 1))) 218 219static uint64_t next_addr; 220 221static errval_t linear_alloc(void *s, 222 genvaddr_t base, 223 size_t size, 224 uint32_t flags, 225 void **ret) 226{ 227 // round to base page size 228 uint32_t npages = (size + BASE_PAGE_SIZE - 1) / BASE_PAGE_SIZE; 229 230 /* *ret = (void *)(uintptr_t)base; */ 231 *ret = (void *)next_addr; 232 233 next_addr += npages * BASE_PAGE_SIZE; 234 return SYS_ERR_OK; 235} 236 237// Helper function to check that addresses assumed to be 32-bit do not 238// have high bits set. 239 240static uint32_t ptr_to_uint32(void *ptr) { 241 uint64_t temp = (uint64_t)ptr; 242 assert(temp < 0x7fffffff); 243 return (uint32_t) temp; 244} 245 246// C code entered from molly_boot.S: 247 248void molly_init(void) { 249 putstr("......................................................................\n"); 250 putstr("molly_init:\n"); 251 putstrptr64(" boot image start : ", &_start_img); 252 putstrptr64(" boot image end : ", &_end_img); 253 254 struct multiboot_info *mbi = molly_get_mbi(); 255 putstrptr64(" multiboot info : ", mbi); 256 257 // Start allocating from one page beyond the boot image: 258 next_addr = (ROUND_UP((uint64_t) &_end_img, BASE_PAGE_SIZE) + 259 BASE_PAGE_SIZE); 260 putstrptr64(" allocating from : ", (void*)next_addr); 261 262 // Load the kernel out from the boot image: 263 struct multiboot_modinfo *mbi_mods; 264 mbi_mods = (struct multiboot_modinfo*)(uint64_t)(mbi->mods_addr); 265 void *kernel = (void*)(uint64_t)(mbi_mods[0].mod_start); 266 uint32_t kernel_bytes = mbi_mods[0].mod_end - mbi_mods[0].mod_start; 267 putstrptr64(" kernel start : ", kernel); 268 putstrptr64(" kernel bytes : ", (void*)(uint64_t)kernel_bytes); 269 270 void *kernel_entry = NULL; 271 lpaddr_t kernel_start = next_addr; 272 genvaddr_t tls_base = 0; 273 size_t tls_init_len = 0; 274 size_t tls_total_len = 0; 275 errval_t err = elf64_load(EM_X86_64, 276 linear_alloc, NULL, 277 (uint64_t) kernel, kernel_bytes, 278 (genvaddr_t *) &kernel_entry, 279 &tls_base, 280 &tls_init_len, 281 &tls_total_len); 282 if (err_is_fail(err)) { 283 putstr("Kernel loading failed\n"); 284 return; 285 } 286 putstrptr64(" kernel entry pt : ", kernel_entry); 287 288 // Relocate kernel image 289 struct Elf64_Ehdr *cpu_head = (struct Elf64_Ehdr *)kernel; 290 struct Elf64_Shdr *rela, *symtab, *symhead = 291 (struct Elf64_Shdr *)(kernel + (uintptr_t)cpu_head->e_shoff); 292 genvaddr_t elfbase = elf_virtual_base64(cpu_head); 293 rela = elf64_find_section_header_type(symhead, 294 cpu_head->e_shnum, 295 SHT_RELA); 296 symtab = elf64_find_section_header_type(symhead, 297 cpu_head->e_shnum, 298 SHT_DYNSYM); 299 elf64_relocate(kernel_start, elfbase, 300 (struct Elf64_Rela *)(uintptr_t)(kernel + rela->sh_offset), 301 rela->sh_size, 302 (struct Elf64_Sym *)(uintptr_t)(kernel + symtab->sh_offset), 303 symtab->sh_size, 304 elfbase, (void *)kernel_start); 305 kernel_entry = kernel_entry - elfbase + kernel_start; 306 putstrptr64(" ...relocated to : ", kernel_entry); 307 308 // Initialize multiboot symbol information for the 309 // relocated kernel: 310 mbi->syms.elf.num = cpu_head->e_shnum; 311 mbi->syms.elf.size = cpu_head->e_shentsize; 312 mbi->syms.elf.addr = ptr_to_uint32(kernel) + cpu_head->e_shoff; 313 mbi->syms.elf.shndx = cpu_head->e_shstrndx; 314 315 putstr("......................................................................\n"); 316 317 molly_to_kernel_transition(kernel_entry, 318 MULTIBOOT_INFO_MAGIC, 319 ptr_to_uint32(mbi) 320 ); 321} 322 323