mirror of
https://github.com/torvalds/linux.git
synced 2024-12-12 14:12:51 +00:00
0d7c1e2218
Non-root cells do not have CMOS access, thus the warm reset cannot be enabled. There is no RTC, thus also no wall clock. Furthermore, there are no ISA IRQs and no PIC. Also disable probing of i8042 devices that are typically blocked for non-root cells. In theory, access could also be granted to a non-root cell, provided the root cell is not using the devices. But there is no concrete scenario in sight, and disabling probing over Jailhouse allows to build generic kernels that keep CONFIG_SERIO enabled for use in normal systems. Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com> Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Cc: jailhouse-dev@googlegroups.com Link: https://lkml.kernel.org/r/39b68cc2c496501c9d95e6f40e5d76e3053c3908.1511770314.git.jan.kiszka@siemens.com
150 lines
3.6 KiB
C
150 lines
3.6 KiB
C
// SPDX-License-Identifier: GPL2.0
|
|
/*
|
|
* Jailhouse paravirt_ops implementation
|
|
*
|
|
* Copyright (c) Siemens AG, 2015-2017
|
|
*
|
|
* Authors:
|
|
* Jan Kiszka <jan.kiszka@siemens.com>
|
|
*/
|
|
|
|
#include <linux/acpi_pmtmr.h>
|
|
#include <linux/kernel.h>
|
|
#include <asm/apic.h>
|
|
#include <asm/cpu.h>
|
|
#include <asm/hypervisor.h>
|
|
#include <asm/i8259.h>
|
|
#include <asm/setup.h>
|
|
|
|
static __initdata struct jailhouse_setup_data setup_data;
|
|
static unsigned int precalibrated_tsc_khz;
|
|
|
|
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();
|
|
}
|
|
|
|
static void jailhouse_get_wallclock(struct timespec *now)
|
|
{
|
|
memset(now, 0, sizeof(*now));
|
|
}
|
|
|
|
static void __init jailhouse_timer_init(void)
|
|
{
|
|
lapic_timer_frequency = setup_data.apic_khz * (1000 / HZ);
|
|
}
|
|
|
|
static unsigned long jailhouse_get_tsc(void)
|
|
{
|
|
return precalibrated_tsc_khz;
|
|
}
|
|
|
|
static void __init jailhouse_get_smp_config(unsigned int early)
|
|
{
|
|
unsigned int cpu;
|
|
|
|
if (x2apic_enabled()) {
|
|
/*
|
|
* 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("", "");
|
|
}
|
|
|
|
register_lapic_address(0xfee00000);
|
|
|
|
for (cpu = 0; cpu < setup_data.num_cpus; cpu++) {
|
|
generic_processor_info(setup_data.cpu_ids[cpu],
|
|
boot_cpu_apic_version);
|
|
}
|
|
|
|
smp_found_config = 1;
|
|
}
|
|
|
|
static void __init jailhouse_init_platform(void)
|
|
{
|
|
u64 pa_data = boot_params.hdr.setup_data;
|
|
struct setup_data header;
|
|
void *mapping;
|
|
|
|
x86_init.irqs.pre_vector_init = x86_init_noop;
|
|
x86_init.timers.timer_init = jailhouse_timer_init;
|
|
x86_init.mpparse.get_smp_config = jailhouse_get_smp_config;
|
|
|
|
x86_platform.calibrate_cpu = jailhouse_get_tsc;
|
|
x86_platform.calibrate_tsc = jailhouse_get_tsc;
|
|
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;
|
|
|
|
while (pa_data) {
|
|
mapping = early_memremap(pa_data, sizeof(header));
|
|
memcpy(&header, mapping, sizeof(header));
|
|
early_memunmap(mapping, sizeof(header));
|
|
|
|
if (header.type == SETUP_JAILHOUSE &&
|
|
header.len >= sizeof(setup_data)) {
|
|
pa_data += offsetof(struct setup_data, data);
|
|
|
|
mapping = early_memremap(pa_data, sizeof(setup_data));
|
|
memcpy(&setup_data, mapping, sizeof(setup_data));
|
|
early_memunmap(mapping, sizeof(setup_data));
|
|
|
|
break;
|
|
}
|
|
|
|
pa_data = header.next;
|
|
}
|
|
|
|
if (!pa_data)
|
|
panic("Jailhouse: No valid setup data found");
|
|
|
|
if (setup_data.compatible_version > JAILHOUSE_SETUP_REQUIRED_VERSION)
|
|
panic("Jailhouse: Unsupported setup data structure");
|
|
|
|
pmtmr_ioport = setup_data.pm_timer_address;
|
|
pr_debug("Jailhouse: PM-Timer IO Port: %#x\n", pmtmr_ioport);
|
|
|
|
precalibrated_tsc_khz = setup_data.tsc_khz;
|
|
}
|
|
|
|
bool jailhouse_paravirt(void)
|
|
{
|
|
return jailhouse_cpuid_base() != 0;
|
|
}
|
|
|
|
static bool jailhouse_x2apic_available(void)
|
|
{
|
|
/*
|
|
* The x2APIC is only available if the root cell enabled it. Jailhouse
|
|
* does not support switching between xAPIC and x2APIC.
|
|
*/
|
|
return x2apic_enabled();
|
|
}
|
|
|
|
const struct hypervisor_x86 x86_hyper_jailhouse __refconst = {
|
|
.name = "Jailhouse",
|
|
.detect = jailhouse_detect,
|
|
.init.init_platform = jailhouse_init_platform,
|
|
.init.x2apic_available = jailhouse_x2apic_available,
|
|
};
|