1/** 2 * \file 3 * \brief x86_32 kernel bootup code. 4 */ 5 6/* 7 * Copyright (c) 2007-2013 ETH Zurich. 8 * Copyright (c) 2014, HP Labs. 9 * All rights reserved. 10 * 11 * This file is distributed under the terms in the attached LICENSE file. 12 * If you do not find this file, copies can be found by writing to: 13 * ETH Zurich D-INFK, Universitaetstrasse 6, CH-8092 Zurich. Attn: Systems Group. 14 */ 15 16#include <kernel.h> 17#include <string.h> 18#include <paging_kernel_arch.h> 19#include <elf/elf.h> 20#include <kernel_multiboot.h> 21#include <irq.h> 22#include <init.h> 23#include <barrelfish_kpi/cpu.h> 24#include <exec.h> 25#include <getopt/getopt.h> 26#include <dispatch.h> 27#include <barrelfish_kpi/init.h> 28#include <arch/x86/apic.h> 29#include <kputchar.h> 30#include <startup.h> 31#include <barrelfish_kpi/paging_arch.h> 32#include <barrelfish_kpi/syscalls.h> 33#include <target/x86/barrelfish_kpi/coredata_target.h> 34#include <arch/x86/startup_x86.h> 35 36/// Quick way to find the base address of a cnode capability 37#define CNODE(cte) (cte)->cap.u.cnode.cnode 38 39/** 40 * init's needed boot pages. 41 */ 42#define INIT_PDIR_SIZE X86_32_PDIR_ENTRIES(X86_32_INIT_SPACE_LIMIT) 43#define INIT_PTABLE_SIZE X86_32_PTABLE_ENTRIES(X86_32_INIT_SPACE_LIMIT) 44#define INIT_PAGE_BITMAP X86_32_PTABLE_PRESENT 45 46/// Pointer to bootinfo structure for init 47static struct bootinfo *bootinfo = (struct bootinfo *)BOOTINFO_BASE; 48 49static struct spawn_state spawn_state; 50 51#ifdef CONFIG_PAE 52/** 53 * Page directory pointer table for init user address space. 54 */ 55static union x86_32_pdpte_entry *init_pdpte; //[INIT_PDPT_SIZE][PTABLE_SIZE] 56#endif 57 58/** 59 * Page directory for init user address space. 60 */ 61static union x86_32_pdir_entry *init_pdir; //[INIT_PDPT_SIZE][INIT_PDIR_SIZE][PTABLE_SIZE] 62 63/** 64 * Page tables for init user address space. 65 */ 66static union x86_32_ptable_entry *init_ptable; //[INIT_PDPT_SIZE][INIT_PDIR_SIZE][INIT_PTABLE_SIZE][PTABLE_SIZE] 67 68/** 69 * \brief Convert elf flags to page flags 70 * 71 * \param flags ELF64 program segment flags. 72 * 73 * \return page flags. 74 * 75 * Not all combinations may be supported by an architecture 76 */ 77static paging_x86_32_flags_t paging_elf_to_page_flags(uint32_t flags) 78{ 79 paging_x86_32_flags_t pageflags = 0; 80 81 pageflags |= flags & PF_R ? PTABLE_USER_SUPERVISOR : 0; 82 pageflags |= flags & PF_W ? PTABLE_READ_WRITE : 0; 83 pageflags |= flags & PF_X ? 0 : PTABLE_EXECUTE_DISABLE; 84 85 return pageflags; 86} 87 88/** 89 * \brief Map init user-space memory. 90 * 91 * This function maps pages of the init user-space module. It expects 92 * the virtual base address 'vbase' of a program segment of the init executable, 93 * its size 'size' and its ELF64 access control flags. It maps pages 94 * to the sequential area of physical memory, given by 'base'. If you 95 * want to allocate physical memory frames as you go, you better use 96 * startup_alloc_init(). 97 * 98 * \param vbase Virtual base address of program segment. 99 * \param base Physical base address of program segment. 100 * \param size Size of program segment in bytes. 101 * \param flags ELF64 access control flags of program segment. 102 */ 103errval_t startup_map_init(lvaddr_t vbase, lpaddr_t base, size_t size, 104 uint32_t flags) 105{ 106 lvaddr_t vaddr; 107 108 paging_align(&vbase, &base, &size, BASE_PAGE_SIZE); 109 assert(vbase + size < X86_32_INIT_SPACE_LIMIT); 110 111 // Map pages 112 for(vaddr = vbase; vaddr < vbase + size; 113 vaddr += BASE_PAGE_SIZE, base += BASE_PAGE_SIZE) { 114#ifdef CONFIG_PAE 115 union x86_32_ptable_entry *ptable_base = &init_ptable[ 116 + X86_32_PDPTE_BASE(vaddr) * X86_32_PTABLE_SIZE * X86_32_PTABLE_SIZE 117 + X86_32_PDIR_BASE(vaddr) * X86_32_PTABLE_SIZE 118 + X86_32_PTABLE_BASE(vaddr)]; 119 120 debug(SUBSYS_PAGING, "Mapping 4K page: vaddr = 0x%"PRIxLVADDR 121 ", base = 0x%"PRIxLPADDR", PDPTE_BASE = %lu, PDIR_BASE = %lu, " 122 "PTABLE_BASE = %lu -- ", vaddr, base, X86_32_PDPTE_BASE(vaddr), 123 X86_32_PDIR_BASE(vaddr), X86_32_PTABLE_BASE(vaddr)); 124#else 125 union x86_32_ptable_entry *ptable_base = &init_ptable[ 126 X86_32_PDIR_BASE(vaddr) * X86_32_PTABLE_SIZE 127 + X86_32_PTABLE_BASE(vaddr)]; 128 129 debug(SUBSYS_PAGING, "Mapping 4K page: vaddr = 0x%"PRIxLVADDR 130 ", base = 0x%"PRIxLPADDR", " 131 "PDIR_BASE = %"PRIuLPADDR", " 132 "PTABLE_BASE = %"PRIuLPADDR" -- ", vaddr, base, 133 X86_32_PDIR_BASE(vaddr), X86_32_PTABLE_BASE(vaddr)); 134#endif 135 136 if(!X86_32_IS_PRESENT(ptable_base)) { 137 debug(SUBSYS_PAGING, "mapped!\n"); 138 paging_x86_32_map(ptable_base, base, 139 INIT_PAGE_BITMAP | paging_elf_to_page_flags(flags)); 140 } else { 141 debug(SUBSYS_PAGING, "already existing!\n"); 142 } 143 } 144 145 return SYS_ERR_OK; 146} 147 148/// Create physical address range or RAM caps to unused physical memory 149static void create_phys_caps(lpaddr_t init_alloc_addr) 150{ 151 errval_t err; 152 153 // map first meg of RAM, which contains lots of crazy BIOS tables 154 err = create_caps_to_cnode(0, X86_32_START_KERNEL_PHYS, 155 RegionType_PlatformData, &spawn_state, bootinfo); 156 assert(err_is_ok(err)); 157 158 /* Walk multiboot MMAP structure, and create appropriate caps for memory */ 159 char *mmap_addr = MBADDR_ASSTRING(glbl_core_data->mmap_addr); 160 genpaddr_t last_end_addr = 0; 161 162 char *clean_mmap_addr; 163 uint32_t clean_mmap_length; 164 cleanup_bios_regions(mmap_addr, &clean_mmap_addr, &clean_mmap_length); 165 166 167 for(char *m = mmap_addr; m < mmap_addr + glbl_core_data->mmap_length;) { 168 struct multiboot_mmap *mmap = (struct multiboot_mmap * SAFE)TC(m); 169 170 debug(SUBSYS_STARTUP, "MMAP %llx--%llx Type %"PRIu32"\n", 171 mmap->base_addr, mmap->base_addr + mmap->length, 172 mmap->type); 173 174#if 0 175 // XXX: Remove intersecting regions 176 bool skip = false; 177 for(int i = 0; i < bootinfo->regions_length; i++) { 178 struct mem_region *r = &bootinfo->regions[i]; 179 180 // Remove intersecting regions (earlier additions take precedence) 181 if((r->base + (1 << r->bits) >= mmap->base_addr 182 && r->base + (1 << r->bits) <= mmap->base_addr + mmap->length) 183 || (r->base >= mmap->base_addr 184 && r->base <= mmap->base_addr + mmap->length)) { 185 skip = true; 186 break; 187 } 188 } 189 190 if(skip) { 191 continue; 192 } 193#endif 194 195 if (last_end_addr >= init_alloc_addr 196 && mmap->base_addr > last_end_addr) { 197 /* we have a gap between regions. add this as a physaddr range */ 198 debug(SUBSYS_STARTUP, "physical address range %llx--%llx\n", 199 last_end_addr, mmap->base_addr); 200 201 err = create_caps_to_cnode(last_end_addr, 202 mmap->base_addr - last_end_addr, 203 RegionType_PhyAddr, &spawn_state, bootinfo); 204 assert(err_is_ok(err)); 205 } 206 207 if (mmap->type == MULTIBOOT_MEM_TYPE_RAM) { 208 genpaddr_t base_addr = mmap->base_addr; 209 genpaddr_t end_addr = base_addr + mmap->length; 210 211 // only map RAM which is greater than init_alloc_addr 212 if (end_addr > local_phys_to_gen_phys(init_alloc_addr)) { 213 if (base_addr < local_phys_to_gen_phys(init_alloc_addr)) { 214 base_addr = local_phys_to_gen_phys(init_alloc_addr); 215 } 216 217#ifndef CONFIG_PAE 218 if(base_addr >= X86_32_PADDR_SPACE_SIZE) { 219 printk(LOG_NOTE, "skipping RAM [%llx--%llx] out of " 220 "mappable space\n", base_addr, end_addr); 221 last_end_addr = mmap->base_addr + mmap->length; 222 m += mmap->size + 4; 223 continue; 224 } 225 if(end_addr > X86_32_PADDR_SPACE_SIZE) { 226 printk(LOG_NOTE, "shortening RAM [%llx--%llx] to mappable " 227 "space [0--%llx]\n", base_addr, end_addr, 228 X86_32_PADDR_SPACE_LIMIT); 229 end_addr = X86_32_PADDR_SPACE_SIZE; 230 } 231#endif 232 233 // XXX: Do not create ram caps for memory the kernel cannot 234 // address to prevent kernel objects from being created there 235 if(base_addr >= PADDR_SPACE_LIMIT) { 236 last_end_addr = mmap->base_addr + mmap->length; 237 m += mmap->size + 4; 238 continue; 239 } 240 if (end_addr > PADDR_SPACE_LIMIT) { 241 end_addr = PADDR_SPACE_LIMIT; 242 } 243 244 debug(SUBSYS_STARTUP, "RAM %llx--%llx\n", base_addr, end_addr); 245 246 assert(end_addr >= base_addr); 247 err = create_caps_to_cnode(base_addr, end_addr - base_addr, 248 RegionType_Empty, &spawn_state, bootinfo); 249 assert(err_is_ok(err)); 250 } 251 } else if (mmap->base_addr > local_phys_to_gen_phys(init_alloc_addr)) { 252 /* XXX: The multiboot spec just says that mapping types other than 253 * RAM are "reserved", but GRUB always maps the ACPI tables as type 254 * 3, and things like the IOAPIC tend to show up as type 2 or 4, 255 * so we map all these regions as platform data 256 */ 257 debug(SUBSYS_STARTUP, "platform %llx--%llx\n", mmap->base_addr, 258 mmap->base_addr + mmap->length); 259 assert(mmap->base_addr > local_phys_to_gen_phys(init_alloc_addr)); 260 err = create_caps_to_cnode(mmap->base_addr, mmap->length, 261 RegionType_PlatformData, &spawn_state, bootinfo); 262 assert(err_is_ok(err)); 263 } 264 265 last_end_addr = mmap->base_addr + mmap->length; 266 m += mmap->size + 4; 267 } 268 269 // Assert that we have some physical address space 270 assert(last_end_addr != 0); 271 272 if (last_end_addr < X86_32_PADDR_SPACE_SIZE) { 273 /* 274 * FIXME: adding the full range results in too many caps to add 275 * to the cnode (and we can't handle such big caps in user-space 276 * yet anyway) so instead we limit it to something much smaller 277 */ 278 genpaddr_t size = X86_32_PADDR_SPACE_SIZE - last_end_addr; 279 const genpaddr_t phys_region_limit = 1ULL << 32; // PCI implementation limit 280 if (last_end_addr > phys_region_limit) { 281 size = 0; // end of RAM is already too high! 282 } else if (last_end_addr + size > phys_region_limit) { 283 size = phys_region_limit - last_end_addr; 284 } 285 debug(SUBSYS_STARTUP, "end physical address range %llx--%llx\n", 286 last_end_addr, last_end_addr + size); 287 err = create_caps_to_cnode(last_end_addr, size, 288 RegionType_PhyAddr, &spawn_state, bootinfo); 289 assert(err_is_ok(err)); 290 } 291} 292 293#define NEEDED_KERNEL_SPACE \ 294 ((SIZE_KERNEL_IMAGE & 0x1000 ) == SIZE_KERNEL_IMAGE ? \ 295 SIZE_KERNEL_IMAGE : \ 296 (SIZE_KERNEL_IMAGE & 0xfffffffffffff000) + 0x1000) 297 298#define OBJSPERPAGE_CTE (1 << (BASE_PAGE_BITS - OBJBITS_CTE)) 299 300 301static void init_page_tables(struct spawn_state *st, alloc_phys_func alloc_phys) 302{ 303 /* Allocate memory for init's page tables */ 304#ifdef CONFIG_PAE 305 init_pdpte = (void *)local_phys_to_mem(alloc_phys(X86_32_PDPTE_SIZE 306 * sizeof(union x86_32_pdpte_entry))); 307#endif 308 init_pdir = (void *)local_phys_to_mem( 309 alloc_phys(X86_32_PTABLE_SIZE * INIT_PDIR_SIZE 310 * sizeof(union x86_32_pdir_entry))); 311 init_ptable = (void *)local_phys_to_mem( 312 alloc_phys(X86_32_PTABLE_SIZE * INIT_PDIR_SIZE 313 * INIT_PTABLE_SIZE * sizeof(union x86_32_ptable_entry))); 314 315 /* Page table setup */ 316 /* Initialize init page tables */ 317 for(size_t j = 0; j < INIT_PDIR_SIZE; j++) { 318 paging_x86_32_clear_pdir(&init_pdir[j]); 319 for(size_t k = 0; k < INIT_PTABLE_SIZE; k++) { 320 paging_x86_32_clear_ptable(&init_ptable[j * X86_32_PTABLE_SIZE + k]); 321 } 322 } 323 /* Map pagetables into pageCN */ 324 int pagecn_pagemap = 0; 325#ifdef CONFIG_PAE 326 // Map PDPTE into first slot in pagecn 327 caps_create_new(ObjType_VNode_x86_32_pdpt, 328 mem_to_local_phys((lvaddr_t)init_pdpte), 329 BASE_PAGE_BITS, 0, my_core_id, 330 caps_locate_slot(CNODE(st->pagecn), pagecn_pagemap++)); 331#endif 332 // Map PDIR into successive slots in pagecn 333 for(size_t i = 0; i < INIT_PDIR_SIZE; i++) { 334 caps_create_new(ObjType_VNode_x86_32_pdir, 335 mem_to_local_phys((lvaddr_t)init_pdir) + i * BASE_PAGE_SIZE, 336 BASE_PAGE_BITS, 0, my_core_id, 337 caps_locate_slot(CNODE(st->pagecn), pagecn_pagemap++)); 338 } 339 // Map page tables into successive slots in pagecn 340 for(size_t i = 0; i < INIT_PTABLE_SIZE; i++) { 341 caps_create_new(ObjType_VNode_x86_32_ptable, 342 mem_to_local_phys((lvaddr_t)init_ptable) + i * BASE_PAGE_SIZE, 343 BASE_PAGE_BITS, 0, my_core_id, 344 caps_locate_slot(CNODE(st->pagecn), pagecn_pagemap++)); 345 } 346 // Connect all page tables to page directories. 347 // init's memory manager expects page tables within the pagecn to 348 // already be connected to the corresponding directories. To avoid 349 // unneccessary special cases, we connect them here. 350 for(lvaddr_t vaddr = 0; vaddr < X86_32_INIT_SPACE_LIMIT; 351 vaddr += BASE_PAGE_SIZE) { 352#ifdef CONFIG_PAE 353 union x86_32_pdpte_entry *pdpte_base = 354 &init_pdpte[X86_32_PDPTE_BASE(vaddr)]; 355 union x86_32_pdir_entry *pdir_base = 356 &init_pdir[X86_32_PDPTE_BASE(vaddr) * X86_32_PTABLE_SIZE + 357 X86_32_PDIR_BASE(vaddr)]; 358 union x86_32_ptable_entry *ptable_base = 359 &init_ptable[X86_32_PDPTE_BASE(vaddr) * X86_32_PTABLE_SIZE * 360 X86_32_PTABLE_SIZE + X86_32_PDIR_BASE(vaddr) * 361 X86_32_PTABLE_SIZE + X86_32_PTABLE_BASE(vaddr)]; 362 363 paging_x86_32_map_pdpte(pdpte_base, mem_to_local_phys((lvaddr_t)pdir_base)); 364#else 365 union x86_32_pdir_entry *pdir_base = 366 &init_pdir[X86_32_PDIR_BASE(vaddr)]; 367 union x86_32_ptable_entry *ptable_base = 368 &init_ptable[X86_32_PDIR_BASE(vaddr) * X86_32_PTABLE_SIZE + 369 X86_32_PTABLE_BASE(vaddr)]; 370#endif 371 paging_x86_32_map_table(pdir_base, 372 mem_to_local_phys((lvaddr_t)ptable_base)); 373 } 374 375 /* Switch to init's VSpace */ 376#ifdef CONFIG_PAE 377 paging_x86_32_context_switch(mem_to_local_phys((lvaddr_t)init_pdpte)); 378#else 379 paging_x86_32_context_switch(mem_to_local_phys((lvaddr_t)init_pdir)); 380#endif 381 382 /***** VSpace available *****/ 383 384 /* Map cmdline args R/W into VSpace at ARGS_BASE */ 385#ifdef CONFIG_PAE 386 paging_x86_32_map_pdpte(&init_pdpte[X86_32_PDPTE_BASE(ARGS_BASE)], 387 mem_to_local_phys((lvaddr_t)init_pdir)); 388#endif 389 paging_x86_32_map_table(&init_pdir[X86_32_PDIR_BASE(ARGS_BASE)], 390 mem_to_local_phys((lvaddr_t)init_ptable)); 391 for (int i = 0; i < ARGS_SIZE / BASE_PAGE_SIZE; i++) { 392 paging_x86_32_map(&init_ptable[X86_32_PTABLE_BASE(ARGS_BASE) + i], 393 st->args_page + i * BASE_PAGE_SIZE, 394 INIT_PAGE_BITMAP | paging_elf_to_page_flags(PF_R | PF_W)); 395 } 396} 397 398static struct dcb *spawn_init_common(struct spawn_state *st, const char *name, 399 int argc, const char *argv[], 400 lpaddr_t bootinfo_phys, 401 alloc_phys_func alloc_phys, 402 alloc_phys_aligned_func alloc_phys_aligned) 403{ 404 errval_t err; 405 406 /* Perform arch-independent spawn */ 407 lvaddr_t paramaddr; 408 struct dcb *init_dcb = spawn_module(st, name, argc, argv, bootinfo_phys, 409 ARGS_BASE, alloc_phys, alloc_phys_aligned, 410 ¶maddr); 411 412 413 414 /* Init page tables */ 415 init_page_tables(st, alloc_phys); 416 417 /* Map dispatcher R/W into VSpace starting at vaddr 0x204000 418 * (Starting after Bootinfo pages)*/ 419#ifdef CONFIG_PAE 420 paging_x86_32_map_pdpte(&init_pdpte[X86_32_PDPTE_BASE(DISPATCHER_BASE)], 421 mem_to_local_phys((lvaddr_t)init_pdir)); 422#endif 423 paging_x86_32_map_table(&init_pdir[X86_32_PDIR_BASE(DISPATCHER_BASE)], 424 mem_to_local_phys((lvaddr_t)init_ptable)); 425 for (int i = 0; i < DISPATCHER_FRAME_SIZE / BASE_PAGE_SIZE; i++) { 426 paging_x86_32_map(&init_ptable[X86_32_PTABLE_BASE(DISPATCHER_BASE) + i], 427 mem_to_local_phys(init_dcb->disp) + i * BASE_PAGE_SIZE, 428 INIT_PAGE_BITMAP | paging_elf_to_page_flags(PF_R | PF_W)); 429 } 430 431 struct dispatcher_shared_generic *init_disp = 432 get_dispatcher_shared_generic(init_dcb->disp); 433 struct dispatcher_shared_x86_32 *init_disp_x86_32 = 434 get_dispatcher_shared_x86_32(init_dcb->disp); 435 436 registers_set_param(&init_disp_x86_32->enabled_save_area, paramaddr); 437 438 // Map IO cap in task cnode 439 struct cte *iocap = caps_locate_slot(CNODE(st->taskcn), TASKCN_SLOT_IO); 440 err = caps_create_new(ObjType_IO, 0, 0, 0, my_core_id, iocap); 441 assert(err_is_ok(err)); 442 443 /* Set fields in DCB */ 444 // Set Vspace 445#ifdef CONFIG_PAE 446 init_dcb->vspace = mem_to_local_phys((lvaddr_t)init_pdpte); 447#else 448 init_dcb->vspace = mem_to_local_phys((lvaddr_t)init_pdir); 449#endif 450 451 /* Initialize dispatcher */ 452 init_disp->disabled = true; 453 strncpy(init_disp->name, argv[0], DISP_NAME_LEN); 454 455 /* tell init the vspace addr of its dispatcher */ 456 init_disp->udisp = DISPATCHER_BASE; 457 458 init_disp_x86_32->disabled_save_area.edi = DISPATCHER_BASE; 459 init_disp_x86_32->disabled_save_area.fs = 0; 460 init_disp_x86_32->disabled_save_area.gs = 0; 461 init_disp_x86_32->disabled_save_area.cs = USER_CS; 462 init_disp_x86_32->disabled_save_area.ss = USER_SS; 463 init_disp_x86_32->disabled_save_area.eflags = USER_EFLAGS; 464 465 return init_dcb; 466} 467 468struct dcb *spawn_bsp_init(const char *name, alloc_phys_func alloc_phys, 469 alloc_phys_aligned_func alloc_phys_aligned) 470{ 471 errval_t err; 472 473 /* Only the first core can run this code */ 474 assert(apic_is_bsp()); 475 476 /* Allocate bootinfo */ 477 lpaddr_t bootinfo_phys = alloc_phys(BOOTINFO_SIZE); 478 memset((void *)local_phys_to_mem(bootinfo_phys), 0, BOOTINFO_SIZE); 479 480 /* Construct cmdline args */ 481 char bootinfochar[16]; 482 snprintf(bootinfochar, sizeof(bootinfochar), "%"PRIuLPADDR, BOOTINFO_BASE); 483 484 const char *argv[6] = { "init", bootinfochar }; 485 int argc = 2; 486 487 struct dcb *init_dcb = spawn_init_common(&spawn_state, name, argc, argv, 488 bootinfo_phys, alloc_phys, 489 alloc_phys_aligned); 490 491 /* Map bootinfo R/W into VSpace at vaddr 0x200000 (BOOTINFO_BASE) */ 492#ifdef CONFIG_PAE 493 paging_x86_32_map_pdpte(&init_pdpte[0], mem_to_local_phys((lvaddr_t)init_pdir)); 494 paging_x86_32_map_table(&init_pdir[1], mem_to_local_phys((lvaddr_t)init_ptable)); 495 for (int i = 0; i < BOOTINFO_SIZE / BASE_PAGE_SIZE; i++) { 496 paging_x86_32_map(&init_ptable[i], bootinfo_phys + i * BASE_PAGE_SIZE, 497 INIT_PAGE_BITMAP | paging_elf_to_page_flags(PF_R|PF_W)); 498 } 499#else 500 paging_x86_32_map_table(&init_pdir[0], mem_to_local_phys((lvaddr_t)init_ptable)); 501 for (int i = 0; i < BOOTINFO_SIZE / BASE_PAGE_SIZE; i++) { 502 paging_x86_32_map(&init_ptable[i + 512], bootinfo_phys + i * BASE_PAGE_SIZE, 503 INIT_PAGE_BITMAP | paging_elf_to_page_flags(PF_R|PF_W)); 504 } 505#endif 506 507 /* Load init ELF32 binary */ 508 struct multiboot_modinfo *module = multiboot_find_module(name); 509 if (module == NULL) { 510 panic("Could not find init module!"); 511 } 512 genvaddr_t init_ep; 513 err = elf_load(EM_386, startup_alloc_init, &spawn_state, 514 local_phys_to_mem(module->mod_start), 515 MULTIBOOT_MODULE_SIZE(*module), &init_ep); 516 if (err_is_fail(err)) { 517 //err_print_calltrace(err); 518 panic("ELF load of init module failed!"); 519 } 520 521 struct dispatcher_shared_x86_32 *init_disp_x86_32 = 522 get_dispatcher_shared_x86_32(init_dcb->disp); 523 init_disp_x86_32->disabled_save_area.eip = init_ep; 524 525 /* Create caps for init to use */ 526 create_module_caps(&spawn_state); 527 lpaddr_t init_alloc_end = alloc_phys(0); // XXX 528 create_phys_caps(init_alloc_end); 529 530 /* Fill bootinfo struct */ 531 bootinfo->mem_spawn_core = NEEDED_KERNEL_SPACE; // Size of kernel 532 533 /* for (int i = 0; i < bootinfo->regions_length; i++) { */ 534 /* printf("%d region %d: 0x%09" PRIxPTR " - 0x%09lx (%lu MB, %u bits)\n", */ 535 /* bootinfo->regions[i].mr_type, i, bootinfo->regions[i].mr_base, */ 536 /* bootinfo->regions[i].mr_base + (1UL<<bootinfo->regions[i].mr_bits), */ 537 /* bootinfo->regions[i].mr_bits >= 20 */ 538 /* ? 1UL << (bootinfo->regions[i].mr_bits - 20) : 0, */ 539 /* bootinfo->regions[i].mr_bits); */ 540 /* } */ 541 542 return init_dcb; 543} 544 545struct dcb *spawn_app_init(struct x86_core_data *core_data, 546 const char *name, alloc_phys_func alloc_phys, 547 alloc_phys_aligned_func alloc_phys_aligned) 548{ 549 errval_t err; 550 551 /* Construct cmdline args */ 552 // Core id of the core that booted this core 553 char coreidchar[10]; 554 snprintf(coreidchar, sizeof(coreidchar), "%d", core_data->src_core_id); 555 556 // IPI channel id of core that booted this core 557 char chanidchar[30]; 558 snprintf(chanidchar, sizeof(chanidchar), "chanid=%"PRIu32, core_data->chan_id); 559 560 // Arch id of the core that booted this core 561 char archidchar[30]; 562 snprintf(archidchar, sizeof(archidchar), "archid=%d", 563 core_data->src_arch_id); 564 565 const char *argv[5] = { name, coreidchar, chanidchar, archidchar }; 566 int argc = 4; 567 568 struct dcb *init_dcb = spawn_init_common(&spawn_state, name, argc, argv, 569 0, alloc_phys, alloc_phys_aligned); 570 571 // Urpc frame cap 572 struct cte *urpc_frame_cte = caps_locate_slot(CNODE(spawn_state.taskcn), 573 TASKCN_SLOT_MON_URPC); 574 // XXX: Create as devframe so the memory is not zeroed out 575 err = caps_create_new(ObjType_DevFrame, core_data->urpc_frame_base, 576 core_data->urpc_frame_bits, 577 core_data->urpc_frame_bits, core_data->src_core_id, 578 urpc_frame_cte); 579 assert(err_is_ok(err)); 580 urpc_frame_cte->cap.type = ObjType_Frame; 581 lpaddr_t urpc_ptr = gen_phys_to_local_phys(urpc_frame_cte->cap.u.frame.base); 582 583 /* Map urpc frame at MON_URPC_BASE */ 584#ifdef CONFIG_PAE 585 paging_x86_32_map_pdpte(&init_pdpte[X86_32_PDPTE_BASE(MON_URPC_BASE)], 586 mem_to_local_phys((lvaddr_t)init_pdir)); 587#endif 588 paging_x86_32_map_table(&init_pdir[X86_32_PDIR_BASE(MON_URPC_BASE)], 589 mem_to_local_phys((lvaddr_t)init_ptable)); 590 for (int i = 0; i < MON_URPC_SIZE / BASE_PAGE_SIZE; i++) { 591 paging_x86_32_map(&init_ptable[X86_32_PTABLE_BASE(MON_URPC_BASE) + i], 592 urpc_ptr + i * BASE_PAGE_SIZE, 593 INIT_PAGE_BITMAP | paging_elf_to_page_flags(PF_R | PF_W)); 594 } 595 596 // elf load the domain 597 genvaddr_t entry_point; 598 err = elf_load(EM_386, startup_alloc_init, &spawn_state, 599 local_phys_to_mem(core_data->monitor_binary), 600 core_data->monitor_binary_size, &entry_point); 601 if (err_is_fail(err)) { 602 //err_print_calltrace(err); 603 panic("ELF load of init module failed!"); 604 } 605 606 struct dispatcher_shared_x86_32 *init_disp_x86_32 = 607 get_dispatcher_shared_x86_32(init_dcb->disp); 608 init_disp_x86_32->disabled_save_area.eip = entry_point; 609 610 return init_dcb; 611} 612