blob: 73b06ca0f62037e626b9f648563fc66cedf872b5 [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'Connor01a85202009-10-18 09:49:59 -040015#include "smbios.h" // struct smbios_structure_header
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
22int qemu_cfg_present;
23
Kevin O'Connor8ed2e532013-01-21 02:32:48 -050024void
25qemu_ramsize_preinit(void)
26{
Kevin O'Connor02313b22013-02-07 22:42:25 -050027 if (!CONFIG_QEMU)
28 return;
29
30 PlatformRunningOn = PF_QEMU;
31
Kevin O'Connor8ed2e532013-01-21 02:32:48 -050032 // On emulators, get memory size from nvram.
33 u32 rs = ((inb_cmos(CMOS_MEM_EXTMEM2_LOW) << 16)
34 | (inb_cmos(CMOS_MEM_EXTMEM2_HIGH) << 24));
35 if (rs)
36 rs += 16 * 1024 * 1024;
37 else
38 rs = (((inb_cmos(CMOS_MEM_EXTMEM_LOW) << 10)
39 | (inb_cmos(CMOS_MEM_EXTMEM_HIGH) << 18))
40 + 1 * 1024 * 1024);
41 RamSize = rs;
42 add_e820(0, rs, E820_RAM);
43
44 // Check for memory over 4Gig
45 u64 high = ((inb_cmos(CMOS_MEM_HIGHMEM_LOW) << 16)
46 | ((u32)inb_cmos(CMOS_MEM_HIGHMEM_MID) << 24)
47 | ((u64)inb_cmos(CMOS_MEM_HIGHMEM_HIGH) << 32));
48 RamSizeOver4G = high;
49 add_e820(0x100000000ull, high, E820_RAM);
50
51 /* reserve 256KB BIOS area at the end of 4 GB */
52 add_e820(0xfffc0000, 256*1024, E820_RESERVED);
53
54 u32 count = qemu_cfg_e820_entries();
55 if (count) {
56 struct e820_reservation entry;
57 int i;
58
59 for (i = 0; i < count; i++) {
60 qemu_cfg_e820_load_next(&entry);
61 add_e820(entry.address, entry.length, entry.type);
62 }
63 } else if (kvm_para_available()) {
64 // Backwards compatibility - provide hard coded range.
65 // 4 pages before the bios, 3 pages for vmx tss pages, the
66 // other page for EPT real mode pagetable
67 add_e820(0xfffbc000, 4*4096, E820_RESERVED);
68 }
69}
70
71void
72qemu_biostable_setup(void)
73{
74 pirtable_setup();
75 mptable_setup();
76 smbios_setup();
77 acpi_setup();
78}
79
Kevin O'Connore7cc7642009-10-04 10:05:16 -040080static void
81qemu_cfg_select(u16 f)
82{
83 outw(f, PORT_QEMU_CFG_CTL);
84}
85
86static void
87qemu_cfg_read(u8 *buf, int len)
88{
Kevin O'Connor6039fc52010-08-25 21:43:19 -040089 insb(PORT_QEMU_CFG_DATA, buf, len);
Kevin O'Connore7cc7642009-10-04 10:05:16 -040090}
91
92static void
Kevin O'Connor4e4b4102009-10-08 21:21:59 -040093qemu_cfg_skip(int len)
94{
95 while (len--)
96 inb(PORT_QEMU_CFG_DATA);
97}
98
99static void
Kevin O'Connore7cc7642009-10-04 10:05:16 -0400100qemu_cfg_read_entry(void *buf, int e, int len)
101{
102 qemu_cfg_select(e);
103 qemu_cfg_read(buf, len);
104}
105
Kevin O'Connord83c87b2013-01-21 01:14:12 -0500106void qemu_cfg_preinit(void)
Kevin O'Connore7cc7642009-10-04 10:05:16 -0400107{
108 char *sig = "QEMU";
109 int i;
110
Kevin O'Connor897fb112013-02-07 23:32:48 -0500111 if (!CONFIG_QEMU)
Kevin O'Connore7cc7642009-10-04 10:05:16 -0400112 return;
113
114 qemu_cfg_present = 1;
115
116 qemu_cfg_select(QEMU_CFG_SIGNATURE);
117
118 for (i = 0; i < 4; i++)
119 if (inb(PORT_QEMU_CFG_DATA) != sig[i]) {
120 qemu_cfg_present = 0;
121 break;
122 }
123 dprintf(4, "qemu_cfg_present=%d\n", qemu_cfg_present);
124}
125
126void qemu_cfg_get_uuid(u8 *uuid)
127{
128 if (!qemu_cfg_present)
129 return;
130
131 qemu_cfg_read_entry(uuid, QEMU_CFG_UUID, 16);
132}
133
134int qemu_cfg_show_boot_menu(void)
135{
136 u16 v;
137 if (!qemu_cfg_present)
138 return 1;
139
140 qemu_cfg_read_entry(&v, QEMU_CFG_BOOT_MENU, sizeof(v));
141
142 return v;
143}
144
Kevin O'Connor4d2b6192009-10-08 21:37:21 -0400145int qemu_cfg_irq0_override(void)
146{
147 u8 v;
148
149 if (!qemu_cfg_present)
150 return 0;
151
152 qemu_cfg_read_entry(&v, QEMU_CFG_IRQ0_OVERRIDE, sizeof(v));
153
154 return v;
155}
156
Kevin O'Connorcc6dc462009-10-08 21:18:41 -0400157u16 qemu_cfg_acpi_additional_tables(void)
158{
159 u16 cnt;
160
161 if (!qemu_cfg_present)
162 return 0;
163
164 qemu_cfg_read_entry(&cnt, QEMU_CFG_ACPI_TABLES, sizeof(cnt));
165
166 return cnt;
167}
168
169u16 qemu_cfg_next_acpi_table_len(void)
170{
171 u16 len;
172
173 qemu_cfg_read((u8*)&len, sizeof(len));
174
175 return len;
176}
177
178void* qemu_cfg_next_acpi_table_load(void *addr, u16 len)
179{
180 qemu_cfg_read(addr, len);
181 return addr;
182}
183
Kevin O'Connor4e4b4102009-10-08 21:21:59 -0400184u16 qemu_cfg_smbios_entries(void)
185{
186 u16 cnt;
187
188 if (!qemu_cfg_present)
189 return 0;
190
191 qemu_cfg_read_entry(&cnt, QEMU_CFG_SMBIOS_ENTRIES, sizeof(cnt));
192
193 return cnt;
194}
195
Jes Sorensen0360e8e2010-02-16 09:46:08 +0100196u32 qemu_cfg_e820_entries(void)
197{
198 u32 cnt;
199
200 if (!qemu_cfg_present)
201 return 0;
202
203 qemu_cfg_read_entry(&cnt, QEMU_CFG_E820_TABLE, sizeof(cnt));
204 return cnt;
205}
206
207void* qemu_cfg_e820_load_next(void *addr)
208{
209 qemu_cfg_read(addr, sizeof(struct e820_reservation));
210 return addr;
211}
212
Kevin O'Connor4e4b4102009-10-08 21:21:59 -0400213struct smbios_header {
214 u16 length;
215 u8 type;
216} PACKED;
217
218struct smbios_field {
219 struct smbios_header header;
220 u8 type;
221 u16 offset;
222 u8 data[];
223} PACKED;
224
225struct smbios_table {
226 struct smbios_header header;
227 u8 data[];
228} PACKED;
229
230#define SMBIOS_FIELD_ENTRY 0
231#define SMBIOS_TABLE_ENTRY 1
232
233size_t qemu_cfg_smbios_load_field(int type, size_t offset, void *addr)
234{
235 int i;
236
237 for (i = qemu_cfg_smbios_entries(); i > 0; i--) {
238 struct smbios_field field;
239
240 qemu_cfg_read((u8 *)&field, sizeof(struct smbios_header));
241 field.header.length -= sizeof(struct smbios_header);
242
243 if (field.header.type != SMBIOS_FIELD_ENTRY) {
244 qemu_cfg_skip(field.header.length);
245 continue;
246 }
247
248 qemu_cfg_read((u8 *)&field.type,
249 sizeof(field) - sizeof(struct smbios_header));
250 field.header.length -= sizeof(field) - sizeof(struct smbios_header);
251
252 if (field.type != type || field.offset != offset) {
253 qemu_cfg_skip(field.header.length);
254 continue;
255 }
256
257 qemu_cfg_read(addr, field.header.length);
258 return (size_t)field.header.length;
259 }
260 return 0;
261}
262
Kevin O'Connor4e4b4102009-10-08 21:21:59 -0400263int qemu_cfg_smbios_load_external(int type, char **p, unsigned *nr_structs,
264 unsigned *max_struct_size, char *end)
265{
266 static u64 used_bitmap[4] = { 0 };
267 char *start = *p;
268 int i;
269
270 /* Check if we've already reported these tables */
271 if (used_bitmap[(type >> 6) & 0x3] & (1ULL << (type & 0x3f)))
272 return 1;
273
274 /* Don't introduce spurious end markers */
275 if (type == 127)
276 return 0;
277
278 for (i = qemu_cfg_smbios_entries(); i > 0; i--) {
279 struct smbios_table table;
280 struct smbios_structure_header *header = (void *)*p;
281 int string;
282
283 qemu_cfg_read((u8 *)&table, sizeof(struct smbios_header));
284 table.header.length -= sizeof(struct smbios_header);
285
286 if (table.header.type != SMBIOS_TABLE_ENTRY) {
287 qemu_cfg_skip(table.header.length);
288 continue;
289 }
290
291 if (end - *p < sizeof(struct smbios_structure_header)) {
Kevin O'Connorcfdc13f2010-02-14 13:07:54 -0500292 warn_noalloc();
Kevin O'Connor4e4b4102009-10-08 21:21:59 -0400293 break;
294 }
295
296 qemu_cfg_read((u8 *)*p, sizeof(struct smbios_structure_header));
297 table.header.length -= sizeof(struct smbios_structure_header);
298
299 if (header->type != type) {
300 qemu_cfg_skip(table.header.length);
301 continue;
302 }
303
304 *p += sizeof(struct smbios_structure_header);
305
306 /* Entries end with a double NULL char, if there's a string at
307 * the end (length is greater than formatted length), the string
308 * terminator provides the first NULL. */
309 string = header->length < table.header.length +
310 sizeof(struct smbios_structure_header);
311
312 /* Read the rest and terminate the entry */
313 if (end - *p < table.header.length) {
Kevin O'Connorcfdc13f2010-02-14 13:07:54 -0500314 warn_noalloc();
Kevin O'Connor4e4b4102009-10-08 21:21:59 -0400315 *p -= sizeof(struct smbios_structure_header);
316 continue;
317 }
318 qemu_cfg_read((u8 *)*p, table.header.length);
319 *p += table.header.length;
320 *((u8*)*p) = 0;
321 (*p)++;
322 if (!string) {
323 *((u8*)*p) = 0;
324 (*p)++;
325 }
326
327 (*nr_structs)++;
328 if (*p - (char *)header > *max_struct_size)
329 *max_struct_size = *p - (char *)header;
330 }
331
332 if (start != *p) {
333 /* Mark that we've reported on this type */
334 used_bitmap[(type >> 6) & 0x3] |= (1ULL << (type & 0x3f));
335 return 1;
336 }
337
338 return 0;
339}
340
Kevin O'Connor590e5542009-10-08 22:09:02 -0400341int qemu_cfg_get_numa_nodes(void)
342{
343 u64 cnt;
344
345 qemu_cfg_read_entry(&cnt, QEMU_CFG_NUMA, sizeof(cnt));
346
347 return (int)cnt;
348}
349
350void qemu_cfg_get_numa_data(u64 *data, int n)
351{
352 int i;
353
354 for (i = 0; i < n; i++)
355 qemu_cfg_read((u8*)(data + i), sizeof(u64));
356}
Kevin O'Connor84705852009-10-08 22:13:15 -0400357
358u16 qemu_cfg_get_max_cpus(void)
359{
360 u16 cnt;
361
362 if (!qemu_cfg_present)
363 return 0;
364
365 qemu_cfg_read_entry(&cnt, QEMU_CFG_MAX_CPUS, sizeof(cnt));
366
367 return cnt;
368}
Gerd Hoffmannc4c9fae2009-12-18 12:16:04 +0100369
Kevin O'Connor59d6ca52012-05-31 00:20:55 -0400370int qemu_cfg_read_file(struct romfile_s *file, void *dst, u32 maxlen)
Gerd Hoffmannc4c9fae2009-12-18 12:16:04 +0100371{
Kevin O'Connor59d6ca52012-05-31 00:20:55 -0400372 if (file->size > maxlen)
373 return -1;
374 qemu_cfg_read_entry(dst, file->id, file->size);
375 return file->size;
376}
377
378struct QemuCfgFile {
379 u32 size; /* file size */
380 u16 select; /* write this to 0x510 to read it */
381 u16 reserved;
382 char name[56];
383};
384
Kevin O'Connord83c87b2013-01-21 01:14:12 -0500385void qemu_romfile_init(void)
Kevin O'Connor59d6ca52012-05-31 00:20:55 -0400386{
Kevin O'Connor897fb112013-02-07 23:32:48 -0500387 if (!CONFIG_QEMU || !qemu_cfg_present)
Kevin O'Connor59d6ca52012-05-31 00:20:55 -0400388 return;
Gerd Hoffmannc4c9fae2009-12-18 12:16:04 +0100389
Kevin O'Connore2304262010-06-13 16:05:17 -0400390 u32 count;
Gerd Hoffmannc4c9fae2009-12-18 12:16:04 +0100391 qemu_cfg_read_entry(&count, QEMU_CFG_FILE_DIR, sizeof(count));
Kevin O'Connorb3064592012-08-14 21:20:10 -0400392 count = be32_to_cpu(count);
Kevin O'Connore2304262010-06-13 16:05:17 -0400393 u32 e;
394 for (e = 0; e < count; e++) {
Kevin O'Connor59d6ca52012-05-31 00:20:55 -0400395 struct QemuCfgFile qfile;
396 qemu_cfg_read((void*)&qfile, sizeof(qfile));
397 struct romfile_s *file = malloc_tmp(sizeof(*file));
398 if (!file) {
399 warn_noalloc();
400 return;
401 }
402 memset(file, 0, sizeof(*file));
403 strtcpy(file->name, qfile.name, sizeof(file->name));
Kevin O'Connorb3064592012-08-14 21:20:10 -0400404 file->size = be32_to_cpu(qfile.size);
405 file->id = be16_to_cpu(qfile.select);
Kevin O'Connor59d6ca52012-05-31 00:20:55 -0400406 file->copy = qemu_cfg_read_file;
407 romfile_add(file);
408 dprintf(3, "Found fw_cfg file: %s (size=%d)\n", file->name, file->size);
Gerd Hoffmannc4c9fae2009-12-18 12:16:04 +0100409 }
Kevin O'Connor8b565782011-07-05 20:32:44 -0400410}