2018-04-23 01:02:09 +03:00
// SPDX-License-Identifier: GPL-2.0
2017-11-27 11:11:46 +03:00
/*
* Jailhouse paravirt_ops implementation
*
* Copyright ( c ) Siemens AG , 2015 - 2017
*
* Authors :
* Jan Kiszka < jan . kiszka @ siemens . com >
*/
2017-11-27 11:11:48 +03:00
# include <linux/acpi_pmtmr.h>
2017-11-27 11:11:46 +03:00
# include <linux/kernel.h>
2017-11-27 11:11:52 +03:00
# include <linux/reboot.h>
2019-10-10 13:21:02 +03:00
# include <linux/serial_8250.h>
2017-11-27 11:11:47 +03:00
# include <asm/apic.h>
2020-08-06 15:34:32 +03:00
# include <asm/io_apic.h>
2020-08-06 15:35:11 +03:00
# include <asm/acpi.h>
2017-11-27 11:11:46 +03:00
# include <asm/cpu.h>
# include <asm/hypervisor.h>
2017-11-27 11:11:50 +03:00
# include <asm/i8259.h>
2017-11-27 11:11:53 +03:00
# include <asm/irqdomain.h>
2017-11-27 11:11:54 +03:00
# include <asm/pci_x86.h>
2017-11-27 11:11:52 +03:00
# include <asm/reboot.h>
2017-11-27 11:11:46 +03:00
# include <asm/setup.h>
2018-11-22 05:04:09 +03:00
# include <asm/jailhouse_para.h>
2017-11-27 11:11:46 +03:00
2019-10-10 13:21:02 +03:00
static struct jailhouse_setup_data setup_data ;
2019-10-10 13:21:01 +03:00
# define SETUP_DATA_V1_LEN (sizeof(setup_data.hdr) + sizeof(setup_data.v1))
2019-10-10 13:21:02 +03:00
# define SETUP_DATA_V2_LEN (SETUP_DATA_V1_LEN + sizeof(setup_data.v2))
2019-10-10 13:21:01 +03:00
2017-11-27 11:11:49 +03:00
static unsigned int precalibrated_tsc_khz ;
2017-11-27 11:11:46 +03:00
2019-10-10 13:21:02 +03:00
static void jailhouse_setup_irq ( unsigned int irq )
{
struct mpc_intsrc mp_irq = {
. type = MP_INTSRC ,
. irqtype = mp_INT ,
. irqflag = MP_IRQPOL_ACTIVE_HIGH | MP_IRQTRIG_EDGE ,
. srcbusirq = irq ,
. dstirq = irq ,
} ;
mp_save_irq ( & mp_irq ) ;
}
2017-11-27 11:11:46 +03:00
static uint32_t jailhouse_cpuid_base ( void )
{
if ( boot_cpu_data . cpuid_level < 0 | |
! boot_cpu_has ( X86_FEATURE_HYPERVISOR ) )
return 0 ;
return hypervisor_cpuid_base ( " Jailhouse \0 \0 \0 " , 0 ) ;
}
static uint32_t __init jailhouse_detect ( void )
{
return jailhouse_cpuid_base ( ) ;
}
2018-04-27 23:13:23 +03:00
static void jailhouse_get_wallclock ( struct timespec64 * now )
2017-11-27 11:11:50 +03:00
{
memset ( now , 0 , sizeof ( * now ) ) ;
}
2017-11-27 11:11:49 +03:00
static void __init jailhouse_timer_init ( void )
{
2019-10-10 13:21:01 +03:00
lapic_timer_period = setup_data . v1 . apic_khz * ( 1000 / HZ ) ;
2017-11-27 11:11:49 +03:00
}
static unsigned long jailhouse_get_tsc ( void )
{
return precalibrated_tsc_khz ;
}
2018-01-15 12:24:34 +03:00
static void __init jailhouse_x2apic_init ( void )
{
# ifdef CONFIG_X86_X2APIC
if ( ! x2apic_enabled ( ) )
return ;
/*
* We do not have access to IR inside Jailhouse non - root cells . So
* we have to run in physical mode .
*/
x2apic_phys = 1 ;
/*
* This will trigger the switch to apic_x2apic_phys . Empty OEM IDs
* ensure that only this APIC driver picks up the call .
*/
default_acpi_madt_oem_check ( " " , " " ) ;
# endif
}
2017-11-27 11:11:47 +03:00
static void __init jailhouse_get_smp_config ( unsigned int early )
{
2017-11-27 11:11:53 +03:00
struct ioapic_domain_cfg ioapic_cfg = {
. type = IOAPIC_DOMAIN_STRICT ,
. ops = & mp_ioapic_irqdomain_ops ,
} ;
2017-11-27 11:11:47 +03:00
unsigned int cpu ;
2018-01-15 12:24:34 +03:00
jailhouse_x2apic_init ( ) ;
2017-11-27 11:11:47 +03:00
register_lapic_address ( 0xfee00000 ) ;
2019-10-10 13:21:01 +03:00
for ( cpu = 0 ; cpu < setup_data . v1 . num_cpus ; cpu + + ) {
generic_processor_info ( setup_data . v1 . cpu_ids [ cpu ] ,
2017-11-27 11:11:47 +03:00
boot_cpu_apic_version ) ;
}
smp_found_config = 1 ;
2017-11-27 11:11:53 +03:00
2019-10-10 13:21:01 +03:00
if ( setup_data . v1 . standard_ioapic ) {
2017-11-27 11:11:53 +03:00
mp_register_ioapic ( 0 , 0xfec00000 , gsi_top , & ioapic_cfg ) ;
2019-10-10 13:21:02 +03:00
if ( IS_ENABLED ( CONFIG_SERIAL_8250 ) & &
setup_data . hdr . version < 2 ) {
/* Register 1:1 mapping for legacy UART IRQs 3 and 4 */
jailhouse_setup_irq ( 3 ) ;
jailhouse_setup_irq ( 4 ) ;
}
2017-11-27 11:11:53 +03:00
}
2017-11-27 11:11:47 +03:00
}
2017-11-27 11:11:52 +03:00
static void jailhouse_no_restart ( void )
{
pr_notice ( " Jailhouse: Restart not supported, halting \n " ) ;
machine_halt ( ) ;
}
2017-11-27 11:11:54 +03:00
static int __init jailhouse_pci_arch_init ( void )
{
pci_direct_init ( 1 ) ;
/*
* There are no bridges on the virtual PCI root bus under Jailhouse ,
* thus no other way to discover all devices than a full scan .
2018-01-19 13:06:30 +03:00
* Respect any overrides via the command line , though .
2017-11-27 11:11:54 +03:00
*/
2018-01-19 13:06:30 +03:00
if ( pcibios_last_bus < 0 )
pcibios_last_bus = 0xff ;
2017-11-27 11:11:54 +03:00
2018-03-07 10:39:14 +03:00
# ifdef CONFIG_PCI_MMCONFIG
2019-10-10 13:21:01 +03:00
if ( setup_data . v1 . pci_mmconfig_base ) {
2018-03-07 10:39:14 +03:00
pci_mmconfig_add ( 0 , 0 , pcibios_last_bus ,
2019-10-10 13:21:01 +03:00
setup_data . v1 . pci_mmconfig_base ) ;
2018-03-07 10:39:14 +03:00
pci_mmcfg_arch_init ( ) ;
}
# endif
2017-11-27 11:11:54 +03:00
return 0 ;
}
2019-10-10 13:21:02 +03:00
# ifdef CONFIG_SERIAL_8250
static inline bool jailhouse_uart_enabled ( unsigned int uart_nr )
{
return setup_data . v2 . flags & BIT ( uart_nr ) ;
}
static void jailhouse_serial_fixup ( int port , struct uart_port * up ,
u32 * capabilities )
{
static const u16 pcuart_base [ ] = { 0x3f8 , 0x2f8 , 0x3e8 , 0x2e8 } ;
unsigned int n ;
for ( n = 0 ; n < ARRAY_SIZE ( pcuart_base ) ; n + + ) {
if ( pcuart_base [ n ] ! = up - > iobase )
continue ;
if ( jailhouse_uart_enabled ( n ) ) {
pr_info ( " Enabling UART%u (port 0x%lx) \n " , n ,
up - > iobase ) ;
jailhouse_setup_irq ( up - > irq ) ;
} else {
/* Deactivate UART if access isn't allowed */
up - > iobase = 0 ;
}
break ;
}
}
static void __init jailhouse_serial_workaround ( void )
{
/*
* There are flags inside setup_data that indicate availability of
* platform UARTs since setup data version 2.
*
* In case of version 1 , we don ' t know which UARTs belong Linux . In
* this case , unconditionally register 1 : 1 mapping for legacy UART IRQs
* 3 and 4.
*/
if ( setup_data . hdr . version > 1 )
serial8250_set_isa_configurator ( jailhouse_serial_fixup ) ;
}
# else /* !CONFIG_SERIAL_8250 */
static inline void jailhouse_serial_workaround ( void )
{
}
# endif /* CONFIG_SERIAL_8250 */
2017-11-27 11:11:46 +03:00
static void __init jailhouse_init_platform ( void )
{
u64 pa_data = boot_params . hdr . setup_data ;
2019-10-10 13:21:01 +03:00
unsigned long setup_data_len ;
2017-11-27 11:11:46 +03:00
struct setup_data header ;
void * mapping ;
2017-11-27 11:11:50 +03:00
x86_init . irqs . pre_vector_init = x86_init_noop ;
2017-11-27 11:11:49 +03:00
x86_init . timers . timer_init = jailhouse_timer_init ;
2017-11-27 11:11:47 +03:00
x86_init . mpparse . get_smp_config = jailhouse_get_smp_config ;
2017-11-27 11:11:54 +03:00
x86_init . pci . arch_init = jailhouse_pci_arch_init ;
2017-11-27 11:11:47 +03:00
2017-11-27 11:11:49 +03:00
x86_platform . calibrate_cpu = jailhouse_get_tsc ;
x86_platform . calibrate_tsc = jailhouse_get_tsc ;
2017-11-27 11:11:50 +03:00
x86_platform . get_wallclock = jailhouse_get_wallclock ;
x86_platform . legacy . rtc = 0 ;
x86_platform . legacy . warm_reset = 0 ;
x86_platform . legacy . i8042 = X86_LEGACY_I8042_PLATFORM_ABSENT ;
legacy_pic = & null_legacy_pic ;
2017-11-27 11:11:49 +03:00
2017-11-27 11:11:52 +03:00
machine_ops . emergency_restart = jailhouse_no_restart ;
2017-11-27 11:11:46 +03:00
while ( pa_data ) {
mapping = early_memremap ( pa_data , sizeof ( header ) ) ;
memcpy ( & header , mapping , sizeof ( header ) ) ;
early_memunmap ( mapping , sizeof ( header ) ) ;
2019-10-10 13:21:01 +03:00
if ( header . type = = SETUP_JAILHOUSE )
2017-11-27 11:11:46 +03:00
break ;
pa_data = header . next ;
}
if ( ! pa_data )
panic ( " Jailhouse: No valid setup data found " ) ;
2019-10-10 13:21:01 +03:00
/* setup data must at least contain the header */
if ( header . len < sizeof ( setup_data . hdr ) )
goto unsupported ;
2017-11-27 11:11:48 +03:00
2019-10-10 13:21:01 +03:00
pa_data + = offsetof ( struct setup_data , data ) ;
setup_data_len = min_t ( unsigned long , sizeof ( setup_data ) ,
( unsigned long ) header . len ) ;
mapping = early_memremap ( pa_data , setup_data_len ) ;
memcpy ( & setup_data , mapping , setup_data_len ) ;
early_memunmap ( mapping , setup_data_len ) ;
if ( setup_data . hdr . version = = 0 | |
setup_data . hdr . compatible_version ! =
JAILHOUSE_SETUP_REQUIRED_VERSION | |
2019-10-10 13:21:02 +03:00
( setup_data . hdr . version = = 1 & & header . len < SETUP_DATA_V1_LEN ) | |
( setup_data . hdr . version > = 2 & & header . len < SETUP_DATA_V2_LEN ) )
2019-10-10 13:21:01 +03:00
goto unsupported ;
pmtmr_ioport = setup_data . v1 . pm_timer_address ;
2017-11-27 11:11:48 +03:00
pr_debug ( " Jailhouse: PM-Timer IO Port: %#x \n " , pmtmr_ioport ) ;
2017-11-27 11:11:49 +03:00
2019-10-10 13:21:01 +03:00
precalibrated_tsc_khz = setup_data . v1 . tsc_khz ;
2018-01-19 13:06:17 +03:00
setup_force_cpu_cap ( X86_FEATURE_TSC_KNOWN_FREQ ) ;
2017-11-27 11:11:51 +03:00
2017-11-27 11:11:54 +03:00
pci_probe = 0 ;
2017-11-27 11:11:51 +03:00
/*
* Avoid that the kernel complains about missing ACPI tables - there
* are none in a non - root cell .
*/
disable_acpi ( ) ;
2019-10-10 13:21:02 +03:00
jailhouse_serial_workaround ( ) ;
2019-10-10 13:21:01 +03:00
return ;
unsupported :
panic ( " Jailhouse: Unsupported setup data structure " ) ;
2017-11-27 11:11:46 +03:00
}
bool jailhouse_paravirt ( void )
{
return jailhouse_cpuid_base ( ) ! = 0 ;
}
2019-06-26 11:54:49 +03:00
static bool __init jailhouse_x2apic_available ( void )
2017-11-27 11:11:47 +03:00
{
/*
* The x2APIC is only available if the root cell enabled it . Jailhouse
* does not support switching between xAPIC and x2APIC .
*/
return x2apic_enabled ( ) ;
}
2017-11-27 11:11:46 +03:00
const struct hypervisor_x86 x86_hyper_jailhouse __refconst = {
. name = " Jailhouse " ,
. detect = jailhouse_detect ,
. init . init_platform = jailhouse_init_platform ,
2017-11-27 11:11:47 +03:00
. init . x2apic_available = jailhouse_x2apic_available ,
2019-07-11 15:02:09 +03:00
. ignore_nopv = true ,
2017-11-27 11:11:46 +03:00
} ;