.. | .. |
---|
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 | }; |
---|