blob: cc6409412710f2d4fae461f0be5eee8ac1e45882 [file] [log] [blame]
Kevin O'Connore7cc7642009-10-04 10:05:16 -04001// Paravirtualization support.
2//
3// Copyright (C) 2009 Red Hat Inc.
4//
5// Authors:
6// Gleb Natapov <gnatapov@redhat.com>
7//
8// This file may be distributed under the terms of the GNU LGPLv3 license.
9
Kevin O'Connor897fb112013-02-07 23:32:48 -050010#include "config.h" // CONFIG_QEMU
Kevin O'Connorb3064592012-08-14 21:20:10 -040011#include "util.h" // dprintf
12#include "byteorder.h" // be32_to_cpu
Kevin O'Connor01a85202009-10-18 09:49:59 -040013#include "ioport.h" // outw
Kevin O'Connord83c87b2013-01-21 01:14:12 -050014#include "paravirt.h" // qemu_cfg_preinit
Kevin O'Connor01a85202009-10-18 09:49:59 -040015#include "smbios.h" // struct smbios_structure_header
Kevin O'Connor8ed2e532013-01-21 02:32:48 -050016#include "memmap.h" // add_e820
17#include "cmos.h" // CMOS_*
18#include "acpi.h" // acpi_setup
19#include "mptable.h" // mptable_setup
20#include "pci.h" // create_pirtable
Kevin O'Connore7cc7642009-10-04 10:05:16 -040021
Kevin O'Connor4edda082013-02-09 13:21:08 -050022struct e820_reservation {
23 u64 address;
24 u64 length;
25 u32 type;
26};
Kevin O'Connore7cc7642009-10-04 10:05:16 -040027
Kevin O'Connor7b5bc502013-02-09 13:07:23 -050028/* This CPUID returns the signature 'KVMKVMKVM' in ebx, ecx, and edx. It
29 * should be used to determine that a VM is running under KVM.
30 */
31#define KVM_CPUID_SIGNATURE 0x40000000
32
33static void kvm_preinit(void)
34{
35 if (!CONFIG_QEMU)
36 return;
37 unsigned int eax, ebx, ecx, edx;
38 char signature[13];
39
40 cpuid(KVM_CPUID_SIGNATURE, &eax, &ebx, &ecx, &edx);
41 memcpy(signature + 0, &ebx, 4);
42 memcpy(signature + 4, &ecx, 4);
43 memcpy(signature + 8, &edx, 4);
44 signature[12] = 0;
45
46 if (strcmp(signature, "KVMKVMKVM") == 0) {
47 dprintf(1, "Running on KVM\n");
48 PlatformRunningOn |= PF_KVM;
49 }
50}
51
Kevin O'Connor8ed2e532013-01-21 02:32:48 -050052void
53qemu_ramsize_preinit(void)
54{
Kevin O'Connor02313b22013-02-07 22:42:25 -050055 if (!CONFIG_QEMU)
56 return;
57
58 PlatformRunningOn = PF_QEMU;
Kevin O'Connor7b5bc502013-02-09 13:07:23 -050059 kvm_preinit();
Kevin O'Connor02313b22013-02-07 22:42:25 -050060
Kevin O'Connor8ed2e532013-01-21 02:32:48 -050061 // On emulators, get memory size from nvram.
62 u32 rs = ((inb_cmos(CMOS_MEM_EXTMEM2_LOW) << 16)
63 | (inb_cmos(CMOS_MEM_EXTMEM2_HIGH) << 24));
64 if (rs)
65 rs += 16 * 1024 * 1024;
66 else
67 rs = (((inb_cmos(CMOS_MEM_EXTMEM_LOW) << 10)
68 | (inb_cmos(CMOS_MEM_EXTMEM_HIGH) << 18))
69 + 1 * 1024 * 1024);
70 RamSize = rs;
71 add_e820(0, rs, E820_RAM);
72
73 // Check for memory over 4Gig
74 u64 high = ((inb_cmos(CMOS_MEM_HIGHMEM_LOW) << 16)
75 | ((u32)inb_cmos(CMOS_MEM_HIGHMEM_MID) << 24)
76 | ((u64)inb_cmos(CMOS_MEM_HIGHMEM_HIGH) << 32));
77 RamSizeOver4G = high;
78 add_e820(0x100000000ull, high, E820_RAM);
79
80 /* reserve 256KB BIOS area at the end of 4 GB */
81 add_e820(0xfffc0000, 256*1024, E820_RESERVED);
82
83 u32 count = qemu_cfg_e820_entries();
84 if (count) {
85 struct e820_reservation entry;
86 int i;
87
88 for (i = 0; i < count; i++) {
89 qemu_cfg_e820_load_next(&entry);
90 add_e820(entry.address, entry.length, entry.type);
91 }
Kevin O'Connor7b5bc502013-02-09 13:07:23 -050092 } else if (runningOnKVM()) {
Kevin O'Connor8ed2e532013-01-21 02:32:48 -050093 // Backwards compatibility - provide hard coded range.
94 // 4 pages before the bios, 3 pages for vmx tss pages, the
95 // other page for EPT real mode pagetable
96 add_e820(0xfffbc000, 4*4096, E820_RESERVED);
97 }
98}
99
100void
101qemu_biostable_setup(void)
102{
103 pirtable_setup();
104 mptable_setup();
105 smbios_setup();
106 acpi_setup();
107}
108
Kevin O'Connor4edda082013-02-09 13:21:08 -0500109
110/****************************************************************
111 * QEMU firmware config (fw_cfg) interface
112 ****************************************************************/
113
114int qemu_cfg_present;
115
116#define QEMU_CFG_SIGNATURE 0x00
117#define QEMU_CFG_ID 0x01
118#define QEMU_CFG_UUID 0x02
119#define QEMU_CFG_NUMA 0x0d
120#define QEMU_CFG_BOOT_MENU 0x0e
121#define QEMU_CFG_MAX_CPUS 0x0f
122#define QEMU_CFG_FILE_DIR 0x19
123#define QEMU_CFG_ARCH_LOCAL 0x8000
124#define QEMU_CFG_ACPI_TABLES (QEMU_CFG_ARCH_LOCAL + 0)
125#define QEMU_CFG_SMBIOS_ENTRIES (QEMU_CFG_ARCH_LOCAL + 1)
126#define QEMU_CFG_IRQ0_OVERRIDE (QEMU_CFG_ARCH_LOCAL + 2)
127#define QEMU_CFG_E820_TABLE (QEMU_CFG_ARCH_LOCAL + 3)
128
Kevin O'Connore7cc7642009-10-04 10:05:16 -0400129static void
130qemu_cfg_select(u16 f)
131{
132 outw(f, PORT_QEMU_CFG_CTL);
133}
134
135static void
136qemu_cfg_read(u8 *buf, int len)
137{
Kevin O'Connor6039fc52010-08-25 21:43:19 -0400138 insb(PORT_QEMU_CFG_DATA, buf, len);
Kevin O'Connore7cc7642009-10-04 10:05:16 -0400139}
140
141static void
Kevin O'Connor4e4b4102009-10-08 21:21:59 -0400142qemu_cfg_skip(int len)
143{
144 while (len--)
145 inb(PORT_QEMU_CFG_DATA);
146}
147
148static void
Kevin O'Connore7cc7642009-10-04 10:05:16 -0400149qemu_cfg_read_entry(void *buf, int e, int len)
150{
151 qemu_cfg_select(e);
152 qemu_cfg_read(buf, len);
153}
154
Kevin O'Connord83c87b2013-01-21 01:14:12 -0500155void qemu_cfg_preinit(void)
Kevin O'Connore7cc7642009-10-04 10:05:16 -0400156{
157 char *sig = "QEMU";
158 int i;
159
Kevin O'Connor897fb112013-02-07 23:32:48 -0500160 if (!CONFIG_QEMU)
Kevin O'Connore7cc7642009-10-04 10:05:16 -0400161 return;
162
163 qemu_cfg_present = 1;
164
165 qemu_cfg_select(QEMU_CFG_SIGNATURE);
166
167 for (i = 0; i < 4; i++)
168 if (inb(PORT_QEMU_CFG_DATA) != sig[i]) {
169 qemu_cfg_present = 0;
170 break;
171 }
172 dprintf(4, "qemu_cfg_present=%d\n", qemu_cfg_present);
173}
174
175void qemu_cfg_get_uuid(u8 *uuid)
176{
177 if (!qemu_cfg_present)
178 return;
179
180 qemu_cfg_read_entry(uuid, QEMU_CFG_UUID, 16);
181}
182
183int qemu_cfg_show_boot_menu(void)
184{
185 u16 v;
186 if (!qemu_cfg_present)
187 return 1;
188
189 qemu_cfg_read_entry(&v, QEMU_CFG_BOOT_MENU, sizeof(v));
190
191 return v;
192}
193
Kevin O'Connor4d2b6192009-10-08 21:37:21 -0400194int qemu_cfg_irq0_override(void)
195{
196 u8 v;
197
198 if (!qemu_cfg_present)
199 return 0;
200
201 qemu_cfg_read_entry(&v, QEMU_CFG_IRQ0_OVERRIDE, sizeof(v));
202
203 return v;
204}
205
Kevin O'Connorcc6dc462009-10-08 21:18:41 -0400206u16 qemu_cfg_acpi_additional_tables(void)
207{
208 u16 cnt;
209
210 if (!qemu_cfg_present)
211 return 0;
212
213 qemu_cfg_read_entry(&cnt, QEMU_CFG_ACPI_TABLES, sizeof(cnt));
214
215 return cnt;
216}
217
218u16 qemu_cfg_next_acpi_table_len(void)
219{
220 u16 len;
221
222 qemu_cfg_read((u8*)&len, sizeof(len));
223
224 return len;
225}
226
227void* qemu_cfg_next_acpi_table_load(void *addr, u16 len)
228{
229 qemu_cfg_read(addr, len);
230 return addr;
231}
232
Kevin O'Connor4e4b4102009-10-08 21:21:59 -0400233u16 qemu_cfg_smbios_entries(void)
234{
235 u16 cnt;
236
237 if (!qemu_cfg_present)
238 return 0;
239
240 qemu_cfg_read_entry(&cnt, QEMU_CFG_SMBIOS_ENTRIES, sizeof(cnt));
241
242 return cnt;
243}
244
Jes Sorensen0360e8e2010-02-16 09:46:08 +0100245u32 qemu_cfg_e820_entries(void)
246{
247 u32 cnt;
248
249 if (!qemu_cfg_present)
250 return 0;
251
252 qemu_cfg_read_entry(&cnt, QEMU_CFG_E820_TABLE, sizeof(cnt));
253 return cnt;
254}
255
256void* qemu_cfg_e820_load_next(void *addr)
257{
258 qemu_cfg_read(addr, sizeof(struct e820_reservation));
259 return addr;
260}
261
Kevin O'Connor4e4b4102009-10-08 21:21:59 -0400262struct smbios_header {
263 u16 length;
264 u8 type;
265} PACKED;
266
267struct smbios_field {
268 struct smbios_header header;
269 u8 type;
270 u16 offset;
271 u8 data[];
272} PACKED;
273
274struct smbios_table {
275 struct smbios_header header;
276 u8 data[];
277} PACKED;
278
279#define SMBIOS_FIELD_ENTRY 0
280#define SMBIOS_TABLE_ENTRY 1
281
282size_t qemu_cfg_smbios_load_field(int type, size_t offset, void *addr)
283{
284 int i;
285
286 for (i = qemu_cfg_smbios_entries(); i > 0; i--) {
287 struct smbios_field field;
288
289 qemu_cfg_read((u8 *)&field, sizeof(struct smbios_header));
290 field.header.length -= sizeof(struct smbios_header);
291
292 if (field.header.type != SMBIOS_FIELD_ENTRY) {
293 qemu_cfg_skip(field.header.length);
294 continue;
295 }
296
297 qemu_cfg_read((u8 *)&field.type,
298 sizeof(field) - sizeof(struct smbios_header));
299 field.header.length -= sizeof(field) - sizeof(struct smbios_header);
300
301 if (field.type != type || field.offset != offset) {
302 qemu_cfg_skip(field.header.length);
303 continue;
304 }
305
306 qemu_cfg_read(addr, field.header.length);
307 return (size_t)field.header.length;
308 }
309 return 0;
310}
311
Kevin O'Connor4e4b4102009-10-08 21:21:59 -0400312int qemu_cfg_smbios_load_external(int type, char **p, unsigned *nr_structs,
313 unsigned *max_struct_size, char *end)
314{
315 static u64 used_bitmap[4] = { 0 };
316 char *start = *p;
317 int i;
318
319 /* Check if we've already reported these tables */
320 if (used_bitmap[(type >> 6) & 0x3] & (1ULL << (type & 0x3f)))
321 return 1;
322
323 /* Don't introduce spurious end markers */
324 if (type == 127)
325 return 0;
326
327 for (i = qemu_cfg_smbios_entries(); i > 0; i--) {
328 struct smbios_table table;
329 struct smbios_structure_header *header = (void *)*p;
330 int string;
331
332 qemu_cfg_read((u8 *)&table, sizeof(struct smbios_header));
333 table.header.length -= sizeof(struct smbios_header);
334
335 if (table.header.type != SMBIOS_TABLE_ENTRY) {
336 qemu_cfg_skip(table.header.length);
337 continue;
338 }
339
340 if (end - *p < sizeof(struct smbios_structure_header)) {
Kevin O'Connorcfdc13f2010-02-14 13:07:54 -0500341 warn_noalloc();
Kevin O'Connor4e4b4102009-10-08 21:21:59 -0400342 break;
343 }
344
345 qemu_cfg_read((u8 *)*p, sizeof(struct smbios_structure_header));
346 table.header.length -= sizeof(struct smbios_structure_header);
347
348 if (header->type != type) {
349 qemu_cfg_skip(table.header.length);
350 continue;
351 }
352
353 *p += sizeof(struct smbios_structure_header);
354
355 /* Entries end with a double NULL char, if there's a string at
356 * the end (length is greater than formatted length), the string
357 * terminator provides the first NULL. */
358 string = header->length < table.header.length +
359 sizeof(struct smbios_structure_header);
360
361 /* Read the rest and terminate the entry */
362 if (end - *p < table.header.length) {
Kevin O'Connorcfdc13f2010-02-14 13:07:54 -0500363 warn_noalloc();
Kevin O'Connor4e4b4102009-10-08 21:21:59 -0400364 *p -= sizeof(struct smbios_structure_header);
365 continue;
366 }
367 qemu_cfg_read((u8 *)*p, table.header.length);
368 *p += table.header.length;
369 *((u8*)*p) = 0;
370 (*p)++;
371 if (!string) {
372 *((u8*)*p) = 0;
373 (*p)++;
374 }
375
376 (*nr_structs)++;
377 if (*p - (char *)header > *max_struct_size)
378 *max_struct_size = *p - (char *)header;
379 }
380
381 if (start != *p) {
382 /* Mark that we've reported on this type */
383 used_bitmap[(type >> 6) & 0x3] |= (1ULL << (type & 0x3f));
384 return 1;
385 }
386
387 return 0;
388}
389
Kevin O'Connor590e5542009-10-08 22:09:02 -0400390int qemu_cfg_get_numa_nodes(void)
391{
392 u64 cnt;
393
394 qemu_cfg_read_entry(&cnt, QEMU_CFG_NUMA, sizeof(cnt));
395
396 return (int)cnt;
397}
398
399void qemu_cfg_get_numa_data(u64 *data, int n)
400{
401 int i;
402
403 for (i = 0; i < n; i++)
404 qemu_cfg_read((u8*)(data + i), sizeof(u64));
405}
Kevin O'Connor84705852009-10-08 22:13:15 -0400406
407u16 qemu_cfg_get_max_cpus(void)
408{
409 u16 cnt;
410
411 if (!qemu_cfg_present)
412 return 0;
413
414 qemu_cfg_read_entry(&cnt, QEMU_CFG_MAX_CPUS, sizeof(cnt));
415
416 return cnt;
417}
Gerd Hoffmannc4c9fae2009-12-18 12:16:04 +0100418
Kevin O'Connor59d6ca52012-05-31 00:20:55 -0400419int qemu_cfg_read_file(struct romfile_s *file, void *dst, u32 maxlen)
Gerd Hoffmannc4c9fae2009-12-18 12:16:04 +0100420{
Kevin O'Connor59d6ca52012-05-31 00:20:55 -0400421 if (file->size > maxlen)
422 return -1;
423 qemu_cfg_read_entry(dst, file->id, file->size);
424 return file->size;
425}
426
427struct QemuCfgFile {
428 u32 size; /* file size */
429 u16 select; /* write this to 0x510 to read it */
430 u16 reserved;
431 char name[56];
432};
433
Kevin O'Connord83c87b2013-01-21 01:14:12 -0500434void qemu_romfile_init(void)
Kevin O'Connor59d6ca52012-05-31 00:20:55 -0400435{
Kevin O'Connor897fb112013-02-07 23:32:48 -0500436 if (!CONFIG_QEMU || !qemu_cfg_present)
Kevin O'Connor59d6ca52012-05-31 00:20:55 -0400437 return;
Gerd Hoffmannc4c9fae2009-12-18 12:16:04 +0100438
Kevin O'Connore2304262010-06-13 16:05:17 -0400439 u32 count;
Gerd Hoffmannc4c9fae2009-12-18 12:16:04 +0100440 qemu_cfg_read_entry(&count, QEMU_CFG_FILE_DIR, sizeof(count));
Kevin O'Connorb3064592012-08-14 21:20:10 -0400441 count = be32_to_cpu(count);
Kevin O'Connore2304262010-06-13 16:05:17 -0400442 u32 e;
443 for (e = 0; e < count; e++) {
Kevin O'Connor59d6ca52012-05-31 00:20:55 -0400444 struct QemuCfgFile qfile;
445 qemu_cfg_read((void*)&qfile, sizeof(qfile));
446 struct romfile_s *file = malloc_tmp(sizeof(*file));
447 if (!file) {
448 warn_noalloc();
449 return;
450 }
451 memset(file, 0, sizeof(*file));
452 strtcpy(file->name, qfile.name, sizeof(file->name));
Kevin O'Connorb3064592012-08-14 21:20:10 -0400453 file->size = be32_to_cpu(qfile.size);
454 file->id = be16_to_cpu(qfile.select);
Kevin O'Connor59d6ca52012-05-31 00:20:55 -0400455 file->copy = qemu_cfg_read_file;
456 romfile_add(file);
457 dprintf(3, "Found fw_cfg file: %s (size=%d)\n", file->name, file->size);
Gerd Hoffmannc4c9fae2009-12-18 12:16:04 +0100458 }
Kevin O'Connor8b565782011-07-05 20:32:44 -0400459}