blob: 7080c7f4baf7eaef3a245b78ba413192ace7037d [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
22int qemu_cfg_present;
23
Kevin O'Connor7b5bc502013-02-09 13:07:23 -050024/* This CPUID returns the signature 'KVMKVMKVM' in ebx, ecx, and edx. It
25 * should be used to determine that a VM is running under KVM.
26 */
27#define KVM_CPUID_SIGNATURE 0x40000000
28
29static void kvm_preinit(void)
30{
31 if (!CONFIG_QEMU)
32 return;
33 unsigned int eax, ebx, ecx, edx;
34 char signature[13];
35
36 cpuid(KVM_CPUID_SIGNATURE, &eax, &ebx, &ecx, &edx);
37 memcpy(signature + 0, &ebx, 4);
38 memcpy(signature + 4, &ecx, 4);
39 memcpy(signature + 8, &edx, 4);
40 signature[12] = 0;
41
42 if (strcmp(signature, "KVMKVMKVM") == 0) {
43 dprintf(1, "Running on KVM\n");
44 PlatformRunningOn |= PF_KVM;
45 }
46}
47
Kevin O'Connor8ed2e532013-01-21 02:32:48 -050048void
49qemu_ramsize_preinit(void)
50{
Kevin O'Connor02313b22013-02-07 22:42:25 -050051 if (!CONFIG_QEMU)
52 return;
53
54 PlatformRunningOn = PF_QEMU;
Kevin O'Connor7b5bc502013-02-09 13:07:23 -050055 kvm_preinit();
Kevin O'Connor02313b22013-02-07 22:42:25 -050056
Kevin O'Connor8ed2e532013-01-21 02:32:48 -050057 // On emulators, get memory size from nvram.
58 u32 rs = ((inb_cmos(CMOS_MEM_EXTMEM2_LOW) << 16)
59 | (inb_cmos(CMOS_MEM_EXTMEM2_HIGH) << 24));
60 if (rs)
61 rs += 16 * 1024 * 1024;
62 else
63 rs = (((inb_cmos(CMOS_MEM_EXTMEM_LOW) << 10)
64 | (inb_cmos(CMOS_MEM_EXTMEM_HIGH) << 18))
65 + 1 * 1024 * 1024);
66 RamSize = rs;
67 add_e820(0, rs, E820_RAM);
68
69 // Check for memory over 4Gig
70 u64 high = ((inb_cmos(CMOS_MEM_HIGHMEM_LOW) << 16)
71 | ((u32)inb_cmos(CMOS_MEM_HIGHMEM_MID) << 24)
72 | ((u64)inb_cmos(CMOS_MEM_HIGHMEM_HIGH) << 32));
73 RamSizeOver4G = high;
74 add_e820(0x100000000ull, high, E820_RAM);
75
76 /* reserve 256KB BIOS area at the end of 4 GB */
77 add_e820(0xfffc0000, 256*1024, E820_RESERVED);
78
79 u32 count = qemu_cfg_e820_entries();
80 if (count) {
81 struct e820_reservation entry;
82 int i;
83
84 for (i = 0; i < count; i++) {
85 qemu_cfg_e820_load_next(&entry);
86 add_e820(entry.address, entry.length, entry.type);
87 }
Kevin O'Connor7b5bc502013-02-09 13:07:23 -050088 } else if (runningOnKVM()) {
Kevin O'Connor8ed2e532013-01-21 02:32:48 -050089 // Backwards compatibility - provide hard coded range.
90 // 4 pages before the bios, 3 pages for vmx tss pages, the
91 // other page for EPT real mode pagetable
92 add_e820(0xfffbc000, 4*4096, E820_RESERVED);
93 }
94}
95
96void
97qemu_biostable_setup(void)
98{
99 pirtable_setup();
100 mptable_setup();
101 smbios_setup();
102 acpi_setup();
103}
104
Kevin O'Connore7cc7642009-10-04 10:05:16 -0400105static void
106qemu_cfg_select(u16 f)
107{
108 outw(f, PORT_QEMU_CFG_CTL);
109}
110
111static void
112qemu_cfg_read(u8 *buf, int len)
113{
Kevin O'Connor6039fc52010-08-25 21:43:19 -0400114 insb(PORT_QEMU_CFG_DATA, buf, len);
Kevin O'Connore7cc7642009-10-04 10:05:16 -0400115}
116
117static void
Kevin O'Connor4e4b4102009-10-08 21:21:59 -0400118qemu_cfg_skip(int len)
119{
120 while (len--)
121 inb(PORT_QEMU_CFG_DATA);
122}
123
124static void
Kevin O'Connore7cc7642009-10-04 10:05:16 -0400125qemu_cfg_read_entry(void *buf, int e, int len)
126{
127 qemu_cfg_select(e);
128 qemu_cfg_read(buf, len);
129}
130
Kevin O'Connord83c87b2013-01-21 01:14:12 -0500131void qemu_cfg_preinit(void)
Kevin O'Connore7cc7642009-10-04 10:05:16 -0400132{
133 char *sig = "QEMU";
134 int i;
135
Kevin O'Connor897fb112013-02-07 23:32:48 -0500136 if (!CONFIG_QEMU)
Kevin O'Connore7cc7642009-10-04 10:05:16 -0400137 return;
138
139 qemu_cfg_present = 1;
140
141 qemu_cfg_select(QEMU_CFG_SIGNATURE);
142
143 for (i = 0; i < 4; i++)
144 if (inb(PORT_QEMU_CFG_DATA) != sig[i]) {
145 qemu_cfg_present = 0;
146 break;
147 }
148 dprintf(4, "qemu_cfg_present=%d\n", qemu_cfg_present);
149}
150
151void qemu_cfg_get_uuid(u8 *uuid)
152{
153 if (!qemu_cfg_present)
154 return;
155
156 qemu_cfg_read_entry(uuid, QEMU_CFG_UUID, 16);
157}
158
159int qemu_cfg_show_boot_menu(void)
160{
161 u16 v;
162 if (!qemu_cfg_present)
163 return 1;
164
165 qemu_cfg_read_entry(&v, QEMU_CFG_BOOT_MENU, sizeof(v));
166
167 return v;
168}
169
Kevin O'Connor4d2b6192009-10-08 21:37:21 -0400170int qemu_cfg_irq0_override(void)
171{
172 u8 v;
173
174 if (!qemu_cfg_present)
175 return 0;
176
177 qemu_cfg_read_entry(&v, QEMU_CFG_IRQ0_OVERRIDE, sizeof(v));
178
179 return v;
180}
181
Kevin O'Connorcc6dc462009-10-08 21:18:41 -0400182u16 qemu_cfg_acpi_additional_tables(void)
183{
184 u16 cnt;
185
186 if (!qemu_cfg_present)
187 return 0;
188
189 qemu_cfg_read_entry(&cnt, QEMU_CFG_ACPI_TABLES, sizeof(cnt));
190
191 return cnt;
192}
193
194u16 qemu_cfg_next_acpi_table_len(void)
195{
196 u16 len;
197
198 qemu_cfg_read((u8*)&len, sizeof(len));
199
200 return len;
201}
202
203void* qemu_cfg_next_acpi_table_load(void *addr, u16 len)
204{
205 qemu_cfg_read(addr, len);
206 return addr;
207}
208
Kevin O'Connor4e4b4102009-10-08 21:21:59 -0400209u16 qemu_cfg_smbios_entries(void)
210{
211 u16 cnt;
212
213 if (!qemu_cfg_present)
214 return 0;
215
216 qemu_cfg_read_entry(&cnt, QEMU_CFG_SMBIOS_ENTRIES, sizeof(cnt));
217
218 return cnt;
219}
220
Jes Sorensen0360e8e2010-02-16 09:46:08 +0100221u32 qemu_cfg_e820_entries(void)
222{
223 u32 cnt;
224
225 if (!qemu_cfg_present)
226 return 0;
227
228 qemu_cfg_read_entry(&cnt, QEMU_CFG_E820_TABLE, sizeof(cnt));
229 return cnt;
230}
231
232void* qemu_cfg_e820_load_next(void *addr)
233{
234 qemu_cfg_read(addr, sizeof(struct e820_reservation));
235 return addr;
236}
237
Kevin O'Connor4e4b4102009-10-08 21:21:59 -0400238struct smbios_header {
239 u16 length;
240 u8 type;
241} PACKED;
242
243struct smbios_field {
244 struct smbios_header header;
245 u8 type;
246 u16 offset;
247 u8 data[];
248} PACKED;
249
250struct smbios_table {
251 struct smbios_header header;
252 u8 data[];
253} PACKED;
254
255#define SMBIOS_FIELD_ENTRY 0
256#define SMBIOS_TABLE_ENTRY 1
257
258size_t qemu_cfg_smbios_load_field(int type, size_t offset, void *addr)
259{
260 int i;
261
262 for (i = qemu_cfg_smbios_entries(); i > 0; i--) {
263 struct smbios_field field;
264
265 qemu_cfg_read((u8 *)&field, sizeof(struct smbios_header));
266 field.header.length -= sizeof(struct smbios_header);
267
268 if (field.header.type != SMBIOS_FIELD_ENTRY) {
269 qemu_cfg_skip(field.header.length);
270 continue;
271 }
272
273 qemu_cfg_read((u8 *)&field.type,
274 sizeof(field) - sizeof(struct smbios_header));
275 field.header.length -= sizeof(field) - sizeof(struct smbios_header);
276
277 if (field.type != type || field.offset != offset) {
278 qemu_cfg_skip(field.header.length);
279 continue;
280 }
281
282 qemu_cfg_read(addr, field.header.length);
283 return (size_t)field.header.length;
284 }
285 return 0;
286}
287
Kevin O'Connor4e4b4102009-10-08 21:21:59 -0400288int qemu_cfg_smbios_load_external(int type, char **p, unsigned *nr_structs,
289 unsigned *max_struct_size, char *end)
290{
291 static u64 used_bitmap[4] = { 0 };
292 char *start = *p;
293 int i;
294
295 /* Check if we've already reported these tables */
296 if (used_bitmap[(type >> 6) & 0x3] & (1ULL << (type & 0x3f)))
297 return 1;
298
299 /* Don't introduce spurious end markers */
300 if (type == 127)
301 return 0;
302
303 for (i = qemu_cfg_smbios_entries(); i > 0; i--) {
304 struct smbios_table table;
305 struct smbios_structure_header *header = (void *)*p;
306 int string;
307
308 qemu_cfg_read((u8 *)&table, sizeof(struct smbios_header));
309 table.header.length -= sizeof(struct smbios_header);
310
311 if (table.header.type != SMBIOS_TABLE_ENTRY) {
312 qemu_cfg_skip(table.header.length);
313 continue;
314 }
315
316 if (end - *p < sizeof(struct smbios_structure_header)) {
Kevin O'Connorcfdc13f2010-02-14 13:07:54 -0500317 warn_noalloc();
Kevin O'Connor4e4b4102009-10-08 21:21:59 -0400318 break;
319 }
320
321 qemu_cfg_read((u8 *)*p, sizeof(struct smbios_structure_header));
322 table.header.length -= sizeof(struct smbios_structure_header);
323
324 if (header->type != type) {
325 qemu_cfg_skip(table.header.length);
326 continue;
327 }
328
329 *p += sizeof(struct smbios_structure_header);
330
331 /* Entries end with a double NULL char, if there's a string at
332 * the end (length is greater than formatted length), the string
333 * terminator provides the first NULL. */
334 string = header->length < table.header.length +
335 sizeof(struct smbios_structure_header);
336
337 /* Read the rest and terminate the entry */
338 if (end - *p < table.header.length) {
Kevin O'Connorcfdc13f2010-02-14 13:07:54 -0500339 warn_noalloc();
Kevin O'Connor4e4b4102009-10-08 21:21:59 -0400340 *p -= sizeof(struct smbios_structure_header);
341 continue;
342 }
343 qemu_cfg_read((u8 *)*p, table.header.length);
344 *p += table.header.length;
345 *((u8*)*p) = 0;
346 (*p)++;
347 if (!string) {
348 *((u8*)*p) = 0;
349 (*p)++;
350 }
351
352 (*nr_structs)++;
353 if (*p - (char *)header > *max_struct_size)
354 *max_struct_size = *p - (char *)header;
355 }
356
357 if (start != *p) {
358 /* Mark that we've reported on this type */
359 used_bitmap[(type >> 6) & 0x3] |= (1ULL << (type & 0x3f));
360 return 1;
361 }
362
363 return 0;
364}
365
Kevin O'Connor590e5542009-10-08 22:09:02 -0400366int qemu_cfg_get_numa_nodes(void)
367{
368 u64 cnt;
369
370 qemu_cfg_read_entry(&cnt, QEMU_CFG_NUMA, sizeof(cnt));
371
372 return (int)cnt;
373}
374
375void qemu_cfg_get_numa_data(u64 *data, int n)
376{
377 int i;
378
379 for (i = 0; i < n; i++)
380 qemu_cfg_read((u8*)(data + i), sizeof(u64));
381}
Kevin O'Connor84705852009-10-08 22:13:15 -0400382
383u16 qemu_cfg_get_max_cpus(void)
384{
385 u16 cnt;
386
387 if (!qemu_cfg_present)
388 return 0;
389
390 qemu_cfg_read_entry(&cnt, QEMU_CFG_MAX_CPUS, sizeof(cnt));
391
392 return cnt;
393}
Gerd Hoffmannc4c9fae2009-12-18 12:16:04 +0100394
Kevin O'Connor59d6ca52012-05-31 00:20:55 -0400395int qemu_cfg_read_file(struct romfile_s *file, void *dst, u32 maxlen)
Gerd Hoffmannc4c9fae2009-12-18 12:16:04 +0100396{
Kevin O'Connor59d6ca52012-05-31 00:20:55 -0400397 if (file->size > maxlen)
398 return -1;
399 qemu_cfg_read_entry(dst, file->id, file->size);
400 return file->size;
401}
402
403struct QemuCfgFile {
404 u32 size; /* file size */
405 u16 select; /* write this to 0x510 to read it */
406 u16 reserved;
407 char name[56];
408};
409
Kevin O'Connord83c87b2013-01-21 01:14:12 -0500410void qemu_romfile_init(void)
Kevin O'Connor59d6ca52012-05-31 00:20:55 -0400411{
Kevin O'Connor897fb112013-02-07 23:32:48 -0500412 if (!CONFIG_QEMU || !qemu_cfg_present)
Kevin O'Connor59d6ca52012-05-31 00:20:55 -0400413 return;
Gerd Hoffmannc4c9fae2009-12-18 12:16:04 +0100414
Kevin O'Connore2304262010-06-13 16:05:17 -0400415 u32 count;
Gerd Hoffmannc4c9fae2009-12-18 12:16:04 +0100416 qemu_cfg_read_entry(&count, QEMU_CFG_FILE_DIR, sizeof(count));
Kevin O'Connorb3064592012-08-14 21:20:10 -0400417 count = be32_to_cpu(count);
Kevin O'Connore2304262010-06-13 16:05:17 -0400418 u32 e;
419 for (e = 0; e < count; e++) {
Kevin O'Connor59d6ca52012-05-31 00:20:55 -0400420 struct QemuCfgFile qfile;
421 qemu_cfg_read((void*)&qfile, sizeof(qfile));
422 struct romfile_s *file = malloc_tmp(sizeof(*file));
423 if (!file) {
424 warn_noalloc();
425 return;
426 }
427 memset(file, 0, sizeof(*file));
428 strtcpy(file->name, qfile.name, sizeof(file->name));
Kevin O'Connorb3064592012-08-14 21:20:10 -0400429 file->size = be32_to_cpu(qfile.size);
430 file->id = be16_to_cpu(qfile.select);
Kevin O'Connor59d6ca52012-05-31 00:20:55 -0400431 file->copy = qemu_cfg_read_file;
432 romfile_add(file);
433 dprintf(3, "Found fw_cfg file: %s (size=%d)\n", file->name, file->size);
Gerd Hoffmannc4c9fae2009-12-18 12:16:04 +0100434 }
Kevin O'Connor8b565782011-07-05 20:32:44 -0400435}