blob: e782227dcca572d850c9afb5884482bee3dcc06a [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'Connorde9e7052013-02-09 19:09:20 -050015#include "smbios.h" // smbios_setup
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
Kevin O'Connorc40e3fa2013-02-09 14:55:30 -0500136qemu_cfg_read(void *buf, int len)
Kevin O'Connore7cc7642009-10-04 10:05:16 -0400137{
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
Jes Sorensen0360e8e2010-02-16 09:46:08 +0100206u32 qemu_cfg_e820_entries(void)
207{
208 u32 cnt;
209
210 if (!qemu_cfg_present)
211 return 0;
212
213 qemu_cfg_read_entry(&cnt, QEMU_CFG_E820_TABLE, sizeof(cnt));
214 return cnt;
215}
216
217void* qemu_cfg_e820_load_next(void *addr)
218{
219 qemu_cfg_read(addr, sizeof(struct e820_reservation));
220 return addr;
221}
222
Kevin O'Connor590e5542009-10-08 22:09:02 -0400223int qemu_cfg_get_numa_nodes(void)
224{
225 u64 cnt;
226
227 qemu_cfg_read_entry(&cnt, QEMU_CFG_NUMA, sizeof(cnt));
228
229 return (int)cnt;
230}
231
232void qemu_cfg_get_numa_data(u64 *data, int n)
233{
234 int i;
235
236 for (i = 0; i < n; i++)
237 qemu_cfg_read((u8*)(data + i), sizeof(u64));
238}
Kevin O'Connor84705852009-10-08 22:13:15 -0400239
240u16 qemu_cfg_get_max_cpus(void)
241{
242 u16 cnt;
243
244 if (!qemu_cfg_present)
245 return 0;
246
247 qemu_cfg_read_entry(&cnt, QEMU_CFG_MAX_CPUS, sizeof(cnt));
248
249 return cnt;
250}
Gerd Hoffmannc4c9fae2009-12-18 12:16:04 +0100251
Kevin O'Connorc40e3fa2013-02-09 14:55:30 -0500252static int
253qemu_cfg_read_file(struct romfile_s *file, void *dst, u32 maxlen)
Gerd Hoffmannc4c9fae2009-12-18 12:16:04 +0100254{
Kevin O'Connor59d6ca52012-05-31 00:20:55 -0400255 if (file->size > maxlen)
256 return -1;
Kevin O'Connorc40e3fa2013-02-09 14:55:30 -0500257 qemu_cfg_select(file->id);
258 qemu_cfg_skip(file->rawsize);
259 qemu_cfg_read(dst, file->size);
Kevin O'Connor59d6ca52012-05-31 00:20:55 -0400260 return file->size;
261}
262
Kevin O'Connorc40e3fa2013-02-09 14:55:30 -0500263static void
264qemu_romfile_add(char *name, int select, int skip, int size)
265{
266 struct romfile_s *file = malloc_tmp(sizeof(*file));
267 if (!file) {
268 warn_noalloc();
269 return;
270 }
271 memset(file, 0, sizeof(*file));
272 strtcpy(file->name, name, sizeof(file->name));
273 file->id = select;
274 file->rawsize = skip; // Use rawsize to indicate skip length.
275 file->size = size;
276 file->copy = qemu_cfg_read_file;
277 romfile_add(file);
278}
279
Kevin O'Connorde9e7052013-02-09 19:09:20 -0500280#define SMBIOS_FIELD_ENTRY 0
281#define SMBIOS_TABLE_ENTRY 1
282
283struct qemu_smbios_header {
284 u16 length;
285 u8 headertype;
286 u8 tabletype;
287 u16 fieldoffset;
288} PACKED;
289
Kevin O'Connor188d9942013-02-09 15:24:08 -0500290// Populate romfile entries for legacy fw_cfg ports (that predate the
291// "file" interface).
292static void
293qemu_cfg_legacy(void)
294{
295 // ACPI tables
296 char name[128];
297 u16 cnt;
298 qemu_cfg_read_entry(&cnt, QEMU_CFG_ACPI_TABLES, sizeof(cnt));
299 int i, offset = sizeof(cnt);
300 for (i = 0; i < cnt; i++) {
301 u16 len;
302 qemu_cfg_read(&len, sizeof(len));
303 offset += sizeof(len);
304 snprintf(name, sizeof(name), "acpi/table%d", i);
305 qemu_romfile_add(name, QEMU_CFG_ACPI_TABLES, offset, len);
306 qemu_cfg_skip(len);
307 offset += len;
308 }
Kevin O'Connorde9e7052013-02-09 19:09:20 -0500309
310 // SMBIOS info
311 qemu_cfg_read_entry(&cnt, QEMU_CFG_SMBIOS_ENTRIES, sizeof(cnt));
312 offset = sizeof(cnt);
313 for (i = 0; i < cnt; i++) {
314 struct qemu_smbios_header header;
315 qemu_cfg_read(&header, sizeof(header));
316 if (header.headertype == SMBIOS_FIELD_ENTRY) {
317 snprintf(name, sizeof(name), "smbios/field%d-%d"
318 , header.tabletype, header.fieldoffset);
319 qemu_romfile_add(name, QEMU_CFG_SMBIOS_ENTRIES
320 , offset + sizeof(header)
321 , header.length - sizeof(header));
322 } else {
323 snprintf(name, sizeof(name), "smbios/table%d-%d"
324 , header.tabletype, i);
325 qemu_romfile_add(name, QEMU_CFG_SMBIOS_ENTRIES
326 , offset + 3, header.length - 3);
327 }
328 qemu_cfg_skip(header.length - sizeof(header));
329 offset += header.length;
330 }
Kevin O'Connor188d9942013-02-09 15:24:08 -0500331}
332
Kevin O'Connor59d6ca52012-05-31 00:20:55 -0400333struct QemuCfgFile {
334 u32 size; /* file size */
335 u16 select; /* write this to 0x510 to read it */
336 u16 reserved;
337 char name[56];
338};
339
Kevin O'Connord83c87b2013-01-21 01:14:12 -0500340void qemu_romfile_init(void)
Kevin O'Connor59d6ca52012-05-31 00:20:55 -0400341{
Kevin O'Connor897fb112013-02-07 23:32:48 -0500342 if (!CONFIG_QEMU || !qemu_cfg_present)
Kevin O'Connor59d6ca52012-05-31 00:20:55 -0400343 return;
Gerd Hoffmannc4c9fae2009-12-18 12:16:04 +0100344
Kevin O'Connor188d9942013-02-09 15:24:08 -0500345 // Populate romfiles for legacy fw_cfg entries
346 qemu_cfg_legacy();
347
348 // Load files found in the fw_cfg file directory
Kevin O'Connore2304262010-06-13 16:05:17 -0400349 u32 count;
Gerd Hoffmannc4c9fae2009-12-18 12:16:04 +0100350 qemu_cfg_read_entry(&count, QEMU_CFG_FILE_DIR, sizeof(count));
Kevin O'Connorb3064592012-08-14 21:20:10 -0400351 count = be32_to_cpu(count);
Kevin O'Connore2304262010-06-13 16:05:17 -0400352 u32 e;
353 for (e = 0; e < count; e++) {
Kevin O'Connor59d6ca52012-05-31 00:20:55 -0400354 struct QemuCfgFile qfile;
Kevin O'Connorc40e3fa2013-02-09 14:55:30 -0500355 qemu_cfg_read(&qfile, sizeof(qfile));
356 qemu_romfile_add(qfile.name, be16_to_cpu(qfile.select)
357 , 0, be32_to_cpu(qfile.size));
Gerd Hoffmannc4c9fae2009-12-18 12:16:04 +0100358 }
Kevin O'Connor8b565782011-07-05 20:32:44 -0400359}