1
// Paravirtualization support.
3
// Copyright (C) 2009 Red Hat Inc.
6
// Gleb Natapov <gnatapov@redhat.com>
8
// This file may be distributed under the terms of the GNU LGPLv3 license.
10
#include "config.h" // CONFIG_COREBOOT
11
#include "util.h" // ntoh[ls]
12
#include "ioport.h" // outw
13
#include "paravirt.h" // qemu_cfg_port_probe
14
#include "smbios.h" // struct smbios_structure_header
19
qemu_cfg_select(u16 f)
21
outw(f, PORT_QEMU_CFG_CTL);
25
qemu_cfg_read(u8 *buf, int len)
28
*(buf++) = inb(PORT_QEMU_CFG_DATA);
32
qemu_cfg_skip(int len)
35
inb(PORT_QEMU_CFG_DATA);
39
qemu_cfg_read_entry(void *buf, int e, int len)
42
qemu_cfg_read(buf, len);
45
void qemu_cfg_port_probe(void)
55
qemu_cfg_select(QEMU_CFG_SIGNATURE);
57
for (i = 0; i < 4; i++)
58
if (inb(PORT_QEMU_CFG_DATA) != sig[i]) {
62
dprintf(4, "qemu_cfg_present=%d\n", qemu_cfg_present);
65
void qemu_cfg_get_uuid(u8 *uuid)
67
if (!qemu_cfg_present)
70
qemu_cfg_read_entry(uuid, QEMU_CFG_UUID, 16);
73
int qemu_cfg_show_boot_menu(void)
76
if (!qemu_cfg_present)
79
qemu_cfg_read_entry(&v, QEMU_CFG_BOOT_MENU, sizeof(v));
84
int qemu_cfg_irq0_override(void)
88
if (!qemu_cfg_present)
91
qemu_cfg_read_entry(&v, QEMU_CFG_IRQ0_OVERRIDE, sizeof(v));
96
u16 qemu_cfg_acpi_additional_tables(void)
100
if (!qemu_cfg_present)
103
qemu_cfg_read_entry(&cnt, QEMU_CFG_ACPI_TABLES, sizeof(cnt));
108
u16 qemu_cfg_next_acpi_table_len(void)
112
qemu_cfg_read((u8*)&len, sizeof(len));
117
void* qemu_cfg_next_acpi_table_load(void *addr, u16 len)
119
qemu_cfg_read(addr, len);
123
u16 qemu_cfg_smbios_entries(void)
127
if (!qemu_cfg_present)
130
qemu_cfg_read_entry(&cnt, QEMU_CFG_SMBIOS_ENTRIES, sizeof(cnt));
135
u32 qemu_cfg_e820_entries(void)
139
if (!qemu_cfg_present)
142
qemu_cfg_read_entry(&cnt, QEMU_CFG_E820_TABLE, sizeof(cnt));
146
void* qemu_cfg_e820_load_next(void *addr)
148
qemu_cfg_read(addr, sizeof(struct e820_reservation));
152
struct smbios_header {
157
struct smbios_field {
158
struct smbios_header header;
164
struct smbios_table {
165
struct smbios_header header;
169
#define SMBIOS_FIELD_ENTRY 0
170
#define SMBIOS_TABLE_ENTRY 1
172
size_t qemu_cfg_smbios_load_field(int type, size_t offset, void *addr)
176
for (i = qemu_cfg_smbios_entries(); i > 0; i--) {
177
struct smbios_field field;
179
qemu_cfg_read((u8 *)&field, sizeof(struct smbios_header));
180
field.header.length -= sizeof(struct smbios_header);
182
if (field.header.type != SMBIOS_FIELD_ENTRY) {
183
qemu_cfg_skip(field.header.length);
187
qemu_cfg_read((u8 *)&field.type,
188
sizeof(field) - sizeof(struct smbios_header));
189
field.header.length -= sizeof(field) - sizeof(struct smbios_header);
191
if (field.type != type || field.offset != offset) {
192
qemu_cfg_skip(field.header.length);
196
qemu_cfg_read(addr, field.header.length);
197
return (size_t)field.header.length;
202
int qemu_cfg_smbios_load_external(int type, char **p, unsigned *nr_structs,
203
unsigned *max_struct_size, char *end)
205
static u64 used_bitmap[4] = { 0 };
209
/* Check if we've already reported these tables */
210
if (used_bitmap[(type >> 6) & 0x3] & (1ULL << (type & 0x3f)))
213
/* Don't introduce spurious end markers */
217
for (i = qemu_cfg_smbios_entries(); i > 0; i--) {
218
struct smbios_table table;
219
struct smbios_structure_header *header = (void *)*p;
222
qemu_cfg_read((u8 *)&table, sizeof(struct smbios_header));
223
table.header.length -= sizeof(struct smbios_header);
225
if (table.header.type != SMBIOS_TABLE_ENTRY) {
226
qemu_cfg_skip(table.header.length);
230
if (end - *p < sizeof(struct smbios_structure_header)) {
235
qemu_cfg_read((u8 *)*p, sizeof(struct smbios_structure_header));
236
table.header.length -= sizeof(struct smbios_structure_header);
238
if (header->type != type) {
239
qemu_cfg_skip(table.header.length);
243
*p += sizeof(struct smbios_structure_header);
245
/* Entries end with a double NULL char, if there's a string at
246
* the end (length is greater than formatted length), the string
247
* terminator provides the first NULL. */
248
string = header->length < table.header.length +
249
sizeof(struct smbios_structure_header);
251
/* Read the rest and terminate the entry */
252
if (end - *p < table.header.length) {
254
*p -= sizeof(struct smbios_structure_header);
257
qemu_cfg_read((u8 *)*p, table.header.length);
258
*p += table.header.length;
267
if (*p - (char *)header > *max_struct_size)
268
*max_struct_size = *p - (char *)header;
272
/* Mark that we've reported on this type */
273
used_bitmap[(type >> 6) & 0x3] |= (1ULL << (type & 0x3f));
280
int qemu_cfg_get_numa_nodes(void)
284
qemu_cfg_read_entry(&cnt, QEMU_CFG_NUMA, sizeof(cnt));
289
void qemu_cfg_get_numa_data(u64 *data, int n)
293
for (i = 0; i < n; i++)
294
qemu_cfg_read((u8*)(data + i), sizeof(u64));
297
u16 qemu_cfg_get_max_cpus(void)
301
if (!qemu_cfg_present)
304
qemu_cfg_read_entry(&cnt, QEMU_CFG_MAX_CPUS, sizeof(cnt));
309
static QemuCfgFile LastFile;
312
__cfg_next_prefix_file(const char *prefix, int prefixlen, u32 prevselect)
314
if (!qemu_cfg_present)
318
qemu_cfg_read_entry(&count, QEMU_CFG_FILE_DIR, sizeof(count));
319
count = ntohl(count);
321
for (e = 0; e < count; e++) {
322
qemu_cfg_read((void*)&LastFile, sizeof(LastFile));
323
u32 select = ntohs(LastFile.select);
324
if (select <= prevselect)
326
if (memcmp(prefix, LastFile.name, prefixlen) == 0)
332
u32 qemu_cfg_next_prefix_file(const char *prefix, u32 prevselect)
334
return __cfg_next_prefix_file(prefix, strlen(prefix), prevselect);
337
u32 qemu_cfg_find_file(const char *name)
339
return __cfg_next_prefix_file(name, strlen(name) + 1, 0);
342
int qemu_cfg_size_file(u32 select)
344
if (select != ntohs(LastFile.select))
346
return ntohl(LastFile.size);
349
int qemu_cfg_read_file(u32 select, void *dst, u32 maxlen)
351
if (!qemu_cfg_present)
353
if (!select || select != ntohs(LastFile.select))
355
int len = qemu_cfg_size_file(select);
356
if (len < 0 || len > maxlen)
358
qemu_cfg_read_entry(dst, select, len);