| .. | .. |
|---|
| 11 | 11 | #include <linux/acpi_pmtmr.h> |
|---|
| 12 | 12 | #include <linux/kernel.h> |
|---|
| 13 | 13 | #include <linux/reboot.h> |
|---|
| 14 | +#include <linux/serial_8250.h> |
|---|
| 14 | 15 | #include <asm/apic.h> |
|---|
| 16 | +#include <asm/io_apic.h> |
|---|
| 17 | +#include <asm/acpi.h> |
|---|
| 15 | 18 | #include <asm/cpu.h> |
|---|
| 16 | 19 | #include <asm/hypervisor.h> |
|---|
| 17 | 20 | #include <asm/i8259.h> |
|---|
| .. | .. |
|---|
| 19 | 22 | #include <asm/pci_x86.h> |
|---|
| 20 | 23 | #include <asm/reboot.h> |
|---|
| 21 | 24 | #include <asm/setup.h> |
|---|
| 25 | +#include <asm/jailhouse_para.h> |
|---|
| 22 | 26 | |
|---|
| 23 | | -static __initdata struct jailhouse_setup_data setup_data; |
|---|
| 27 | +static struct jailhouse_setup_data setup_data; |
|---|
| 28 | +#define SETUP_DATA_V1_LEN (sizeof(setup_data.hdr) + sizeof(setup_data.v1)) |
|---|
| 29 | +#define SETUP_DATA_V2_LEN (SETUP_DATA_V1_LEN + sizeof(setup_data.v2)) |
|---|
| 30 | + |
|---|
| 24 | 31 | static unsigned int precalibrated_tsc_khz; |
|---|
| 32 | + |
|---|
| 33 | +static void jailhouse_setup_irq(unsigned int irq) |
|---|
| 34 | +{ |
|---|
| 35 | + struct mpc_intsrc mp_irq = { |
|---|
| 36 | + .type = MP_INTSRC, |
|---|
| 37 | + .irqtype = mp_INT, |
|---|
| 38 | + .irqflag = MP_IRQPOL_ACTIVE_HIGH | MP_IRQTRIG_EDGE, |
|---|
| 39 | + .srcbusirq = irq, |
|---|
| 40 | + .dstirq = irq, |
|---|
| 41 | + }; |
|---|
| 42 | + mp_save_irq(&mp_irq); |
|---|
| 43 | +} |
|---|
| 25 | 44 | |
|---|
| 26 | 45 | static uint32_t jailhouse_cpuid_base(void) |
|---|
| 27 | 46 | { |
|---|
| .. | .. |
|---|
| 44 | 63 | |
|---|
| 45 | 64 | static void __init jailhouse_timer_init(void) |
|---|
| 46 | 65 | { |
|---|
| 47 | | - lapic_timer_frequency = setup_data.apic_khz * (1000 / HZ); |
|---|
| 66 | + lapic_timer_period = setup_data.v1.apic_khz * (1000 / HZ); |
|---|
| 48 | 67 | } |
|---|
| 49 | 68 | |
|---|
| 50 | 69 | static unsigned long jailhouse_get_tsc(void) |
|---|
| .. | .. |
|---|
| 76 | 95 | .type = IOAPIC_DOMAIN_STRICT, |
|---|
| 77 | 96 | .ops = &mp_ioapic_irqdomain_ops, |
|---|
| 78 | 97 | }; |
|---|
| 79 | | - struct mpc_intsrc mp_irq = { |
|---|
| 80 | | - .type = MP_INTSRC, |
|---|
| 81 | | - .irqtype = mp_INT, |
|---|
| 82 | | - .irqflag = MP_IRQPOL_ACTIVE_HIGH | MP_IRQTRIG_EDGE, |
|---|
| 83 | | - }; |
|---|
| 84 | 98 | unsigned int cpu; |
|---|
| 85 | 99 | |
|---|
| 86 | 100 | jailhouse_x2apic_init(); |
|---|
| 87 | 101 | |
|---|
| 88 | 102 | register_lapic_address(0xfee00000); |
|---|
| 89 | 103 | |
|---|
| 90 | | - for (cpu = 0; cpu < setup_data.num_cpus; cpu++) { |
|---|
| 91 | | - generic_processor_info(setup_data.cpu_ids[cpu], |
|---|
| 104 | + for (cpu = 0; cpu < setup_data.v1.num_cpus; cpu++) { |
|---|
| 105 | + generic_processor_info(setup_data.v1.cpu_ids[cpu], |
|---|
| 92 | 106 | boot_cpu_apic_version); |
|---|
| 93 | 107 | } |
|---|
| 94 | 108 | |
|---|
| 95 | 109 | smp_found_config = 1; |
|---|
| 96 | 110 | |
|---|
| 97 | | - if (setup_data.standard_ioapic) { |
|---|
| 111 | + if (setup_data.v1.standard_ioapic) { |
|---|
| 98 | 112 | mp_register_ioapic(0, 0xfec00000, gsi_top, &ioapic_cfg); |
|---|
| 99 | 113 | |
|---|
| 100 | | - /* Register 1:1 mapping for legacy UART IRQs 3 and 4 */ |
|---|
| 101 | | - mp_irq.srcbusirq = mp_irq.dstirq = 3; |
|---|
| 102 | | - mp_save_irq(&mp_irq); |
|---|
| 103 | | - |
|---|
| 104 | | - mp_irq.srcbusirq = mp_irq.dstirq = 4; |
|---|
| 105 | | - mp_save_irq(&mp_irq); |
|---|
| 114 | + if (IS_ENABLED(CONFIG_SERIAL_8250) && |
|---|
| 115 | + setup_data.hdr.version < 2) { |
|---|
| 116 | + /* Register 1:1 mapping for legacy UART IRQs 3 and 4 */ |
|---|
| 117 | + jailhouse_setup_irq(3); |
|---|
| 118 | + jailhouse_setup_irq(4); |
|---|
| 119 | + } |
|---|
| 106 | 120 | } |
|---|
| 107 | 121 | } |
|---|
| 108 | 122 | |
|---|
| .. | .. |
|---|
| 125 | 139 | pcibios_last_bus = 0xff; |
|---|
| 126 | 140 | |
|---|
| 127 | 141 | #ifdef CONFIG_PCI_MMCONFIG |
|---|
| 128 | | - if (setup_data.pci_mmconfig_base) { |
|---|
| 142 | + if (setup_data.v1.pci_mmconfig_base) { |
|---|
| 129 | 143 | pci_mmconfig_add(0, 0, pcibios_last_bus, |
|---|
| 130 | | - setup_data.pci_mmconfig_base); |
|---|
| 144 | + setup_data.v1.pci_mmconfig_base); |
|---|
| 131 | 145 | pci_mmcfg_arch_init(); |
|---|
| 132 | 146 | } |
|---|
| 133 | 147 | #endif |
|---|
| .. | .. |
|---|
| 135 | 149 | return 0; |
|---|
| 136 | 150 | } |
|---|
| 137 | 151 | |
|---|
| 152 | +#ifdef CONFIG_SERIAL_8250 |
|---|
| 153 | +static inline bool jailhouse_uart_enabled(unsigned int uart_nr) |
|---|
| 154 | +{ |
|---|
| 155 | + return setup_data.v2.flags & BIT(uart_nr); |
|---|
| 156 | +} |
|---|
| 157 | + |
|---|
| 158 | +static void jailhouse_serial_fixup(int port, struct uart_port *up, |
|---|
| 159 | + u32 *capabilities) |
|---|
| 160 | +{ |
|---|
| 161 | + static const u16 pcuart_base[] = {0x3f8, 0x2f8, 0x3e8, 0x2e8}; |
|---|
| 162 | + unsigned int n; |
|---|
| 163 | + |
|---|
| 164 | + for (n = 0; n < ARRAY_SIZE(pcuart_base); n++) { |
|---|
| 165 | + if (pcuart_base[n] != up->iobase) |
|---|
| 166 | + continue; |
|---|
| 167 | + |
|---|
| 168 | + if (jailhouse_uart_enabled(n)) { |
|---|
| 169 | + pr_info("Enabling UART%u (port 0x%lx)\n", n, |
|---|
| 170 | + up->iobase); |
|---|
| 171 | + jailhouse_setup_irq(up->irq); |
|---|
| 172 | + } else { |
|---|
| 173 | + /* Deactivate UART if access isn't allowed */ |
|---|
| 174 | + up->iobase = 0; |
|---|
| 175 | + } |
|---|
| 176 | + break; |
|---|
| 177 | + } |
|---|
| 178 | +} |
|---|
| 179 | + |
|---|
| 180 | +static void __init jailhouse_serial_workaround(void) |
|---|
| 181 | +{ |
|---|
| 182 | + /* |
|---|
| 183 | + * There are flags inside setup_data that indicate availability of |
|---|
| 184 | + * platform UARTs since setup data version 2. |
|---|
| 185 | + * |
|---|
| 186 | + * In case of version 1, we don't know which UARTs belong Linux. In |
|---|
| 187 | + * this case, unconditionally register 1:1 mapping for legacy UART IRQs |
|---|
| 188 | + * 3 and 4. |
|---|
| 189 | + */ |
|---|
| 190 | + if (setup_data.hdr.version > 1) |
|---|
| 191 | + serial8250_set_isa_configurator(jailhouse_serial_fixup); |
|---|
| 192 | +} |
|---|
| 193 | +#else /* !CONFIG_SERIAL_8250 */ |
|---|
| 194 | +static inline void jailhouse_serial_workaround(void) |
|---|
| 195 | +{ |
|---|
| 196 | +} |
|---|
| 197 | +#endif /* CONFIG_SERIAL_8250 */ |
|---|
| 198 | + |
|---|
| 138 | 199 | static void __init jailhouse_init_platform(void) |
|---|
| 139 | 200 | { |
|---|
| 140 | 201 | u64 pa_data = boot_params.hdr.setup_data; |
|---|
| 202 | + unsigned long setup_data_len; |
|---|
| 141 | 203 | struct setup_data header; |
|---|
| 142 | 204 | void *mapping; |
|---|
| 143 | 205 | |
|---|
| .. | .. |
|---|
| 162 | 224 | memcpy(&header, mapping, sizeof(header)); |
|---|
| 163 | 225 | early_memunmap(mapping, sizeof(header)); |
|---|
| 164 | 226 | |
|---|
| 165 | | - if (header.type == SETUP_JAILHOUSE && |
|---|
| 166 | | - header.len >= sizeof(setup_data)) { |
|---|
| 167 | | - pa_data += offsetof(struct setup_data, data); |
|---|
| 168 | | - |
|---|
| 169 | | - mapping = early_memremap(pa_data, sizeof(setup_data)); |
|---|
| 170 | | - memcpy(&setup_data, mapping, sizeof(setup_data)); |
|---|
| 171 | | - early_memunmap(mapping, sizeof(setup_data)); |
|---|
| 172 | | - |
|---|
| 227 | + if (header.type == SETUP_JAILHOUSE) |
|---|
| 173 | 228 | break; |
|---|
| 174 | | - } |
|---|
| 175 | 229 | |
|---|
| 176 | 230 | pa_data = header.next; |
|---|
| 177 | 231 | } |
|---|
| .. | .. |
|---|
| 179 | 233 | if (!pa_data) |
|---|
| 180 | 234 | panic("Jailhouse: No valid setup data found"); |
|---|
| 181 | 235 | |
|---|
| 182 | | - if (setup_data.compatible_version > JAILHOUSE_SETUP_REQUIRED_VERSION) |
|---|
| 183 | | - panic("Jailhouse: Unsupported setup data structure"); |
|---|
| 236 | + /* setup data must at least contain the header */ |
|---|
| 237 | + if (header.len < sizeof(setup_data.hdr)) |
|---|
| 238 | + goto unsupported; |
|---|
| 184 | 239 | |
|---|
| 185 | | - pmtmr_ioport = setup_data.pm_timer_address; |
|---|
| 240 | + pa_data += offsetof(struct setup_data, data); |
|---|
| 241 | + setup_data_len = min_t(unsigned long, sizeof(setup_data), |
|---|
| 242 | + (unsigned long)header.len); |
|---|
| 243 | + mapping = early_memremap(pa_data, setup_data_len); |
|---|
| 244 | + memcpy(&setup_data, mapping, setup_data_len); |
|---|
| 245 | + early_memunmap(mapping, setup_data_len); |
|---|
| 246 | + |
|---|
| 247 | + if (setup_data.hdr.version == 0 || |
|---|
| 248 | + setup_data.hdr.compatible_version != |
|---|
| 249 | + JAILHOUSE_SETUP_REQUIRED_VERSION || |
|---|
| 250 | + (setup_data.hdr.version == 1 && header.len < SETUP_DATA_V1_LEN) || |
|---|
| 251 | + (setup_data.hdr.version >= 2 && header.len < SETUP_DATA_V2_LEN)) |
|---|
| 252 | + goto unsupported; |
|---|
| 253 | + |
|---|
| 254 | + pmtmr_ioport = setup_data.v1.pm_timer_address; |
|---|
| 186 | 255 | pr_debug("Jailhouse: PM-Timer IO Port: %#x\n", pmtmr_ioport); |
|---|
| 187 | 256 | |
|---|
| 188 | | - precalibrated_tsc_khz = setup_data.tsc_khz; |
|---|
| 257 | + precalibrated_tsc_khz = setup_data.v1.tsc_khz; |
|---|
| 189 | 258 | setup_force_cpu_cap(X86_FEATURE_TSC_KNOWN_FREQ); |
|---|
| 190 | 259 | |
|---|
| 191 | 260 | pci_probe = 0; |
|---|
| .. | .. |
|---|
| 195 | 264 | * are none in a non-root cell. |
|---|
| 196 | 265 | */ |
|---|
| 197 | 266 | disable_acpi(); |
|---|
| 267 | + |
|---|
| 268 | + jailhouse_serial_workaround(); |
|---|
| 269 | + return; |
|---|
| 270 | + |
|---|
| 271 | +unsupported: |
|---|
| 272 | + panic("Jailhouse: Unsupported setup data structure"); |
|---|
| 198 | 273 | } |
|---|
| 199 | 274 | |
|---|
| 200 | 275 | bool jailhouse_paravirt(void) |
|---|
| .. | .. |
|---|
| 202 | 277 | return jailhouse_cpuid_base() != 0; |
|---|
| 203 | 278 | } |
|---|
| 204 | 279 | |
|---|
| 205 | | -static bool jailhouse_x2apic_available(void) |
|---|
| 280 | +static bool __init jailhouse_x2apic_available(void) |
|---|
| 206 | 281 | { |
|---|
| 207 | 282 | /* |
|---|
| 208 | 283 | * The x2APIC is only available if the root cell enabled it. Jailhouse |
|---|
| .. | .. |
|---|
| 216 | 291 | .detect = jailhouse_detect, |
|---|
| 217 | 292 | .init.init_platform = jailhouse_init_platform, |
|---|
| 218 | 293 | .init.x2apic_available = jailhouse_x2apic_available, |
|---|
| 294 | + .ignore_nopv = true, |
|---|
| 219 | 295 | }; |
|---|