1ebf5747bSPedro F. Giffuni /*- 2ebf5747bSPedro F. Giffuni * SPDX-License-Identifier: BSD-2-Clause-NetBSD 3ebf5747bSPedro 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> 51a2495c36SRoger Pau Monné #include <sys/efi.h> 521a9cdd37SRoger Pau Monné 531a9cdd37SRoger Pau Monné #include <vm/vm.h> 541a9cdd37SRoger Pau Monné #include <vm/vm_extern.h> 551a9cdd37SRoger Pau Monné #include <vm/vm_kern.h> 561a9cdd37SRoger Pau Monné #include <vm/vm_page.h> 571a9cdd37SRoger Pau Monné #include <vm/vm_map.h> 581a9cdd37SRoger Pau Monné #include <vm/vm_object.h> 591a9cdd37SRoger Pau Monné #include <vm/vm_pager.h> 601a9cdd37SRoger Pau Monné #include <vm/vm_param.h> 611a9cdd37SRoger Pau Monné 62b0663c33SRoger Pau Monné #include <machine/_inttypes.h> 63fae92773SJohn Baldwin #include <machine/intr_machdep.h> 64fae92773SJohn Baldwin #include <x86/apicvar.h> 6597baeefdSRoger Pau Monné #include <x86/init.h> 661e69553eSRoger Pau Monné #include <machine/pc/bios.h> 67079f7ef8SRoger Pau Monné #include <machine/smp.h> 6844e06d15SRoger Pau Monné #include <machine/intr_machdep.h> 69a2495c36SRoger Pau Monné #include <machine/md_var.h> 70ca49b334SRoger Pau Monné #include <machine/metadata.h> 7177cb05dbSRoger Pau Monné #include <machine/cpu.h> 7297baeefdSRoger Pau Monné 731a9cdd37SRoger Pau Monné #include <xen/xen-os.h> 74b0663c33SRoger Pau Monné #include <xen/hvm.h> 751a9cdd37SRoger Pau Monné #include <xen/hypervisor.h> 76b7df74eeSWarner Losh #include <xen/xenstore/xenstorevar.h> 77842471b3SRoger Pau Monné #include <xen/xen_pv.h> 781a9cdd37SRoger Pau Monné 79ad7dd514SElliott Mitchell #include <contrib/xen/arch-x86/hvm/start_info.h> 80ad7dd514SElliott Mitchell #include <contrib/xen/vcpu.h> 81079f7ef8SRoger Pau Monné 825f05c794SRoger Pau Monné #include <dev/xen/timer/timer.h> 835f05c794SRoger Pau Monné 84c98a2727SRoger Pau Monné #ifdef DDB 85c98a2727SRoger Pau Monné #include <ddb/ddb.h> 86c98a2727SRoger Pau Monné #endif 87c98a2727SRoger Pau Monné 881a9cdd37SRoger Pau Monné /* Native initial function */ 891a9cdd37SRoger Pau Monné extern u_int64_t hammer_time(u_int64_t, u_int64_t); 901a9cdd37SRoger Pau Monné /* Xen initial function */ 91b0663c33SRoger Pau Monné uint64_t hammer_time_xen(vm_paddr_t); 921a9cdd37SRoger Pau Monné 931e69553eSRoger Pau Monné #define MAX_E820_ENTRIES 128 941e69553eSRoger Pau Monné 9597baeefdSRoger Pau Monné /*--------------------------- Forward Declarations ---------------------------*/ 96b0663c33SRoger Pau Monné static caddr_t xen_pvh_parse_preload_data(uint64_t); 97*023a025bSColin Percival static void pvh_parse_memmap(caddr_t, vm_paddr_t *, int *); 9897baeefdSRoger Pau Monné 99079f7ef8SRoger Pau Monné /*---------------------------- Extern Declarations ---------------------------*/ 100c98a2727SRoger Pau Monné /* 101c98a2727SRoger Pau Monné * Placed by the linker at the end of the bss section, which is the last 102c98a2727SRoger Pau Monné * section loaded by Xen before loading the symtab and strtab. 103c98a2727SRoger Pau Monné */ 104c98a2727SRoger Pau Monné extern uint32_t end; 105c98a2727SRoger Pau Monné 10697baeefdSRoger Pau Monné /*-------------------------------- Global Data -------------------------------*/ 107b0663c33SRoger Pau Monné struct init_ops xen_pvh_init_ops = { 108b0663c33SRoger Pau Monné .parse_preload_data = xen_pvh_parse_preload_data, 109b0663c33SRoger Pau Monné .early_clock_source_init = xen_clock_init, 110b0663c33SRoger Pau Monné .early_delay = xen_delay, 111*023a025bSColin Percival .parse_memmap = pvh_parse_memmap, 112b0663c33SRoger Pau Monné }; 113b0663c33SRoger Pau Monné 1141e69553eSRoger Pau Monné static struct bios_smap xen_smap[MAX_E820_ENTRIES]; 1151e69553eSRoger Pau Monné 116b0663c33SRoger Pau Monné static struct hvm_start_info *start_info; 117cfa0b7b8SRoger Pau Monné 11897baeefdSRoger Pau Monné /*-------------------------------- Xen PV init -------------------------------*/ 11997baeefdSRoger Pau Monné 120b0663c33SRoger Pau Monné uint64_t 121b0663c33SRoger Pau Monné hammer_time_xen(vm_paddr_t start_info_paddr) 122b0663c33SRoger Pau Monné { 123b0663c33SRoger Pau Monné struct hvm_modlist_entry *mod; 124b0663c33SRoger Pau Monné struct xen_add_to_physmap xatp; 125b0663c33SRoger Pau Monné uint64_t physfree; 126b0663c33SRoger Pau Monné char *kenv; 127b0663c33SRoger Pau Monné int rc; 128b0663c33SRoger Pau Monné 129b0663c33SRoger Pau Monné xen_domain_type = XEN_HVM_DOMAIN; 130b0663c33SRoger Pau Monné vm_guest = VM_GUEST_XEN; 131b0663c33SRoger Pau Monné 132b0663c33SRoger Pau Monné rc = xen_hvm_init_hypercall_stubs(XEN_HVM_INIT_EARLY); 133b0663c33SRoger Pau Monné if (rc) { 134b0663c33SRoger Pau Monné xc_printf("ERROR: failed to initialize hypercall page: %d\n", 135b0663c33SRoger Pau Monné rc); 136b0663c33SRoger Pau Monné HYPERVISOR_shutdown(SHUTDOWN_crash); 137b0663c33SRoger Pau Monné } 138b0663c33SRoger Pau Monné 139b0663c33SRoger Pau Monné start_info = (struct hvm_start_info *)(start_info_paddr + KERNBASE); 140b0663c33SRoger Pau Monné if (start_info->magic != XEN_HVM_START_MAGIC_VALUE) { 141b0663c33SRoger Pau Monné xc_printf("Unknown magic value in start_info struct: %#x\n", 142b0663c33SRoger Pau Monné start_info->magic); 143b0663c33SRoger Pau Monné HYPERVISOR_shutdown(SHUTDOWN_crash); 144b0663c33SRoger Pau Monné } 145b0663c33SRoger Pau Monné 146b0663c33SRoger Pau Monné /* 14777cb05dbSRoger Pau Monné * Select the higher address to use as physfree: either after 14877cb05dbSRoger Pau Monné * start_info, after the kernel, after the memory map or after any of 14977cb05dbSRoger Pau Monné * the modules. We assume enough memory to be available after the 15077cb05dbSRoger Pau Monné * selected address for the needs of very early memory allocations. 151b0663c33SRoger Pau Monné */ 15277cb05dbSRoger Pau Monné physfree = roundup2(start_info_paddr + sizeof(struct hvm_start_info), 15377cb05dbSRoger Pau Monné PAGE_SIZE); 15477cb05dbSRoger Pau Monné physfree = MAX(roundup2((vm_paddr_t)_end - KERNBASE, PAGE_SIZE), 15577cb05dbSRoger Pau Monné physfree); 15677cb05dbSRoger Pau Monné 15777cb05dbSRoger Pau Monné if (start_info->memmap_paddr != 0) 15877cb05dbSRoger Pau Monné physfree = MAX(roundup2(start_info->memmap_paddr + 15977cb05dbSRoger Pau Monné start_info->memmap_entries * 16077cb05dbSRoger Pau Monné sizeof(struct hvm_memmap_table_entry), PAGE_SIZE), 16177cb05dbSRoger Pau Monné physfree); 16277cb05dbSRoger Pau Monné 16377cb05dbSRoger Pau Monné if (start_info->modlist_paddr != 0) { 16477cb05dbSRoger Pau Monné unsigned int i; 16577cb05dbSRoger Pau Monné 16677cb05dbSRoger Pau Monné if (start_info->nr_modules == 0) { 16777cb05dbSRoger Pau Monné xc_printf( 16877cb05dbSRoger Pau Monné "ERROR: modlist_paddr != 0 but nr_modules == 0\n"); 16977cb05dbSRoger Pau Monné HYPERVISOR_shutdown(SHUTDOWN_crash); 17077cb05dbSRoger Pau Monné } 17177cb05dbSRoger Pau Monné mod = (struct hvm_modlist_entry *) 17277cb05dbSRoger Pau Monné (start_info->modlist_paddr + KERNBASE); 17377cb05dbSRoger Pau Monné for (i = 0; i < start_info->nr_modules; i++) 17477cb05dbSRoger Pau Monné physfree = MAX(roundup2(mod[i].paddr + mod[i].size, 17577cb05dbSRoger Pau Monné PAGE_SIZE), physfree); 17677cb05dbSRoger Pau Monné } 177b0663c33SRoger Pau Monné 178b0663c33SRoger Pau Monné xatp.domid = DOMID_SELF; 179b0663c33SRoger Pau Monné xatp.idx = 0; 180b0663c33SRoger Pau Monné xatp.space = XENMAPSPACE_shared_info; 181b0663c33SRoger Pau Monné xatp.gpfn = atop(physfree); 182b0663c33SRoger Pau Monné if (HYPERVISOR_memory_op(XENMEM_add_to_physmap, &xatp)) { 183b0663c33SRoger Pau Monné xc_printf("ERROR: failed to setup shared_info page\n"); 184b0663c33SRoger Pau Monné HYPERVISOR_shutdown(SHUTDOWN_crash); 185b0663c33SRoger Pau Monné } 186b0663c33SRoger Pau Monné HYPERVISOR_shared_info = (shared_info_t *)(physfree + KERNBASE); 187b0663c33SRoger Pau Monné physfree += PAGE_SIZE; 188b0663c33SRoger Pau Monné 189b0663c33SRoger Pau Monné /* 190b0663c33SRoger Pau Monné * Init a static kenv using a free page. The contents will be filled 191b0663c33SRoger Pau Monné * from the parse_preload_data hook. 192b0663c33SRoger Pau Monné */ 193b0663c33SRoger Pau Monné kenv = (void *)(physfree + KERNBASE); 194b0663c33SRoger Pau Monné physfree += PAGE_SIZE; 1953f102f58SMateusz Guzik bzero_early(kenv, PAGE_SIZE); 196b0663c33SRoger Pau Monné init_static_kenv(kenv, PAGE_SIZE); 197b0663c33SRoger Pau Monné 198b0663c33SRoger Pau Monné /* Set the hooks for early functions that diverge from bare metal */ 199b0663c33SRoger Pau Monné init_ops = xen_pvh_init_ops; 200b0663c33SRoger Pau Monné hvm_start_flags = start_info->flags; 201b0663c33SRoger Pau Monné 202b0663c33SRoger Pau Monné /* Now we can jump into the native init function */ 203b0663c33SRoger Pau Monné return (hammer_time(0, physfree)); 204b0663c33SRoger Pau Monné } 205b0663c33SRoger Pau Monné 20697baeefdSRoger Pau Monné /*-------------------------------- PV specific -------------------------------*/ 207079f7ef8SRoger Pau Monné 20897baeefdSRoger Pau Monné /* 209b0663c33SRoger Pau Monné * When booted as a PVH guest FreeBSD needs to avoid using the RSDP address 210b0663c33SRoger Pau Monné * hint provided by the loader because it points to the native set of ACPI 211b0663c33SRoger Pau Monné * tables instead of the ones crafted by Xen. The acpi.rsdp env variable is 212b0663c33SRoger Pau Monné * removed from kenv if present, and a new acpi.rsdp is added to kenv that 213b0663c33SRoger Pau Monné * points to the address of the Xen crafted RSDP. 21497baeefdSRoger Pau Monné */ 215b0663c33SRoger Pau Monné static bool reject_option(const char *option) 21697baeefdSRoger Pau Monné { 217b0663c33SRoger Pau Monné static const char *reject[] = { 218b0663c33SRoger Pau Monné "acpi.rsdp", 219b0663c33SRoger Pau Monné }; 220b0663c33SRoger Pau Monné unsigned int i; 22197baeefdSRoger Pau Monné 222b0663c33SRoger Pau Monné for (i = 0; i < nitems(reject); i++) 223b0663c33SRoger Pau Monné if (strncmp(option, reject[i], strlen(reject[i])) == 0) 224b0663c33SRoger Pau Monné return (true); 22597baeefdSRoger Pau Monné 226b0663c33SRoger Pau Monné return (false); 227b0663c33SRoger Pau Monné } 22897baeefdSRoger Pau Monné 229b0663c33SRoger Pau Monné static void 230b0663c33SRoger Pau Monné xen_pvh_set_env(char *env, bool (*filter)(const char *)) 231b0663c33SRoger Pau Monné { 232b0663c33SRoger Pau Monné char *option; 23397baeefdSRoger Pau Monné 234b0663c33SRoger Pau Monné if (env == NULL) 235b0663c33SRoger Pau Monné return; 236b0663c33SRoger Pau Monné 237b0663c33SRoger Pau Monné option = env; 238b0663c33SRoger Pau Monné while (*option != 0) { 239b0663c33SRoger Pau Monné char *value; 240b0663c33SRoger Pau Monné 241b0663c33SRoger Pau Monné if (filter != NULL && filter(option)) { 242b0663c33SRoger Pau Monné option += strlen(option) + 1; 243b0663c33SRoger Pau Monné continue; 244b0663c33SRoger Pau Monné } 245b0663c33SRoger Pau Monné 246b0663c33SRoger Pau Monné value = option; 247b0663c33SRoger Pau Monné option = strsep(&value, "="); 248b0663c33SRoger Pau Monné if (kern_setenv(option, value) != 0) 249b0663c33SRoger Pau Monné xc_printf("unable to add kenv %s=%s\n", option, value); 250b0663c33SRoger Pau Monné option = value + strlen(value) + 1; 251b0663c33SRoger Pau Monné } 25297baeefdSRoger Pau Monné } 25397baeefdSRoger Pau Monné 254c98a2727SRoger Pau Monné #ifdef DDB 255c98a2727SRoger Pau Monné /* 256c98a2727SRoger Pau Monné * The way Xen loads the symtab is different from the native boot loader, 257c98a2727SRoger Pau Monné * because it's tailored for NetBSD. So we have to adapt and use the same 258c98a2727SRoger Pau Monné * method as NetBSD. Portions of the code below have been picked from NetBSD: 259c98a2727SRoger Pau Monné * sys/kern/kern_ksyms.c CVS Revision 1.71. 260c98a2727SRoger Pau Monné */ 261c98a2727SRoger Pau Monné static void 262b0663c33SRoger Pau Monné xen_pvh_parse_symtab(void) 263c98a2727SRoger Pau Monné { 264c98a2727SRoger Pau Monné Elf_Ehdr *ehdr; 265c98a2727SRoger Pau Monné Elf_Shdr *shdr; 266c98a2727SRoger Pau Monné int i, j; 267c98a2727SRoger Pau Monné 268c98a2727SRoger Pau Monné ehdr = (Elf_Ehdr *)(&end + 1); 269c98a2727SRoger Pau Monné if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG) || 270c98a2727SRoger Pau Monné ehdr->e_ident[EI_CLASS] != ELF_TARG_CLASS || 271c98a2727SRoger Pau Monné ehdr->e_version > 1) { 272c98a2727SRoger Pau Monné xc_printf("Unable to load ELF symtab: invalid symbol table\n"); 273c98a2727SRoger Pau Monné return; 274c98a2727SRoger Pau Monné } 275c98a2727SRoger Pau Monné 276c98a2727SRoger Pau Monné shdr = (Elf_Shdr *)((uint8_t *)ehdr + ehdr->e_shoff); 277c98a2727SRoger Pau Monné /* Find the symbol table and the corresponding string table. */ 278c98a2727SRoger Pau Monné for (i = 1; i < ehdr->e_shnum; i++) { 279c98a2727SRoger Pau Monné if (shdr[i].sh_type != SHT_SYMTAB) 280c98a2727SRoger Pau Monné continue; 281c98a2727SRoger Pau Monné if (shdr[i].sh_offset == 0) 282c98a2727SRoger Pau Monné continue; 283c98a2727SRoger Pau Monné ksymtab = (uintptr_t)((uint8_t *)ehdr + shdr[i].sh_offset); 284c98a2727SRoger Pau Monné ksymtab_size = shdr[i].sh_size; 285c98a2727SRoger Pau Monné j = shdr[i].sh_link; 286c98a2727SRoger Pau Monné if (shdr[j].sh_offset == 0) 287c98a2727SRoger Pau Monné continue; /* Can this happen? */ 288c98a2727SRoger Pau Monné kstrtab = (uintptr_t)((uint8_t *)ehdr + shdr[j].sh_offset); 289c98a2727SRoger Pau Monné break; 290c98a2727SRoger Pau Monné } 291c98a2727SRoger Pau Monné 292b0663c33SRoger Pau Monné if (ksymtab == 0 || kstrtab == 0) 293c98a2727SRoger Pau Monné xc_printf( 294c98a2727SRoger Pau Monné "Unable to load ELF symtab: could not find symtab or strtab\n"); 295c98a2727SRoger Pau Monné } 296c98a2727SRoger Pau Monné #endif 297c98a2727SRoger Pau Monné 29897baeefdSRoger Pau Monné static caddr_t 299b0663c33SRoger Pau Monné xen_pvh_parse_preload_data(uint64_t modulep) 300b0663c33SRoger Pau Monné { 301b0663c33SRoger Pau Monné caddr_t kmdp; 302b0663c33SRoger Pau Monné vm_ooffset_t off; 303b0663c33SRoger Pau Monné vm_paddr_t metadata; 304b0663c33SRoger Pau Monné char *envp; 305b0663c33SRoger Pau Monné char acpi_rsdp[19]; 306b0663c33SRoger Pau Monné 307b0663c33SRoger Pau Monné if (start_info->modlist_paddr != 0) { 308b0663c33SRoger Pau Monné struct hvm_modlist_entry *mod; 309b6d85a5fSRoger Pau Monné const char *cmdline; 310b0663c33SRoger Pau Monné 311b0663c33SRoger Pau Monné mod = (struct hvm_modlist_entry *) 312b0663c33SRoger Pau Monné (start_info->modlist_paddr + KERNBASE); 313b6d85a5fSRoger Pau Monné cmdline = mod[0].cmdline_paddr ? 314b6d85a5fSRoger Pau Monné (const char *)(mod[0].cmdline_paddr + KERNBASE) : NULL; 315b6d85a5fSRoger Pau Monné 316b6d85a5fSRoger Pau Monné if (strcmp(cmdline, "header") == 0) { 317b6d85a5fSRoger Pau Monné struct xen_header *header; 318b6d85a5fSRoger Pau Monné 319b6d85a5fSRoger Pau Monné header = (struct xen_header *)(mod[0].paddr + KERNBASE); 320b6d85a5fSRoger Pau Monné 321b6d85a5fSRoger Pau Monné if ((header->flags & XENHEADER_HAS_MODULEP_OFFSET) != 322b6d85a5fSRoger Pau Monné XENHEADER_HAS_MODULEP_OFFSET) { 323b6d85a5fSRoger Pau Monné xc_printf("Unable to load module metadata\n"); 324b6d85a5fSRoger Pau Monné HYPERVISOR_shutdown(SHUTDOWN_crash); 325b6d85a5fSRoger Pau Monné } 326b6d85a5fSRoger Pau Monné 327b6d85a5fSRoger Pau Monné preload_metadata = (caddr_t)(mod[0].paddr + 328b6d85a5fSRoger Pau Monné header->modulep_offset + KERNBASE); 329b6d85a5fSRoger Pau Monné 330b6d85a5fSRoger Pau Monné kmdp = preload_search_by_type("elf kernel"); 331b6d85a5fSRoger Pau Monné if (kmdp == NULL) 332b6d85a5fSRoger Pau Monné kmdp = preload_search_by_type("elf64 kernel"); 333b6d85a5fSRoger Pau Monné if (kmdp == NULL) { 334b6d85a5fSRoger Pau Monné xc_printf("Unable to find kernel\n"); 335b6d85a5fSRoger Pau Monné HYPERVISOR_shutdown(SHUTDOWN_crash); 336b6d85a5fSRoger Pau Monné } 337b6d85a5fSRoger Pau Monné 338b6d85a5fSRoger Pau Monné /* 339b6d85a5fSRoger Pau Monné * Xen has relocated the metadata and the modules, so 340b6d85a5fSRoger Pau Monné * we need to recalculate it's position. This is done 341b6d85a5fSRoger Pau Monné * by saving the original modulep address and then 342b6d85a5fSRoger Pau Monné * calculating the offset from the real modulep 343b6d85a5fSRoger Pau Monné * position. 344b6d85a5fSRoger Pau Monné */ 345b6d85a5fSRoger Pau Monné metadata = MD_FETCH(kmdp, MODINFOMD_MODULEP, 346b6d85a5fSRoger Pau Monné vm_paddr_t); 347b6d85a5fSRoger Pau Monné off = mod[0].paddr + header->modulep_offset - metadata + 348b6d85a5fSRoger Pau Monné KERNBASE; 349b6d85a5fSRoger Pau Monné } else { 350b0663c33SRoger Pau Monné preload_metadata = (caddr_t)(mod[0].paddr + KERNBASE); 351b0663c33SRoger Pau Monné 352b0663c33SRoger Pau Monné kmdp = preload_search_by_type("elf kernel"); 353b0663c33SRoger Pau Monné if (kmdp == NULL) 354b0663c33SRoger Pau Monné kmdp = preload_search_by_type("elf64 kernel"); 355b6d85a5fSRoger Pau Monné if (kmdp == NULL) { 356b6d85a5fSRoger Pau Monné xc_printf("Unable to find kernel\n"); 357b6d85a5fSRoger Pau Monné HYPERVISOR_shutdown(SHUTDOWN_crash); 358b6d85a5fSRoger Pau Monné } 359b0663c33SRoger Pau Monné 360b0663c33SRoger Pau Monné metadata = MD_FETCH(kmdp, MODINFOMD_MODULEP, vm_paddr_t); 361b0663c33SRoger Pau Monné off = mod[0].paddr + KERNBASE - metadata; 362b6d85a5fSRoger Pau Monné } 363b0663c33SRoger Pau Monné 364b0663c33SRoger Pau Monné preload_bootstrap_relocate(off); 365b0663c33SRoger Pau Monné 366b0663c33SRoger Pau Monné boothowto = MD_FETCH(kmdp, MODINFOMD_HOWTO, int); 367b0663c33SRoger Pau Monné envp = MD_FETCH(kmdp, MODINFOMD_ENVP, char *); 368b0663c33SRoger Pau Monné if (envp != NULL) 369b0663c33SRoger Pau Monné envp += off; 370b0663c33SRoger Pau Monné xen_pvh_set_env(envp, reject_option); 371a2495c36SRoger Pau Monné 372a2495c36SRoger Pau Monné if (MD_FETCH(kmdp, MODINFOMD_EFI_MAP, void *) != NULL) 373a2495c36SRoger Pau Monné strlcpy(bootmethod, "UEFI", sizeof(bootmethod)); 374a2495c36SRoger Pau Monné else 375a2495c36SRoger Pau Monné strlcpy(bootmethod, "BIOS", sizeof(bootmethod)); 376b0663c33SRoger Pau Monné } else { 377b0663c33SRoger Pau Monné /* Parse the extra boot information given by Xen */ 378b0663c33SRoger Pau Monné if (start_info->cmdline_paddr != 0) 379b0663c33SRoger Pau Monné boot_parse_cmdline_delim( 380b0663c33SRoger Pau Monné (char *)(start_info->cmdline_paddr + KERNBASE), 381b0663c33SRoger Pau Monné ","); 382b0663c33SRoger Pau Monné kmdp = NULL; 383a2495c36SRoger Pau Monné strlcpy(bootmethod, "XEN", sizeof(bootmethod)); 384b0663c33SRoger Pau Monné } 385b0663c33SRoger Pau Monné 386b0663c33SRoger Pau Monné boothowto |= boot_env_to_howto(); 387b0663c33SRoger Pau Monné 388b0663c33SRoger Pau Monné snprintf(acpi_rsdp, sizeof(acpi_rsdp), "%#" PRIx64, 389b0663c33SRoger Pau Monné start_info->rsdp_paddr); 390b0663c33SRoger Pau Monné kern_setenv("acpi.rsdp", acpi_rsdp); 391b0663c33SRoger Pau Monné 392b0663c33SRoger Pau Monné #ifdef DDB 393b0663c33SRoger Pau Monné xen_pvh_parse_symtab(); 394c98a2727SRoger Pau Monné #endif 395ca49b334SRoger Pau Monné return (kmdp); 39697baeefdSRoger Pau Monné } 3971e69553eSRoger Pau Monné 3981e69553eSRoger Pau Monné static void 399*023a025bSColin Percival pvh_parse_memmap_start_info(caddr_t kmdp, vm_paddr_t *physmap, 400*023a025bSColin Percival int *physmap_idx) 401*023a025bSColin Percival { 402*023a025bSColin Percival const struct hvm_memmap_table_entry * entries; 403*023a025bSColin Percival size_t nentries; 404*023a025bSColin Percival size_t i; 405*023a025bSColin Percival 406*023a025bSColin Percival /* Extract from HVM start_info. */ 407*023a025bSColin Percival entries = (struct hvm_memmap_table_entry *)(start_info->memmap_paddr + KERNBASE); 408*023a025bSColin Percival nentries = start_info->memmap_entries; 409*023a025bSColin Percival 410*023a025bSColin Percival /* Convert into E820 format and handle one by one. */ 411*023a025bSColin Percival for (i = 0; i < nentries; i++) { 412*023a025bSColin Percival struct bios_smap entry; 413*023a025bSColin Percival 414*023a025bSColin Percival entry.base = entries[i].addr; 415*023a025bSColin Percival entry.length = entries[i].size; 416*023a025bSColin Percival 417*023a025bSColin Percival /* 418*023a025bSColin Percival * Luckily for us, the XEN_HVM_MEMMAP_TYPE_* values exactly 419*023a025bSColin Percival * match the SMAP_TYPE_* values so we don't need to translate 420*023a025bSColin Percival * anything here. 421*023a025bSColin Percival */ 422*023a025bSColin Percival entry.type = entries[i].type; 423*023a025bSColin Percival 424*023a025bSColin Percival bios_add_smap_entries(&entry, 1, physmap, physmap_idx); 425*023a025bSColin Percival } 426*023a025bSColin Percival } 427*023a025bSColin Percival 428*023a025bSColin Percival static void 429b0663c33SRoger Pau Monné xen_pvh_parse_memmap(caddr_t kmdp, vm_paddr_t *physmap, int *physmap_idx) 4301e69553eSRoger Pau Monné { 4311e69553eSRoger Pau Monné struct xen_memory_map memmap; 4321e69553eSRoger Pau Monné u_int32_t size; 4331e69553eSRoger Pau Monné int rc; 4341e69553eSRoger Pau Monné 4351e69553eSRoger Pau Monné /* Fetch the E820 map from Xen */ 4361e69553eSRoger Pau Monné memmap.nr_entries = MAX_E820_ENTRIES; 4371e69553eSRoger Pau Monné set_xen_guest_handle(memmap.buffer, xen_smap); 4381e69553eSRoger Pau Monné rc = HYPERVISOR_memory_op(XENMEM_memory_map, &memmap); 439b0663c33SRoger Pau Monné if (rc) { 440b0663c33SRoger Pau Monné xc_printf("ERROR: unable to fetch Xen E820 memory map: %d\n", 441b0663c33SRoger Pau Monné rc); 442b0663c33SRoger Pau Monné HYPERVISOR_shutdown(SHUTDOWN_crash); 443b0663c33SRoger Pau Monné } 444b0663c33SRoger Pau Monné 4451e69553eSRoger Pau Monné size = memmap.nr_entries * sizeof(xen_smap[0]); 4461e69553eSRoger Pau Monné 4471e69553eSRoger Pau Monné bios_add_smap_entries(xen_smap, size, physmap, physmap_idx); 4481e69553eSRoger Pau Monné } 449*023a025bSColin Percival 450*023a025bSColin Percival static void 451*023a025bSColin Percival pvh_parse_memmap(caddr_t kmdp, vm_paddr_t *physmap, int *physmap_idx) 452*023a025bSColin Percival { 453*023a025bSColin Percival 454*023a025bSColin Percival /* 455*023a025bSColin Percival * If version >= 1 and memmap_paddr != 0, use the memory map provided 456*023a025bSColin Percival * in the start_info structure; if not, we're running under legacy 457*023a025bSColin Percival * Xen and need to use the Xen hypercall. 458*023a025bSColin Percival */ 459*023a025bSColin Percival if ((start_info->version >= 1) && (start_info->memmap_paddr != 0)) 460*023a025bSColin Percival pvh_parse_memmap_start_info(kmdp, physmap, physmap_idx); 461*023a025bSColin Percival else 462*023a025bSColin Percival xen_pvh_parse_memmap(kmdp, physmap, physmap_idx); 463*023a025bSColin Percival } 464