blob: ea2bbfb8d07cf175b3cfd86bf49f171bb3325cc9 [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'Connor897fb112013-02-07 23:32:48 -050011#include "config.h" // CONFIG_QEMU
Kevin O'Connorb3064592012-08-14 21:20:10 -040012#include "util.h" // dprintf
13#include "byteorder.h" // be32_to_cpu
Kevin O'Connor01a85202009-10-18 09:49:59 -040014#include "ioport.h" // outw
Kevin O'Connord83c87b2013-01-21 01:14:12 -050015#include "paravirt.h" // qemu_cfg_preinit
Kevin O'Connorde9e7052013-02-09 19:09:20 -050016#include "smbios.h" // smbios_setup
Kevin O'Connor8ed2e532013-01-21 02:32:48 -050017#include "memmap.h" // add_e820
Kevin O'Connor5d369d82013-09-02 20:48:46 -040018#include "hw/cmos.h" // CMOS_*
Kevin O'Connor8ed2e532013-01-21 02:32:48 -050019#include "acpi.h" // acpi_setup
20#include "mptable.h" // mptable_setup
Kevin O'Connor5d369d82013-09-02 20:48:46 -040021#include "hw/pci.h" // create_pirtable
Kevin O'Connora2a86e22013-02-13 19:35:12 -050022#include "xen.h" // xen_biostable_setup
Kevin O'Connor9dea5902013-09-14 20:23:54 -040023#include "malloc.h" // malloc_tmp
Kevin O'Connor41639f82013-09-14 19:37:36 -040024#include "romfile.h" // romfile_loadint
Kevin O'Connorfa9c66a2013-09-14 19:10:40 -040025#include "string.h" // memset
Kevin O'Connorb9c6a962013-09-14 13:01:30 -040026#include "x86.h" // cpuid
Kevin O'Connore7cc7642009-10-04 10:05:16 -040027
Kevin O'Connorf85e4bc2013-02-19 01:33:45 -050028// Amount of continuous ram under 4Gig
29u32 RamSize;
30// Amount of continuous ram >4Gig
31u64 RamSizeOver4G;
Kevin O'Connor89a2f962013-02-18 23:36:03 -050032// Type of emulator platform.
33int PlatformRunningOn VARFSEG;
34
Kevin O'Connor7b5bc502013-02-09 13:07:23 -050035/* This CPUID returns the signature 'KVMKVMKVM' in ebx, ecx, and edx. It
36 * should be used to determine that a VM is running under KVM.
37 */
38#define KVM_CPUID_SIGNATURE 0x40000000
39
40static void kvm_preinit(void)
41{
42 if (!CONFIG_QEMU)
43 return;
44 unsigned int eax, ebx, ecx, edx;
45 char signature[13];
46
47 cpuid(KVM_CPUID_SIGNATURE, &eax, &ebx, &ecx, &edx);
48 memcpy(signature + 0, &ebx, 4);
49 memcpy(signature + 4, &ecx, 4);
50 memcpy(signature + 8, &edx, 4);
51 signature[12] = 0;
52
53 if (strcmp(signature, "KVMKVMKVM") == 0) {
54 dprintf(1, "Running on KVM\n");
55 PlatformRunningOn |= PF_KVM;
56 }
57}
58
Kevin O'Connor8ed2e532013-01-21 02:32:48 -050059void
Kevin O'Connora2a86e22013-02-13 19:35:12 -050060qemu_preinit(void)
Kevin O'Connor8ed2e532013-01-21 02:32:48 -050061{
Kevin O'Connor02313b22013-02-07 22:42:25 -050062 if (!CONFIG_QEMU)
63 return;
64
Kevin O'Connora2a86e22013-02-13 19:35:12 -050065 if (runningOnXen()) {
66 xen_ramsize_preinit();
67 return;
68 }
69
Kevin O'Connor02313b22013-02-07 22:42:25 -050070 PlatformRunningOn = PF_QEMU;
Kevin O'Connor7b5bc502013-02-09 13:07:23 -050071 kvm_preinit();
Kevin O'Connor02313b22013-02-07 22:42:25 -050072
Kevin O'Connor8ed2e532013-01-21 02:32:48 -050073 // On emulators, get memory size from nvram.
74 u32 rs = ((inb_cmos(CMOS_MEM_EXTMEM2_LOW) << 16)
75 | (inb_cmos(CMOS_MEM_EXTMEM2_HIGH) << 24));
76 if (rs)
77 rs += 16 * 1024 * 1024;
78 else
79 rs = (((inb_cmos(CMOS_MEM_EXTMEM_LOW) << 10)
80 | (inb_cmos(CMOS_MEM_EXTMEM_HIGH) << 18))
81 + 1 * 1024 * 1024);
82 RamSize = rs;
83 add_e820(0, rs, E820_RAM);
84
85 // Check for memory over 4Gig
86 u64 high = ((inb_cmos(CMOS_MEM_HIGHMEM_LOW) << 16)
87 | ((u32)inb_cmos(CMOS_MEM_HIGHMEM_MID) << 24)
88 | ((u64)inb_cmos(CMOS_MEM_HIGHMEM_HIGH) << 32));
89 RamSizeOver4G = high;
90 add_e820(0x100000000ull, high, E820_RAM);
91
92 /* reserve 256KB BIOS area at the end of 4 GB */
93 add_e820(0xfffc0000, 256*1024, E820_RESERVED);
Kevin O'Connorf85e4bc2013-02-19 01:33:45 -050094
95 dprintf(1, "Ram Size=0x%08x (0x%016llx high)\n", RamSize, RamSizeOver4G);
Kevin O'Connor8ed2e532013-01-21 02:32:48 -050096}
97
98void
Kevin O'Connora2a86e22013-02-13 19:35:12 -050099qemu_platform_setup(void)
Kevin O'Connor8ed2e532013-01-21 02:32:48 -0500100{
Kevin O'Connora2a86e22013-02-13 19:35:12 -0500101 if (!CONFIG_QEMU)
102 return;
103
104 if (runningOnXen()) {
105 pci_probe_devices();
106 xen_hypercall_setup();
107 xen_biostable_setup();
108 return;
109 }
110
111 // Initialize pci
112 pci_setup();
Kevin O'Connorcdbac7f2013-03-08 19:33:39 -0500113 smm_device_setup();
Kevin O'Connora2a86e22013-02-13 19:35:12 -0500114 smm_setup();
115
116 // Initialize mtrr and smp
117 mtrr_setup();
118 smp_setup();
119
120 // Create bios tables
Kevin O'Connor8ed2e532013-01-21 02:32:48 -0500121 pirtable_setup();
122 mptable_setup();
123 smbios_setup();
124 acpi_setup();
125}
126
Kevin O'Connor4edda082013-02-09 13:21:08 -0500127
128/****************************************************************
129 * QEMU firmware config (fw_cfg) interface
130 ****************************************************************/
131
Kevin O'Connorb840ba92013-02-09 20:09:22 -0500132// List of QEMU fw_cfg entries. DO NOT ADD MORE. (All new content
133// should be passed via the fw_cfg "file" interface.)
Kevin O'Connor4edda082013-02-09 13:21:08 -0500134#define QEMU_CFG_SIGNATURE 0x00
135#define QEMU_CFG_ID 0x01
136#define QEMU_CFG_UUID 0x02
137#define QEMU_CFG_NUMA 0x0d
138#define QEMU_CFG_BOOT_MENU 0x0e
139#define QEMU_CFG_MAX_CPUS 0x0f
140#define QEMU_CFG_FILE_DIR 0x19
141#define QEMU_CFG_ARCH_LOCAL 0x8000
142#define QEMU_CFG_ACPI_TABLES (QEMU_CFG_ARCH_LOCAL + 0)
143#define QEMU_CFG_SMBIOS_ENTRIES (QEMU_CFG_ARCH_LOCAL + 1)
144#define QEMU_CFG_IRQ0_OVERRIDE (QEMU_CFG_ARCH_LOCAL + 2)
145#define QEMU_CFG_E820_TABLE (QEMU_CFG_ARCH_LOCAL + 3)
146
Kevin O'Connore7cc7642009-10-04 10:05:16 -0400147static void
148qemu_cfg_select(u16 f)
149{
150 outw(f, PORT_QEMU_CFG_CTL);
151}
152
153static void
Kevin O'Connorc40e3fa2013-02-09 14:55:30 -0500154qemu_cfg_read(void *buf, int len)
Kevin O'Connore7cc7642009-10-04 10:05:16 -0400155{
Kevin O'Connor6039fc52010-08-25 21:43:19 -0400156 insb(PORT_QEMU_CFG_DATA, buf, len);
Kevin O'Connore7cc7642009-10-04 10:05:16 -0400157}
158
159static void
Kevin O'Connor4e4b4102009-10-08 21:21:59 -0400160qemu_cfg_skip(int len)
161{
162 while (len--)
163 inb(PORT_QEMU_CFG_DATA);
164}
165
166static void
Kevin O'Connore7cc7642009-10-04 10:05:16 -0400167qemu_cfg_read_entry(void *buf, int e, int len)
168{
169 qemu_cfg_select(e);
170 qemu_cfg_read(buf, len);
171}
172
Kevin O'Connor4158c8c2013-03-30 09:12:11 -0400173struct qemu_romfile_s {
174 struct romfile_s file;
175 int select, skip;
176};
177
Kevin O'Connorc40e3fa2013-02-09 14:55:30 -0500178static int
179qemu_cfg_read_file(struct romfile_s *file, void *dst, u32 maxlen)
Gerd Hoffmannc4c9fae2009-12-18 12:16:04 +0100180{
Kevin O'Connor59d6ca52012-05-31 00:20:55 -0400181 if (file->size > maxlen)
182 return -1;
Kevin O'Connor4158c8c2013-03-30 09:12:11 -0400183 struct qemu_romfile_s *qfile;
184 qfile = container_of(file, struct qemu_romfile_s, file);
185 qemu_cfg_select(qfile->select);
186 qemu_cfg_skip(qfile->skip);
Kevin O'Connorc40e3fa2013-02-09 14:55:30 -0500187 qemu_cfg_read(dst, file->size);
Kevin O'Connor59d6ca52012-05-31 00:20:55 -0400188 return file->size;
189}
190
Kevin O'Connorc40e3fa2013-02-09 14:55:30 -0500191static void
192qemu_romfile_add(char *name, int select, int skip, int size)
193{
Kevin O'Connor4158c8c2013-03-30 09:12:11 -0400194 struct qemu_romfile_s *qfile = malloc_tmp(sizeof(*qfile));
195 if (!qfile) {
Kevin O'Connorc40e3fa2013-02-09 14:55:30 -0500196 warn_noalloc();
197 return;
198 }
Kevin O'Connor4158c8c2013-03-30 09:12:11 -0400199 memset(qfile, 0, sizeof(*qfile));
200 strtcpy(qfile->file.name, name, sizeof(qfile->file.name));
201 qfile->file.size = size;
202 qfile->select = select;
203 qfile->skip = skip;
204 qfile->file.copy = qemu_cfg_read_file;
205 romfile_add(&qfile->file);
Kevin O'Connorc40e3fa2013-02-09 14:55:30 -0500206}
207
Kevin O'Connorfe090302013-02-09 20:00:06 -0500208struct e820_reservation {
209 u64 address;
210 u64 length;
211 u32 type;
212};
213
Kevin O'Connorde9e7052013-02-09 19:09:20 -0500214#define SMBIOS_FIELD_ENTRY 0
215#define SMBIOS_TABLE_ENTRY 1
216
217struct qemu_smbios_header {
218 u16 length;
219 u8 headertype;
220 u8 tabletype;
221 u16 fieldoffset;
222} PACKED;
223
Kevin O'Connor188d9942013-02-09 15:24:08 -0500224// Populate romfile entries for legacy fw_cfg ports (that predate the
225// "file" interface).
226static void
227qemu_cfg_legacy(void)
228{
Kevin O'Connor7507ce22013-06-13 20:04:31 -0400229 if (!CONFIG_QEMU)
230 return;
231
Kevin O'Connor56c50892013-02-09 19:25:51 -0500232 // Misc config items.
233 qemu_romfile_add("etc/show-boot-menu", QEMU_CFG_BOOT_MENU, 0, 2);
234 qemu_romfile_add("etc/irq0-override", QEMU_CFG_IRQ0_OVERRIDE, 0, 1);
235 qemu_romfile_add("etc/max-cpus", QEMU_CFG_MAX_CPUS, 0, 2);
236
Kevin O'Connorf9e4e372013-02-09 19:45:45 -0500237 // NUMA data
238 u64 numacount;
239 qemu_cfg_read_entry(&numacount, QEMU_CFG_NUMA, sizeof(numacount));
Kevin O'Connorfb76cff2013-03-23 11:38:45 -0400240 int max_cpu = romfile_loadint("etc/max-cpus", 0);
241 qemu_romfile_add("etc/numa-cpu-map", QEMU_CFG_NUMA, sizeof(numacount)
242 , max_cpu*sizeof(u64));
243 qemu_romfile_add("etc/numa-nodes", QEMU_CFG_NUMA
244 , sizeof(numacount) + max_cpu*sizeof(u64)
Kevin O'Connorf9e4e372013-02-09 19:45:45 -0500245 , numacount*sizeof(u64));
246
Kevin O'Connorfe090302013-02-09 20:00:06 -0500247 // e820 data
248 u32 count32;
249 qemu_cfg_read_entry(&count32, QEMU_CFG_E820_TABLE, sizeof(count32));
250 if (count32) {
251 struct e820_reservation entry;
252 int i;
253 for (i = 0; i < count32; i++) {
254 qemu_cfg_read(&entry, sizeof(entry));
255 add_e820(entry.address, entry.length, entry.type);
256 }
257 } else if (runningOnKVM()) {
258 // Backwards compatibility - provide hard coded range.
259 // 4 pages before the bios, 3 pages for vmx tss pages, the
260 // other page for EPT real mode pagetable
261 add_e820(0xfffbc000, 4*4096, E820_RESERVED);
262 }
263
Kevin O'Connor188d9942013-02-09 15:24:08 -0500264 // ACPI tables
265 char name[128];
266 u16 cnt;
267 qemu_cfg_read_entry(&cnt, QEMU_CFG_ACPI_TABLES, sizeof(cnt));
268 int i, offset = sizeof(cnt);
269 for (i = 0; i < cnt; i++) {
270 u16 len;
271 qemu_cfg_read(&len, sizeof(len));
272 offset += sizeof(len);
273 snprintf(name, sizeof(name), "acpi/table%d", i);
274 qemu_romfile_add(name, QEMU_CFG_ACPI_TABLES, offset, len);
275 qemu_cfg_skip(len);
276 offset += len;
277 }
Kevin O'Connorde9e7052013-02-09 19:09:20 -0500278
279 // SMBIOS info
280 qemu_cfg_read_entry(&cnt, QEMU_CFG_SMBIOS_ENTRIES, sizeof(cnt));
281 offset = sizeof(cnt);
282 for (i = 0; i < cnt; i++) {
283 struct qemu_smbios_header header;
284 qemu_cfg_read(&header, sizeof(header));
285 if (header.headertype == SMBIOS_FIELD_ENTRY) {
286 snprintf(name, sizeof(name), "smbios/field%d-%d"
287 , header.tabletype, header.fieldoffset);
288 qemu_romfile_add(name, QEMU_CFG_SMBIOS_ENTRIES
289 , offset + sizeof(header)
290 , header.length - sizeof(header));
291 } else {
292 snprintf(name, sizeof(name), "smbios/table%d-%d"
293 , header.tabletype, i);
294 qemu_romfile_add(name, QEMU_CFG_SMBIOS_ENTRIES
295 , offset + 3, header.length - 3);
296 }
297 qemu_cfg_skip(header.length - sizeof(header));
298 offset += header.length;
299 }
Kevin O'Connor188d9942013-02-09 15:24:08 -0500300}
301
Kevin O'Connor59d6ca52012-05-31 00:20:55 -0400302struct QemuCfgFile {
303 u32 size; /* file size */
304 u16 select; /* write this to 0x510 to read it */
305 u16 reserved;
306 char name[56];
307};
308
Kevin O'Connorb840ba92013-02-09 20:09:22 -0500309void qemu_cfg_init(void)
Kevin O'Connor59d6ca52012-05-31 00:20:55 -0400310{
Kevin O'Connor7507ce22013-06-13 20:04:31 -0400311 if (!runningOnQEMU())
Kevin O'Connor59d6ca52012-05-31 00:20:55 -0400312 return;
Gerd Hoffmannc4c9fae2009-12-18 12:16:04 +0100313
Kevin O'Connorb840ba92013-02-09 20:09:22 -0500314 // Detect fw_cfg interface.
315 qemu_cfg_select(QEMU_CFG_SIGNATURE);
316 char *sig = "QEMU";
317 int i;
318 for (i = 0; i < 4; i++)
319 if (inb(PORT_QEMU_CFG_DATA) != sig[i])
320 return;
321 dprintf(1, "Found QEMU fw_cfg\n");
322
Kevin O'Connor188d9942013-02-09 15:24:08 -0500323 // Populate romfiles for legacy fw_cfg entries
324 qemu_cfg_legacy();
325
326 // Load files found in the fw_cfg file directory
Kevin O'Connore2304262010-06-13 16:05:17 -0400327 u32 count;
Gerd Hoffmannc4c9fae2009-12-18 12:16:04 +0100328 qemu_cfg_read_entry(&count, QEMU_CFG_FILE_DIR, sizeof(count));
Kevin O'Connorb3064592012-08-14 21:20:10 -0400329 count = be32_to_cpu(count);
Kevin O'Connore2304262010-06-13 16:05:17 -0400330 u32 e;
331 for (e = 0; e < count; e++) {
Kevin O'Connor59d6ca52012-05-31 00:20:55 -0400332 struct QemuCfgFile qfile;
Kevin O'Connorc40e3fa2013-02-09 14:55:30 -0500333 qemu_cfg_read(&qfile, sizeof(qfile));
334 qemu_romfile_add(qfile.name, be16_to_cpu(qfile.select)
335 , 0, be32_to_cpu(qfile.size));
Gerd Hoffmannc4c9fae2009-12-18 12:16:04 +0100336 }
Kevin O'Connor8b565782011-07-05 20:32:44 -0400337}