blob: 0770c47b12e7f4fccb1793ccd344d8fc86b4d376 [file] [log] [blame]
Kevin O'Connore7cc7642009-10-04 10:05:16 -04001// Paravirtualization support.
2//
Kevin O'Connorb840ba92013-02-09 20:09:22 -05003// Copyright (C) 2013 Kevin O'Connor <kevin@koconnor.net>
Kevin O'Connore7cc7642009-10-04 10:05:16 -04004// Copyright (C) 2009 Red Hat Inc.
5//
6// Authors:
7// Gleb Natapov <gnatapov@redhat.com>
8//
9// This file may be distributed under the terms of the GNU LGPLv3 license.
10
Kevin O'Connor2d2fa312013-09-14 21:55:26 -040011#include "byteorder.h" // be32_to_cpu
12#include "config.h" // CONFIG_QEMU
Kevin O'Connorc167e542015-09-29 09:40:46 -040013#include "e820map.h" // e820_add
Kevin O'Connor4d8510c2016-02-03 01:28:20 -050014#include "hw/pci.h" // pci_config_readw
15#include "hw/pcidevice.h" // pci_probe_devices
Gerd Hoffmannebfece82013-09-03 11:41:01 +020016#include "hw/pci_regs.h" // PCI_DEVICE_ID
Gerd Hoffmann0ebc29f2017-09-18 10:47:22 +020017#include "hw/serialio.h" // PORT_SERIAL1
Kevin O'Connor8b7861c2013-09-15 02:29:06 -040018#include "hw/rtc.h" // CMOS_*
Kevin O'Connor9dea5902013-09-14 20:23:54 -040019#include "malloc.h" // malloc_tmp
Kevin O'Connor2d2fa312013-09-14 21:55:26 -040020#include "output.h" // dprintf
21#include "paravirt.h" // qemu_cfg_preinit
Kevin O'Connor41639f82013-09-14 19:37:36 -040022#include "romfile.h" // romfile_loadint
Kevin O'Connor836b4d82014-04-07 15:42:04 -040023#include "romfile_loader.h" // romfile_loader_execute
Kevin O'Connorfa9c66a2013-09-14 19:10:40 -040024#include "string.h" // memset
Kevin O'Connor2d2fa312013-09-14 21:55:26 -040025#include "util.h" // pci_setup
Kevin O'Connorb9c6a962013-09-14 13:01:30 -040026#include "x86.h" // cpuid
Kevin O'Connor2d2fa312013-09-14 21:55:26 -040027#include "xen.h" // xen_biostable_setup
Marc Marí06316c92015-10-08 17:03:26 +020028#include "stacks.h" // yield
Kevin O'Connore7cc7642009-10-04 10:05:16 -040029
Kevin O'Connorf85e4bc2013-02-19 01:33:45 -050030// Amount of continuous ram under 4Gig
31u32 RamSize;
32// Amount of continuous ram >4Gig
33u64 RamSizeOver4G;
Kevin O'Connor89a2f962013-02-18 23:36:03 -050034// Type of emulator platform.
35int PlatformRunningOn VARFSEG;
Petr Berky5fbf2462017-03-28 23:03:53 +020036// cfg enabled
37int cfg_enabled = 0;
Marc Marí06316c92015-10-08 17:03:26 +020038// cfg_dma enabled
39int cfg_dma_enabled = 0;
40
Petr Berky5fbf2462017-03-28 23:03:53 +020041inline int qemu_cfg_enabled(void)
42{
43 return cfg_enabled;
44}
45
Marc Marí06316c92015-10-08 17:03:26 +020046inline int qemu_cfg_dma_enabled(void)
47{
48 return cfg_dma_enabled;
49}
Kevin O'Connor89a2f962013-02-18 23:36:03 -050050
Kevin O'Connor7b5bc502013-02-09 13:07:23 -050051/* This CPUID returns the signature 'KVMKVMKVM' in ebx, ecx, and edx. It
52 * should be used to determine that a VM is running under KVM.
53 */
54#define KVM_CPUID_SIGNATURE 0x40000000
55
Gerd Hoffmannebfece82013-09-03 11:41:01 +020056static void kvm_detect(void)
Kevin O'Connor7b5bc502013-02-09 13:07:23 -050057{
Kevin O'Connor7b5bc502013-02-09 13:07:23 -050058 unsigned int eax, ebx, ecx, edx;
59 char signature[13];
60
61 cpuid(KVM_CPUID_SIGNATURE, &eax, &ebx, &ecx, &edx);
62 memcpy(signature + 0, &ebx, 4);
63 memcpy(signature + 4, &ecx, 4);
64 memcpy(signature + 8, &edx, 4);
65 signature[12] = 0;
66
67 if (strcmp(signature, "KVMKVMKVM") == 0) {
68 dprintf(1, "Running on KVM\n");
69 PlatformRunningOn |= PF_KVM;
70 }
71}
72
Gerd Hoffmannebfece82013-09-03 11:41:01 +020073static void qemu_detect(void)
74{
75 if (!CONFIG_QEMU_HARDWARE)
76 return;
77
78 // check northbridge @ 00:00.0
79 u16 v = pci_config_readw(0, PCI_VENDOR_ID);
80 if (v == 0x0000 || v == 0xffff)
81 return;
82 u16 d = pci_config_readw(0, PCI_DEVICE_ID);
83 u16 sv = pci_config_readw(0, PCI_SUBSYSTEM_VENDOR_ID);
84 u16 sd = pci_config_readw(0, PCI_SUBSYSTEM_ID);
85
86 if (sv != 0x1af4 || /* Red Hat, Inc */
87 sd != 0x1100) /* Qemu virtual machine */
88 return;
89
90 PlatformRunningOn |= PF_QEMU;
91 switch (d) {
92 case 0x1237:
93 dprintf(1, "Running on QEMU (i440fx)\n");
94 break;
95 case 0x29c0:
96 dprintf(1, "Running on QEMU (q35)\n");
97 break;
98 default:
99 dprintf(1, "Running on QEMU (unknown nb: %04x:%04x)\n", v, d);
100 break;
101 }
102 kvm_detect();
103}
104
Kevin O'Connor8ed2e532013-01-21 02:32:48 -0500105void
Kevin O'Connora2a86e22013-02-13 19:35:12 -0500106qemu_preinit(void)
Kevin O'Connor8ed2e532013-01-21 02:32:48 -0500107{
Gerd Hoffmannebfece82013-09-03 11:41:01 +0200108 qemu_detect();
109
Kevin O'Connor02313b22013-02-07 22:42:25 -0500110 if (!CONFIG_QEMU)
111 return;
112
Kevin O'Connora2a86e22013-02-13 19:35:12 -0500113 if (runningOnXen()) {
114 xen_ramsize_preinit();
115 return;
116 }
117
Gerd Hoffmannebfece82013-09-03 11:41:01 +0200118 if (!runningOnQEMU()) {
119 dprintf(1, "Warning: No QEMU Northbridge found (isapc?)\n");
120 PlatformRunningOn |= PF_QEMU;
121 kvm_detect();
122 }
Kevin O'Connor02313b22013-02-07 22:42:25 -0500123
Kevin O'Connor8ed2e532013-01-21 02:32:48 -0500124 // On emulators, get memory size from nvram.
Kevin O'Connor8b7861c2013-09-15 02:29:06 -0400125 u32 rs = ((rtc_read(CMOS_MEM_EXTMEM2_LOW) << 16)
126 | (rtc_read(CMOS_MEM_EXTMEM2_HIGH) << 24));
Kevin O'Connor8ed2e532013-01-21 02:32:48 -0500127 if (rs)
128 rs += 16 * 1024 * 1024;
129 else
Kevin O'Connor8b7861c2013-09-15 02:29:06 -0400130 rs = (((rtc_read(CMOS_MEM_EXTMEM_LOW) << 10)
131 | (rtc_read(CMOS_MEM_EXTMEM_HIGH) << 18))
Kevin O'Connor8ed2e532013-01-21 02:32:48 -0500132 + 1 * 1024 * 1024);
133 RamSize = rs;
Kevin O'Connorc167e542015-09-29 09:40:46 -0400134 e820_add(0, rs, E820_RAM);
Kevin O'Connor8ed2e532013-01-21 02:32:48 -0500135
Kevin O'Connor8ed2e532013-01-21 02:32:48 -0500136 /* reserve 256KB BIOS area at the end of 4 GB */
Kevin O'Connorc167e542015-09-29 09:40:46 -0400137 e820_add(0xfffc0000, 256*1024, E820_RESERVED);
Kevin O'Connorf85e4bc2013-02-19 01:33:45 -0500138
Gerd Hoffmann6e1b0822013-10-18 12:18:19 +0200139 dprintf(1, "RamSize: 0x%08x [cmos]\n", RamSize);
Kevin O'Connor8ed2e532013-01-21 02:32:48 -0500140}
141
Haozhong Zhang20f83d52016-06-22 14:53:24 +0800142#define MSR_IA32_FEATURE_CONTROL 0x0000003a
143
144static void msr_feature_control_setup(void)
145{
146 u64 feature_control_bits = romfile_loadint("etc/msr_feature_control", 0);
147 if (feature_control_bits)
148 wrmsr_smp(MSR_IA32_FEATURE_CONTROL, feature_control_bits);
149}
150
Kevin O'Connor8ed2e532013-01-21 02:32:48 -0500151void
Kevin O'Connora2a86e22013-02-13 19:35:12 -0500152qemu_platform_setup(void)
Kevin O'Connor8ed2e532013-01-21 02:32:48 -0500153{
Kevin O'Connora2a86e22013-02-13 19:35:12 -0500154 if (!CONFIG_QEMU)
155 return;
156
157 if (runningOnXen()) {
158 pci_probe_devices();
159 xen_hypercall_setup();
160 xen_biostable_setup();
161 return;
162 }
163
164 // Initialize pci
165 pci_setup();
Kevin O'Connorcdbac7f2013-03-08 19:33:39 -0500166 smm_device_setup();
Kevin O'Connora2a86e22013-02-13 19:35:12 -0500167 smm_setup();
168
Haozhong Zhang20f83d52016-06-22 14:53:24 +0800169 // Initialize mtrr, msr_feature_control and smp
Kevin O'Connora2a86e22013-02-13 19:35:12 -0500170 mtrr_setup();
Haozhong Zhang20f83d52016-06-22 14:53:24 +0800171 msr_feature_control_setup();
Kevin O'Connora2a86e22013-02-13 19:35:12 -0500172 smp_setup();
173
174 // Create bios tables
Igor Mammedovf7695892016-10-13 14:38:25 +0200175 if (MaxCountCPUs <= 255) {
176 pirtable_setup();
177 mptable_setup();
178 }
Kevin O'Connor8ed2e532013-01-21 02:32:48 -0500179 smbios_setup();
Kevin O'Connor836b4d82014-04-07 15:42:04 -0400180
181 if (CONFIG_FW_ROMFILE_LOAD) {
182 int loader_err;
183
184 dprintf(3, "load ACPI tables\n");
185
186 loader_err = romfile_loader_execute("etc/table-loader");
187
188 RsdpAddr = find_acpi_rsdp();
189
190 if (RsdpAddr)
191 return;
192
193 /* If present, loader should have installed an RSDP.
194 * Not installed? We might still be able to continue
195 * using the builtin RSDP.
196 */
197 if (!loader_err)
198 warn_internalerror();
199 }
200
Kevin O'Connor8ed2e532013-01-21 02:32:48 -0500201 acpi_setup();
202}
203
Kevin O'Connor4edda082013-02-09 13:21:08 -0500204
205/****************************************************************
206 * QEMU firmware config (fw_cfg) interface
207 ****************************************************************/
208
Kevin O'Connorb840ba92013-02-09 20:09:22 -0500209// List of QEMU fw_cfg entries. DO NOT ADD MORE. (All new content
210// should be passed via the fw_cfg "file" interface.)
Kevin O'Connor4edda082013-02-09 13:21:08 -0500211#define QEMU_CFG_SIGNATURE 0x00
212#define QEMU_CFG_ID 0x01
213#define QEMU_CFG_UUID 0x02
Gerd Hoffmann0ebc29f2017-09-18 10:47:22 +0200214#define QEMU_CFG_NOGRAPHIC 0x04
Kevin O'Connor4edda082013-02-09 13:21:08 -0500215#define QEMU_CFG_NUMA 0x0d
216#define QEMU_CFG_BOOT_MENU 0x0e
Igor Mammedovb98c6582016-11-11 16:35:15 +0100217#define QEMU_CFG_NB_CPUS 0x05
Kevin O'Connor4edda082013-02-09 13:21:08 -0500218#define QEMU_CFG_MAX_CPUS 0x0f
219#define QEMU_CFG_FILE_DIR 0x19
220#define QEMU_CFG_ARCH_LOCAL 0x8000
221#define QEMU_CFG_ACPI_TABLES (QEMU_CFG_ARCH_LOCAL + 0)
222#define QEMU_CFG_SMBIOS_ENTRIES (QEMU_CFG_ARCH_LOCAL + 1)
223#define QEMU_CFG_IRQ0_OVERRIDE (QEMU_CFG_ARCH_LOCAL + 2)
224#define QEMU_CFG_E820_TABLE (QEMU_CFG_ARCH_LOCAL + 3)
225
Kevin O'Connore7cc7642009-10-04 10:05:16 -0400226static void
227qemu_cfg_select(u16 f)
228{
229 outw(f, PORT_QEMU_CFG_CTL);
230}
231
232static void
Marc Marí06316c92015-10-08 17:03:26 +0200233qemu_cfg_dma_transfer(void *address, u32 length, u32 control)
234{
235 QemuCfgDmaAccess access;
236
237 access.address = cpu_to_be64((u64)(u32)address);
238 access.length = cpu_to_be32(length);
239 access.control = cpu_to_be32(control);
240
241 barrier();
242
243 outl(cpu_to_be32((u32)&access), PORT_QEMU_CFG_DMA_ADDR_LOW);
244
245 while(be32_to_cpu(access.control) & ~QEMU_CFG_DMA_CTL_ERROR) {
246 yield();
247 }
248}
249
250static void
Kevin O'Connorc40e3fa2013-02-09 14:55:30 -0500251qemu_cfg_read(void *buf, int len)
Kevin O'Connore7cc7642009-10-04 10:05:16 -0400252{
Marc Marí06316c92015-10-08 17:03:26 +0200253 if (len == 0) {
254 return;
255 }
256
257 if (qemu_cfg_dma_enabled()) {
258 qemu_cfg_dma_transfer(buf, len, QEMU_CFG_DMA_CTL_READ);
259 } else {
260 insb(PORT_QEMU_CFG_DATA, buf, len);
261 }
Kevin O'Connore7cc7642009-10-04 10:05:16 -0400262}
263
264static void
Ben Warrenf9918222017-02-20 19:56:15 -0800265qemu_cfg_write(void *buf, int len)
266{
267 if (len == 0) {
268 return;
269 }
270
271 if (qemu_cfg_dma_enabled()) {
272 qemu_cfg_dma_transfer(buf, len, QEMU_CFG_DMA_CTL_WRITE);
273 } else {
274 warn_internalerror();
275 }
276}
277
278static void
Kevin O'Connor4e4b4102009-10-08 21:21:59 -0400279qemu_cfg_skip(int len)
280{
Marc Marí06316c92015-10-08 17:03:26 +0200281 if (len == 0) {
282 return;
283 }
284
285 if (qemu_cfg_dma_enabled()) {
286 qemu_cfg_dma_transfer(0, len, QEMU_CFG_DMA_CTL_SKIP);
287 } else {
288 while (len--)
289 inb(PORT_QEMU_CFG_DATA);
290 }
Kevin O'Connor4e4b4102009-10-08 21:21:59 -0400291}
292
293static void
Kevin O'Connore7cc7642009-10-04 10:05:16 -0400294qemu_cfg_read_entry(void *buf, int e, int len)
295{
Marc Marí06316c92015-10-08 17:03:26 +0200296 if (qemu_cfg_dma_enabled()) {
297 u32 control = (e << 16) | QEMU_CFG_DMA_CTL_SELECT
298 | QEMU_CFG_DMA_CTL_READ;
299 qemu_cfg_dma_transfer(buf, len, control);
300 } else {
301 qemu_cfg_select(e);
302 qemu_cfg_read(buf, len);
303 }
Kevin O'Connore7cc7642009-10-04 10:05:16 -0400304}
305
Ben Warrenf9918222017-02-20 19:56:15 -0800306static void
307qemu_cfg_write_entry(void *buf, int e, int len)
308{
309 if (qemu_cfg_dma_enabled()) {
310 u32 control = (e << 16) | QEMU_CFG_DMA_CTL_SELECT
311 | QEMU_CFG_DMA_CTL_WRITE;
312 qemu_cfg_dma_transfer(buf, len, control);
313 } else {
314 warn_internalerror();
315 }
316}
317
Kevin O'Connor4158c8c2013-03-30 09:12:11 -0400318struct qemu_romfile_s {
319 struct romfile_s file;
320 int select, skip;
321};
322
Kevin O'Connorc40e3fa2013-02-09 14:55:30 -0500323static int
324qemu_cfg_read_file(struct romfile_s *file, void *dst, u32 maxlen)
Gerd Hoffmannc4c9fae2009-12-18 12:16:04 +0100325{
Kevin O'Connor59d6ca52012-05-31 00:20:55 -0400326 if (file->size > maxlen)
327 return -1;
Kevin O'Connor4158c8c2013-03-30 09:12:11 -0400328 struct qemu_romfile_s *qfile;
329 qfile = container_of(file, struct qemu_romfile_s, file);
Marc Marí06316c92015-10-08 17:03:26 +0200330 if (qfile->skip == 0) {
331 /* Do it in one transfer */
332 qemu_cfg_read_entry(dst, qfile->select, file->size);
333 } else {
334 qemu_cfg_select(qfile->select);
335 qemu_cfg_skip(qfile->skip);
336 qemu_cfg_read(dst, file->size);
337 }
Kevin O'Connor59d6ca52012-05-31 00:20:55 -0400338 return file->size;
339}
340
Ben Warren336b60b2017-02-20 19:56:18 -0800341// Bare-bones function for writing a file knowing only its unique
342// identifying key (select)
343int
344qemu_cfg_write_file_simple(void *src, u16 key, u32 offset, u32 len)
345{
346 if (offset == 0) {
347 /* Do it in one transfer */
348 qemu_cfg_write_entry(src, key, len);
349 } else {
350 qemu_cfg_select(key);
351 qemu_cfg_skip(offset);
352 qemu_cfg_write(src, len);
353 }
354 return len;
355}
356
Ben Warrenf9918222017-02-20 19:56:15 -0800357int
358qemu_cfg_write_file(void *src, struct romfile_s *file, u32 offset, u32 len)
359{
360 if ((offset + len) > file->size)
361 return -1;
362
363 if (!qemu_cfg_dma_enabled() || (file->copy != qemu_cfg_read_file)) {
364 warn_internalerror();
365 return -1;
366 }
Ben Warren336b60b2017-02-20 19:56:18 -0800367 return qemu_cfg_write_file_simple(src, qemu_get_romfile_key(file),
368 offset, len);
Ben Warrenf9918222017-02-20 19:56:15 -0800369}
370
Kevin O'Connorc40e3fa2013-02-09 14:55:30 -0500371static void
372qemu_romfile_add(char *name, int select, int skip, int size)
373{
Kevin O'Connor4158c8c2013-03-30 09:12:11 -0400374 struct qemu_romfile_s *qfile = malloc_tmp(sizeof(*qfile));
375 if (!qfile) {
Kevin O'Connorc40e3fa2013-02-09 14:55:30 -0500376 warn_noalloc();
377 return;
378 }
Kevin O'Connor4158c8c2013-03-30 09:12:11 -0400379 memset(qfile, 0, sizeof(*qfile));
380 strtcpy(qfile->file.name, name, sizeof(qfile->file.name));
381 qfile->file.size = size;
382 qfile->select = select;
383 qfile->skip = skip;
384 qfile->file.copy = qemu_cfg_read_file;
385 romfile_add(&qfile->file);
Kevin O'Connorc40e3fa2013-02-09 14:55:30 -0500386}
387
Igor Mammedov023b1d02016-10-13 14:38:27 +0200388u16
Ben Warren336b60b2017-02-20 19:56:18 -0800389qemu_get_romfile_key(struct romfile_s *file)
390{
391 struct qemu_romfile_s *qfile;
392 if (file->copy != qemu_cfg_read_file) {
393 warn_internalerror();
394 return 0;
395 }
396 qfile = container_of(file, struct qemu_romfile_s, file);
397 return qfile->select;
398}
399
400u16
Igor Mammedov023b1d02016-10-13 14:38:27 +0200401qemu_get_present_cpus_count(void)
402{
Igor Mammedovb98c6582016-11-11 16:35:15 +0100403 u16 smp_count = 0;
Petr Berky5fbf2462017-03-28 23:03:53 +0200404 if (qemu_cfg_enabled()) {
405 qemu_cfg_read_entry(&smp_count, QEMU_CFG_NB_CPUS, sizeof(smp_count));
406 }
Igor Mammedovb98c6582016-11-11 16:35:15 +0100407 u16 cmos_cpu_count = rtc_read(CMOS_BIOS_SMP_COUNT) + 1;
408 if (smp_count < cmos_cpu_count) {
409 smp_count = cmos_cpu_count;
Igor Mammedov023b1d02016-10-13 14:38:27 +0200410 }
411 return smp_count;
412}
413
Kevin O'Connorfe090302013-02-09 20:00:06 -0500414struct e820_reservation {
415 u64 address;
416 u64 length;
417 u32 type;
418};
419
Kevin O'Connorde9e7052013-02-09 19:09:20 -0500420#define SMBIOS_FIELD_ENTRY 0
421#define SMBIOS_TABLE_ENTRY 1
422
423struct qemu_smbios_header {
424 u16 length;
425 u8 headertype;
426 u8 tabletype;
427 u16 fieldoffset;
428} PACKED;
429
Gerd Hoffmann6e1b0822013-10-18 12:18:19 +0200430static void
431qemu_cfg_e820(void)
432{
Gerd Hoffmannce39bd42013-10-18 12:22:36 +0200433 struct e820_reservation *table;
434 int i, size;
435
Gerd Hoffmannb3d4aae2013-12-06 13:27:09 +0100436 if (!CONFIG_QEMU)
437 return;
438
Gerd Hoffmannce39bd42013-10-18 12:22:36 +0200439 // "etc/e820" has both ram and reservations
440 table = romfile_loadfile("etc/e820", &size);
441 if (table) {
442 for (i = 0; i < size / sizeof(struct e820_reservation); i++) {
443 switch (table[i].type) {
444 case E820_RAM:
445 dprintf(1, "RamBlock: addr 0x%016llx len 0x%016llx [e820]\n",
446 table[i].address, table[i].length);
447 if (table[i].address < RamSize)
448 // ignore, preinit got it from cmos already and
449 // adding this again would ruin any reservations
450 // done so far
451 continue;
452 if (table[i].address < 0x100000000LL) {
453 // below 4g -- adjust RamSize to mark highest lowram addr
454 if (RamSize < table[i].address + table[i].length)
455 RamSize = table[i].address + table[i].length;
456 } else {
457 // above 4g -- adjust RamSizeOver4G to mark highest ram addr
458 if (0x100000000LL + RamSizeOver4G < table[i].address + table[i].length)
459 RamSizeOver4G = table[i].address + table[i].length - 0x100000000LL;
460 }
461 /* fall through */
462 case E820_RESERVED:
Kevin O'Connorc167e542015-09-29 09:40:46 -0400463 e820_add(table[i].address, table[i].length, table[i].type);
Gerd Hoffmannce39bd42013-10-18 12:22:36 +0200464 break;
465 default:
466 /*
467 * Qemu 1.7 uses RAM + RESERVED only. Ignore
468 * everything else, so we have the option to
469 * extend this in the future without breakage.
470 */
471 break;
472 }
473 }
474 return;
475 }
476
Gerd Hoffmann6e1b0822013-10-18 12:18:19 +0200477 // QEMU_CFG_E820_TABLE has reservations only
478 u32 count32;
479 qemu_cfg_read_entry(&count32, QEMU_CFG_E820_TABLE, sizeof(count32));
480 if (count32) {
481 struct e820_reservation entry;
482 int i;
483 for (i = 0; i < count32; i++) {
484 qemu_cfg_read(&entry, sizeof(entry));
Kevin O'Connorc167e542015-09-29 09:40:46 -0400485 e820_add(entry.address, entry.length, entry.type);
Gerd Hoffmann6e1b0822013-10-18 12:18:19 +0200486 }
487 } else if (runningOnKVM()) {
488 // Backwards compatibility - provide hard coded range.
489 // 4 pages before the bios, 3 pages for vmx tss pages, the
490 // other page for EPT real mode pagetable
Kevin O'Connorc167e542015-09-29 09:40:46 -0400491 e820_add(0xfffbc000, 4*4096, E820_RESERVED);
Gerd Hoffmann6e1b0822013-10-18 12:18:19 +0200492 }
493
494 // Check for memory over 4Gig in cmos
495 u64 high = ((rtc_read(CMOS_MEM_HIGHMEM_LOW) << 16)
496 | ((u32)rtc_read(CMOS_MEM_HIGHMEM_MID) << 24)
497 | ((u64)rtc_read(CMOS_MEM_HIGHMEM_HIGH) << 32));
498 RamSizeOver4G = high;
Kevin O'Connorc167e542015-09-29 09:40:46 -0400499 e820_add(0x100000000ull, high, E820_RAM);
Gerd Hoffmann6e1b0822013-10-18 12:18:19 +0200500 dprintf(1, "RamSizeOver4G: 0x%016llx [cmos]\n", RamSizeOver4G);
501}
502
Kevin O'Connor188d9942013-02-09 15:24:08 -0500503// Populate romfile entries for legacy fw_cfg ports (that predate the
504// "file" interface).
505static void
506qemu_cfg_legacy(void)
507{
Kevin O'Connor7507ce22013-06-13 20:04:31 -0400508 if (!CONFIG_QEMU)
509 return;
510
Kevin O'Connor56c50892013-02-09 19:25:51 -0500511 // Misc config items.
512 qemu_romfile_add("etc/show-boot-menu", QEMU_CFG_BOOT_MENU, 0, 2);
513 qemu_romfile_add("etc/irq0-override", QEMU_CFG_IRQ0_OVERRIDE, 0, 1);
514 qemu_romfile_add("etc/max-cpus", QEMU_CFG_MAX_CPUS, 0, 2);
515
Kevin O'Connorf9e4e372013-02-09 19:45:45 -0500516 // NUMA data
517 u64 numacount;
518 qemu_cfg_read_entry(&numacount, QEMU_CFG_NUMA, sizeof(numacount));
Kevin O'Connorfb76cff2013-03-23 11:38:45 -0400519 int max_cpu = romfile_loadint("etc/max-cpus", 0);
520 qemu_romfile_add("etc/numa-cpu-map", QEMU_CFG_NUMA, sizeof(numacount)
521 , max_cpu*sizeof(u64));
522 qemu_romfile_add("etc/numa-nodes", QEMU_CFG_NUMA
523 , sizeof(numacount) + max_cpu*sizeof(u64)
Kevin O'Connorf9e4e372013-02-09 19:45:45 -0500524 , numacount*sizeof(u64));
525
Kevin O'Connor188d9942013-02-09 15:24:08 -0500526 // ACPI tables
527 char name[128];
528 u16 cnt;
529 qemu_cfg_read_entry(&cnt, QEMU_CFG_ACPI_TABLES, sizeof(cnt));
530 int i, offset = sizeof(cnt);
531 for (i = 0; i < cnt; i++) {
532 u16 len;
533 qemu_cfg_read(&len, sizeof(len));
534 offset += sizeof(len);
535 snprintf(name, sizeof(name), "acpi/table%d", i);
536 qemu_romfile_add(name, QEMU_CFG_ACPI_TABLES, offset, len);
537 qemu_cfg_skip(len);
538 offset += len;
539 }
Kevin O'Connorde9e7052013-02-09 19:09:20 -0500540
541 // SMBIOS info
542 qemu_cfg_read_entry(&cnt, QEMU_CFG_SMBIOS_ENTRIES, sizeof(cnt));
543 offset = sizeof(cnt);
544 for (i = 0; i < cnt; i++) {
545 struct qemu_smbios_header header;
546 qemu_cfg_read(&header, sizeof(header));
547 if (header.headertype == SMBIOS_FIELD_ENTRY) {
548 snprintf(name, sizeof(name), "smbios/field%d-%d"
549 , header.tabletype, header.fieldoffset);
550 qemu_romfile_add(name, QEMU_CFG_SMBIOS_ENTRIES
551 , offset + sizeof(header)
552 , header.length - sizeof(header));
553 } else {
554 snprintf(name, sizeof(name), "smbios/table%d-%d"
555 , header.tabletype, i);
556 qemu_romfile_add(name, QEMU_CFG_SMBIOS_ENTRIES
557 , offset + 3, header.length - 3);
558 }
559 qemu_cfg_skip(header.length - sizeof(header));
560 offset += header.length;
561 }
Kevin O'Connor188d9942013-02-09 15:24:08 -0500562}
563
Kevin O'Connor59d6ca52012-05-31 00:20:55 -0400564struct QemuCfgFile {
565 u32 size; /* file size */
566 u16 select; /* write this to 0x510 to read it */
567 u16 reserved;
568 char name[56];
569};
570
Kevin O'Connorb840ba92013-02-09 20:09:22 -0500571void qemu_cfg_init(void)
Kevin O'Connor59d6ca52012-05-31 00:20:55 -0400572{
Kevin O'Connor7507ce22013-06-13 20:04:31 -0400573 if (!runningOnQEMU())
Kevin O'Connor59d6ca52012-05-31 00:20:55 -0400574 return;
Gerd Hoffmannc4c9fae2009-12-18 12:16:04 +0100575
Kevin O'Connorb840ba92013-02-09 20:09:22 -0500576 // Detect fw_cfg interface.
577 qemu_cfg_select(QEMU_CFG_SIGNATURE);
578 char *sig = "QEMU";
579 int i;
580 for (i = 0; i < 4; i++)
581 if (inb(PORT_QEMU_CFG_DATA) != sig[i])
582 return;
Marc Marí06316c92015-10-08 17:03:26 +0200583
Kevin O'Connorb840ba92013-02-09 20:09:22 -0500584 dprintf(1, "Found QEMU fw_cfg\n");
Petr Berky5fbf2462017-03-28 23:03:53 +0200585 cfg_enabled = 1;
Kevin O'Connorb840ba92013-02-09 20:09:22 -0500586
Marc Marí06316c92015-10-08 17:03:26 +0200587 // Detect DMA interface.
588 u32 id;
589 qemu_cfg_read_entry(&id, QEMU_CFG_ID, sizeof(id));
590
591 if (id & QEMU_CFG_VERSION_DMA) {
592 dprintf(1, "QEMU fw_cfg DMA interface supported\n");
593 cfg_dma_enabled = 1;
594 }
595
Kevin O'Connor188d9942013-02-09 15:24:08 -0500596 // Populate romfiles for legacy fw_cfg entries
597 qemu_cfg_legacy();
598
599 // Load files found in the fw_cfg file directory
Kevin O'Connore2304262010-06-13 16:05:17 -0400600 u32 count;
Gerd Hoffmannc4c9fae2009-12-18 12:16:04 +0100601 qemu_cfg_read_entry(&count, QEMU_CFG_FILE_DIR, sizeof(count));
Kevin O'Connorb3064592012-08-14 21:20:10 -0400602 count = be32_to_cpu(count);
Kevin O'Connore2304262010-06-13 16:05:17 -0400603 u32 e;
604 for (e = 0; e < count; e++) {
Kevin O'Connor59d6ca52012-05-31 00:20:55 -0400605 struct QemuCfgFile qfile;
Kevin O'Connorc40e3fa2013-02-09 14:55:30 -0500606 qemu_cfg_read(&qfile, sizeof(qfile));
607 qemu_romfile_add(qfile.name, be16_to_cpu(qfile.select)
608 , 0, be32_to_cpu(qfile.size));
Gerd Hoffmannc4c9fae2009-12-18 12:16:04 +0100609 }
Gerd Hoffmann6e1b0822013-10-18 12:18:19 +0200610
611 qemu_cfg_e820();
Gerd Hoffmann7eac0c42014-05-13 14:09:00 +0200612
613 if (romfile_find("etc/table-loader")) {
614 acpi_pm_base = 0x0600;
615 dprintf(1, "Moving pm_base to 0x%x\n", acpi_pm_base);
616 }
Kevin O'Connor0541f2f2017-11-10 12:20:35 -0500617
618 // serial console
619 u16 nogfx = 0;
620 qemu_cfg_read_entry(&nogfx, QEMU_CFG_NOGRAPHIC, sizeof(nogfx));
621 if (nogfx && !romfile_find("etc/sercon-port")
622 && !romfile_find("vgaroms/sgabios.bin"))
623 const_romfile_add_int("etc/sercon-port", PORT_SERIAL1);
Kevin O'Connor8b565782011-07-05 20:32:44 -0400624}