errval_t pcie_setup_confspace(void) { errval_t err; uint64_t address; uint16_t segment; uint8_t sbus; uint8_t ebus; struct acpi_rpc_client* cl = get_acpi_rpc_client(); cl->vtbl.get_pcie_confspace(cl, &err, &address, &segment, &sbus, &ebus); if (err_is_ok(err)) { size_t region_pages = (ebus + 1 - sbus) << 8; size_t region_bytes = region_pages * BASE_PAGE_SIZE; uint8_t region_bits = log2ceil(region_bytes); struct capref pcie_cap; struct acpi_rpc_client* acl = get_acpi_rpc_client(); errval_t error_code; err = acl->vtbl.mm_alloc_range_proxy(acl, region_bits, address, address + (1UL << region_bits), &pcie_cap, &error_code); if (err_is_fail(err)) { return err; } if (err_is_fail(error_code)) { return error_code; } PCI_DEBUG("calling confspace init with: %"PRIu64", %"PRIu16", %"PRIu8", %"PRIu8"", address, segment, sbus, ebus); int r = pcie_confspace_init(pcie_cap, address, segment, sbus, ebus); assert(r == 0); } return err; }
int start_aps_x86_32_start(uint8_t core_id, genvaddr_t entry) { DEBUG("%s:%d: start_aps_x86_32_start\n", __FILE__, __LINE__); // Copy the startup code to the real-mode address uint8_t *real_src = (uint8_t *) &x86_32_start_ap; uint8_t *real_end = (uint8_t *) &x86_32_start_ap_end; struct capref bootcap; struct acpi_rpc_client* acl = get_acpi_rpc_client(); errval_t error_code; errval_t err = acl->vtbl.mm_realloc_range_proxy(acl, 16, 0x0, &bootcap, &error_code); if (err_is_fail(err)) { USER_PANIC_ERR(err, "mm_alloc_range_proxy failed."); } if (err_is_fail(error_code)) { USER_PANIC_ERR(error_code, "mm_alloc_range_proxy return failed."); } void* real_base; err = vspace_map_one_frame(&real_base, 1<<16, bootcap, NULL, NULL); uint8_t* real_dest = (uint8_t*)real_base + X86_32_REAL_MODE_LINEAR_OFFSET; memcpy(real_dest, real_src, real_end - real_src); /* Pointer to the entry point called from init_ap.S */ volatile uint64_t *absolute_entry_ptr = (volatile uint64_t *) (( (lpaddr_t) &x86_32_init_ap_absolute_entry - (lpaddr_t) &x86_32_start_ap ) + real_dest); //copy the address of the function start (in boot.S) to the long-mode //assembler code to be able to perform an absolute jump *absolute_entry_ptr = entry; // pointer to the shared global variable amongst all kernels volatile uint64_t *ap_global = (volatile uint64_t *) (( (lpaddr_t) &x86_32_init_ap_global - (lpaddr_t) &x86_32_start_ap ) + real_dest); genpaddr_t global; struct monitor_blocking_rpc_client *mc = get_monitor_blocking_rpc_client(); err = mc->vtbl.get_global_paddr(mc, &global); if (err_is_fail(err)) { DEBUG_ERR(err, "invoke spawn core"); return err_push(err, MON_ERR_SPAWN_CORE); } *ap_global = (uint64_t)(genpaddr_t)global; // pointer to the pseudo-lock used to detect boot up of new core volatile uint32_t *ap_wait = (volatile uint32_t *) ((lpaddr_t) &x86_32_init_ap_wait - ((lpaddr_t) &x86_32_start_ap) + real_dest); // Pointer to the lock variable in the realmode code volatile uint8_t *ap_lock = (volatile uint8_t *) ((lpaddr_t) &x86_32_init_ap_lock - ((lpaddr_t) &x86_32_start_ap) + real_dest); *ap_wait = AP_STARTING_UP; end = bench_tsc(); err = invoke_send_init_ipi(ipi_cap, core_id); if (err_is_fail(err)) { DEBUG_ERR(err, "invoke send init ipi"); return err; } err = invoke_send_start_ipi(ipi_cap, core_id, entry); if (err_is_fail(err)) { DEBUG_ERR(err, "invoke sipi"); return err; } //give the new core a bit time to start-up and set the lock for (uint64_t i = 0; i < STARTUP_TIMEOUT; i++) { if (*ap_lock != 0) { break; } } // If the lock is set, the core has been started, otherwise assume, that // a core with this APIC ID doesn't exist. if (*ap_lock != 0) { while (*ap_wait != AP_STARTED); trace_event(TRACE_SUBSYS_KERNEL, TRACE_EVENT_KERNEL_CORE_START_REQUEST_ACK, core_id); *ap_lock = 0; return 0; } assert(!"badness"); return -1; }