1 /*-
   2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
   3  *
   4  * Copyright (c) 2012 NetApp, Inc.
   5  * All rights reserved.
   6  *
   7  * Redistribution and use in source and binary forms, with or without
   8  * modification, are permitted provided that the following conditions
   9  * are met:
  10  * 1. Redistributions of source code must retain the above copyright
  11  *    notice, this list of conditions and the following disclaimer.
  12  * 2. Redistributions in binary form must reproduce the above copyright
  13  *    notice, this list of conditions and the following disclaimer in the
  14  *    documentation and/or other materials provided with the distribution.
  15  *
  16  * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND
  17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  19  * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE
  20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  26  * SUCH DAMAGE.
  27  *
  28  * $FreeBSD$
  29  */
  30 /*
  31  * This file and its contents are supplied under the terms of the
  32  * Common Development and Distribution License ("CDDL"), version 1.0.
  33  * You may only use this file in accordance with the terms of version
  34  * 1.0 of the CDDL.
  35  *
  36  * A full copy of the text of the CDDL should have accompanied this
  37  * source.  A copy of the CDDL is also available via the Internet at
  38  * http://www.illumos.org/license/CDDL.
  39  *
  40  * Copyright 2020 Oxide Computer Company
  41  */
  42 
  43 #include <sys/cdefs.h>
  44 __FBSDID("$FreeBSD$");
  45 
  46 #include <sys/param.h>
  47 #include <sys/types.h>
  48 
  49 #include <machine/vmm.h>
  50 #include <vmmapi.h>
  51 
  52 #include <stdio.h>
  53 #include <stdlib.h>
  54 #include <assert.h>
  55 
  56 #include "bhyverun.h"
  57 #include "spinup_ap.h"
  58 
  59 #ifdef __FreeBSD__
  60 static void
  61 spinup_ap_realmode(struct vmctx *ctx, int newcpu, uint64_t *rip)
  62 {
  63         int vector, error;
  64         uint16_t cs;
  65         uint64_t desc_base;
  66         uint32_t desc_limit, desc_access;
  67 
  68         vector = *rip >> PAGE_SHIFT;
  69         *rip = 0;
  70 
  71         /*
  72          * Update the %cs and %rip of the guest so that it starts
  73          * executing real mode code at at 'vector << 12'.
  74          */
  75         error = vm_set_register(ctx, newcpu, VM_REG_GUEST_RIP, *rip);
  76         assert(error == 0);
  77 
  78         error = vm_get_desc(ctx, newcpu, VM_REG_GUEST_CS, &desc_base,
  79                             &desc_limit, &desc_access);
  80         assert(error == 0);
  81 
  82         desc_base = vector << PAGE_SHIFT;
  83         error = vm_set_desc(ctx, newcpu, VM_REG_GUEST_CS,
  84                             desc_base, desc_limit, desc_access);
  85         assert(error == 0);
  86 
  87         cs = (vector << PAGE_SHIFT) >> 4;
  88         error = vm_set_register(ctx, newcpu, VM_REG_GUEST_CS, cs);
  89         assert(error == 0);
  90 }
  91 
  92 int
  93 spinup_ap(struct vmctx *ctx, int vcpu, int newcpu, uint64_t rip)
  94 {
  95         int error;
  96 
  97         assert(newcpu != 0);
  98         assert(newcpu < guest_ncpus);
  99 
 100         error = vcpu_reset(ctx, newcpu);
 101         assert(error == 0);
 102 
 103         fbsdrun_set_capabilities(ctx, newcpu);
 104 
 105         /*
 106          * Enable the 'unrestricted guest' mode for 'newcpu'.
 107          *
 108          * Set up the processor state in power-on 16-bit mode, with the CS:IP
 109          * init'd to the specified low-mem 4K page.
 110          */
 111         error = vm_set_capability(ctx, newcpu, VM_CAP_UNRESTRICTED_GUEST, 1);
 112         assert(error == 0);
 113 
 114         spinup_ap_realmode(ctx, newcpu, &rip);
 115 
 116         fbsdrun_addcpu(ctx, vcpu, newcpu, rip);
 117 
 118         return (newcpu);
 119 }
 120 #else /* __FreeBSD__ */
 121 void
 122 spinup_halted_ap(struct vmctx *ctx, int newcpu)
 123 {
 124         int error;
 125 
 126         assert(newcpu != 0);
 127         assert(newcpu < guest_ncpus);
 128 
 129         error = vcpu_reset(ctx, newcpu);
 130         assert(error == 0);
 131 
 132         fbsdrun_set_capabilities(ctx, newcpu);
 133 
 134         error = vm_set_run_state(ctx, newcpu, VRS_HALT, 0);
 135         assert(error == 0);
 136 
 137         fbsdrun_addcpu(ctx, newcpu, 0, false);
 138 }
 139 #endif /* __FreeBSD__ */