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)
27 insb(PORT_QEMU_CFG_DATA, buf, len);
31 qemu_cfg_skip(int len)
34 inb(PORT_QEMU_CFG_DATA);
38 qemu_cfg_read_entry(void *buf, int e, int len)
41 qemu_cfg_read(buf, len);
44 void qemu_cfg_port_probe(void)
54 qemu_cfg_select(QEMU_CFG_SIGNATURE);
56 for (i = 0; i < 4; i++)
57 if (inb(PORT_QEMU_CFG_DATA) != sig[i]) {
61 dprintf(4, "qemu_cfg_present=%d\n", qemu_cfg_present);
64 void qemu_cfg_get_uuid(u8 *uuid)
66 if (!qemu_cfg_present)
69 qemu_cfg_read_entry(uuid, QEMU_CFG_UUID, 16);
72 int qemu_cfg_show_boot_menu(void)
75 if (!qemu_cfg_present)
78 qemu_cfg_read_entry(&v, QEMU_CFG_BOOT_MENU, sizeof(v));
83 int qemu_cfg_irq0_override(void)
87 if (!qemu_cfg_present)
90 qemu_cfg_read_entry(&v, QEMU_CFG_IRQ0_OVERRIDE, sizeof(v));
95 u16 qemu_cfg_acpi_additional_tables(void)
99 if (!qemu_cfg_present)
102 qemu_cfg_read_entry(&cnt, QEMU_CFG_ACPI_TABLES, sizeof(cnt));
107 u16 qemu_cfg_next_acpi_table_len(void)
111 qemu_cfg_read((u8*)&len, sizeof(len));
116 void* qemu_cfg_next_acpi_table_load(void *addr, u16 len)
118 qemu_cfg_read(addr, len);
122 u16 qemu_cfg_smbios_entries(void)
126 if (!qemu_cfg_present)
129 qemu_cfg_read_entry(&cnt, QEMU_CFG_SMBIOS_ENTRIES, sizeof(cnt));
134 u32 qemu_cfg_e820_entries(void)
138 if (!qemu_cfg_present)
141 qemu_cfg_read_entry(&cnt, QEMU_CFG_E820_TABLE, sizeof(cnt));
145 void* qemu_cfg_e820_load_next(void *addr)
147 qemu_cfg_read(addr, sizeof(struct e820_reservation));
151 struct smbios_header {
156 struct smbios_field {
157 struct smbios_header header;
163 struct smbios_table {
164 struct smbios_header header;
168 #define SMBIOS_FIELD_ENTRY 0
169 #define SMBIOS_TABLE_ENTRY 1
171 size_t qemu_cfg_smbios_load_field(int type, size_t offset, void *addr)
175 for (i = qemu_cfg_smbios_entries(); i > 0; i--) {
176 struct smbios_field field;
178 qemu_cfg_read((u8 *)&field, sizeof(struct smbios_header));
179 field.header.length -= sizeof(struct smbios_header);
181 if (field.header.type != SMBIOS_FIELD_ENTRY) {
182 qemu_cfg_skip(field.header.length);
186 qemu_cfg_read((u8 *)&field.type,
187 sizeof(field) - sizeof(struct smbios_header));
188 field.header.length -= sizeof(field) - sizeof(struct smbios_header);
190 if (field.type != type || field.offset != offset) {
191 qemu_cfg_skip(field.header.length);
195 qemu_cfg_read(addr, field.header.length);
196 return (size_t)field.header.length;
201 int qemu_cfg_smbios_load_external(int type, char **p, unsigned *nr_structs,
202 unsigned *max_struct_size, char *end)
204 static u64 used_bitmap[4] = { 0 };
208 /* Check if we've already reported these tables */
209 if (used_bitmap[(type >> 6) & 0x3] & (1ULL << (type & 0x3f)))
212 /* Don't introduce spurious end markers */
216 for (i = qemu_cfg_smbios_entries(); i > 0; i--) {
217 struct smbios_table table;
218 struct smbios_structure_header *header = (void *)*p;
221 qemu_cfg_read((u8 *)&table, sizeof(struct smbios_header));
222 table.header.length -= sizeof(struct smbios_header);
224 if (table.header.type != SMBIOS_TABLE_ENTRY) {
225 qemu_cfg_skip(table.header.length);
229 if (end - *p < sizeof(struct smbios_structure_header)) {
234 qemu_cfg_read((u8 *)*p, sizeof(struct smbios_structure_header));
235 table.header.length -= sizeof(struct smbios_structure_header);
237 if (header->type != type) {
238 qemu_cfg_skip(table.header.length);
242 *p += sizeof(struct smbios_structure_header);
244 /* Entries end with a double NULL char, if there's a string at
245 * the end (length is greater than formatted length), the string
246 * terminator provides the first NULL. */
247 string = header->length < table.header.length +
248 sizeof(struct smbios_structure_header);
250 /* Read the rest and terminate the entry */
251 if (end - *p < table.header.length) {
253 *p -= sizeof(struct smbios_structure_header);
256 qemu_cfg_read((u8 *)*p, table.header.length);
257 *p += table.header.length;
266 if (*p - (char *)header > *max_struct_size)
267 *max_struct_size = *p - (char *)header;
271 /* Mark that we've reported on this type */
272 used_bitmap[(type >> 6) & 0x3] |= (1ULL << (type & 0x3f));
279 int qemu_cfg_get_numa_nodes(void)
283 qemu_cfg_read_entry(&cnt, QEMU_CFG_NUMA, sizeof(cnt));
288 void qemu_cfg_get_numa_data(u64 *data, int n)
292 for (i = 0; i < n; i++)
293 qemu_cfg_read((u8*)(data + i), sizeof(u64));
296 u16 qemu_cfg_get_max_cpus(void)
300 if (!qemu_cfg_present)
303 qemu_cfg_read_entry(&cnt, QEMU_CFG_MAX_CPUS, sizeof(cnt));
308 static QemuCfgFile LastFile;
311 __cfg_next_prefix_file(const char *prefix, int prefixlen, u32 prevselect)
313 if (!qemu_cfg_present)
317 qemu_cfg_read_entry(&count, QEMU_CFG_FILE_DIR, sizeof(count));
318 count = ntohl(count);
320 for (e = 0; e < count; e++) {
321 qemu_cfg_read((void*)&LastFile, sizeof(LastFile));
322 u32 select = ntohs(LastFile.select);
323 if (select <= prevselect)
325 if (memcmp(prefix, LastFile.name, prefixlen) == 0)
331 u32 qemu_cfg_next_prefix_file(const char *prefix, u32 prevselect)
333 return __cfg_next_prefix_file(prefix, strlen(prefix), prevselect);
336 u32 qemu_cfg_find_file(const char *name)
338 return __cfg_next_prefix_file(name, strlen(name) + 1, 0);
342 __qemu_cfg_set_file(u32 select)
344 if (!qemu_cfg_present || !select)
346 if (select == ntohs(LastFile.select))
350 qemu_cfg_read_entry(&count, QEMU_CFG_FILE_DIR, sizeof(count));
351 count = ntohl(count);
353 for (e = 0; e < count; e++) {
354 qemu_cfg_read((void*)&LastFile, sizeof(LastFile));
355 if (select == ntohs(LastFile.select))
361 int qemu_cfg_size_file(u32 select)
363 if (__qemu_cfg_set_file(select))
365 return ntohl(LastFile.size);
368 const char* qemu_cfg_name_file(u32 select)
370 if (__qemu_cfg_set_file(select))
372 return LastFile.name;
375 int qemu_cfg_read_file(u32 select, void *dst, u32 maxlen)
377 if (__qemu_cfg_set_file(select))
379 int len = qemu_cfg_size_file(select);
380 if (len < 0 || len > maxlen)
382 qemu_cfg_read_entry(dst, select, len);
386 // Helper function to find, malloc_tmphigh, and copy a romfile. This
387 // function adds a trailing zero to the malloc'd copy.
389 romfile_loadfile(const char *name, int *psize)
391 u32 file = romfile_find(name);
395 int filesize = romfile_size(file);
399 char *data = malloc_tmphigh(filesize+1);
405 dprintf(5, "Copying romfile '%s' (len %d)\n", name, filesize);
406 romfile_copy(file, data, filesize);
409 data[filesize] = '\0';
413 // Attempt to load an integer from the given file - return 'defval'
416 romfile_loadint(const char *name, u64 defval)
418 u32 file = romfile_find(name);
422 int filesize = romfile_size(file);
423 if (!filesize || filesize > sizeof(u64) || (filesize & (filesize-1)))
424 // Doesn't look like a valid integer.
428 romfile_copy(file, &val, sizeof(val));