blob: 9ea3dd535d1f17976e06e8d3d02d68c06a869249 [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
18#include "cmos.h" // CMOS_*
19#include "acpi.h" // acpi_setup
20#include "mptable.h" // mptable_setup
21#include "pci.h" // create_pirtable
Kevin O'Connora2a86e22013-02-13 19:35:12 -050022#include "xen.h" // xen_biostable_setup
Kevin O'Connore7cc7642009-10-04 10:05:16 -040023
Kevin O'Connor89a2f962013-02-18 23:36:03 -050024// Type of emulator platform.
25int PlatformRunningOn VARFSEG;
26
Kevin O'Connor7b5bc502013-02-09 13:07:23 -050027/* This CPUID returns the signature 'KVMKVMKVM' in ebx, ecx, and edx. It
28 * should be used to determine that a VM is running under KVM.
29 */
30#define KVM_CPUID_SIGNATURE 0x40000000
31
32static void kvm_preinit(void)
33{
34 if (!CONFIG_QEMU)
35 return;
36 unsigned int eax, ebx, ecx, edx;
37 char signature[13];
38
39 cpuid(KVM_CPUID_SIGNATURE, &eax, &ebx, &ecx, &edx);
40 memcpy(signature + 0, &ebx, 4);
41 memcpy(signature + 4, &ecx, 4);
42 memcpy(signature + 8, &edx, 4);
43 signature[12] = 0;
44
45 if (strcmp(signature, "KVMKVMKVM") == 0) {
46 dprintf(1, "Running on KVM\n");
47 PlatformRunningOn |= PF_KVM;
48 }
49}
50
Kevin O'Connor8ed2e532013-01-21 02:32:48 -050051void
Kevin O'Connora2a86e22013-02-13 19:35:12 -050052qemu_preinit(void)
Kevin O'Connor8ed2e532013-01-21 02:32:48 -050053{
Kevin O'Connor02313b22013-02-07 22:42:25 -050054 if (!CONFIG_QEMU)
55 return;
56
Kevin O'Connora2a86e22013-02-13 19:35:12 -050057 if (runningOnXen()) {
58 xen_ramsize_preinit();
59 return;
60 }
61
Kevin O'Connor02313b22013-02-07 22:42:25 -050062 PlatformRunningOn = PF_QEMU;
Kevin O'Connor7b5bc502013-02-09 13:07:23 -050063 kvm_preinit();
Kevin O'Connor02313b22013-02-07 22:42:25 -050064
Kevin O'Connor8ed2e532013-01-21 02:32:48 -050065 // On emulators, get memory size from nvram.
66 u32 rs = ((inb_cmos(CMOS_MEM_EXTMEM2_LOW) << 16)
67 | (inb_cmos(CMOS_MEM_EXTMEM2_HIGH) << 24));
68 if (rs)
69 rs += 16 * 1024 * 1024;
70 else
71 rs = (((inb_cmos(CMOS_MEM_EXTMEM_LOW) << 10)
72 | (inb_cmos(CMOS_MEM_EXTMEM_HIGH) << 18))
73 + 1 * 1024 * 1024);
74 RamSize = rs;
75 add_e820(0, rs, E820_RAM);
76
77 // Check for memory over 4Gig
78 u64 high = ((inb_cmos(CMOS_MEM_HIGHMEM_LOW) << 16)
79 | ((u32)inb_cmos(CMOS_MEM_HIGHMEM_MID) << 24)
80 | ((u64)inb_cmos(CMOS_MEM_HIGHMEM_HIGH) << 32));
81 RamSizeOver4G = high;
82 add_e820(0x100000000ull, high, E820_RAM);
83
84 /* reserve 256KB BIOS area at the end of 4 GB */
85 add_e820(0xfffc0000, 256*1024, E820_RESERVED);
Kevin O'Connor8ed2e532013-01-21 02:32:48 -050086}
87
88void
Kevin O'Connora2a86e22013-02-13 19:35:12 -050089qemu_platform_setup(void)
Kevin O'Connor8ed2e532013-01-21 02:32:48 -050090{
Kevin O'Connora2a86e22013-02-13 19:35:12 -050091 if (!CONFIG_QEMU)
92 return;
93
94 if (runningOnXen()) {
95 pci_probe_devices();
96 xen_hypercall_setup();
97 xen_biostable_setup();
98 return;
99 }
100
101 // Initialize pci
102 pci_setup();
103 smm_setup();
104
105 // Initialize mtrr and smp
106 mtrr_setup();
107 smp_setup();
108
109 // Create bios tables
Kevin O'Connor8ed2e532013-01-21 02:32:48 -0500110 pirtable_setup();
111 mptable_setup();
112 smbios_setup();
113 acpi_setup();
114}
115
Kevin O'Connor4edda082013-02-09 13:21:08 -0500116
117/****************************************************************
118 * QEMU firmware config (fw_cfg) interface
119 ****************************************************************/
120
Kevin O'Connorb840ba92013-02-09 20:09:22 -0500121// List of QEMU fw_cfg entries. DO NOT ADD MORE. (All new content
122// should be passed via the fw_cfg "file" interface.)
Kevin O'Connor4edda082013-02-09 13:21:08 -0500123#define QEMU_CFG_SIGNATURE 0x00
124#define QEMU_CFG_ID 0x01
125#define QEMU_CFG_UUID 0x02
126#define QEMU_CFG_NUMA 0x0d
127#define QEMU_CFG_BOOT_MENU 0x0e
128#define QEMU_CFG_MAX_CPUS 0x0f
129#define QEMU_CFG_FILE_DIR 0x19
130#define QEMU_CFG_ARCH_LOCAL 0x8000
131#define QEMU_CFG_ACPI_TABLES (QEMU_CFG_ARCH_LOCAL + 0)
132#define QEMU_CFG_SMBIOS_ENTRIES (QEMU_CFG_ARCH_LOCAL + 1)
133#define QEMU_CFG_IRQ0_OVERRIDE (QEMU_CFG_ARCH_LOCAL + 2)
134#define QEMU_CFG_E820_TABLE (QEMU_CFG_ARCH_LOCAL + 3)
135
Kevin O'Connore7cc7642009-10-04 10:05:16 -0400136static void
137qemu_cfg_select(u16 f)
138{
139 outw(f, PORT_QEMU_CFG_CTL);
140}
141
142static void
Kevin O'Connorc40e3fa2013-02-09 14:55:30 -0500143qemu_cfg_read(void *buf, int len)
Kevin O'Connore7cc7642009-10-04 10:05:16 -0400144{
Kevin O'Connor6039fc52010-08-25 21:43:19 -0400145 insb(PORT_QEMU_CFG_DATA, buf, len);
Kevin O'Connore7cc7642009-10-04 10:05:16 -0400146}
147
148static void
Kevin O'Connor4e4b4102009-10-08 21:21:59 -0400149qemu_cfg_skip(int len)
150{
151 while (len--)
152 inb(PORT_QEMU_CFG_DATA);
153}
154
155static void
Kevin O'Connore7cc7642009-10-04 10:05:16 -0400156qemu_cfg_read_entry(void *buf, int e, int len)
157{
158 qemu_cfg_select(e);
159 qemu_cfg_read(buf, len);
160}
161
Kevin O'Connorc40e3fa2013-02-09 14:55:30 -0500162static int
163qemu_cfg_read_file(struct romfile_s *file, void *dst, u32 maxlen)
Gerd Hoffmannc4c9fae2009-12-18 12:16:04 +0100164{
Kevin O'Connor59d6ca52012-05-31 00:20:55 -0400165 if (file->size > maxlen)
166 return -1;
Kevin O'Connorc40e3fa2013-02-09 14:55:30 -0500167 qemu_cfg_select(file->id);
168 qemu_cfg_skip(file->rawsize);
169 qemu_cfg_read(dst, file->size);
Kevin O'Connor59d6ca52012-05-31 00:20:55 -0400170 return file->size;
171}
172
Kevin O'Connorc40e3fa2013-02-09 14:55:30 -0500173static void
174qemu_romfile_add(char *name, int select, int skip, int size)
175{
176 struct romfile_s *file = malloc_tmp(sizeof(*file));
177 if (!file) {
178 warn_noalloc();
179 return;
180 }
181 memset(file, 0, sizeof(*file));
182 strtcpy(file->name, name, sizeof(file->name));
183 file->id = select;
184 file->rawsize = skip; // Use rawsize to indicate skip length.
185 file->size = size;
186 file->copy = qemu_cfg_read_file;
187 romfile_add(file);
188}
189
Kevin O'Connorfe090302013-02-09 20:00:06 -0500190struct e820_reservation {
191 u64 address;
192 u64 length;
193 u32 type;
194};
195
Kevin O'Connorde9e7052013-02-09 19:09:20 -0500196#define SMBIOS_FIELD_ENTRY 0
197#define SMBIOS_TABLE_ENTRY 1
198
199struct qemu_smbios_header {
200 u16 length;
201 u8 headertype;
202 u8 tabletype;
203 u16 fieldoffset;
204} PACKED;
205
Kevin O'Connor188d9942013-02-09 15:24:08 -0500206// Populate romfile entries for legacy fw_cfg ports (that predate the
207// "file" interface).
208static void
209qemu_cfg_legacy(void)
210{
Kevin O'Connor56c50892013-02-09 19:25:51 -0500211 // Misc config items.
212 qemu_romfile_add("etc/show-boot-menu", QEMU_CFG_BOOT_MENU, 0, 2);
213 qemu_romfile_add("etc/irq0-override", QEMU_CFG_IRQ0_OVERRIDE, 0, 1);
214 qemu_romfile_add("etc/max-cpus", QEMU_CFG_MAX_CPUS, 0, 2);
215
Kevin O'Connorf9e4e372013-02-09 19:45:45 -0500216 // NUMA data
217 u64 numacount;
218 qemu_cfg_read_entry(&numacount, QEMU_CFG_NUMA, sizeof(numacount));
219 numacount += romfile_loadint("etc/max-cpus", 0);
220 qemu_romfile_add("etc/numa-nodes", QEMU_CFG_NUMA, sizeof(numacount)
221 , numacount*sizeof(u64));
222
Kevin O'Connorfe090302013-02-09 20:00:06 -0500223 // e820 data
224 u32 count32;
225 qemu_cfg_read_entry(&count32, QEMU_CFG_E820_TABLE, sizeof(count32));
226 if (count32) {
227 struct e820_reservation entry;
228 int i;
229 for (i = 0; i < count32; i++) {
230 qemu_cfg_read(&entry, sizeof(entry));
231 add_e820(entry.address, entry.length, entry.type);
232 }
233 } else if (runningOnKVM()) {
234 // Backwards compatibility - provide hard coded range.
235 // 4 pages before the bios, 3 pages for vmx tss pages, the
236 // other page for EPT real mode pagetable
237 add_e820(0xfffbc000, 4*4096, E820_RESERVED);
238 }
239
Kevin O'Connor188d9942013-02-09 15:24:08 -0500240 // ACPI tables
241 char name[128];
242 u16 cnt;
243 qemu_cfg_read_entry(&cnt, QEMU_CFG_ACPI_TABLES, sizeof(cnt));
244 int i, offset = sizeof(cnt);
245 for (i = 0; i < cnt; i++) {
246 u16 len;
247 qemu_cfg_read(&len, sizeof(len));
248 offset += sizeof(len);
249 snprintf(name, sizeof(name), "acpi/table%d", i);
250 qemu_romfile_add(name, QEMU_CFG_ACPI_TABLES, offset, len);
251 qemu_cfg_skip(len);
252 offset += len;
253 }
Kevin O'Connorde9e7052013-02-09 19:09:20 -0500254
255 // SMBIOS info
256 qemu_cfg_read_entry(&cnt, QEMU_CFG_SMBIOS_ENTRIES, sizeof(cnt));
257 offset = sizeof(cnt);
258 for (i = 0; i < cnt; i++) {
259 struct qemu_smbios_header header;
260 qemu_cfg_read(&header, sizeof(header));
261 if (header.headertype == SMBIOS_FIELD_ENTRY) {
262 snprintf(name, sizeof(name), "smbios/field%d-%d"
263 , header.tabletype, header.fieldoffset);
264 qemu_romfile_add(name, QEMU_CFG_SMBIOS_ENTRIES
265 , offset + sizeof(header)
266 , header.length - sizeof(header));
267 } else {
268 snprintf(name, sizeof(name), "smbios/table%d-%d"
269 , header.tabletype, i);
270 qemu_romfile_add(name, QEMU_CFG_SMBIOS_ENTRIES
271 , offset + 3, header.length - 3);
272 }
273 qemu_cfg_skip(header.length - sizeof(header));
274 offset += header.length;
275 }
Kevin O'Connor188d9942013-02-09 15:24:08 -0500276}
277
Kevin O'Connor59d6ca52012-05-31 00:20:55 -0400278struct QemuCfgFile {
279 u32 size; /* file size */
280 u16 select; /* write this to 0x510 to read it */
281 u16 reserved;
282 char name[56];
283};
284
Kevin O'Connorb840ba92013-02-09 20:09:22 -0500285void qemu_cfg_init(void)
Kevin O'Connor59d6ca52012-05-31 00:20:55 -0400286{
Kevin O'Connorb840ba92013-02-09 20:09:22 -0500287 if (!CONFIG_QEMU)
Kevin O'Connor59d6ca52012-05-31 00:20:55 -0400288 return;
Gerd Hoffmannc4c9fae2009-12-18 12:16:04 +0100289
Kevin O'Connorb840ba92013-02-09 20:09:22 -0500290 // Detect fw_cfg interface.
291 qemu_cfg_select(QEMU_CFG_SIGNATURE);
292 char *sig = "QEMU";
293 int i;
294 for (i = 0; i < 4; i++)
295 if (inb(PORT_QEMU_CFG_DATA) != sig[i])
296 return;
297 dprintf(1, "Found QEMU fw_cfg\n");
298
Kevin O'Connor188d9942013-02-09 15:24:08 -0500299 // Populate romfiles for legacy fw_cfg entries
300 qemu_cfg_legacy();
301
302 // Load files found in the fw_cfg file directory
Kevin O'Connore2304262010-06-13 16:05:17 -0400303 u32 count;
Gerd Hoffmannc4c9fae2009-12-18 12:16:04 +0100304 qemu_cfg_read_entry(&count, QEMU_CFG_FILE_DIR, sizeof(count));
Kevin O'Connorb3064592012-08-14 21:20:10 -0400305 count = be32_to_cpu(count);
Kevin O'Connore2304262010-06-13 16:05:17 -0400306 u32 e;
307 for (e = 0; e < count; e++) {
Kevin O'Connor59d6ca52012-05-31 00:20:55 -0400308 struct QemuCfgFile qfile;
Kevin O'Connorc40e3fa2013-02-09 14:55:30 -0500309 qemu_cfg_read(&qfile, sizeof(qfile));
310 qemu_romfile_add(qfile.name, be16_to_cpu(qfile.select)
311 , 0, be32_to_cpu(qfile.size));
Gerd Hoffmannc4c9fae2009-12-18 12:16:04 +0100312 }
Kevin O'Connor8b565782011-07-05 20:32:44 -0400313}