2018-08-28 09:40:15 +02:00
// SPDX-License-Identifier: GPL-2.0
2017-11-09 14:27:39 +01:00
# include <linux/acpi.h>
2017-03-14 18:35:40 +01:00
# include <linux/cpu.h>
# include <linux/kexec.h>
2017-06-12 13:53:56 +02:00
# include <linux/memblock.h>
2022-06-22 08:38:38 +02:00
# include <linux/virtio_anchor.h>
2017-03-14 18:35:40 +01:00
# include <xen/features.h>
# include <xen/events.h>
2022-07-29 08:04:16 +01:00
# include <xen/hvm.h>
# include <xen/interface/hvm/hvm_op.h>
2017-03-14 18:35:40 +01:00
# include <xen/interface/memory.h>
2022-01-21 10:01:46 +01:00
# include <asm/apic.h>
2017-03-14 18:35:40 +01:00
# include <asm/cpu.h>
# include <asm/smp.h>
2020-08-06 14:34:32 +02:00
# include <asm/io_apic.h>
2017-03-14 18:35:40 +01:00
# include <asm/reboot.h>
# include <asm/setup.h>
2020-05-21 22:05:44 +02:00
# include <asm/idtentry.h>
2017-03-14 18:35:40 +01:00
# include <asm/hypervisor.h>
2017-06-12 13:53:56 +02:00
# include <asm/e820/api.h>
2017-07-28 12:23:14 +02:00
# include <asm/early_ioremap.h>
2017-03-14 18:35:40 +01:00
# include <asm/xen/cpuid.h>
# include <asm/xen/hypervisor.h>
2017-06-12 13:53:56 +02:00
# include <asm/xen/page.h>
2017-03-14 18:35:40 +01:00
# include "xen-ops.h"
# include "mmu.h"
# include "smp.h"
2017-07-28 12:23:14 +02:00
static unsigned long shared_info_pfn ;
2022-07-29 08:04:16 +01:00
__ro_after_init bool xen_percpu_upcall ;
EXPORT_SYMBOL_GPL ( xen_percpu_upcall ) ;
2017-07-28 12:23:13 +02:00
void xen_hvm_init_shared_info ( void )
2017-03-14 18:35:40 +01:00
{
struct xen_add_to_physmap xatp ;
xatp . domid = DOMID_SELF ;
xatp . idx = 0 ;
xatp . space = XENMAPSPACE_shared_info ;
2017-07-28 12:23:14 +02:00
xatp . gpfn = shared_info_pfn ;
2017-03-14 18:35:40 +01:00
if ( HYPERVISOR_memory_op ( XENMEM_add_to_physmap , & xatp ) )
BUG ( ) ;
}
2017-07-28 12:23:13 +02:00
static void __init reserve_shared_info ( void )
{
u64 pa ;
/*
* Search for a free page starting at 4 kB physical address .
* Low memory is preferred to avoid an EPT large page split up
* by the mapping .
* Starting below X86_RESERVE_LOW ( usually 64 kB ) is fine as
* the BIOS used for HVM guests is well behaved and won ' t
* clobber memory other than the first 4 kB .
*/
for ( pa = PAGE_SIZE ;
! e820__mapped_all ( pa , pa + PAGE_SIZE , E820_TYPE_RAM ) | |
memblock_is_reserved ( pa ) ;
pa + = PAGE_SIZE )
;
2017-07-28 12:23:14 +02:00
shared_info_pfn = PHYS_PFN ( pa ) ;
2017-07-28 12:23:13 +02:00
memblock_reserve ( pa , PAGE_SIZE ) ;
2017-07-28 12:23:14 +02:00
HYPERVISOR_shared_info = early_memremap ( pa , PAGE_SIZE ) ;
}
static void __init xen_hvm_init_mem_mapping ( void )
{
early_memunmap ( HYPERVISOR_shared_info , PAGE_SIZE ) ;
HYPERVISOR_shared_info = __va ( PFN_PHYS ( shared_info_pfn ) ) ;
2018-05-04 16:11:00 -04:00
/*
* The virtual address of the shared_info page has changed , so
* the vcpu_info pointer for VCPU 0 is now stale .
*
* The prepare_boot_cpu callback will re - initialize it via
* xen_vcpu_setup , but we can ' t rely on that to be called for
* old Xen versions ( xen_have_vector_callback = = 0 ) .
*
* It is , in any case , bad to have a stale vcpu_info pointer
* so reset it now .
*/
xen_vcpu_info_reset ( 0 ) ;
2017-07-28 12:23:13 +02:00
}
2017-03-14 18:35:40 +01:00
static void __init init_hvm_pv_info ( void )
{
int major , minor ;
uint32_t eax , ebx , ecx , edx , base ;
base = xen_cpuid_base ( ) ;
eax = cpuid_eax ( base + 1 ) ;
major = eax > > 16 ;
minor = eax & 0xffff ;
printk ( KERN_INFO " Xen version %d.%d. \n " , major , minor ) ;
xen_domain_type = XEN_HVM_DOMAIN ;
/* PVH set up hypercall page in xen_prepare_pvh(). */
if ( xen_pvh_domain ( ) )
pv_info . name = " Xen PVH " ;
else {
u64 pfn ;
uint32_t msr ;
pv_info . name = " Xen HVM " ;
msr = cpuid_ebx ( base + 2 ) ;
pfn = __pa ( hypercall_page ) ;
wrmsr_safe ( msr , ( u32 ) pfn , ( u32 ) ( pfn > > 32 ) ) ;
}
xen_setup_features ( ) ;
cpuid ( base + 4 , & eax , & ebx , & ecx , & edx ) ;
if ( eax & XEN_HVM_CPUID_VCPU_ID_PRESENT )
this_cpu_write ( xen_vcpu_id , ebx ) ;
else
this_cpu_write ( xen_vcpu_id , smp_processor_id ( ) ) ;
}
2020-05-21 22:05:44 +02:00
DEFINE_IDTENTRY_SYSVEC ( sysvec_xen_hvm_callback )
{
struct pt_regs * old_regs = set_irq_regs ( regs ) ;
2022-07-29 08:04:16 +01:00
if ( xen_percpu_upcall )
2023-08-09 08:16:46 -07:00
apic_eoi ( ) ;
2022-07-29 08:04:16 +01:00
2020-05-21 22:05:44 +02:00
inc_irq_stat ( irq_hv_callback_count ) ;
xen_hvm_evtchn_do_upcall ( ) ;
set_irq_regs ( old_regs ) ;
}
2017-03-14 18:35:40 +01:00
# ifdef CONFIG_KEXEC_CORE
static void xen_hvm_shutdown ( void )
{
native_machine_shutdown ( ) ;
if ( kexec_in_progress )
xen_reboot ( SHUTDOWN_soft_reset ) ;
}
static void xen_hvm_crash_shutdown ( struct pt_regs * regs )
{
native_machine_crash_shutdown ( regs ) ;
xen_reboot ( SHUTDOWN_soft_reset ) ;
}
# endif
static int xen_cpu_up_prepare_hvm ( unsigned int cpu )
{
2017-06-02 17:06:01 -07:00
int rc = 0 ;
2017-03-14 18:35:40 +01:00
/*
2023-05-12 23:07:25 +02:00
* If a CPU was offlined earlier and offlining timed out then the
* lock mechanism is still initialized . Uninit it unconditionally
* as it ' s safe to call even if already uninited . Interrupts and
* timer have already been handled in xen_cpu_dead_hvm ( ) .
2017-03-14 18:35:40 +01:00
*/
2023-05-12 23:07:25 +02:00
xen_uninit_lock_cpu ( cpu ) ;
2017-03-14 18:35:40 +01:00
if ( cpu_acpi_id ( cpu ) ! = U32_MAX )
per_cpu ( xen_vcpu_id , cpu ) = cpu_acpi_id ( cpu ) ;
else
per_cpu ( xen_vcpu_id , cpu ) = cpu ;
2021-10-28 09:27:47 +02:00
xen_vcpu_setup ( cpu ) ;
if ( ! xen_have_vector_callback )
return 0 ;
2017-03-14 18:35:40 +01:00
2022-07-29 08:04:16 +01:00
if ( xen_percpu_upcall ) {
rc = xen_set_upcall_vector ( cpu ) ;
if ( rc ) {
WARN ( 1 , " HVMOP_set_evtchn_upcall_vector "
" for CPU %d failed: %d \n " , cpu , rc ) ;
return rc ;
}
}
2021-01-06 15:39:57 +00:00
if ( xen_feature ( XENFEAT_hvm_safe_pvclock ) )
2017-03-14 18:35:40 +01:00
xen_setup_timer ( cpu ) ;
rc = xen_smp_intr_init ( cpu ) ;
if ( rc ) {
WARN ( 1 , " xen_smp_intr_init() for CPU %d failed: %d \n " ,
cpu , rc ) ;
}
2017-06-02 17:06:01 -07:00
return rc ;
2017-03-14 18:35:40 +01:00
}
static int xen_cpu_dead_hvm ( unsigned int cpu )
{
xen_smp_intr_free ( cpu ) ;
2017-04-24 15:04:53 -04:00
if ( xen_have_vector_callback & & xen_feature ( XENFEAT_hvm_safe_pvclock ) )
2017-03-14 18:35:40 +01:00
xen_teardown_timer ( cpu ) ;
2022-02-07 18:35:06 +08:00
return 0 ;
2017-03-14 18:35:40 +01:00
}
static void __init xen_hvm_guest_init ( void )
{
if ( xen_pv_domain ( ) )
return ;
2022-06-22 08:38:38 +02:00
if ( IS_ENABLED ( CONFIG_XEN_VIRTIO_FORCE_GRANT ) )
2022-08-29 13:26:08 +02:00
virtio_set_mem_acc_cb ( xen_virtio_restricted_mem_acc ) ;
2022-06-02 22:23:49 +03:00
2017-03-14 18:35:40 +01:00
init_hvm_pv_info ( ) ;
2017-07-28 12:23:13 +02:00
reserve_shared_info ( ) ;
2017-03-14 18:35:40 +01:00
xen_hvm_init_shared_info ( ) ;
2017-06-02 17:05:59 -07:00
/*
* xen_vcpu is a pointer to the vcpu_info struct in the shared_info
* page , we use it in the event channel upcall and in some pvclock
* related functions .
*/
xen_vcpu_info_reset ( 0 ) ;
2017-03-14 18:35:40 +01:00
xen_panic_handler_init ( ) ;
xen_hvm_smp_init ( ) ;
WARN_ON ( xen_cpuhp_setup ( xen_cpu_up_prepare_hvm , xen_cpu_dead_hvm ) ) ;
xen_unplug_emulated_devices ( ) ;
x86_init . irqs . intr_init = xen_init_IRQ ;
xen_hvm_init_time_ops ( ) ;
xen_hvm_init_mmu_ops ( ) ;
# ifdef CONFIG_KEXEC_CORE
machine_ops . shutdown = xen_hvm_shutdown ;
machine_ops . crash_shutdown = xen_hvm_crash_shutdown ;
# endif
}
static __init int xen_parse_nopv ( char * arg )
{
2019-07-11 20:02:10 +08:00
pr_notice ( " \" xen_nopv \" is deprecated, please use \" nopv \" instead \n " ) ;
if ( xen_cpuid_base ( ) )
nopv = true ;
return 0 ;
2017-03-14 18:35:40 +01:00
}
early_param ( " xen_nopv " , xen_parse_nopv ) ;
2021-01-06 15:39:56 +00:00
static __init int xen_parse_no_vector_callback ( char * arg )
{
2022-07-29 08:04:16 +01:00
xen_have_vector_callback = false ;
2021-01-06 15:39:56 +00:00
return 0 ;
}
early_param ( " xen_no_vector_callback " , xen_parse_no_vector_callback ) ;
2022-01-21 10:01:46 +01:00
static __init bool xen_x2apic_available ( void )
2017-03-14 18:35:40 +01:00
{
2022-01-21 10:01:46 +01:00
return x2apic_supported ( ) ;
2017-03-14 18:35:40 +01:00
}
2022-01-20 16:25:27 +01:00
static bool __init msi_ext_dest_id ( void )
{
return cpuid_eax ( xen_cpuid_base ( ) + 4 ) & XEN_HVM_CPUID_EXT_DEST_ID ;
}
2017-11-09 14:27:39 +01:00
static __init void xen_hvm_guest_late_init ( void )
{
# ifdef CONFIG_XEN_PVH
/* Test for PVH domain (PVH boot path taken overrides ACPI flags). */
if ( ! xen_pvh & &
( x86_platform . legacy . rtc | | ! x86_platform . legacy . no_vga ) )
return ;
/* PVH detected. */
xen_pvh = true ;
2019-07-16 12:26:09 +08:00
if ( nopv )
panic ( " \" nopv \" and \" xen_nopv \" parameters are unsupported in PVH guest. " ) ;
2017-11-09 14:27:39 +01:00
/* Make sure we don't fall back to (default) ACPI_IRQ_MODEL_PIC. */
if ( ! nr_ioapics & & acpi_irq_model = = ACPI_IRQ_MODEL_PIC )
acpi_irq_model = ACPI_IRQ_MODEL_PLATFORM ;
machine_ops . emergency_restart = xen_emergency_restart ;
pv_info . name = " Xen PVH " ;
# endif
}
2019-07-16 12:26:09 +08:00
static uint32_t __init xen_platform_hvm ( void )
{
uint32_t xen_domain = xen_cpuid_base ( ) ;
struct x86_hyper_init * h = & x86_hyper_xen_hvm . init ;
if ( xen_pv_domain ( ) )
return 0 ;
if ( xen_pvh_domain ( ) & & nopv ) {
/* Guest booting via the Xen-PVH boot entry goes here */
pr_info ( " \" nopv \" parameter is ignored in PVH guest \n " ) ;
nopv = false ;
} else if ( nopv & & xen_domain ) {
/*
* Guest booting via normal boot entry ( like via grub2 ) goes
* here .
*
* Use interface functions for bare hardware if nopv ,
* xen_hvm_guest_late_init is an exception as we need to
* detect PVH and panic there .
*/
h - > init_platform = x86_init_noop ;
h - > x2apic_available = bool_x86_init_noop ;
h - > init_mem_mapping = x86_init_noop ;
h - > init_after_bootmem = x86_init_noop ;
h - > guest_late_init = xen_hvm_guest_late_init ;
x86_hyper_xen_hvm . runtime . pin_vcpu = x86_op_int_noop ;
}
return xen_domain ;
}
2019-07-16 12:26:08 +08:00
struct hypervisor_x86 x86_hyper_xen_hvm __initdata = {
2017-03-14 18:35:40 +01:00
. name = " Xen HVM " ,
. detect = xen_platform_hvm ,
2017-11-09 14:27:36 +01:00
. type = X86_HYPER_XEN_HVM ,
2017-11-09 14:27:35 +01:00
. init . init_platform = xen_hvm_guest_init ,
2022-01-21 10:01:46 +01:00
. init . x2apic_available = xen_x2apic_available ,
2017-11-09 14:27:35 +01:00
. init . init_mem_mapping = xen_hvm_init_mem_mapping ,
2017-11-09 14:27:39 +01:00
. init . guest_late_init = xen_hvm_guest_late_init ,
2022-01-20 16:25:27 +01:00
. init . msi_ext_dest_id = msi_ext_dest_id ,
2017-11-09 14:27:35 +01:00
. runtime . pin_vcpu = xen_pin_vcpu ,
2019-07-16 12:26:09 +08:00
. ignore_nopv = true ,
2017-03-14 18:35:40 +01:00
} ;