]>
Commit | Line | Data |
---|---|---|
7010adcd | 1 | // SPDX-License-Identifier: GPL-2.0 |
4a362601 JK |
2 | /* |
3 | * Jailhouse paravirt_ops implementation | |
4 | * | |
5 | * Copyright (c) Siemens AG, 2015-2017 | |
6 | * | |
7 | * Authors: | |
8 | * Jan Kiszka <jan.kiszka@siemens.com> | |
9 | */ | |
10 | ||
87e65d05 | 11 | #include <linux/acpi_pmtmr.h> |
4a362601 | 12 | #include <linux/kernel.h> |
fd498076 | 13 | #include <linux/reboot.h> |
7a56b81c | 14 | #include <linux/serial_8250.h> |
11c8dc41 | 15 | #include <asm/apic.h> |
4a362601 JK |
16 | #include <asm/cpu.h> |
17 | #include <asm/hypervisor.h> | |
0d7c1e22 | 18 | #include <asm/i8259.h> |
cf878e16 | 19 | #include <asm/irqdomain.h> |
a0c01e4b | 20 | #include <asm/pci_x86.h> |
fd498076 | 21 | #include <asm/reboot.h> |
4a362601 | 22 | #include <asm/setup.h> |
89f579ce | 23 | #include <asm/jailhouse_para.h> |
4a362601 | 24 | |
7a56b81c | 25 | static struct jailhouse_setup_data setup_data; |
0935e5f7 | 26 | #define SETUP_DATA_V1_LEN (sizeof(setup_data.hdr) + sizeof(setup_data.v1)) |
7a56b81c | 27 | #define SETUP_DATA_V2_LEN (SETUP_DATA_V1_LEN + sizeof(setup_data.v2)) |
0935e5f7 | 28 | |
e85eb632 | 29 | static unsigned int precalibrated_tsc_khz; |
4a362601 | 30 | |
7a56b81c RR |
31 | static void jailhouse_setup_irq(unsigned int irq) |
32 | { | |
33 | struct mpc_intsrc mp_irq = { | |
34 | .type = MP_INTSRC, | |
35 | .irqtype = mp_INT, | |
36 | .irqflag = MP_IRQPOL_ACTIVE_HIGH | MP_IRQTRIG_EDGE, | |
37 | .srcbusirq = irq, | |
38 | .dstirq = irq, | |
39 | }; | |
40 | mp_save_irq(&mp_irq); | |
41 | } | |
42 | ||
4a362601 JK |
43 | static uint32_t jailhouse_cpuid_base(void) |
44 | { | |
45 | if (boot_cpu_data.cpuid_level < 0 || | |
46 | !boot_cpu_has(X86_FEATURE_HYPERVISOR)) | |
47 | return 0; | |
48 | ||
49 | return hypervisor_cpuid_base("Jailhouse\0\0\0", 0); | |
50 | } | |
51 | ||
52 | static uint32_t __init jailhouse_detect(void) | |
53 | { | |
54 | return jailhouse_cpuid_base(); | |
55 | } | |
56 | ||
e27c4929 | 57 | static void jailhouse_get_wallclock(struct timespec64 *now) |
0d7c1e22 JK |
58 | { |
59 | memset(now, 0, sizeof(*now)); | |
60 | } | |
61 | ||
e85eb632 JK |
62 | static void __init jailhouse_timer_init(void) |
63 | { | |
0935e5f7 | 64 | lapic_timer_period = setup_data.v1.apic_khz * (1000 / HZ); |
e85eb632 JK |
65 | } |
66 | ||
67 | static unsigned long jailhouse_get_tsc(void) | |
68 | { | |
69 | return precalibrated_tsc_khz; | |
70 | } | |
71 | ||
be6d447e TG |
72 | static void __init jailhouse_x2apic_init(void) |
73 | { | |
74 | #ifdef CONFIG_X86_X2APIC | |
75 | if (!x2apic_enabled()) | |
76 | return; | |
77 | /* | |
78 | * We do not have access to IR inside Jailhouse non-root cells. So | |
79 | * we have to run in physical mode. | |
80 | */ | |
81 | x2apic_phys = 1; | |
82 | /* | |
83 | * This will trigger the switch to apic_x2apic_phys. Empty OEM IDs | |
84 | * ensure that only this APIC driver picks up the call. | |
85 | */ | |
86 | default_acpi_madt_oem_check("", ""); | |
87 | #endif | |
88 | } | |
89 | ||
11c8dc41 JK |
90 | static void __init jailhouse_get_smp_config(unsigned int early) |
91 | { | |
cf878e16 JK |
92 | struct ioapic_domain_cfg ioapic_cfg = { |
93 | .type = IOAPIC_DOMAIN_STRICT, | |
94 | .ops = &mp_ioapic_irqdomain_ops, | |
95 | }; | |
11c8dc41 JK |
96 | unsigned int cpu; |
97 | ||
be6d447e | 98 | jailhouse_x2apic_init(); |
11c8dc41 JK |
99 | |
100 | register_lapic_address(0xfee00000); | |
101 | ||
0935e5f7 RR |
102 | for (cpu = 0; cpu < setup_data.v1.num_cpus; cpu++) { |
103 | generic_processor_info(setup_data.v1.cpu_ids[cpu], | |
11c8dc41 JK |
104 | boot_cpu_apic_version); |
105 | } | |
106 | ||
107 | smp_found_config = 1; | |
cf878e16 | 108 | |
0935e5f7 | 109 | if (setup_data.v1.standard_ioapic) { |
cf878e16 JK |
110 | mp_register_ioapic(0, 0xfec00000, gsi_top, &ioapic_cfg); |
111 | ||
7a56b81c RR |
112 | if (IS_ENABLED(CONFIG_SERIAL_8250) && |
113 | setup_data.hdr.version < 2) { | |
114 | /* Register 1:1 mapping for legacy UART IRQs 3 and 4 */ | |
115 | jailhouse_setup_irq(3); | |
116 | jailhouse_setup_irq(4); | |
117 | } | |
cf878e16 | 118 | } |
11c8dc41 JK |
119 | } |
120 | ||
fd498076 JK |
121 | static void jailhouse_no_restart(void) |
122 | { | |
123 | pr_notice("Jailhouse: Restart not supported, halting\n"); | |
124 | machine_halt(); | |
125 | } | |
126 | ||
a0c01e4b JK |
127 | static int __init jailhouse_pci_arch_init(void) |
128 | { | |
129 | pci_direct_init(1); | |
130 | ||
131 | /* | |
132 | * There are no bridges on the virtual PCI root bus under Jailhouse, | |
133 | * thus no other way to discover all devices than a full scan. | |
3b42349d | 134 | * Respect any overrides via the command line, though. |
a0c01e4b | 135 | */ |
3b42349d JK |
136 | if (pcibios_last_bus < 0) |
137 | pcibios_last_bus = 0xff; | |
a0c01e4b | 138 | |
6fa4a94e | 139 | #ifdef CONFIG_PCI_MMCONFIG |
0935e5f7 | 140 | if (setup_data.v1.pci_mmconfig_base) { |
6fa4a94e | 141 | pci_mmconfig_add(0, 0, pcibios_last_bus, |
0935e5f7 | 142 | setup_data.v1.pci_mmconfig_base); |
6fa4a94e OP |
143 | pci_mmcfg_arch_init(); |
144 | } | |
145 | #endif | |
146 | ||
a0c01e4b JK |
147 | return 0; |
148 | } | |
149 | ||
7a56b81c RR |
150 | #ifdef CONFIG_SERIAL_8250 |
151 | static inline bool jailhouse_uart_enabled(unsigned int uart_nr) | |
152 | { | |
153 | return setup_data.v2.flags & BIT(uart_nr); | |
154 | } | |
155 | ||
156 | static void jailhouse_serial_fixup(int port, struct uart_port *up, | |
157 | u32 *capabilities) | |
158 | { | |
159 | static const u16 pcuart_base[] = {0x3f8, 0x2f8, 0x3e8, 0x2e8}; | |
160 | unsigned int n; | |
161 | ||
162 | for (n = 0; n < ARRAY_SIZE(pcuart_base); n++) { | |
163 | if (pcuart_base[n] != up->iobase) | |
164 | continue; | |
165 | ||
166 | if (jailhouse_uart_enabled(n)) { | |
167 | pr_info("Enabling UART%u (port 0x%lx)\n", n, | |
168 | up->iobase); | |
169 | jailhouse_setup_irq(up->irq); | |
170 | } else { | |
171 | /* Deactivate UART if access isn't allowed */ | |
172 | up->iobase = 0; | |
173 | } | |
174 | break; | |
175 | } | |
176 | } | |
177 | ||
178 | static void __init jailhouse_serial_workaround(void) | |
179 | { | |
180 | /* | |
181 | * There are flags inside setup_data that indicate availability of | |
182 | * platform UARTs since setup data version 2. | |
183 | * | |
184 | * In case of version 1, we don't know which UARTs belong Linux. In | |
185 | * this case, unconditionally register 1:1 mapping for legacy UART IRQs | |
186 | * 3 and 4. | |
187 | */ | |
188 | if (setup_data.hdr.version > 1) | |
189 | serial8250_set_isa_configurator(jailhouse_serial_fixup); | |
190 | } | |
191 | #else /* !CONFIG_SERIAL_8250 */ | |
192 | static inline void jailhouse_serial_workaround(void) | |
193 | { | |
194 | } | |
195 | #endif /* CONFIG_SERIAL_8250 */ | |
196 | ||
4a362601 JK |
197 | static void __init jailhouse_init_platform(void) |
198 | { | |
199 | u64 pa_data = boot_params.hdr.setup_data; | |
0935e5f7 | 200 | unsigned long setup_data_len; |
4a362601 JK |
201 | struct setup_data header; |
202 | void *mapping; | |
203 | ||
0d7c1e22 | 204 | x86_init.irqs.pre_vector_init = x86_init_noop; |
e85eb632 | 205 | x86_init.timers.timer_init = jailhouse_timer_init; |
11c8dc41 | 206 | x86_init.mpparse.get_smp_config = jailhouse_get_smp_config; |
a0c01e4b | 207 | x86_init.pci.arch_init = jailhouse_pci_arch_init; |
11c8dc41 | 208 | |
e85eb632 JK |
209 | x86_platform.calibrate_cpu = jailhouse_get_tsc; |
210 | x86_platform.calibrate_tsc = jailhouse_get_tsc; | |
0d7c1e22 JK |
211 | x86_platform.get_wallclock = jailhouse_get_wallclock; |
212 | x86_platform.legacy.rtc = 0; | |
213 | x86_platform.legacy.warm_reset = 0; | |
214 | x86_platform.legacy.i8042 = X86_LEGACY_I8042_PLATFORM_ABSENT; | |
215 | ||
216 | legacy_pic = &null_legacy_pic; | |
e85eb632 | 217 | |
fd498076 JK |
218 | machine_ops.emergency_restart = jailhouse_no_restart; |
219 | ||
4a362601 JK |
220 | while (pa_data) { |
221 | mapping = early_memremap(pa_data, sizeof(header)); | |
222 | memcpy(&header, mapping, sizeof(header)); | |
223 | early_memunmap(mapping, sizeof(header)); | |
224 | ||
0935e5f7 | 225 | if (header.type == SETUP_JAILHOUSE) |
4a362601 | 226 | break; |
4a362601 JK |
227 | |
228 | pa_data = header.next; | |
229 | } | |
230 | ||
231 | if (!pa_data) | |
232 | panic("Jailhouse: No valid setup data found"); | |
233 | ||
0935e5f7 RR |
234 | /* setup data must at least contain the header */ |
235 | if (header.len < sizeof(setup_data.hdr)) | |
236 | goto unsupported; | |
87e65d05 | 237 | |
0935e5f7 RR |
238 | pa_data += offsetof(struct setup_data, data); |
239 | setup_data_len = min_t(unsigned long, sizeof(setup_data), | |
240 | (unsigned long)header.len); | |
241 | mapping = early_memremap(pa_data, setup_data_len); | |
242 | memcpy(&setup_data, mapping, setup_data_len); | |
243 | early_memunmap(mapping, setup_data_len); | |
244 | ||
245 | if (setup_data.hdr.version == 0 || | |
246 | setup_data.hdr.compatible_version != | |
247 | JAILHOUSE_SETUP_REQUIRED_VERSION || | |
7a56b81c RR |
248 | (setup_data.hdr.version == 1 && header.len < SETUP_DATA_V1_LEN) || |
249 | (setup_data.hdr.version >= 2 && header.len < SETUP_DATA_V2_LEN)) | |
0935e5f7 RR |
250 | goto unsupported; |
251 | ||
252 | pmtmr_ioport = setup_data.v1.pm_timer_address; | |
87e65d05 | 253 | pr_debug("Jailhouse: PM-Timer IO Port: %#x\n", pmtmr_ioport); |
e85eb632 | 254 | |
0935e5f7 | 255 | precalibrated_tsc_khz = setup_data.v1.tsc_khz; |
11f19ec0 | 256 | setup_force_cpu_cap(X86_FEATURE_TSC_KNOWN_FREQ); |
5ae44430 | 257 | |
a0c01e4b JK |
258 | pci_probe = 0; |
259 | ||
5ae44430 JK |
260 | /* |
261 | * Avoid that the kernel complains about missing ACPI tables - there | |
262 | * are none in a non-root cell. | |
263 | */ | |
264 | disable_acpi(); | |
7a56b81c RR |
265 | |
266 | jailhouse_serial_workaround(); | |
0935e5f7 RR |
267 | return; |
268 | ||
269 | unsupported: | |
270 | panic("Jailhouse: Unsupported setup data structure"); | |
4a362601 JK |
271 | } |
272 | ||
273 | bool jailhouse_paravirt(void) | |
274 | { | |
275 | return jailhouse_cpuid_base() != 0; | |
276 | } | |
277 | ||
d97ee99b | 278 | static bool __init jailhouse_x2apic_available(void) |
11c8dc41 JK |
279 | { |
280 | /* | |
281 | * The x2APIC is only available if the root cell enabled it. Jailhouse | |
282 | * does not support switching between xAPIC and x2APIC. | |
283 | */ | |
284 | return x2apic_enabled(); | |
285 | } | |
286 | ||
4a362601 JK |
287 | const struct hypervisor_x86 x86_hyper_jailhouse __refconst = { |
288 | .name = "Jailhouse", | |
289 | .detect = jailhouse_detect, | |
290 | .init.init_platform = jailhouse_init_platform, | |
11c8dc41 | 291 | .init.x2apic_available = jailhouse_x2apic_available, |
30978346 | 292 | .ignore_nopv = true, |
4a362601 | 293 | }; |