1/** 2 * \file 3 * \brief Elver - Intermediary stage bootloader 4 * 5 * Elver is used to switch the system into 64-bit long-mode and load 6 * the kernel, which is a relocatable ELF64 image. Unfortunately, GRUB 7 * is not able to this without a patch. This is purely for 8 * backwards-compatibility. As soon as bootloaders support loading 9 * relocatable ELF64 images into 64-bit mode, this can be dropped. 10 */ 11 12/* 13 * Copyright (c) 2007, 2008, 2009, 2010, ETH Zurich. 14 * All rights reserved. 15 * 16 * This file is distributed under the terms in the attached LICENSE file. 17 * If you do not find this file, copies can be found by writing to: 18 * ETH Zurich D-INFK, Universitaetstrasse 6, CH-8092 Zurich. Attn: Systems Group. 19 */ 20 21#include <stdio.h> 22#include <stdint.h> 23#include <stddef.h> 24#include <string.h> 25#include <barrelfish_kpi/types.h> 26#include <errors/errno.h> 27#include <elf/elf.h> 28#include <multiboot.h> 29 30#include <xeon_phi/xeon_phi.h> 31 32/* the boot magic */ 33#define K1OM_BOOT_MAGIC 0xB001B001 34 35/* the address of the Xeon Phi SBOX registers used for status prints*/ 36#define SBOX_BASE 0x08007D0000ULL 37 38/* reference to the end of bootloader */ 39extern char _end_bootloader; 40 41/// Round up n to the next multiple of size 42#define ROUND_UP(n, size) ((((n) + (size) - 1)) & (~((size) - 1))) 43#define MAX(x,y) ((x)>(y) ? (x) : (y)) 44#define BASE_PAGE_SIZE 0x1000 45 46/* Pointer to the multiboot struct we use */ 47struct multiboot_info *multiboot_info; 48 49/* Address where we can safely allocate memory */ 50static lpaddr_t phys_alloc_start; 51 52/* the entry address of the loaded kernel */ 53genvaddr_t kernel_entry; 54 55/** 56 * C level entry point for the boot loader 57 * 58 * \param magic this field must hold the value K1OM_BOOT_MAGIC 59 * \param mb pointer to the boot_params struct setup by the boot loader 60 */ 61int 62loader(uint64_t magic, 63 struct xeon_phi_boot_params *bp); 64 65/* 66 * ---------------------------------------------------------------------------- 67 * Basic Error Reporting Mechanism 68 * ---------------------------------------------------------------------------- 69 */ 70union status 71{ 72 uint32_t raw; 73 char vals[4]; 74}; 75 76static void 77print_status(char a, 78 char b) 79{ 80 81 volatile uint32_t *p = (volatile uint32_t *) ((SBOX_BASE) + 0x0000AB40); 82 volatile uint32_t *p2 = (volatile uint32_t *) ((SBOX_BASE) + 0x0000AB5C); 83 84 union status s; 85 86 s.vals[3] = 0x0a; 87 s.vals[2] = b; 88 s.vals[1] = a; 89 s.vals[0] = '>'; 90 91 *p2 = s.raw; 92 *p = 0x7A7A7A7A; 93} 94 95static inline void 96eabort(char a, 97 char b) 98{ 99 print_status(a, b); 100 while (1) 101 ; 102} 103 104static inline void notify_host(void) 105{ 106 volatile uint32_t *p = (volatile uint32_t *) ((SBOX_BASE) + 0xAB28); 107 *p = (*p) | 0x1; 108} 109 110 111/* 112 * ---------------------------------------------------------------------------- 113 * ELF Utility Functions 114 * ---------------------------------------------------------------------------- 115 */ 116 117static errval_t 118linear_alloc(void *s, 119 genvaddr_t base, 120 size_t size, 121 uint32_t flags, 122 void **ret) 123{ 124 // round to base page size 125 uint32_t npages = (size + BASE_PAGE_SIZE - 1) / BASE_PAGE_SIZE; 126 127 *ret = (void *) phys_alloc_start; 128 129 phys_alloc_start += npages * BASE_PAGE_SIZE; 130 return SYS_ERR_OK; 131} 132 133 134static struct multiboot_modinfo * 135multiboot_find_module(const char *basename) 136{ 137 struct multiboot_modinfo *mod; 138 mod = (struct multiboot_modinfo *) (uintptr_t) multiboot_info->mods_addr; 139 140 for (size_t i = 0; i < multiboot_info->mods_count; i++) { 141 const char *modname = strrchr((char *) (uintptr_t) mod[i].string, '/'); 142 143 if (modname == NULL) { 144 modname = (char *) (uintptr_t) mod[i].string; 145 } else { 146 modname++; 147 } 148 149 if (!strncmp(modname, basename, strlen(basename))) { 150 return &mod[i]; 151 } 152 } 153 154 return NULL; 155} 156 157static void 158set_elf_headers(uintptr_t base) 159{ 160 struct Elf64_Ehdr *head = (struct Elf64_Ehdr *) (base); 161 162 multiboot_info->syms.elf.num = head->e_shnum; 163 multiboot_info->syms.elf.size = head->e_shentsize; 164 multiboot_info->syms.elf.addr = base + head->e_shoff; 165 multiboot_info->syms.elf.shndx = head->e_shstrndx; 166} 167 168/* 169 * ---------------------------------------------------------------------------- 170 * Loader 171 * ---------------------------------------------------------------------------- 172 */ 173 174/** 175 * Entry point from boot.S 176 * Long mode, paging and protected mode enabled 177 * 178 * \param magic magic value 179 * \param bootparam pointer to struct boot param 180 * 181 */ 182int 183loader(uint64_t magic, 184 struct xeon_phi_boot_params *bp) 185{ 186 errval_t err; 187 188 print_status('S', '0'); 189 190 if (magic != K1OM_BOOT_MAGIC) { 191 /* wrong value */ 192 eabort('E', '0'); 193 } 194 195 if (((uintptr_t)bp)>>32) { 196 /* 197 * sanity check that the boot params has a value which is less than 4G, 198 * since we store the boot params in a 32bit value 199 */ 200 eabort('E', 'a'); 201 } 202 203 print_status('S', '1'); 204 205 /* 206 * XXX: copying the boot loader information structure around 207 */ 208 209 210 multiboot_info = (struct multiboot_info *)(uint64_t)bp->mbi; 211 212 print_status('S', '2'); 213 214 /* look up the kernel module */ 215 struct multiboot_modinfo *kernel; 216 kernel = multiboot_find_module("cpu"); 217 if (kernel == NULL) { 218 kernel = multiboot_find_module("kernel"); 219 } 220 if (kernel == NULL) { 221 eabort('E', '3'); 222 } 223 224 /* set the start address where we can allocate ram */ 225 phys_alloc_start = ROUND_UP(bp->ramdisk_image + bp->ramdisk_size, 226 BASE_PAGE_SIZE)+BASE_PAGE_SIZE; 227 228 lpaddr_t kernel_start = phys_alloc_start; 229 230 /* overwrite the cmd line with the one supplied by the host */ 231 multiboot_info->cmdline = bp->cmdline_ptr; 232 multiboot_info->flags |= MULTIBOOT_INFO_FLAG_HAS_CMDLINE; 233 234 /* we use the mem_lower and mem_upper for the mulitboot image location */ 235 236 multiboot_info->mem_lower = bp->ramdisk_image; 237 multiboot_info->mem_upper = bp->ramdisk_image+bp->ramdisk_size; 238 multiboot_info->flags |= MULTIBOOT_INFO_FLAG_HAS_MEMINFO; 239 240 241 /* we use the config table to store the pointer to struct boot param */ 242 multiboot_info->config_table = (uint32_t)(uintptr_t)bp; 243 multiboot_info->flags |= MULTIBOOT_INFO_FLAG_HAS_CONFIG; 244 245 if ((bp->xeon_phi_id & 0xFF00) != 0xFF00) { 246 eabort('E', '4'); 247 } 248 249 multiboot_info->xeon_phi_id = (uint8_t)(bp->xeon_phi_id & 0xff); 250 251 252 print_status('S', '3'); 253 254 err = elf64_load(EM_K1OM, linear_alloc, NULL, kernel->mod_start, 255 MULTIBOOT_MODULE_SIZE(*kernel), &kernel_entry, NULL, NULL, 256 NULL); 257 258 if (err_is_fail(err)) { 259 switch(err_no(err)) { 260 case ELF_ERR_FILESZ : 261 eabort('E', '5'); 262 break; 263 case ELF_ERR_HEADER: 264 eabort('E', '6'); 265 break; 266 case ELF_ERR_PROGHDR: 267 eabort('E', '7'); 268 break; 269 case ELF_ERR_ALLOCATE: 270 eabort('E', '8'); 271 break; 272 default: 273 eabort('E', '9'); 274 break; 275 } 276 } 277 278 struct Elf64_Ehdr *cpu_head = (struct Elf64_Ehdr *) (uint64_t) kernel->mod_start; 279 struct Elf64_Shdr *rela, *symtab, *symhead; 280 281 symhead = (struct Elf64_Shdr *) (kernel->mod_start 282 + (uintptr_t) cpu_head->e_shoff); 283 284 genvaddr_t elfbase = elf_virtual_base64(cpu_head); 285 286 rela = elf64_find_section_header_type(symhead, cpu_head->e_shnum, SHT_RELA); 287 288 symtab = elf64_find_section_header_type(symhead, cpu_head->e_shnum, SHT_DYNSYM); 289 290 print_status('S', '4'); 291 292 elf64_relocate( 293 kernel_start, elfbase, 294 (struct Elf64_Rela *) (uintptr_t) (kernel->mod_start + rela->sh_offset), 295 rela->sh_size, 296 (struct Elf64_Sym *) (uintptr_t) (kernel->mod_start + symtab->sh_offset), 297 symtab->sh_size, elfbase, (void *) kernel_start); 298 299 kernel_entry = kernel_entry - elfbase + kernel_start; 300 301 print_status('S', '5'); 302 303 set_elf_headers(kernel->mod_start); 304 305 print_status('S', '6'); 306 307 return kernel_entry; 308 309} 310 311