1*ebf5747bSPedro F. Giffuni /*- 2*ebf5747bSPedro F. Giffuni * SPDX-License-Identifier: BSD-2-Clause-NetBSD 3*ebf5747bSPedro F. Giffuni * 41a9cdd37SRoger Pau Monné * Copyright (c) 2004 Christian Limpach. 51a9cdd37SRoger Pau Monné * Copyright (c) 2004-2006,2008 Kip Macy 69b4e54d3SRoger Pau Monné * Copyright (c) 2008 The NetBSD Foundation, Inc. 71a9cdd37SRoger Pau Monné * Copyright (c) 2013 Roger Pau Monné <roger.pau@citrix.com> 81a9cdd37SRoger Pau Monné * All rights reserved. 91a9cdd37SRoger Pau Monné * 101a9cdd37SRoger Pau Monné * Redistribution and use in source and binary forms, with or without 111a9cdd37SRoger Pau Monné * modification, are permitted provided that the following conditions 121a9cdd37SRoger Pau Monné * are met: 131a9cdd37SRoger Pau Monné * 1. Redistributions of source code must retain the above copyright 141a9cdd37SRoger Pau Monné * notice, this list of conditions and the following disclaimer. 151a9cdd37SRoger Pau Monné * 2. Redistributions in binary form must reproduce the above copyright 161a9cdd37SRoger Pau Monné * notice, this list of conditions and the following disclaimer in the 171a9cdd37SRoger Pau Monné * documentation and/or other materials provided with the distribution. 181a9cdd37SRoger Pau Monné * 191a9cdd37SRoger Pau Monné * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS AS IS'' AND 201a9cdd37SRoger Pau Monné * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 211a9cdd37SRoger Pau Monné * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 221a9cdd37SRoger Pau Monné * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 231a9cdd37SRoger Pau Monné * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 241a9cdd37SRoger Pau Monné * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 251a9cdd37SRoger Pau Monné * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 261a9cdd37SRoger Pau Monné * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 271a9cdd37SRoger Pau Monné * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 281a9cdd37SRoger Pau Monné * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 291a9cdd37SRoger Pau Monné * SUCH DAMAGE. 301a9cdd37SRoger Pau Monné */ 311a9cdd37SRoger Pau Monné 321a9cdd37SRoger Pau Monné #include <sys/cdefs.h> 331a9cdd37SRoger Pau Monné __FBSDID("$FreeBSD$"); 341a9cdd37SRoger Pau Monné 35c98a2727SRoger Pau Monné #include "opt_ddb.h" 36721555e7SZbigniew Bodek #include "opt_kstack_pages.h" 37c98a2727SRoger Pau Monné 381a9cdd37SRoger Pau Monné #include <sys/param.h> 391a9cdd37SRoger Pau Monné #include <sys/bus.h> 401a9cdd37SRoger Pau Monné #include <sys/kernel.h> 411a9cdd37SRoger Pau Monné #include <sys/reboot.h> 421a9cdd37SRoger Pau Monné #include <sys/systm.h> 43079f7ef8SRoger Pau Monné #include <sys/malloc.h> 44c98a2727SRoger Pau Monné #include <sys/linker.h> 451a9cdd37SRoger Pau Monné #include <sys/lock.h> 461a9cdd37SRoger Pau Monné #include <sys/rwlock.h> 47aa389b4fSRoger Pau Monné #include <sys/boot.h> 4897baeefdSRoger Pau Monné #include <sys/ctype.h> 49079f7ef8SRoger Pau Monné #include <sys/mutex.h> 50079f7ef8SRoger Pau Monné #include <sys/smp.h> 511a9cdd37SRoger Pau Monné 521a9cdd37SRoger Pau Monné #include <vm/vm.h> 531a9cdd37SRoger Pau Monné #include <vm/vm_extern.h> 541a9cdd37SRoger Pau Monné #include <vm/vm_kern.h> 551a9cdd37SRoger Pau Monné #include <vm/vm_page.h> 561a9cdd37SRoger Pau Monné #include <vm/vm_map.h> 571a9cdd37SRoger Pau Monné #include <vm/vm_object.h> 581a9cdd37SRoger Pau Monné #include <vm/vm_pager.h> 591a9cdd37SRoger Pau Monné #include <vm/vm_param.h> 601a9cdd37SRoger Pau Monné 61fae92773SJohn Baldwin #include <machine/intr_machdep.h> 62fae92773SJohn Baldwin #include <x86/apicvar.h> 6397baeefdSRoger Pau Monné #include <x86/init.h> 641e69553eSRoger Pau Monné #include <machine/pc/bios.h> 65079f7ef8SRoger Pau Monné #include <machine/smp.h> 6644e06d15SRoger Pau Monné #include <machine/intr_machdep.h> 67ca49b334SRoger Pau Monné #include <machine/metadata.h> 6897baeefdSRoger Pau Monné 691a9cdd37SRoger Pau Monné #include <xen/xen-os.h> 701a9cdd37SRoger Pau Monné #include <xen/hypervisor.h> 71b7df74eeSWarner Losh #include <xen/xenstore/xenstorevar.h> 72842471b3SRoger Pau Monné #include <xen/xen_pv.h> 7344e06d15SRoger Pau Monné #include <xen/xen_msi.h> 741a9cdd37SRoger Pau Monné 75079f7ef8SRoger Pau Monné #include <xen/interface/vcpu.h> 76079f7ef8SRoger Pau Monné 775f05c794SRoger Pau Monné #include <dev/xen/timer/timer.h> 785f05c794SRoger Pau Monné 79c98a2727SRoger Pau Monné #ifdef DDB 80c98a2727SRoger Pau Monné #include <ddb/ddb.h> 81c98a2727SRoger Pau Monné #endif 82c98a2727SRoger Pau Monné 831a9cdd37SRoger Pau Monné /* Native initial function */ 841a9cdd37SRoger Pau Monné extern u_int64_t hammer_time(u_int64_t, u_int64_t); 851a9cdd37SRoger Pau Monné /* Xen initial function */ 861a9cdd37SRoger Pau Monné uint64_t hammer_time_xen(start_info_t *, uint64_t); 871a9cdd37SRoger Pau Monné 881e69553eSRoger Pau Monné #define MAX_E820_ENTRIES 128 891e69553eSRoger Pau Monné 9097baeefdSRoger Pau Monné /*--------------------------- Forward Declarations ---------------------------*/ 9197baeefdSRoger Pau Monné static caddr_t xen_pv_parse_preload_data(u_int64_t); 921e69553eSRoger Pau Monné static void xen_pv_parse_memmap(caddr_t, vm_paddr_t *, int *); 9397baeefdSRoger Pau Monné 94079f7ef8SRoger Pau Monné #ifdef SMP 95079f7ef8SRoger Pau Monné static int xen_pv_start_all_aps(void); 96079f7ef8SRoger Pau Monné #endif 97079f7ef8SRoger Pau Monné 98079f7ef8SRoger Pau Monné /*---------------------------- Extern Declarations ---------------------------*/ 99079f7ef8SRoger Pau Monné #ifdef SMP 100079f7ef8SRoger Pau Monné /* Variables used by amd64 mp_machdep to start APs */ 101079f7ef8SRoger Pau Monné extern char *doublefault_stack; 102079f7ef8SRoger Pau Monné extern char *nmi_stack; 103079f7ef8SRoger Pau Monné #endif 104079f7ef8SRoger Pau Monné 105c98a2727SRoger Pau Monné /* 106c98a2727SRoger Pau Monné * Placed by the linker at the end of the bss section, which is the last 107c98a2727SRoger Pau Monné * section loaded by Xen before loading the symtab and strtab. 108c98a2727SRoger Pau Monné */ 109c98a2727SRoger Pau Monné extern uint32_t end; 110c98a2727SRoger Pau Monné 11197baeefdSRoger Pau Monné /*-------------------------------- Global Data -------------------------------*/ 11297baeefdSRoger Pau Monné /* Xen init_ops implementation. */ 11397baeefdSRoger Pau Monné struct init_ops xen_init_ops = { 11497baeefdSRoger Pau Monné .parse_preload_data = xen_pv_parse_preload_data, 1155f05c794SRoger Pau Monné .early_clock_source_init = xen_clock_init, 1165f05c794SRoger Pau Monné .early_delay = xen_delay, 1171e69553eSRoger Pau Monné .parse_memmap = xen_pv_parse_memmap, 118079f7ef8SRoger Pau Monné #ifdef SMP 119079f7ef8SRoger Pau Monné .start_all_aps = xen_pv_start_all_aps, 120079f7ef8SRoger Pau Monné #endif 12144e06d15SRoger Pau Monné .msi_init = xen_msi_init, 12297baeefdSRoger Pau Monné }; 12397baeefdSRoger Pau Monné 1241e69553eSRoger Pau Monné static struct bios_smap xen_smap[MAX_E820_ENTRIES]; 1251e69553eSRoger Pau Monné 12697baeefdSRoger Pau Monné /*-------------------------------- Xen PV init -------------------------------*/ 1271a9cdd37SRoger Pau Monné /* 1281a9cdd37SRoger Pau Monné * First function called by the Xen PVH boot sequence. 1291a9cdd37SRoger Pau Monné * 1301a9cdd37SRoger Pau Monné * Set some Xen global variables and prepare the environment so it is 1311a9cdd37SRoger Pau Monné * as similar as possible to what native FreeBSD init function expects. 1321a9cdd37SRoger Pau Monné */ 1331a9cdd37SRoger Pau Monné uint64_t 1341a9cdd37SRoger Pau Monné hammer_time_xen(start_info_t *si, uint64_t xenstack) 1351a9cdd37SRoger Pau Monné { 1361a9cdd37SRoger Pau Monné uint64_t physfree; 1371a9cdd37SRoger Pau Monné uint64_t *PT4 = (u_int64_t *)xenstack; 1381a9cdd37SRoger Pau Monné uint64_t *PT3 = (u_int64_t *)(xenstack + PAGE_SIZE); 1391a9cdd37SRoger Pau Monné uint64_t *PT2 = (u_int64_t *)(xenstack + 2 * PAGE_SIZE); 1401a9cdd37SRoger Pau Monné int i; 1411a9cdd37SRoger Pau Monné 1421a9cdd37SRoger Pau Monné xen_domain_type = XEN_PV_DOMAIN; 1431a9cdd37SRoger Pau Monné vm_guest = VM_GUEST_XEN; 1441a9cdd37SRoger Pau Monné 1451a9cdd37SRoger Pau Monné if ((si == NULL) || (xenstack == 0)) { 146c203fa69SRoger Pau Monné xc_printf("ERROR: invalid start_info or xen stack, halting\n"); 1471a9cdd37SRoger Pau Monné HYPERVISOR_shutdown(SHUTDOWN_crash); 1481a9cdd37SRoger Pau Monné } 1491a9cdd37SRoger Pau Monné 150c203fa69SRoger Pau Monné xc_printf("FreeBSD PVH running on %s\n", si->magic); 151c203fa69SRoger Pau Monné 1521a9cdd37SRoger Pau Monné /* We use 3 pages of xen stack for the boot pagetables */ 1531a9cdd37SRoger Pau Monné physfree = xenstack + 3 * PAGE_SIZE - KERNBASE; 1541a9cdd37SRoger Pau Monné 1551a9cdd37SRoger Pau Monné /* Setup Xen global variables */ 1561a9cdd37SRoger Pau Monné HYPERVISOR_start_info = si; 1571a9cdd37SRoger Pau Monné HYPERVISOR_shared_info = 1581a9cdd37SRoger Pau Monné (shared_info_t *)(si->shared_info + KERNBASE); 1591a9cdd37SRoger Pau Monné 1601a9cdd37SRoger Pau Monné /* 1611a9cdd37SRoger Pau Monné * Setup some misc global variables for Xen devices 1621a9cdd37SRoger Pau Monné * 1631a9cdd37SRoger Pau Monné * XXX: Devices that need these specific variables should 1641a9cdd37SRoger Pau Monné * be rewritten to fetch this info by themselves from the 1651a9cdd37SRoger Pau Monné * start_info page. 1661a9cdd37SRoger Pau Monné */ 1671a9cdd37SRoger Pau Monné xen_store = (struct xenstore_domain_interface *) 1681a9cdd37SRoger Pau Monné (ptoa(si->store_mfn) + KERNBASE); 169c203fa69SRoger Pau Monné console_page = (char *)(ptoa(si->console.domU.mfn) + KERNBASE); 1701a9cdd37SRoger Pau Monné 1711a9cdd37SRoger Pau Monné /* 1721a9cdd37SRoger Pau Monné * Use the stack Xen gives us to build the page tables 1731a9cdd37SRoger Pau Monné * as native FreeBSD expects to find them (created 1741a9cdd37SRoger Pau Monné * by the boot trampoline). 1751a9cdd37SRoger Pau Monné */ 1761a9cdd37SRoger Pau Monné for (i = 0; i < (PAGE_SIZE / sizeof(uint64_t)); i++) { 1775f35f84fSRoger Pau Monné /* 1785f35f84fSRoger Pau Monné * Each slot of the level 4 pages points 1795f35f84fSRoger Pau Monné * to the same level 3 page 1805f35f84fSRoger Pau Monné */ 1811a9cdd37SRoger Pau Monné PT4[i] = ((uint64_t)&PT3[0]) - KERNBASE; 1821a9cdd37SRoger Pau Monné PT4[i] |= PG_V | PG_RW | PG_U; 1831a9cdd37SRoger Pau Monné 1845f35f84fSRoger Pau Monné /* 1855f35f84fSRoger Pau Monné * Each slot of the level 3 pages points 1865f35f84fSRoger Pau Monné * to the same level 2 page 1875f35f84fSRoger Pau Monné */ 1881a9cdd37SRoger Pau Monné PT3[i] = ((uint64_t)&PT2[0]) - KERNBASE; 1891a9cdd37SRoger Pau Monné PT3[i] |= PG_V | PG_RW | PG_U; 1901a9cdd37SRoger Pau Monné 1915f35f84fSRoger Pau Monné /* 1925f35f84fSRoger Pau Monné * The level 2 page slots are mapped with 1935f35f84fSRoger Pau Monné * 2MB pages for 1GB. 1945f35f84fSRoger Pau Monné */ 1951a9cdd37SRoger Pau Monné PT2[i] = i * (2 * 1024 * 1024); 1961a9cdd37SRoger Pau Monné PT2[i] |= PG_V | PG_RW | PG_PS | PG_U; 1971a9cdd37SRoger Pau Monné } 1981a9cdd37SRoger Pau Monné load_cr3(((uint64_t)&PT4[0]) - KERNBASE); 1991a9cdd37SRoger Pau Monné 20097baeefdSRoger Pau Monné /* Set the hooks for early functions that diverge from bare metal */ 20197baeefdSRoger Pau Monné init_ops = xen_init_ops; 202842471b3SRoger Pau Monné apic_ops = xen_apic_ops; 20397baeefdSRoger Pau Monné 2041a9cdd37SRoger Pau Monné /* Now we can jump into the native init function */ 2051a9cdd37SRoger Pau Monné return (hammer_time(0, physfree)); 2061a9cdd37SRoger Pau Monné } 20797baeefdSRoger Pau Monné 20897baeefdSRoger Pau Monné /*-------------------------------- PV specific -------------------------------*/ 209079f7ef8SRoger Pau Monné #ifdef SMP 210079f7ef8SRoger Pau Monné static bool 211079f7ef8SRoger Pau Monné start_xen_ap(int cpu) 212079f7ef8SRoger Pau Monné { 213079f7ef8SRoger Pau Monné struct vcpu_guest_context *ctxt; 214079f7ef8SRoger Pau Monné int ms, cpus = mp_naps; 215edc82223SKonstantin Belousov const size_t stacksize = kstack_pages * PAGE_SIZE; 216079f7ef8SRoger Pau Monné 217079f7ef8SRoger Pau Monné /* allocate and set up an idle stack data page */ 218079f7ef8SRoger Pau Monné bootstacks[cpu] = 219079f7ef8SRoger Pau Monné (void *)kmem_malloc(kernel_arena, stacksize, M_WAITOK | M_ZERO); 220079f7ef8SRoger Pau Monné doublefault_stack = 221079f7ef8SRoger Pau Monné (char *)kmem_malloc(kernel_arena, PAGE_SIZE, M_WAITOK | M_ZERO); 222079f7ef8SRoger Pau Monné nmi_stack = 223079f7ef8SRoger Pau Monné (char *)kmem_malloc(kernel_arena, PAGE_SIZE, M_WAITOK | M_ZERO); 224079f7ef8SRoger Pau Monné dpcpu = 225079f7ef8SRoger Pau Monné (void *)kmem_malloc(kernel_arena, DPCPU_SIZE, M_WAITOK | M_ZERO); 226079f7ef8SRoger Pau Monné 227edc82223SKonstantin Belousov bootSTK = (char *)bootstacks[cpu] + kstack_pages * PAGE_SIZE - 8; 228079f7ef8SRoger Pau Monné bootAP = cpu; 229079f7ef8SRoger Pau Monné 230079f7ef8SRoger Pau Monné ctxt = malloc(sizeof(*ctxt), M_TEMP, M_WAITOK | M_ZERO); 231079f7ef8SRoger Pau Monné 232079f7ef8SRoger Pau Monné ctxt->flags = VGCF_IN_KERNEL; 233079f7ef8SRoger Pau Monné ctxt->user_regs.rip = (unsigned long) init_secondary; 234079f7ef8SRoger Pau Monné ctxt->user_regs.rsp = (unsigned long) bootSTK; 235079f7ef8SRoger Pau Monné 236079f7ef8SRoger Pau Monné /* Set the AP to use the same page tables */ 237079f7ef8SRoger Pau Monné ctxt->ctrlreg[3] = KPML4phys; 238079f7ef8SRoger Pau Monné 239079f7ef8SRoger Pau Monné if (HYPERVISOR_vcpu_op(VCPUOP_initialise, cpu, ctxt)) 240079f7ef8SRoger Pau Monné panic("unable to initialize AP#%d", cpu); 241079f7ef8SRoger Pau Monné 242079f7ef8SRoger Pau Monné free(ctxt, M_TEMP); 243079f7ef8SRoger Pau Monné 244079f7ef8SRoger Pau Monné /* Launch the vCPU */ 245079f7ef8SRoger Pau Monné if (HYPERVISOR_vcpu_op(VCPUOP_up, cpu, NULL)) 246079f7ef8SRoger Pau Monné panic("unable to start AP#%d", cpu); 247079f7ef8SRoger Pau Monné 248079f7ef8SRoger Pau Monné /* Wait up to 5 seconds for it to start. */ 249079f7ef8SRoger Pau Monné for (ms = 0; ms < 5000; ms++) { 250079f7ef8SRoger Pau Monné if (mp_naps > cpus) 251079f7ef8SRoger Pau Monné return (true); 252079f7ef8SRoger Pau Monné DELAY(1000); 253079f7ef8SRoger Pau Monné } 254079f7ef8SRoger Pau Monné 255079f7ef8SRoger Pau Monné return (false); 256079f7ef8SRoger Pau Monné } 257079f7ef8SRoger Pau Monné 258079f7ef8SRoger Pau Monné static int 259079f7ef8SRoger Pau Monné xen_pv_start_all_aps(void) 260079f7ef8SRoger Pau Monné { 261079f7ef8SRoger Pau Monné int cpu; 262079f7ef8SRoger Pau Monné 263079f7ef8SRoger Pau Monné mtx_init(&ap_boot_mtx, "ap boot", NULL, MTX_SPIN); 264079f7ef8SRoger Pau Monné 265079f7ef8SRoger Pau Monné for (cpu = 1; cpu < mp_ncpus; cpu++) { 266079f7ef8SRoger Pau Monné 267079f7ef8SRoger Pau Monné /* attempt to start the Application Processor */ 268079f7ef8SRoger Pau Monné if (!start_xen_ap(cpu)) 269079f7ef8SRoger Pau Monné panic("AP #%d failed to start!", cpu); 270079f7ef8SRoger Pau Monné 271079f7ef8SRoger Pau Monné CPU_SET(cpu, &all_cpus); /* record AP in CPU map */ 272079f7ef8SRoger Pau Monné } 273079f7ef8SRoger Pau Monné 274079f7ef8SRoger Pau Monné return (mp_naps); 275079f7ef8SRoger Pau Monné } 276079f7ef8SRoger Pau Monné #endif /* SMP */ 277079f7ef8SRoger Pau Monné 27897baeefdSRoger Pau Monné /* 27997baeefdSRoger Pau Monné * Functions to convert the "extra" parameters passed by Xen 28097baeefdSRoger Pau Monné * into FreeBSD boot options. 28197baeefdSRoger Pau Monné */ 28297baeefdSRoger Pau Monné static void 28397baeefdSRoger Pau Monné xen_pv_set_env(void) 28497baeefdSRoger Pau Monné { 28597baeefdSRoger Pau Monné char *cmd_line_next, *cmd_line; 28697baeefdSRoger Pau Monné size_t env_size; 28797baeefdSRoger Pau Monné 28897baeefdSRoger Pau Monné cmd_line = HYPERVISOR_start_info->cmd_line; 28997baeefdSRoger Pau Monné env_size = sizeof(HYPERVISOR_start_info->cmd_line); 29097baeefdSRoger Pau Monné 29197baeefdSRoger Pau Monné /* Skip leading spaces */ 29297baeefdSRoger Pau Monné for (; isspace(*cmd_line) && (env_size != 0); cmd_line++) 29397baeefdSRoger Pau Monné env_size--; 29497baeefdSRoger Pau Monné 29597baeefdSRoger Pau Monné /* Replace ',' with '\0' */ 29697baeefdSRoger Pau Monné for (cmd_line_next = cmd_line; strsep(&cmd_line_next, ",") != NULL;) 29797baeefdSRoger Pau Monné ; 29897baeefdSRoger Pau Monné 29969dcb7e7SIan Lepore init_static_kenv(cmd_line, 0); 30097baeefdSRoger Pau Monné } 30197baeefdSRoger Pau Monné 30297baeefdSRoger Pau Monné static void 30397baeefdSRoger Pau Monné xen_pv_set_boothowto(void) 30497baeefdSRoger Pau Monné { 30597baeefdSRoger Pau Monné int i; 306b2537024SRoger Pau Monné char *env; 30797baeefdSRoger Pau Monné 30897baeefdSRoger Pau Monné /* get equivalents from the environment */ 30997baeefdSRoger Pau Monné for (i = 0; howto_names[i].ev != NULL; i++) { 310b2537024SRoger Pau Monné if ((env = kern_getenv(howto_names[i].ev)) != NULL) { 31197baeefdSRoger Pau Monné boothowto |= howto_names[i].mask; 312b2537024SRoger Pau Monné freeenv(env); 313b2537024SRoger Pau Monné } 31497baeefdSRoger Pau Monné } 31597baeefdSRoger Pau Monné } 31697baeefdSRoger Pau Monné 317c98a2727SRoger Pau Monné #ifdef DDB 318c98a2727SRoger Pau Monné /* 319c98a2727SRoger Pau Monné * The way Xen loads the symtab is different from the native boot loader, 320c98a2727SRoger Pau Monné * because it's tailored for NetBSD. So we have to adapt and use the same 321c98a2727SRoger Pau Monné * method as NetBSD. Portions of the code below have been picked from NetBSD: 322c98a2727SRoger Pau Monné * sys/kern/kern_ksyms.c CVS Revision 1.71. 323c98a2727SRoger Pau Monné */ 324c98a2727SRoger Pau Monné static void 325c98a2727SRoger Pau Monné xen_pv_parse_symtab(void) 326c98a2727SRoger Pau Monné { 327c98a2727SRoger Pau Monné Elf_Ehdr *ehdr; 328c98a2727SRoger Pau Monné Elf_Shdr *shdr; 329c98a2727SRoger Pau Monné vm_offset_t sym_end; 330c98a2727SRoger Pau Monné uint32_t size; 331c98a2727SRoger Pau Monné int i, j; 332c98a2727SRoger Pau Monné 333c98a2727SRoger Pau Monné size = end; 334c98a2727SRoger Pau Monné sym_end = HYPERVISOR_start_info->mod_start != 0 ? 335c98a2727SRoger Pau Monné HYPERVISOR_start_info->mod_start : 336c98a2727SRoger Pau Monné HYPERVISOR_start_info->mfn_list; 337c98a2727SRoger Pau Monné 338c98a2727SRoger Pau Monné /* 339c98a2727SRoger Pau Monné * Make sure the size is right headed, sym_end is just a 340c98a2727SRoger Pau Monné * high boundary, but at least allows us to fail earlier. 341c98a2727SRoger Pau Monné */ 342c98a2727SRoger Pau Monné if ((vm_offset_t)&end + size > sym_end) { 343c98a2727SRoger Pau Monné xc_printf("Unable to load ELF symtab: size mismatch\n"); 344c98a2727SRoger Pau Monné return; 345c98a2727SRoger Pau Monné } 346c98a2727SRoger Pau Monné 347c98a2727SRoger Pau Monné ehdr = (Elf_Ehdr *)(&end + 1); 348c98a2727SRoger Pau Monné if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG) || 349c98a2727SRoger Pau Monné ehdr->e_ident[EI_CLASS] != ELF_TARG_CLASS || 350c98a2727SRoger Pau Monné ehdr->e_version > 1) { 351c98a2727SRoger Pau Monné xc_printf("Unable to load ELF symtab: invalid symbol table\n"); 352c98a2727SRoger Pau Monné return; 353c98a2727SRoger Pau Monné } 354c98a2727SRoger Pau Monné 355c98a2727SRoger Pau Monné shdr = (Elf_Shdr *)((uint8_t *)ehdr + ehdr->e_shoff); 356c98a2727SRoger Pau Monné /* Find the symbol table and the corresponding string table. */ 357c98a2727SRoger Pau Monné for (i = 1; i < ehdr->e_shnum; i++) { 358c98a2727SRoger Pau Monné if (shdr[i].sh_type != SHT_SYMTAB) 359c98a2727SRoger Pau Monné continue; 360c98a2727SRoger Pau Monné if (shdr[i].sh_offset == 0) 361c98a2727SRoger Pau Monné continue; 362c98a2727SRoger Pau Monné ksymtab = (uintptr_t)((uint8_t *)ehdr + shdr[i].sh_offset); 363c98a2727SRoger Pau Monné ksymtab_size = shdr[i].sh_size; 364c98a2727SRoger Pau Monné j = shdr[i].sh_link; 365c98a2727SRoger Pau Monné if (shdr[j].sh_offset == 0) 366c98a2727SRoger Pau Monné continue; /* Can this happen? */ 367c98a2727SRoger Pau Monné kstrtab = (uintptr_t)((uint8_t *)ehdr + shdr[j].sh_offset); 368c98a2727SRoger Pau Monné break; 369c98a2727SRoger Pau Monné } 370c98a2727SRoger Pau Monné 371c98a2727SRoger Pau Monné if (ksymtab == 0 || kstrtab == 0) { 372c98a2727SRoger Pau Monné xc_printf( 373c98a2727SRoger Pau Monné "Unable to load ELF symtab: could not find symtab or strtab\n"); 374c98a2727SRoger Pau Monné return; 375c98a2727SRoger Pau Monné } 376c98a2727SRoger Pau Monné } 377c98a2727SRoger Pau Monné #endif 378c98a2727SRoger Pau Monné 37997baeefdSRoger Pau Monné static caddr_t 38097baeefdSRoger Pau Monné xen_pv_parse_preload_data(u_int64_t modulep) 38197baeefdSRoger Pau Monné { 382ca49b334SRoger Pau Monné caddr_t kmdp; 383ca49b334SRoger Pau Monné vm_ooffset_t off; 384ca49b334SRoger Pau Monné vm_paddr_t metadata; 38569dcb7e7SIan Lepore char *envp; 386ca49b334SRoger Pau Monné 387ca49b334SRoger Pau Monné if (HYPERVISOR_start_info->mod_start != 0) { 388ca49b334SRoger Pau Monné preload_metadata = (caddr_t)(HYPERVISOR_start_info->mod_start); 389ca49b334SRoger Pau Monné 390ca49b334SRoger Pau Monné kmdp = preload_search_by_type("elf kernel"); 391ca49b334SRoger Pau Monné if (kmdp == NULL) 392ca49b334SRoger Pau Monné kmdp = preload_search_by_type("elf64 kernel"); 393ca49b334SRoger Pau Monné KASSERT(kmdp != NULL, ("unable to find kernel")); 394ca49b334SRoger Pau Monné 395ca49b334SRoger Pau Monné /* 396ca49b334SRoger Pau Monné * Xen has relocated the metadata and the modules, 397ca49b334SRoger Pau Monné * so we need to recalculate it's position. This is 398ca49b334SRoger Pau Monné * done by saving the original modulep address and 399ca49b334SRoger Pau Monné * then calculating the offset with mod_start, 400ca49b334SRoger Pau Monné * which contains the relocated modulep address. 401ca49b334SRoger Pau Monné */ 402b829c841SRoger Pau Monné metadata = MD_FETCH(kmdp, MODINFOMD_MODULEP, vm_paddr_t); 403ca49b334SRoger Pau Monné off = HYPERVISOR_start_info->mod_start - metadata; 404ca49b334SRoger Pau Monné 405ca49b334SRoger Pau Monné preload_bootstrap_relocate(off); 406ca49b334SRoger Pau Monné 407ca49b334SRoger Pau Monné boothowto = MD_FETCH(kmdp, MODINFOMD_HOWTO, int); 40869dcb7e7SIan Lepore envp = MD_FETCH(kmdp, MODINFOMD_ENVP, char *); 40969dcb7e7SIan Lepore if (envp != NULL) 41069dcb7e7SIan Lepore envp += off; 41169dcb7e7SIan Lepore init_static_kenv(envp, 0); 412ca49b334SRoger Pau Monné } else { 41397baeefdSRoger Pau Monné /* Parse the extra boot information given by Xen */ 41497baeefdSRoger Pau Monné xen_pv_set_env(); 41597baeefdSRoger Pau Monné xen_pv_set_boothowto(); 416ca49b334SRoger Pau Monné kmdp = NULL; 417ca49b334SRoger Pau Monné } 41897baeefdSRoger Pau Monné 419c98a2727SRoger Pau Monné #ifdef DDB 420c98a2727SRoger Pau Monné xen_pv_parse_symtab(); 421c98a2727SRoger Pau Monné #endif 422ca49b334SRoger Pau Monné return (kmdp); 42397baeefdSRoger Pau Monné } 4241e69553eSRoger Pau Monné 4251e69553eSRoger Pau Monné static void 4261e69553eSRoger Pau Monné xen_pv_parse_memmap(caddr_t kmdp, vm_paddr_t *physmap, int *physmap_idx) 4271e69553eSRoger Pau Monné { 4281e69553eSRoger Pau Monné struct xen_memory_map memmap; 4291e69553eSRoger Pau Monné u_int32_t size; 4301e69553eSRoger Pau Monné int rc; 4311e69553eSRoger Pau Monné 4321e69553eSRoger Pau Monné /* Fetch the E820 map from Xen */ 4331e69553eSRoger Pau Monné memmap.nr_entries = MAX_E820_ENTRIES; 4341e69553eSRoger Pau Monné set_xen_guest_handle(memmap.buffer, xen_smap); 4351e69553eSRoger Pau Monné rc = HYPERVISOR_memory_op(XENMEM_memory_map, &memmap); 4361e69553eSRoger Pau Monné if (rc) 4371e69553eSRoger Pau Monné panic("unable to fetch Xen E820 memory map"); 4381e69553eSRoger Pau Monné size = memmap.nr_entries * sizeof(xen_smap[0]); 4391e69553eSRoger Pau Monné 4401e69553eSRoger Pau Monné bios_add_smap_entries(xen_smap, size, physmap, physmap_idx); 4411e69553eSRoger Pau Monné } 442