blob: 79b1c56a667e162db8cf66163e0d9ede9ee0bd2a [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
Jes Sorensen0360e8e2010-02-16 09:46:08 +0100175u32 qemu_cfg_e820_entries(void)
176{
177 u32 cnt;
178
179 if (!qemu_cfg_present)
180 return 0;
181
182 qemu_cfg_read_entry(&cnt, QEMU_CFG_E820_TABLE, sizeof(cnt));
183 return cnt;
184}
185
186void* qemu_cfg_e820_load_next(void *addr)
187{
188 qemu_cfg_read(addr, sizeof(struct e820_reservation));
189 return addr;
190}
191
Kevin O'Connor590e5542009-10-08 22:09:02 -0400192int qemu_cfg_get_numa_nodes(void)
193{
194 u64 cnt;
195
196 qemu_cfg_read_entry(&cnt, QEMU_CFG_NUMA, sizeof(cnt));
197
198 return (int)cnt;
199}
200
201void qemu_cfg_get_numa_data(u64 *data, int n)
202{
203 int i;
204
205 for (i = 0; i < n; i++)
206 qemu_cfg_read((u8*)(data + i), sizeof(u64));
207}
Kevin O'Connor84705852009-10-08 22:13:15 -0400208
Kevin O'Connorc40e3fa2013-02-09 14:55:30 -0500209static int
210qemu_cfg_read_file(struct romfile_s *file, void *dst, u32 maxlen)
Gerd Hoffmannc4c9fae2009-12-18 12:16:04 +0100211{
Kevin O'Connor59d6ca52012-05-31 00:20:55 -0400212 if (file->size > maxlen)
213 return -1;
Kevin O'Connorc40e3fa2013-02-09 14:55:30 -0500214 qemu_cfg_select(file->id);
215 qemu_cfg_skip(file->rawsize);
216 qemu_cfg_read(dst, file->size);
Kevin O'Connor59d6ca52012-05-31 00:20:55 -0400217 return file->size;
218}
219
Kevin O'Connorc40e3fa2013-02-09 14:55:30 -0500220static void
221qemu_romfile_add(char *name, int select, int skip, int size)
222{
223 struct romfile_s *file = malloc_tmp(sizeof(*file));
224 if (!file) {
225 warn_noalloc();
226 return;
227 }
228 memset(file, 0, sizeof(*file));
229 strtcpy(file->name, name, sizeof(file->name));
230 file->id = select;
231 file->rawsize = skip; // Use rawsize to indicate skip length.
232 file->size = size;
233 file->copy = qemu_cfg_read_file;
234 romfile_add(file);
235}
236
Kevin O'Connorde9e7052013-02-09 19:09:20 -0500237#define SMBIOS_FIELD_ENTRY 0
238#define SMBIOS_TABLE_ENTRY 1
239
240struct qemu_smbios_header {
241 u16 length;
242 u8 headertype;
243 u8 tabletype;
244 u16 fieldoffset;
245} PACKED;
246
Kevin O'Connor188d9942013-02-09 15:24:08 -0500247// Populate romfile entries for legacy fw_cfg ports (that predate the
248// "file" interface).
249static void
250qemu_cfg_legacy(void)
251{
Kevin O'Connor56c50892013-02-09 19:25:51 -0500252 // Misc config items.
253 qemu_romfile_add("etc/show-boot-menu", QEMU_CFG_BOOT_MENU, 0, 2);
254 qemu_romfile_add("etc/irq0-override", QEMU_CFG_IRQ0_OVERRIDE, 0, 1);
255 qemu_romfile_add("etc/max-cpus", QEMU_CFG_MAX_CPUS, 0, 2);
256
Kevin O'Connor188d9942013-02-09 15:24:08 -0500257 // ACPI tables
258 char name[128];
259 u16 cnt;
260 qemu_cfg_read_entry(&cnt, QEMU_CFG_ACPI_TABLES, sizeof(cnt));
261 int i, offset = sizeof(cnt);
262 for (i = 0; i < cnt; i++) {
263 u16 len;
264 qemu_cfg_read(&len, sizeof(len));
265 offset += sizeof(len);
266 snprintf(name, sizeof(name), "acpi/table%d", i);
267 qemu_romfile_add(name, QEMU_CFG_ACPI_TABLES, offset, len);
268 qemu_cfg_skip(len);
269 offset += len;
270 }
Kevin O'Connorde9e7052013-02-09 19:09:20 -0500271
272 // SMBIOS info
273 qemu_cfg_read_entry(&cnt, QEMU_CFG_SMBIOS_ENTRIES, sizeof(cnt));
274 offset = sizeof(cnt);
275 for (i = 0; i < cnt; i++) {
276 struct qemu_smbios_header header;
277 qemu_cfg_read(&header, sizeof(header));
278 if (header.headertype == SMBIOS_FIELD_ENTRY) {
279 snprintf(name, sizeof(name), "smbios/field%d-%d"
280 , header.tabletype, header.fieldoffset);
281 qemu_romfile_add(name, QEMU_CFG_SMBIOS_ENTRIES
282 , offset + sizeof(header)
283 , header.length - sizeof(header));
284 } else {
285 snprintf(name, sizeof(name), "smbios/table%d-%d"
286 , header.tabletype, i);
287 qemu_romfile_add(name, QEMU_CFG_SMBIOS_ENTRIES
288 , offset + 3, header.length - 3);
289 }
290 qemu_cfg_skip(header.length - sizeof(header));
291 offset += header.length;
292 }
Kevin O'Connor188d9942013-02-09 15:24:08 -0500293}
294
Kevin O'Connor59d6ca52012-05-31 00:20:55 -0400295struct QemuCfgFile {
296 u32 size; /* file size */
297 u16 select; /* write this to 0x510 to read it */
298 u16 reserved;
299 char name[56];
300};
301
Kevin O'Connord83c87b2013-01-21 01:14:12 -0500302void qemu_romfile_init(void)
Kevin O'Connor59d6ca52012-05-31 00:20:55 -0400303{
Kevin O'Connor897fb112013-02-07 23:32:48 -0500304 if (!CONFIG_QEMU || !qemu_cfg_present)
Kevin O'Connor59d6ca52012-05-31 00:20:55 -0400305 return;
Gerd Hoffmannc4c9fae2009-12-18 12:16:04 +0100306
Kevin O'Connor188d9942013-02-09 15:24:08 -0500307 // Populate romfiles for legacy fw_cfg entries
308 qemu_cfg_legacy();
309
310 // Load files found in the fw_cfg file directory
Kevin O'Connore2304262010-06-13 16:05:17 -0400311 u32 count;
Gerd Hoffmannc4c9fae2009-12-18 12:16:04 +0100312 qemu_cfg_read_entry(&count, QEMU_CFG_FILE_DIR, sizeof(count));
Kevin O'Connorb3064592012-08-14 21:20:10 -0400313 count = be32_to_cpu(count);
Kevin O'Connore2304262010-06-13 16:05:17 -0400314 u32 e;
315 for (e = 0; e < count; e++) {
Kevin O'Connor59d6ca52012-05-31 00:20:55 -0400316 struct QemuCfgFile qfile;
Kevin O'Connorc40e3fa2013-02-09 14:55:30 -0500317 qemu_cfg_read(&qfile, sizeof(qfile));
318 qemu_romfile_add(qfile.name, be16_to_cpu(qfile.select)
319 , 0, be32_to_cpu(qfile.size));
Gerd Hoffmannc4c9fae2009-12-18 12:16:04 +0100320 }
Kevin O'Connor8b565782011-07-05 20:32:44 -0400321}