11a9cdd37SRoger Pau Monné /* 21a9cdd37SRoger Pau Monné * Copyright (c) 2004 Christian Limpach. 31a9cdd37SRoger Pau Monné * Copyright (c) 2004-2006,2008 Kip Macy 41a9cdd37SRoger Pau Monné * Copyright (c) 2013 Roger Pau Monné <roger.pau@citrix.com> 51a9cdd37SRoger Pau Monné * All rights reserved. 61a9cdd37SRoger Pau Monné * 71a9cdd37SRoger Pau Monné * Redistribution and use in source and binary forms, with or without 81a9cdd37SRoger Pau Monné * modification, are permitted provided that the following conditions 91a9cdd37SRoger Pau Monné * are met: 101a9cdd37SRoger Pau Monné * 1. Redistributions of source code must retain the above copyright 111a9cdd37SRoger Pau Monné * notice, this list of conditions and the following disclaimer. 121a9cdd37SRoger Pau Monné * 2. Redistributions in binary form must reproduce the above copyright 131a9cdd37SRoger Pau Monné * notice, this list of conditions and the following disclaimer in the 141a9cdd37SRoger Pau Monné * documentation and/or other materials provided with the distribution. 151a9cdd37SRoger Pau Monné * 161a9cdd37SRoger Pau Monné * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS AS IS'' AND 171a9cdd37SRoger Pau Monné * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 181a9cdd37SRoger Pau Monné * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 191a9cdd37SRoger Pau Monné * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 201a9cdd37SRoger Pau Monné * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 211a9cdd37SRoger Pau Monné * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 221a9cdd37SRoger Pau Monné * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 231a9cdd37SRoger Pau Monné * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 241a9cdd37SRoger Pau Monné * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 251a9cdd37SRoger Pau Monné * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 261a9cdd37SRoger Pau Monné * SUCH DAMAGE. 271a9cdd37SRoger Pau Monné */ 281a9cdd37SRoger Pau Monné 291a9cdd37SRoger Pau Monné #include <sys/cdefs.h> 301a9cdd37SRoger Pau Monné __FBSDID("$FreeBSD$"); 311a9cdd37SRoger Pau Monné 321a9cdd37SRoger Pau Monné #include <sys/param.h> 331a9cdd37SRoger Pau Monné #include <sys/bus.h> 341a9cdd37SRoger Pau Monné #include <sys/kernel.h> 351a9cdd37SRoger Pau Monné #include <sys/reboot.h> 361a9cdd37SRoger Pau Monné #include <sys/systm.h> 37*079f7ef8SRoger Pau Monné #include <sys/malloc.h> 381a9cdd37SRoger Pau Monné #include <sys/lock.h> 391a9cdd37SRoger Pau Monné #include <sys/rwlock.h> 40aa389b4fSRoger Pau Monné #include <sys/boot.h> 4197baeefdSRoger Pau Monné #include <sys/ctype.h> 42*079f7ef8SRoger Pau Monné #include <sys/mutex.h> 43*079f7ef8SRoger Pau Monné #include <sys/smp.h> 441a9cdd37SRoger Pau Monné 451a9cdd37SRoger Pau Monné #include <vm/vm.h> 461a9cdd37SRoger Pau Monné #include <vm/vm_extern.h> 471a9cdd37SRoger Pau Monné #include <vm/vm_kern.h> 481a9cdd37SRoger Pau Monné #include <vm/vm_page.h> 491a9cdd37SRoger Pau Monné #include <vm/vm_map.h> 501a9cdd37SRoger Pau Monné #include <vm/vm_object.h> 511a9cdd37SRoger Pau Monné #include <vm/vm_pager.h> 521a9cdd37SRoger Pau Monné #include <vm/vm_param.h> 531a9cdd37SRoger Pau Monné 5497baeefdSRoger Pau Monné #include <x86/init.h> 551e69553eSRoger Pau Monné #include <machine/pc/bios.h> 56*079f7ef8SRoger Pau Monné #include <machine/smp.h> 5797baeefdSRoger Pau Monné 581a9cdd37SRoger Pau Monné #include <xen/xen-os.h> 591a9cdd37SRoger Pau Monné #include <xen/hypervisor.h> 601a9cdd37SRoger Pau Monné 61*079f7ef8SRoger Pau Monné #include <xen/interface/vcpu.h> 62*079f7ef8SRoger Pau Monné 635f05c794SRoger Pau Monné #include <dev/xen/timer/timer.h> 645f05c794SRoger Pau Monné 651a9cdd37SRoger Pau Monné /* Native initial function */ 661a9cdd37SRoger Pau Monné extern u_int64_t hammer_time(u_int64_t, u_int64_t); 671a9cdd37SRoger Pau Monné /* Xen initial function */ 681a9cdd37SRoger Pau Monné uint64_t hammer_time_xen(start_info_t *, uint64_t); 691a9cdd37SRoger Pau Monné 701e69553eSRoger Pau Monné #define MAX_E820_ENTRIES 128 711e69553eSRoger Pau Monné 7297baeefdSRoger Pau Monné /*--------------------------- Forward Declarations ---------------------------*/ 7397baeefdSRoger Pau Monné static caddr_t xen_pv_parse_preload_data(u_int64_t); 741e69553eSRoger Pau Monné static void xen_pv_parse_memmap(caddr_t, vm_paddr_t *, int *); 7597baeefdSRoger Pau Monné 76*079f7ef8SRoger Pau Monné #ifdef SMP 77*079f7ef8SRoger Pau Monné static int xen_pv_start_all_aps(void); 78*079f7ef8SRoger Pau Monné #endif 79*079f7ef8SRoger Pau Monné 80*079f7ef8SRoger Pau Monné /*---------------------------- Extern Declarations ---------------------------*/ 81*079f7ef8SRoger Pau Monné #ifdef SMP 82*079f7ef8SRoger Pau Monné /* Variables used by amd64 mp_machdep to start APs */ 83*079f7ef8SRoger Pau Monné extern struct mtx ap_boot_mtx; 84*079f7ef8SRoger Pau Monné extern void *bootstacks[]; 85*079f7ef8SRoger Pau Monné extern char *doublefault_stack; 86*079f7ef8SRoger Pau Monné extern char *nmi_stack; 87*079f7ef8SRoger Pau Monné extern void *dpcpu; 88*079f7ef8SRoger Pau Monné extern int bootAP; 89*079f7ef8SRoger Pau Monné extern char *bootSTK; 90*079f7ef8SRoger Pau Monné #endif 91*079f7ef8SRoger Pau Monné 9297baeefdSRoger Pau Monné /*-------------------------------- Global Data -------------------------------*/ 9397baeefdSRoger Pau Monné /* Xen init_ops implementation. */ 9497baeefdSRoger Pau Monné struct init_ops xen_init_ops = { 9597baeefdSRoger Pau Monné .parse_preload_data = xen_pv_parse_preload_data, 965f05c794SRoger Pau Monné .early_clock_source_init = xen_clock_init, 975f05c794SRoger Pau Monné .early_delay = xen_delay, 981e69553eSRoger Pau Monné .parse_memmap = xen_pv_parse_memmap, 99*079f7ef8SRoger Pau Monné #ifdef SMP 100*079f7ef8SRoger Pau Monné .start_all_aps = xen_pv_start_all_aps, 101*079f7ef8SRoger Pau Monné #endif 10297baeefdSRoger Pau Monné }; 10397baeefdSRoger Pau Monné 1041e69553eSRoger Pau Monné static struct bios_smap xen_smap[MAX_E820_ENTRIES]; 1051e69553eSRoger Pau Monné 10697baeefdSRoger Pau Monné /*-------------------------------- Xen PV init -------------------------------*/ 1071a9cdd37SRoger Pau Monné /* 1081a9cdd37SRoger Pau Monné * First function called by the Xen PVH boot sequence. 1091a9cdd37SRoger Pau Monné * 1101a9cdd37SRoger Pau Monné * Set some Xen global variables and prepare the environment so it is 1111a9cdd37SRoger Pau Monné * as similar as possible to what native FreeBSD init function expects. 1121a9cdd37SRoger Pau Monné */ 1131a9cdd37SRoger Pau Monné uint64_t 1141a9cdd37SRoger Pau Monné hammer_time_xen(start_info_t *si, uint64_t xenstack) 1151a9cdd37SRoger Pau Monné { 1161a9cdd37SRoger Pau Monné uint64_t physfree; 1171a9cdd37SRoger Pau Monné uint64_t *PT4 = (u_int64_t *)xenstack; 1181a9cdd37SRoger Pau Monné uint64_t *PT3 = (u_int64_t *)(xenstack + PAGE_SIZE); 1191a9cdd37SRoger Pau Monné uint64_t *PT2 = (u_int64_t *)(xenstack + 2 * PAGE_SIZE); 1201a9cdd37SRoger Pau Monné int i; 1211a9cdd37SRoger Pau Monné 1221a9cdd37SRoger Pau Monné xen_domain_type = XEN_PV_DOMAIN; 1231a9cdd37SRoger Pau Monné vm_guest = VM_GUEST_XEN; 1241a9cdd37SRoger Pau Monné 1251a9cdd37SRoger Pau Monné if ((si == NULL) || (xenstack == 0)) { 126c203fa69SRoger Pau Monné xc_printf("ERROR: invalid start_info or xen stack, halting\n"); 1271a9cdd37SRoger Pau Monné HYPERVISOR_shutdown(SHUTDOWN_crash); 1281a9cdd37SRoger Pau Monné } 1291a9cdd37SRoger Pau Monné 130c203fa69SRoger Pau Monné xc_printf("FreeBSD PVH running on %s\n", si->magic); 131c203fa69SRoger Pau Monné 1321a9cdd37SRoger Pau Monné /* We use 3 pages of xen stack for the boot pagetables */ 1331a9cdd37SRoger Pau Monné physfree = xenstack + 3 * PAGE_SIZE - KERNBASE; 1341a9cdd37SRoger Pau Monné 1351a9cdd37SRoger Pau Monné /* Setup Xen global variables */ 1361a9cdd37SRoger Pau Monné HYPERVISOR_start_info = si; 1371a9cdd37SRoger Pau Monné HYPERVISOR_shared_info = 1381a9cdd37SRoger Pau Monné (shared_info_t *)(si->shared_info + KERNBASE); 1391a9cdd37SRoger Pau Monné 1401a9cdd37SRoger Pau Monné /* 1411a9cdd37SRoger Pau Monné * Setup some misc global variables for Xen devices 1421a9cdd37SRoger Pau Monné * 1431a9cdd37SRoger Pau Monné * XXX: Devices that need these specific variables should 1441a9cdd37SRoger Pau Monné * be rewritten to fetch this info by themselves from the 1451a9cdd37SRoger Pau Monné * start_info page. 1461a9cdd37SRoger Pau Monné */ 1471a9cdd37SRoger Pau Monné xen_store = (struct xenstore_domain_interface *) 1481a9cdd37SRoger Pau Monné (ptoa(si->store_mfn) + KERNBASE); 149c203fa69SRoger Pau Monné console_page = (char *)(ptoa(si->console.domU.mfn) + KERNBASE); 1501a9cdd37SRoger Pau Monné 1511a9cdd37SRoger Pau Monné /* 1521a9cdd37SRoger Pau Monné * Use the stack Xen gives us to build the page tables 1531a9cdd37SRoger Pau Monné * as native FreeBSD expects to find them (created 1541a9cdd37SRoger Pau Monné * by the boot trampoline). 1551a9cdd37SRoger Pau Monné */ 1561a9cdd37SRoger Pau Monné for (i = 0; i < (PAGE_SIZE / sizeof(uint64_t)); i++) { 1571a9cdd37SRoger Pau Monné /* Each slot of the level 4 pages points to the same level 3 page */ 1581a9cdd37SRoger Pau Monné PT4[i] = ((uint64_t)&PT3[0]) - KERNBASE; 1591a9cdd37SRoger Pau Monné PT4[i] |= PG_V | PG_RW | PG_U; 1601a9cdd37SRoger Pau Monné 1611a9cdd37SRoger Pau Monné /* Each slot of the level 3 pages points to the same level 2 page */ 1621a9cdd37SRoger Pau Monné PT3[i] = ((uint64_t)&PT2[0]) - KERNBASE; 1631a9cdd37SRoger Pau Monné PT3[i] |= PG_V | PG_RW | PG_U; 1641a9cdd37SRoger Pau Monné 1651a9cdd37SRoger Pau Monné /* The level 2 page slots are mapped with 2MB pages for 1GB. */ 1661a9cdd37SRoger Pau Monné PT2[i] = i * (2 * 1024 * 1024); 1671a9cdd37SRoger Pau Monné PT2[i] |= PG_V | PG_RW | PG_PS | PG_U; 1681a9cdd37SRoger Pau Monné } 1691a9cdd37SRoger Pau Monné load_cr3(((uint64_t)&PT4[0]) - KERNBASE); 1701a9cdd37SRoger Pau Monné 17197baeefdSRoger Pau Monné /* Set the hooks for early functions that diverge from bare metal */ 17297baeefdSRoger Pau Monné init_ops = xen_init_ops; 17397baeefdSRoger Pau Monné 1741a9cdd37SRoger Pau Monné /* Now we can jump into the native init function */ 1751a9cdd37SRoger Pau Monné return (hammer_time(0, physfree)); 1761a9cdd37SRoger Pau Monné } 17797baeefdSRoger Pau Monné 17897baeefdSRoger Pau Monné /*-------------------------------- PV specific -------------------------------*/ 179*079f7ef8SRoger Pau Monné #ifdef SMP 180*079f7ef8SRoger Pau Monné static bool 181*079f7ef8SRoger Pau Monné start_xen_ap(int cpu) 182*079f7ef8SRoger Pau Monné { 183*079f7ef8SRoger Pau Monné struct vcpu_guest_context *ctxt; 184*079f7ef8SRoger Pau Monné int ms, cpus = mp_naps; 185*079f7ef8SRoger Pau Monné const size_t stacksize = KSTACK_PAGES * PAGE_SIZE; 186*079f7ef8SRoger Pau Monné 187*079f7ef8SRoger Pau Monné /* allocate and set up an idle stack data page */ 188*079f7ef8SRoger Pau Monné bootstacks[cpu] = 189*079f7ef8SRoger Pau Monné (void *)kmem_malloc(kernel_arena, stacksize, M_WAITOK | M_ZERO); 190*079f7ef8SRoger Pau Monné doublefault_stack = 191*079f7ef8SRoger Pau Monné (char *)kmem_malloc(kernel_arena, PAGE_SIZE, M_WAITOK | M_ZERO); 192*079f7ef8SRoger Pau Monné nmi_stack = 193*079f7ef8SRoger Pau Monné (char *)kmem_malloc(kernel_arena, PAGE_SIZE, M_WAITOK | M_ZERO); 194*079f7ef8SRoger Pau Monné dpcpu = 195*079f7ef8SRoger Pau Monné (void *)kmem_malloc(kernel_arena, DPCPU_SIZE, M_WAITOK | M_ZERO); 196*079f7ef8SRoger Pau Monné 197*079f7ef8SRoger Pau Monné bootSTK = (char *)bootstacks[cpu] + KSTACK_PAGES * PAGE_SIZE - 8; 198*079f7ef8SRoger Pau Monné bootAP = cpu; 199*079f7ef8SRoger Pau Monné 200*079f7ef8SRoger Pau Monné ctxt = malloc(sizeof(*ctxt), M_TEMP, M_WAITOK | M_ZERO); 201*079f7ef8SRoger Pau Monné if (ctxt == NULL) 202*079f7ef8SRoger Pau Monné panic("unable to allocate memory"); 203*079f7ef8SRoger Pau Monné 204*079f7ef8SRoger Pau Monné ctxt->flags = VGCF_IN_KERNEL; 205*079f7ef8SRoger Pau Monné ctxt->user_regs.rip = (unsigned long) init_secondary; 206*079f7ef8SRoger Pau Monné ctxt->user_regs.rsp = (unsigned long) bootSTK; 207*079f7ef8SRoger Pau Monné 208*079f7ef8SRoger Pau Monné /* Set the AP to use the same page tables */ 209*079f7ef8SRoger Pau Monné ctxt->ctrlreg[3] = KPML4phys; 210*079f7ef8SRoger Pau Monné 211*079f7ef8SRoger Pau Monné if (HYPERVISOR_vcpu_op(VCPUOP_initialise, cpu, ctxt)) 212*079f7ef8SRoger Pau Monné panic("unable to initialize AP#%d", cpu); 213*079f7ef8SRoger Pau Monné 214*079f7ef8SRoger Pau Monné free(ctxt, M_TEMP); 215*079f7ef8SRoger Pau Monné 216*079f7ef8SRoger Pau Monné /* Launch the vCPU */ 217*079f7ef8SRoger Pau Monné if (HYPERVISOR_vcpu_op(VCPUOP_up, cpu, NULL)) 218*079f7ef8SRoger Pau Monné panic("unable to start AP#%d", cpu); 219*079f7ef8SRoger Pau Monné 220*079f7ef8SRoger Pau Monné /* Wait up to 5 seconds for it to start. */ 221*079f7ef8SRoger Pau Monné for (ms = 0; ms < 5000; ms++) { 222*079f7ef8SRoger Pau Monné if (mp_naps > cpus) 223*079f7ef8SRoger Pau Monné return (true); 224*079f7ef8SRoger Pau Monné DELAY(1000); 225*079f7ef8SRoger Pau Monné } 226*079f7ef8SRoger Pau Monné 227*079f7ef8SRoger Pau Monné return (false); 228*079f7ef8SRoger Pau Monné } 229*079f7ef8SRoger Pau Monné 230*079f7ef8SRoger Pau Monné static int 231*079f7ef8SRoger Pau Monné xen_pv_start_all_aps(void) 232*079f7ef8SRoger Pau Monné { 233*079f7ef8SRoger Pau Monné int cpu; 234*079f7ef8SRoger Pau Monné 235*079f7ef8SRoger Pau Monné mtx_init(&ap_boot_mtx, "ap boot", NULL, MTX_SPIN); 236*079f7ef8SRoger Pau Monné 237*079f7ef8SRoger Pau Monné for (cpu = 1; cpu < mp_ncpus; cpu++) { 238*079f7ef8SRoger Pau Monné 239*079f7ef8SRoger Pau Monné /* attempt to start the Application Processor */ 240*079f7ef8SRoger Pau Monné if (!start_xen_ap(cpu)) 241*079f7ef8SRoger Pau Monné panic("AP #%d failed to start!", cpu); 242*079f7ef8SRoger Pau Monné 243*079f7ef8SRoger Pau Monné CPU_SET(cpu, &all_cpus); /* record AP in CPU map */ 244*079f7ef8SRoger Pau Monné } 245*079f7ef8SRoger Pau Monné 246*079f7ef8SRoger Pau Monné return (mp_naps); 247*079f7ef8SRoger Pau Monné } 248*079f7ef8SRoger Pau Monné #endif /* SMP */ 249*079f7ef8SRoger Pau Monné 25097baeefdSRoger Pau Monné /* 25197baeefdSRoger Pau Monné * Functions to convert the "extra" parameters passed by Xen 25297baeefdSRoger Pau Monné * into FreeBSD boot options. 25397baeefdSRoger Pau Monné */ 25497baeefdSRoger Pau Monné static void 25597baeefdSRoger Pau Monné xen_pv_set_env(void) 25697baeefdSRoger Pau Monné { 25797baeefdSRoger Pau Monné char *cmd_line_next, *cmd_line; 25897baeefdSRoger Pau Monné size_t env_size; 25997baeefdSRoger Pau Monné 26097baeefdSRoger Pau Monné cmd_line = HYPERVISOR_start_info->cmd_line; 26197baeefdSRoger Pau Monné env_size = sizeof(HYPERVISOR_start_info->cmd_line); 26297baeefdSRoger Pau Monné 26397baeefdSRoger Pau Monné /* Skip leading spaces */ 26497baeefdSRoger Pau Monné for (; isspace(*cmd_line) && (env_size != 0); cmd_line++) 26597baeefdSRoger Pau Monné env_size--; 26697baeefdSRoger Pau Monné 26797baeefdSRoger Pau Monné /* Replace ',' with '\0' */ 26897baeefdSRoger Pau Monné for (cmd_line_next = cmd_line; strsep(&cmd_line_next, ",") != NULL;) 26997baeefdSRoger Pau Monné ; 27097baeefdSRoger Pau Monné 27197baeefdSRoger Pau Monné init_static_kenv(cmd_line, env_size); 27297baeefdSRoger Pau Monné } 27397baeefdSRoger Pau Monné 27497baeefdSRoger Pau Monné static void 27597baeefdSRoger Pau Monné xen_pv_set_boothowto(void) 27697baeefdSRoger Pau Monné { 27797baeefdSRoger Pau Monné int i; 27897baeefdSRoger Pau Monné 27997baeefdSRoger Pau Monné /* get equivalents from the environment */ 28097baeefdSRoger Pau Monné for (i = 0; howto_names[i].ev != NULL; i++) { 28197baeefdSRoger Pau Monné if (getenv(howto_names[i].ev) != NULL) 28297baeefdSRoger Pau Monné boothowto |= howto_names[i].mask; 28397baeefdSRoger Pau Monné } 28497baeefdSRoger Pau Monné } 28597baeefdSRoger Pau Monné 28697baeefdSRoger Pau Monné static caddr_t 28797baeefdSRoger Pau Monné xen_pv_parse_preload_data(u_int64_t modulep) 28897baeefdSRoger Pau Monné { 28997baeefdSRoger Pau Monné /* Parse the extra boot information given by Xen */ 29097baeefdSRoger Pau Monné xen_pv_set_env(); 29197baeefdSRoger Pau Monné xen_pv_set_boothowto(); 29297baeefdSRoger Pau Monné 29397baeefdSRoger Pau Monné return (NULL); 29497baeefdSRoger Pau Monné } 2951e69553eSRoger Pau Monné 2961e69553eSRoger Pau Monné static void 2971e69553eSRoger Pau Monné xen_pv_parse_memmap(caddr_t kmdp, vm_paddr_t *physmap, int *physmap_idx) 2981e69553eSRoger Pau Monné { 2991e69553eSRoger Pau Monné struct xen_memory_map memmap; 3001e69553eSRoger Pau Monné u_int32_t size; 3011e69553eSRoger Pau Monné int rc; 3021e69553eSRoger Pau Monné 3031e69553eSRoger Pau Monné /* Fetch the E820 map from Xen */ 3041e69553eSRoger Pau Monné memmap.nr_entries = MAX_E820_ENTRIES; 3051e69553eSRoger Pau Monné set_xen_guest_handle(memmap.buffer, xen_smap); 3061e69553eSRoger Pau Monné rc = HYPERVISOR_memory_op(XENMEM_memory_map, &memmap); 3071e69553eSRoger Pau Monné if (rc) 3081e69553eSRoger Pau Monné panic("unable to fetch Xen E820 memory map"); 3091e69553eSRoger Pau Monné size = memmap.nr_entries * sizeof(xen_smap[0]); 3101e69553eSRoger Pau Monné 3111e69553eSRoger Pau Monné bios_add_smap_entries(xen_smap, size, physmap, physmap_idx); 3121e69553eSRoger Pau Monné } 313