[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] [xen master] x86: introduce CONFIG_GUEST and move code
commit ca363f186d6f2d43ba1b9e335284feb9d6d9fd79 Author: Wei Liu <liuwe@xxxxxxxxxxxxx> AuthorDate: Thu Sep 19 13:22:05 2019 +0100 Commit: Wei Liu <wl@xxxxxxx> CommitDate: Wed Dec 4 10:31:25 2019 +0000 x86: introduce CONFIG_GUEST and move code Xen is able to run as a guest on Xen. We plan to make it able to run on Hyper-V as well. Introduce CONFIG_GUEST which is set to true if either running on Xen or Hyper-V is desired. Restructure code hierarchy for new code to come. No functional change intended. Signed-off-by: Wei Liu <liuwe@xxxxxxxxxxxxx> Reviewed-by: Roger Pau Monné <roger.pau@xxxxxxxxxx> Acked-by: Jan Beulich <jbeulich@xxxxxxxx> --- xen/arch/x86/Kconfig | 7 +- xen/arch/x86/Makefile | 2 +- xen/arch/x86/guest/Makefile | 5 +- xen/arch/x86/guest/hypercall_page.S | 78 -------- xen/arch/x86/guest/pvh-boot.c | 151 -------------- xen/arch/x86/guest/xen.c | 342 -------------------------------- xen/arch/x86/guest/xen/Makefile | 4 + xen/arch/x86/guest/xen/hypercall_page.S | 78 ++++++++ xen/arch/x86/guest/xen/pvh-boot.c | 151 ++++++++++++++ xen/arch/x86/guest/xen/xen.c | 342 ++++++++++++++++++++++++++++++++ 10 files changed, 582 insertions(+), 578 deletions(-) diff --git a/xen/arch/x86/Kconfig b/xen/arch/x86/Kconfig index 28b3b4692a..18c8f6fd26 100644 --- a/xen/arch/x86/Kconfig +++ b/xen/arch/x86/Kconfig @@ -161,9 +161,12 @@ config XEN_ALIGN_2M endchoice +config GUEST + bool + config XEN_GUEST - def_bool n - prompt "Xen Guest" + bool "Xen Guest" + select GUEST ---help--- Support for Xen detecting when it is running under Xen. diff --git a/xen/arch/x86/Makefile b/xen/arch/x86/Makefile index a0b2f4ab15..7da5a2631e 100644 --- a/xen/arch/x86/Makefile +++ b/xen/arch/x86/Makefile @@ -1,7 +1,7 @@ subdir-y += acpi subdir-y += cpu subdir-y += genapic -subdir-$(CONFIG_XEN_GUEST) += guest +subdir-$(CONFIG_GUEST) += guest subdir-$(CONFIG_HVM) += hvm subdir-y += mm subdir-$(CONFIG_XENOPROF) += oprofile diff --git a/xen/arch/x86/guest/Makefile b/xen/arch/x86/guest/Makefile index 26fb4b1007..6806f04947 100644 --- a/xen/arch/x86/guest/Makefile +++ b/xen/arch/x86/guest/Makefile @@ -1,4 +1 @@ -obj-y += hypercall_page.o -obj-y += xen.o - -obj-bin-$(CONFIG_PVH_GUEST) += pvh-boot.init.o +subdir-$(CONFIG_XEN_GUEST) += xen diff --git a/xen/arch/x86/guest/hypercall_page.S b/xen/arch/x86/guest/hypercall_page.S deleted file mode 100644 index 6485e9150e..0000000000 --- a/xen/arch/x86/guest/hypercall_page.S +++ /dev/null @@ -1,78 +0,0 @@ -#include <asm/page.h> -#include <asm/asm_defns.h> -#include <public/xen.h> - - .section ".text.page_aligned", "ax", @progbits - .p2align PAGE_SHIFT - -GLOBAL(hypercall_page) - /* Poisoned with `ret` for safety before hypercalls are set up. */ - .fill PAGE_SIZE, 1, 0xc3 - .type hypercall_page, STT_OBJECT - .size hypercall_page, PAGE_SIZE - -/* - * Identify a specific hypercall in the hypercall page - * @param name Hypercall name. - */ -#define DECLARE_HYPERCALL(name) \ - .globl HYPERCALL_ ## name; \ - .set HYPERCALL_ ## name, hypercall_page + __HYPERVISOR_ ## name * 32; \ - .type HYPERCALL_ ## name, STT_FUNC; \ - .size HYPERCALL_ ## name, 32 - -DECLARE_HYPERCALL(set_trap_table) -DECLARE_HYPERCALL(mmu_update) -DECLARE_HYPERCALL(set_gdt) -DECLARE_HYPERCALL(stack_switch) -DECLARE_HYPERCALL(set_callbacks) -DECLARE_HYPERCALL(fpu_taskswitch) -DECLARE_HYPERCALL(sched_op_compat) -DECLARE_HYPERCALL(platform_op) -DECLARE_HYPERCALL(set_debugreg) -DECLARE_HYPERCALL(get_debugreg) -DECLARE_HYPERCALL(update_descriptor) -DECLARE_HYPERCALL(memory_op) -DECLARE_HYPERCALL(multicall) -DECLARE_HYPERCALL(update_va_mapping) -DECLARE_HYPERCALL(set_timer_op) -DECLARE_HYPERCALL(event_channel_op_compat) -DECLARE_HYPERCALL(xen_version) -DECLARE_HYPERCALL(console_io) -DECLARE_HYPERCALL(physdev_op_compat) -DECLARE_HYPERCALL(grant_table_op) -DECLARE_HYPERCALL(vm_assist) -DECLARE_HYPERCALL(update_va_mapping_otherdomain) -DECLARE_HYPERCALL(iret) -DECLARE_HYPERCALL(vcpu_op) -DECLARE_HYPERCALL(set_segment_base) -DECLARE_HYPERCALL(mmuext_op) -DECLARE_HYPERCALL(xsm_op) -DECLARE_HYPERCALL(nmi_op) -DECLARE_HYPERCALL(sched_op) -DECLARE_HYPERCALL(callback_op) -DECLARE_HYPERCALL(xenoprof_op) -DECLARE_HYPERCALL(event_channel_op) -DECLARE_HYPERCALL(physdev_op) -DECLARE_HYPERCALL(hvm_op) -DECLARE_HYPERCALL(sysctl) -DECLARE_HYPERCALL(domctl) -DECLARE_HYPERCALL(kexec_op) -DECLARE_HYPERCALL(argo_op) -DECLARE_HYPERCALL(xenpmu_op) - -DECLARE_HYPERCALL(arch_0) -DECLARE_HYPERCALL(arch_1) -DECLARE_HYPERCALL(arch_2) -DECLARE_HYPERCALL(arch_3) -DECLARE_HYPERCALL(arch_4) -DECLARE_HYPERCALL(arch_5) -DECLARE_HYPERCALL(arch_6) -DECLARE_HYPERCALL(arch_7) - -/* - * Local variables: - * tab-width: 8 - * indent-tabs-mode: nil - * End: - */ diff --git a/xen/arch/x86/guest/pvh-boot.c b/xen/arch/x86/guest/pvh-boot.c deleted file mode 100644 index ca8e156f7d..0000000000 --- a/xen/arch/x86/guest/pvh-boot.c +++ /dev/null @@ -1,151 +0,0 @@ -/****************************************************************************** - * arch/x86/guest/pvh-boot.c - * - * PVH boot time support - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; If not, see <http://www.gnu.org/licenses/>. - * - * Copyright (c) 2017 Citrix Systems Ltd. - */ -#include <xen/init.h> -#include <xen/lib.h> -#include <xen/mm.h> - -#include <asm/e820.h> -#include <asm/guest.h> - -#include <public/arch-x86/hvm/start_info.h> - -/* Initialised in head.S, before .bss is zeroed. */ -bool __initdata pvh_boot; -uint32_t __initdata pvh_start_info_pa; - -static multiboot_info_t __initdata pvh_mbi; -static module_t __initdata pvh_mbi_mods[8]; -static const char *__initdata pvh_loader = "PVH Directboot"; - -static void __init convert_pvh_info(multiboot_info_t **mbi, - module_t **mod) -{ - const struct hvm_start_info *pvh_info = __va(pvh_start_info_pa); - const struct hvm_modlist_entry *entry; - unsigned int i; - - if ( pvh_info->magic != XEN_HVM_START_MAGIC_VALUE ) - panic("Magic value is wrong: %x\n", pvh_info->magic); - - /* - * Temporary module array needs to be at least one element bigger than - * required. The extra element is used to aid relocation. See - * arch/x86/setup.c:__start_xen(). - */ - if ( ARRAY_SIZE(pvh_mbi_mods) <= pvh_info->nr_modules ) - panic("The module array is too small, size %zu, requested %u\n", - ARRAY_SIZE(pvh_mbi_mods), pvh_info->nr_modules); - - /* - * Turn hvm_start_info into mbi. Luckily all modules are placed under 4GB - * boundary on x86. - */ - pvh_mbi.flags = MBI_CMDLINE | MBI_MODULES | MBI_LOADERNAME; - - BUG_ON(pvh_info->cmdline_paddr >> 32); - pvh_mbi.cmdline = pvh_info->cmdline_paddr; - pvh_mbi.boot_loader_name = __pa(pvh_loader); - - BUG_ON(pvh_info->nr_modules >= ARRAY_SIZE(pvh_mbi_mods)); - pvh_mbi.mods_count = pvh_info->nr_modules; - pvh_mbi.mods_addr = __pa(pvh_mbi_mods); - - entry = __va(pvh_info->modlist_paddr); - for ( i = 0; i < pvh_info->nr_modules; i++ ) - { - BUG_ON(entry[i].paddr >> 32); - BUG_ON(entry[i].cmdline_paddr >> 32); - - pvh_mbi_mods[i].mod_start = entry[i].paddr; - pvh_mbi_mods[i].mod_end = entry[i].paddr + entry[i].size; - pvh_mbi_mods[i].string = entry[i].cmdline_paddr; - } - - rsdp_hint = pvh_info->rsdp_paddr; - - *mbi = &pvh_mbi; - *mod = pvh_mbi_mods; -} - -static void __init get_memory_map(void) -{ - struct xen_memory_map memmap = { - .nr_entries = E820MAX, - }; - - set_xen_guest_handle(memmap.buffer, e820_raw.map); - BUG_ON(xen_hypercall_memory_op(XENMEM_memory_map, &memmap)); - e820_raw.nr_map = memmap.nr_entries; - - /* :( Various toolstacks don't sort the memory map. */ - sanitize_e820_map(e820_raw.map, &e820_raw.nr_map); -} - -void __init pvh_init(multiboot_info_t **mbi, module_t **mod) -{ - convert_pvh_info(mbi, mod); - - probe_hypervisor(); - ASSERT(xen_guest); - - get_memory_map(); -} - -void __init pvh_print_info(void) -{ - const struct hvm_start_info *pvh_info = __va(pvh_start_info_pa); - const struct hvm_modlist_entry *entry; - unsigned int i; - - ASSERT(pvh_info->magic == XEN_HVM_START_MAGIC_VALUE); - - printk("PVH start info: (pa %08x)\n", pvh_start_info_pa); - printk(" version: %u\n", pvh_info->version); - printk(" flags: %#"PRIx32"\n", pvh_info->flags); - printk(" nr_modules: %u\n", pvh_info->nr_modules); - printk(" modlist_pa: %016"PRIx64"\n", pvh_info->modlist_paddr); - printk(" cmdline_pa: %016"PRIx64"\n", pvh_info->cmdline_paddr); - if ( pvh_info->cmdline_paddr ) - printk(" cmdline: '%s'\n", (char *)__va(pvh_info->cmdline_paddr)); - printk(" rsdp_pa: %016"PRIx64"\n", pvh_info->rsdp_paddr); - - entry = __va(pvh_info->modlist_paddr); - for ( i = 0; i < pvh_info->nr_modules; i++ ) - { - printk(" mod[%u].pa: %016"PRIx64"\n", i, entry[i].paddr); - printk(" mod[%u].size: %016"PRIu64"\n", i, entry[i].size); - printk(" mod[%u].cmdline_pa: %016"PRIx64"\n", - i, entry[i].cmdline_paddr); - if ( entry[i].cmdline_paddr ) - printk(" mod[%1u].cmdline: '%s'\n", i, - (char *)__va(entry[i].cmdline_paddr)); - } -} - -/* - * Local variables: - * mode: C - * c-file-style: "BSD" - * c-basic-offset: 4 - * tab-width: 4 - * indent-tabs-mode: nil - * End: - */ diff --git a/xen/arch/x86/guest/xen.c b/xen/arch/x86/guest/xen.c deleted file mode 100644 index a329e7c886..0000000000 --- a/xen/arch/x86/guest/xen.c +++ /dev/null @@ -1,342 +0,0 @@ -/****************************************************************************** - * arch/x86/guest/xen.c - * - * Support for detecting and running under Xen. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; If not, see <http://www.gnu.org/licenses/>. - * - * Copyright (c) 2017 Citrix Systems Ltd. - */ -#include <xen/event.h> -#include <xen/init.h> -#include <xen/mm.h> -#include <xen/pfn.h> -#include <xen/rangeset.h> -#include <xen/types.h> -#include <xen/pv_console.h> - -#include <asm/apic.h> -#include <asm/e820.h> -#include <asm/guest.h> -#include <asm/msr.h> -#include <asm/processor.h> - -#include <public/arch-x86/cpuid.h> -#include <public/hvm/params.h> - -bool __read_mostly xen_guest; - -static __read_mostly uint32_t xen_cpuid_base; -extern char hypercall_page[]; -static struct rangeset *mem; - -DEFINE_PER_CPU(unsigned int, vcpu_id); - -static struct vcpu_info *vcpu_info; -static unsigned long vcpu_info_mapped[BITS_TO_LONGS(NR_CPUS)]; -DEFINE_PER_CPU(struct vcpu_info *, vcpu_info); - -static void __init find_xen_leaves(void) -{ - uint32_t eax, ebx, ecx, edx, base; - - for ( base = XEN_CPUID_FIRST_LEAF; - base < XEN_CPUID_FIRST_LEAF + 0x10000; base += 0x100 ) - { - cpuid(base, &eax, &ebx, &ecx, &edx); - - if ( (ebx == XEN_CPUID_SIGNATURE_EBX) && - (ecx == XEN_CPUID_SIGNATURE_ECX) && - (edx == XEN_CPUID_SIGNATURE_EDX) && - ((eax - base) >= 2) ) - { - xen_cpuid_base = base; - break; - } - } -} - -void __init probe_hypervisor(void) -{ - if ( xen_guest || !cpu_has_hypervisor ) - return; - - find_xen_leaves(); - - if ( !xen_cpuid_base ) - return; - - /* Fill the hypercall page. */ - wrmsrl(cpuid_ebx(xen_cpuid_base + 2), __pa(hypercall_page)); - - xen_guest = true; -} - -static void map_shared_info(void) -{ - mfn_t mfn; - struct xen_add_to_physmap xatp = { - .domid = DOMID_SELF, - .space = XENMAPSPACE_shared_info, - }; - unsigned int i; - unsigned long rc; - - if ( hypervisor_alloc_unused_page(&mfn) ) - panic("unable to reserve shared info memory page\n"); - - xatp.gpfn = mfn_x(mfn); - rc = xen_hypercall_memory_op(XENMEM_add_to_physmap, &xatp); - if ( rc ) - panic("failed to map shared_info page: %ld\n", rc); - - set_fixmap(FIX_XEN_SHARED_INFO, mfn_x(mfn) << PAGE_SHIFT); - - /* Mask all upcalls */ - for ( i = 0; i < ARRAY_SIZE(XEN_shared_info->evtchn_mask); i++ ) - write_atomic(&XEN_shared_info->evtchn_mask[i], ~0ul); -} - -static int map_vcpuinfo(void) -{ - unsigned int vcpu = this_cpu(vcpu_id); - struct vcpu_register_vcpu_info info; - int rc; - - if ( !vcpu_info ) - { - this_cpu(vcpu_info) = &XEN_shared_info->vcpu_info[vcpu]; - return 0; - } - - if ( test_bit(vcpu, vcpu_info_mapped) ) - { - this_cpu(vcpu_info) = &vcpu_info[vcpu]; - return 0; - } - - info.mfn = virt_to_mfn(&vcpu_info[vcpu]); - info.offset = (unsigned long)&vcpu_info[vcpu] & ~PAGE_MASK; - rc = xen_hypercall_vcpu_op(VCPUOP_register_vcpu_info, vcpu, &info); - if ( rc ) - { - BUG_ON(vcpu >= XEN_LEGACY_MAX_VCPUS); - this_cpu(vcpu_info) = &XEN_shared_info->vcpu_info[vcpu]; - } - else - { - this_cpu(vcpu_info) = &vcpu_info[vcpu]; - set_bit(vcpu, vcpu_info_mapped); - } - - return rc; -} - -static void set_vcpu_id(void) -{ - uint32_t eax, ebx, ecx, edx; - - ASSERT(xen_cpuid_base); - - /* Fetch vcpu id from cpuid. */ - cpuid(xen_cpuid_base + 4, &eax, &ebx, &ecx, &edx); - if ( eax & XEN_HVM_CPUID_VCPU_ID_PRESENT ) - this_cpu(vcpu_id) = ebx; - else - this_cpu(vcpu_id) = smp_processor_id(); -} - -static void __init init_memmap(void) -{ - unsigned int i; - - mem = rangeset_new(NULL, "host memory map", 0); - if ( !mem ) - panic("failed to allocate PFN usage rangeset\n"); - - /* - * Mark up to the last memory page (or 4GiB) as RAM. This is done because - * Xen doesn't know the position of possible MMIO holes, so at least try to - * avoid the know MMIO hole below 4GiB. Note that this is subject to future - * discussion and improvements. - */ - if ( rangeset_add_range(mem, 0, max_t(unsigned long, max_page - 1, - PFN_DOWN(GB(4) - 1))) ) - panic("unable to add RAM to in-use PFN rangeset\n"); - - for ( i = 0; i < e820.nr_map; i++ ) - { - struct e820entry *e = &e820.map[i]; - - if ( rangeset_add_range(mem, PFN_DOWN(e->addr), - PFN_UP(e->addr + e->size - 1)) ) - panic("unable to add range [%#lx, %#lx] to in-use PFN rangeset\n", - PFN_DOWN(e->addr), PFN_UP(e->addr + e->size - 1)); - } -} - -static void xen_evtchn_upcall(struct cpu_user_regs *regs) -{ - struct vcpu_info *vcpu_info = this_cpu(vcpu_info); - unsigned long pending; - - vcpu_info->evtchn_upcall_pending = 0; - pending = xchg(&vcpu_info->evtchn_pending_sel, 0); - - while ( pending ) - { - unsigned int l1 = find_first_set_bit(pending); - unsigned long evtchn = xchg(&XEN_shared_info->evtchn_pending[l1], 0); - - __clear_bit(l1, &pending); - evtchn &= ~XEN_shared_info->evtchn_mask[l1]; - while ( evtchn ) - { - unsigned int port = find_first_set_bit(evtchn); - - __clear_bit(port, &evtchn); - port += l1 * BITS_PER_LONG; - - if ( pv_console && port == pv_console_evtchn() ) - pv_console_rx(regs); - else if ( pv_shim ) - pv_shim_inject_evtchn(port); - } - } - - ack_APIC_irq(); -} - -static void init_evtchn(void) -{ - static uint8_t evtchn_upcall_vector; - int rc; - - if ( !evtchn_upcall_vector ) - alloc_direct_apic_vector(&evtchn_upcall_vector, xen_evtchn_upcall); - - ASSERT(evtchn_upcall_vector); - - rc = xen_hypercall_set_evtchn_upcall_vector(this_cpu(vcpu_id), - evtchn_upcall_vector); - if ( rc ) - panic("Unable to set evtchn upcall vector: %d\n", rc); - - /* Trick toolstack to think we are enlightened */ - { - struct xen_hvm_param a = { - .domid = DOMID_SELF, - .index = HVM_PARAM_CALLBACK_IRQ, - .value = 1, - }; - - BUG_ON(xen_hypercall_hvm_op(HVMOP_set_param, &a)); - } -} - -void __init hypervisor_setup(void) -{ - init_memmap(); - - map_shared_info(); - - set_vcpu_id(); - vcpu_info = xzalloc_array(struct vcpu_info, nr_cpu_ids); - if ( map_vcpuinfo() ) - { - xfree(vcpu_info); - vcpu_info = NULL; - } - if ( !vcpu_info && nr_cpu_ids > XEN_LEGACY_MAX_VCPUS ) - { - unsigned int i; - - for ( i = XEN_LEGACY_MAX_VCPUS; i < nr_cpu_ids; i++ ) - __cpumask_clear_cpu(i, &cpu_present_map); - nr_cpu_ids = XEN_LEGACY_MAX_VCPUS; - printk(XENLOG_WARNING - "unable to map vCPU info, limiting vCPUs to: %u\n", - XEN_LEGACY_MAX_VCPUS); - } - - init_evtchn(); -} - -void hypervisor_ap_setup(void) -{ - set_vcpu_id(); - map_vcpuinfo(); - init_evtchn(); -} - -int hypervisor_alloc_unused_page(mfn_t *mfn) -{ - unsigned long m; - int rc; - - rc = rangeset_claim_range(mem, 1, &m); - if ( !rc ) - *mfn = _mfn(m); - - return rc; -} - -int hypervisor_free_unused_page(mfn_t mfn) -{ - return rangeset_remove_range(mem, mfn_x(mfn), mfn_x(mfn)); -} - -uint32_t hypervisor_cpuid_base(void) -{ - return xen_cpuid_base; -} - -static void ap_resume(void *unused) -{ - map_vcpuinfo(); - init_evtchn(); -} - -void hypervisor_resume(void) -{ - /* Reset shared info page. */ - map_shared_info(); - - /* - * Reset vcpu_info. Just clean the mapped bitmap and try to map the vcpu - * area again. On failure to map (when it was previously mapped) panic - * since it's impossible to safely shut down running guest vCPUs in order - * to meet the new XEN_LEGACY_MAX_VCPUS requirement. - */ - bitmap_zero(vcpu_info_mapped, NR_CPUS); - if ( map_vcpuinfo() && nr_cpu_ids > XEN_LEGACY_MAX_VCPUS ) - panic("unable to remap vCPU info and vCPUs > legacy limit\n"); - - /* Setup event channel upcall vector. */ - init_evtchn(); - smp_call_function(ap_resume, NULL, 1); - - if ( pv_console ) - pv_console_init(); -} - -/* - * Local variables: - * mode: C - * c-file-style: "BSD" - * c-basic-offset: 4 - * tab-width: 4 - * indent-tabs-mode: nil - * End: - */ diff --git a/xen/arch/x86/guest/xen/Makefile b/xen/arch/x86/guest/xen/Makefile new file mode 100644 index 0000000000..26fb4b1007 --- /dev/null +++ b/xen/arch/x86/guest/xen/Makefile @@ -0,0 +1,4 @@ +obj-y += hypercall_page.o +obj-y += xen.o + +obj-bin-$(CONFIG_PVH_GUEST) += pvh-boot.init.o diff --git a/xen/arch/x86/guest/xen/hypercall_page.S b/xen/arch/x86/guest/xen/hypercall_page.S new file mode 100644 index 0000000000..6485e9150e --- /dev/null +++ b/xen/arch/x86/guest/xen/hypercall_page.S @@ -0,0 +1,78 @@ +#include <asm/page.h> +#include <asm/asm_defns.h> +#include <public/xen.h> + + .section ".text.page_aligned", "ax", @progbits + .p2align PAGE_SHIFT + +GLOBAL(hypercall_page) + /* Poisoned with `ret` for safety before hypercalls are set up. */ + .fill PAGE_SIZE, 1, 0xc3 + .type hypercall_page, STT_OBJECT + .size hypercall_page, PAGE_SIZE + +/* + * Identify a specific hypercall in the hypercall page + * @param name Hypercall name. + */ +#define DECLARE_HYPERCALL(name) \ + .globl HYPERCALL_ ## name; \ + .set HYPERCALL_ ## name, hypercall_page + __HYPERVISOR_ ## name * 32; \ + .type HYPERCALL_ ## name, STT_FUNC; \ + .size HYPERCALL_ ## name, 32 + +DECLARE_HYPERCALL(set_trap_table) +DECLARE_HYPERCALL(mmu_update) +DECLARE_HYPERCALL(set_gdt) +DECLARE_HYPERCALL(stack_switch) +DECLARE_HYPERCALL(set_callbacks) +DECLARE_HYPERCALL(fpu_taskswitch) +DECLARE_HYPERCALL(sched_op_compat) +DECLARE_HYPERCALL(platform_op) +DECLARE_HYPERCALL(set_debugreg) +DECLARE_HYPERCALL(get_debugreg) +DECLARE_HYPERCALL(update_descriptor) +DECLARE_HYPERCALL(memory_op) +DECLARE_HYPERCALL(multicall) +DECLARE_HYPERCALL(update_va_mapping) +DECLARE_HYPERCALL(set_timer_op) +DECLARE_HYPERCALL(event_channel_op_compat) +DECLARE_HYPERCALL(xen_version) +DECLARE_HYPERCALL(console_io) +DECLARE_HYPERCALL(physdev_op_compat) +DECLARE_HYPERCALL(grant_table_op) +DECLARE_HYPERCALL(vm_assist) +DECLARE_HYPERCALL(update_va_mapping_otherdomain) +DECLARE_HYPERCALL(iret) +DECLARE_HYPERCALL(vcpu_op) +DECLARE_HYPERCALL(set_segment_base) +DECLARE_HYPERCALL(mmuext_op) +DECLARE_HYPERCALL(xsm_op) +DECLARE_HYPERCALL(nmi_op) +DECLARE_HYPERCALL(sched_op) +DECLARE_HYPERCALL(callback_op) +DECLARE_HYPERCALL(xenoprof_op) +DECLARE_HYPERCALL(event_channel_op) +DECLARE_HYPERCALL(physdev_op) +DECLARE_HYPERCALL(hvm_op) +DECLARE_HYPERCALL(sysctl) +DECLARE_HYPERCALL(domctl) +DECLARE_HYPERCALL(kexec_op) +DECLARE_HYPERCALL(argo_op) +DECLARE_HYPERCALL(xenpmu_op) + +DECLARE_HYPERCALL(arch_0) +DECLARE_HYPERCALL(arch_1) +DECLARE_HYPERCALL(arch_2) +DECLARE_HYPERCALL(arch_3) +DECLARE_HYPERCALL(arch_4) +DECLARE_HYPERCALL(arch_5) +DECLARE_HYPERCALL(arch_6) +DECLARE_HYPERCALL(arch_7) + +/* + * Local variables: + * tab-width: 8 + * indent-tabs-mode: nil + * End: + */ diff --git a/xen/arch/x86/guest/xen/pvh-boot.c b/xen/arch/x86/guest/xen/pvh-boot.c new file mode 100644 index 0000000000..ca8e156f7d --- /dev/null +++ b/xen/arch/x86/guest/xen/pvh-boot.c @@ -0,0 +1,151 @@ +/****************************************************************************** + * arch/x86/guest/pvh-boot.c + * + * PVH boot time support + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; If not, see <http://www.gnu.org/licenses/>. + * + * Copyright (c) 2017 Citrix Systems Ltd. + */ +#include <xen/init.h> +#include <xen/lib.h> +#include <xen/mm.h> + +#include <asm/e820.h> +#include <asm/guest.h> + +#include <public/arch-x86/hvm/start_info.h> + +/* Initialised in head.S, before .bss is zeroed. */ +bool __initdata pvh_boot; +uint32_t __initdata pvh_start_info_pa; + +static multiboot_info_t __initdata pvh_mbi; +static module_t __initdata pvh_mbi_mods[8]; +static const char *__initdata pvh_loader = "PVH Directboot"; + +static void __init convert_pvh_info(multiboot_info_t **mbi, + module_t **mod) +{ + const struct hvm_start_info *pvh_info = __va(pvh_start_info_pa); + const struct hvm_modlist_entry *entry; + unsigned int i; + + if ( pvh_info->magic != XEN_HVM_START_MAGIC_VALUE ) + panic("Magic value is wrong: %x\n", pvh_info->magic); + + /* + * Temporary module array needs to be at least one element bigger than + * required. The extra element is used to aid relocation. See + * arch/x86/setup.c:__start_xen(). + */ + if ( ARRAY_SIZE(pvh_mbi_mods) <= pvh_info->nr_modules ) + panic("The module array is too small, size %zu, requested %u\n", + ARRAY_SIZE(pvh_mbi_mods), pvh_info->nr_modules); + + /* + * Turn hvm_start_info into mbi. Luckily all modules are placed under 4GB + * boundary on x86. + */ + pvh_mbi.flags = MBI_CMDLINE | MBI_MODULES | MBI_LOADERNAME; + + BUG_ON(pvh_info->cmdline_paddr >> 32); + pvh_mbi.cmdline = pvh_info->cmdline_paddr; + pvh_mbi.boot_loader_name = __pa(pvh_loader); + + BUG_ON(pvh_info->nr_modules >= ARRAY_SIZE(pvh_mbi_mods)); + pvh_mbi.mods_count = pvh_info->nr_modules; + pvh_mbi.mods_addr = __pa(pvh_mbi_mods); + + entry = __va(pvh_info->modlist_paddr); + for ( i = 0; i < pvh_info->nr_modules; i++ ) + { + BUG_ON(entry[i].paddr >> 32); + BUG_ON(entry[i].cmdline_paddr >> 32); + + pvh_mbi_mods[i].mod_start = entry[i].paddr; + pvh_mbi_mods[i].mod_end = entry[i].paddr + entry[i].size; + pvh_mbi_mods[i].string = entry[i].cmdline_paddr; + } + + rsdp_hint = pvh_info->rsdp_paddr; + + *mbi = &pvh_mbi; + *mod = pvh_mbi_mods; +} + +static void __init get_memory_map(void) +{ + struct xen_memory_map memmap = { + .nr_entries = E820MAX, + }; + + set_xen_guest_handle(memmap.buffer, e820_raw.map); + BUG_ON(xen_hypercall_memory_op(XENMEM_memory_map, &memmap)); + e820_raw.nr_map = memmap.nr_entries; + + /* :( Various toolstacks don't sort the memory map. */ + sanitize_e820_map(e820_raw.map, &e820_raw.nr_map); +} + +void __init pvh_init(multiboot_info_t **mbi, module_t **mod) +{ + convert_pvh_info(mbi, mod); + + probe_hypervisor(); + ASSERT(xen_guest); + + get_memory_map(); +} + +void __init pvh_print_info(void) +{ + const struct hvm_start_info *pvh_info = __va(pvh_start_info_pa); + const struct hvm_modlist_entry *entry; + unsigned int i; + + ASSERT(pvh_info->magic == XEN_HVM_START_MAGIC_VALUE); + + printk("PVH start info: (pa %08x)\n", pvh_start_info_pa); + printk(" version: %u\n", pvh_info->version); + printk(" flags: %#"PRIx32"\n", pvh_info->flags); + printk(" nr_modules: %u\n", pvh_info->nr_modules); + printk(" modlist_pa: %016"PRIx64"\n", pvh_info->modlist_paddr); + printk(" cmdline_pa: %016"PRIx64"\n", pvh_info->cmdline_paddr); + if ( pvh_info->cmdline_paddr ) + printk(" cmdline: '%s'\n", (char *)__va(pvh_info->cmdline_paddr)); + printk(" rsdp_pa: %016"PRIx64"\n", pvh_info->rsdp_paddr); + + entry = __va(pvh_info->modlist_paddr); + for ( i = 0; i < pvh_info->nr_modules; i++ ) + { + printk(" mod[%u].pa: %016"PRIx64"\n", i, entry[i].paddr); + printk(" mod[%u].size: %016"PRIu64"\n", i, entry[i].size); + printk(" mod[%u].cmdline_pa: %016"PRIx64"\n", + i, entry[i].cmdline_paddr); + if ( entry[i].cmdline_paddr ) + printk(" mod[%1u].cmdline: '%s'\n", i, + (char *)__va(entry[i].cmdline_paddr)); + } +} + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/xen/arch/x86/guest/xen/xen.c b/xen/arch/x86/guest/xen/xen.c new file mode 100644 index 0000000000..a329e7c886 --- /dev/null +++ b/xen/arch/x86/guest/xen/xen.c @@ -0,0 +1,342 @@ +/****************************************************************************** + * arch/x86/guest/xen.c + * + * Support for detecting and running under Xen. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; If not, see <http://www.gnu.org/licenses/>. + * + * Copyright (c) 2017 Citrix Systems Ltd. + */ +#include <xen/event.h> +#include <xen/init.h> +#include <xen/mm.h> +#include <xen/pfn.h> +#include <xen/rangeset.h> +#include <xen/types.h> +#include <xen/pv_console.h> + +#include <asm/apic.h> +#include <asm/e820.h> +#include <asm/guest.h> +#include <asm/msr.h> +#include <asm/processor.h> + +#include <public/arch-x86/cpuid.h> +#include <public/hvm/params.h> + +bool __read_mostly xen_guest; + +static __read_mostly uint32_t xen_cpuid_base; +extern char hypercall_page[]; +static struct rangeset *mem; + +DEFINE_PER_CPU(unsigned int, vcpu_id); + +static struct vcpu_info *vcpu_info; +static unsigned long vcpu_info_mapped[BITS_TO_LONGS(NR_CPUS)]; +DEFINE_PER_CPU(struct vcpu_info *, vcpu_info); + +static void __init find_xen_leaves(void) +{ + uint32_t eax, ebx, ecx, edx, base; + + for ( base = XEN_CPUID_FIRST_LEAF; + base < XEN_CPUID_FIRST_LEAF + 0x10000; base += 0x100 ) + { + cpuid(base, &eax, &ebx, &ecx, &edx); + + if ( (ebx == XEN_CPUID_SIGNATURE_EBX) && + (ecx == XEN_CPUID_SIGNATURE_ECX) && + (edx == XEN_CPUID_SIGNATURE_EDX) && + ((eax - base) >= 2) ) + { + xen_cpuid_base = base; + break; + } + } +} + +void __init probe_hypervisor(void) +{ + if ( xen_guest || !cpu_has_hypervisor ) + return; + + find_xen_leaves(); + + if ( !xen_cpuid_base ) + return; + + /* Fill the hypercall page. */ + wrmsrl(cpuid_ebx(xen_cpuid_base + 2), __pa(hypercall_page)); + + xen_guest = true; +} + +static void map_shared_info(void) +{ + mfn_t mfn; + struct xen_add_to_physmap xatp = { + .domid = DOMID_SELF, + .space = XENMAPSPACE_shared_info, + }; + unsigned int i; + unsigned long rc; + + if ( hypervisor_alloc_unused_page(&mfn) ) + panic("unable to reserve shared info memory page\n"); + + xatp.gpfn = mfn_x(mfn); + rc = xen_hypercall_memory_op(XENMEM_add_to_physmap, &xatp); + if ( rc ) + panic("failed to map shared_info page: %ld\n", rc); + + set_fixmap(FIX_XEN_SHARED_INFO, mfn_x(mfn) << PAGE_SHIFT); + + /* Mask all upcalls */ + for ( i = 0; i < ARRAY_SIZE(XEN_shared_info->evtchn_mask); i++ ) + write_atomic(&XEN_shared_info->evtchn_mask[i], ~0ul); +} + +static int map_vcpuinfo(void) +{ + unsigned int vcpu = this_cpu(vcpu_id); + struct vcpu_register_vcpu_info info; + int rc; + + if ( !vcpu_info ) + { + this_cpu(vcpu_info) = &XEN_shared_info->vcpu_info[vcpu]; + return 0; + } + + if ( test_bit(vcpu, vcpu_info_mapped) ) + { + this_cpu(vcpu_info) = &vcpu_info[vcpu]; + return 0; + } + + info.mfn = virt_to_mfn(&vcpu_info[vcpu]); + info.offset = (unsigned long)&vcpu_info[vcpu] & ~PAGE_MASK; + rc = xen_hypercall_vcpu_op(VCPUOP_register_vcpu_info, vcpu, &info); + if ( rc ) + { + BUG_ON(vcpu >= XEN_LEGACY_MAX_VCPUS); + this_cpu(vcpu_info) = &XEN_shared_info->vcpu_info[vcpu]; + } + else + { + this_cpu(vcpu_info) = &vcpu_info[vcpu]; + set_bit(vcpu, vcpu_info_mapped); + } + + return rc; +} + +static void set_vcpu_id(void) +{ + uint32_t eax, ebx, ecx, edx; + + ASSERT(xen_cpuid_base); + + /* Fetch vcpu id from cpuid. */ + cpuid(xen_cpuid_base + 4, &eax, &ebx, &ecx, &edx); + if ( eax & XEN_HVM_CPUID_VCPU_ID_PRESENT ) + this_cpu(vcpu_id) = ebx; + else + this_cpu(vcpu_id) = smp_processor_id(); +} + +static void __init init_memmap(void) +{ + unsigned int i; + + mem = rangeset_new(NULL, "host memory map", 0); + if ( !mem ) + panic("failed to allocate PFN usage rangeset\n"); + + /* + * Mark up to the last memory page (or 4GiB) as RAM. This is done because + * Xen doesn't know the position of possible MMIO holes, so at least try to + * avoid the know MMIO hole below 4GiB. Note that this is subject to future + * discussion and improvements. + */ + if ( rangeset_add_range(mem, 0, max_t(unsigned long, max_page - 1, + PFN_DOWN(GB(4) - 1))) ) + panic("unable to add RAM to in-use PFN rangeset\n"); + + for ( i = 0; i < e820.nr_map; i++ ) + { + struct e820entry *e = &e820.map[i]; + + if ( rangeset_add_range(mem, PFN_DOWN(e->addr), + PFN_UP(e->addr + e->size - 1)) ) + panic("unable to add range [%#lx, %#lx] to in-use PFN rangeset\n", + PFN_DOWN(e->addr), PFN_UP(e->addr + e->size - 1)); + } +} + +static void xen_evtchn_upcall(struct cpu_user_regs *regs) +{ + struct vcpu_info *vcpu_info = this_cpu(vcpu_info); + unsigned long pending; + + vcpu_info->evtchn_upcall_pending = 0; + pending = xchg(&vcpu_info->evtchn_pending_sel, 0); + + while ( pending ) + { + unsigned int l1 = find_first_set_bit(pending); + unsigned long evtchn = xchg(&XEN_shared_info->evtchn_pending[l1], 0); + + __clear_bit(l1, &pending); + evtchn &= ~XEN_shared_info->evtchn_mask[l1]; + while ( evtchn ) + { + unsigned int port = find_first_set_bit(evtchn); + + __clear_bit(port, &evtchn); + port += l1 * BITS_PER_LONG; + + if ( pv_console && port == pv_console_evtchn() ) + pv_console_rx(regs); + else if ( pv_shim ) + pv_shim_inject_evtchn(port); + } + } + + ack_APIC_irq(); +} + +static void init_evtchn(void) +{ + static uint8_t evtchn_upcall_vector; + int rc; + + if ( !evtchn_upcall_vector ) + alloc_direct_apic_vector(&evtchn_upcall_vector, xen_evtchn_upcall); + + ASSERT(evtchn_upcall_vector); + + rc = xen_hypercall_set_evtchn_upcall_vector(this_cpu(vcpu_id), + evtchn_upcall_vector); + if ( rc ) + panic("Unable to set evtchn upcall vector: %d\n", rc); + + /* Trick toolstack to think we are enlightened */ + { + struct xen_hvm_param a = { + .domid = DOMID_SELF, + .index = HVM_PARAM_CALLBACK_IRQ, + .value = 1, + }; + + BUG_ON(xen_hypercall_hvm_op(HVMOP_set_param, &a)); + } +} + +void __init hypervisor_setup(void) +{ + init_memmap(); + + map_shared_info(); + + set_vcpu_id(); + vcpu_info = xzalloc_array(struct vcpu_info, nr_cpu_ids); + if ( map_vcpuinfo() ) + { + xfree(vcpu_info); + vcpu_info = NULL; + } + if ( !vcpu_info && nr_cpu_ids > XEN_LEGACY_MAX_VCPUS ) + { + unsigned int i; + + for ( i = XEN_LEGACY_MAX_VCPUS; i < nr_cpu_ids; i++ ) + __cpumask_clear_cpu(i, &cpu_present_map); + nr_cpu_ids = XEN_LEGACY_MAX_VCPUS; + printk(XENLOG_WARNING + "unable to map vCPU info, limiting vCPUs to: %u\n", + XEN_LEGACY_MAX_VCPUS); + } + + init_evtchn(); +} + +void hypervisor_ap_setup(void) +{ + set_vcpu_id(); + map_vcpuinfo(); + init_evtchn(); +} + +int hypervisor_alloc_unused_page(mfn_t *mfn) +{ + unsigned long m; + int rc; + + rc = rangeset_claim_range(mem, 1, &m); + if ( !rc ) + *mfn = _mfn(m); + + return rc; +} + +int hypervisor_free_unused_page(mfn_t mfn) +{ + return rangeset_remove_range(mem, mfn_x(mfn), mfn_x(mfn)); +} + +uint32_t hypervisor_cpuid_base(void) +{ + return xen_cpuid_base; +} + +static void ap_resume(void *unused) +{ + map_vcpuinfo(); + init_evtchn(); +} + +void hypervisor_resume(void) +{ + /* Reset shared info page. */ + map_shared_info(); + + /* + * Reset vcpu_info. Just clean the mapped bitmap and try to map the vcpu + * area again. On failure to map (when it was previously mapped) panic + * since it's impossible to safely shut down running guest vCPUs in order + * to meet the new XEN_LEGACY_MAX_VCPUS requirement. + */ + bitmap_zero(vcpu_info_mapped, NR_CPUS); + if ( map_vcpuinfo() && nr_cpu_ids > XEN_LEGACY_MAX_VCPUS ) + panic("unable to remap vCPU info and vCPUs > legacy limit\n"); + + /* Setup event channel upcall vector. */ + init_evtchn(); + smp_call_function(ap_resume, NULL, 1); + + if ( pv_console ) + pv_console_init(); +} + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ -- generated by git-patchbot for /home/xen/git/xen.git#master _______________________________________________ Xen-changelog mailing list Xen-changelog@xxxxxxxxxxxxxxxxxxxx https://lists.xenproject.org/xen-changelog
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |