X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;ds=sidebyside;f=src%2Fparavirt.c;h=9cf77def2892eb51ade6e445a7edb1706603631e;hb=87b533bf71bb41e32319db0ed8f167f50171afc5;hp=56d8421e983441a04b02ba7deed3c8fab4940cd1;hpb=e7cc7642e0fa437dad181cf8a3a8c8e7039dd17d;p=seabios.git diff --git a/src/paravirt.c b/src/paravirt.c index 56d8421..9cf77de 100644 --- a/src/paravirt.c +++ b/src/paravirt.c @@ -7,9 +7,11 @@ // // This file may be distributed under the terms of the GNU LGPLv3 license. -#include "config.h" -#include "ioport.h" -#include "paravirt.h" +#include "config.h" // CONFIG_COREBOOT +#include "util.h" // ntoh[ls] +#include "ioport.h" // outw +#include "paravirt.h" // qemu_cfg_port_probe +#include "smbios.h" // struct smbios_structure_header int qemu_cfg_present; @@ -21,9 +23,15 @@ qemu_cfg_select(u16 f) static void qemu_cfg_read(u8 *buf, int len) +{ + insb(PORT_QEMU_CFG_DATA, buf, len); +} + +static void +qemu_cfg_skip(int len) { while (len--) - *(buf++) = inb(PORT_QEMU_CFG_DATA); + inb(PORT_QEMU_CFG_DATA); } static void @@ -72,3 +80,351 @@ int qemu_cfg_show_boot_menu(void) return v; } +int qemu_cfg_irq0_override(void) +{ + u8 v; + + if (!qemu_cfg_present) + return 0; + + qemu_cfg_read_entry(&v, QEMU_CFG_IRQ0_OVERRIDE, sizeof(v)); + + return v; +} + +u16 qemu_cfg_acpi_additional_tables(void) +{ + u16 cnt; + + if (!qemu_cfg_present) + return 0; + + qemu_cfg_read_entry(&cnt, QEMU_CFG_ACPI_TABLES, sizeof(cnt)); + + return cnt; +} + +u16 qemu_cfg_next_acpi_table_len(void) +{ + u16 len; + + qemu_cfg_read((u8*)&len, sizeof(len)); + + return len; +} + +void* qemu_cfg_next_acpi_table_load(void *addr, u16 len) +{ + qemu_cfg_read(addr, len); + return addr; +} + +u16 qemu_cfg_smbios_entries(void) +{ + u16 cnt; + + if (!qemu_cfg_present) + return 0; + + qemu_cfg_read_entry(&cnt, QEMU_CFG_SMBIOS_ENTRIES, sizeof(cnt)); + + return cnt; +} + +u32 qemu_cfg_e820_entries(void) +{ + u32 cnt; + + if (!qemu_cfg_present) + return 0; + + qemu_cfg_read_entry(&cnt, QEMU_CFG_E820_TABLE, sizeof(cnt)); + return cnt; +} + +void* qemu_cfg_e820_load_next(void *addr) +{ + qemu_cfg_read(addr, sizeof(struct e820_reservation)); + return addr; +} + +struct smbios_header { + u16 length; + u8 type; +} PACKED; + +struct smbios_field { + struct smbios_header header; + u8 type; + u16 offset; + u8 data[]; +} PACKED; + +struct smbios_table { + struct smbios_header header; + u8 data[]; +} PACKED; + +#define SMBIOS_FIELD_ENTRY 0 +#define SMBIOS_TABLE_ENTRY 1 + +size_t qemu_cfg_smbios_load_field(int type, size_t offset, void *addr) +{ + int i; + + for (i = qemu_cfg_smbios_entries(); i > 0; i--) { + struct smbios_field field; + + qemu_cfg_read((u8 *)&field, sizeof(struct smbios_header)); + field.header.length -= sizeof(struct smbios_header); + + if (field.header.type != SMBIOS_FIELD_ENTRY) { + qemu_cfg_skip(field.header.length); + continue; + } + + qemu_cfg_read((u8 *)&field.type, + sizeof(field) - sizeof(struct smbios_header)); + field.header.length -= sizeof(field) - sizeof(struct smbios_header); + + if (field.type != type || field.offset != offset) { + qemu_cfg_skip(field.header.length); + continue; + } + + qemu_cfg_read(addr, field.header.length); + return (size_t)field.header.length; + } + return 0; +} + +int qemu_cfg_smbios_load_external(int type, char **p, unsigned *nr_structs, + unsigned *max_struct_size, char *end) +{ + static u64 used_bitmap[4] = { 0 }; + char *start = *p; + int i; + + /* Check if we've already reported these tables */ + if (used_bitmap[(type >> 6) & 0x3] & (1ULL << (type & 0x3f))) + return 1; + + /* Don't introduce spurious end markers */ + if (type == 127) + return 0; + + for (i = qemu_cfg_smbios_entries(); i > 0; i--) { + struct smbios_table table; + struct smbios_structure_header *header = (void *)*p; + int string; + + qemu_cfg_read((u8 *)&table, sizeof(struct smbios_header)); + table.header.length -= sizeof(struct smbios_header); + + if (table.header.type != SMBIOS_TABLE_ENTRY) { + qemu_cfg_skip(table.header.length); + continue; + } + + if (end - *p < sizeof(struct smbios_structure_header)) { + warn_noalloc(); + break; + } + + qemu_cfg_read((u8 *)*p, sizeof(struct smbios_structure_header)); + table.header.length -= sizeof(struct smbios_structure_header); + + if (header->type != type) { + qemu_cfg_skip(table.header.length); + continue; + } + + *p += sizeof(struct smbios_structure_header); + + /* Entries end with a double NULL char, if there's a string at + * the end (length is greater than formatted length), the string + * terminator provides the first NULL. */ + string = header->length < table.header.length + + sizeof(struct smbios_structure_header); + + /* Read the rest and terminate the entry */ + if (end - *p < table.header.length) { + warn_noalloc(); + *p -= sizeof(struct smbios_structure_header); + continue; + } + qemu_cfg_read((u8 *)*p, table.header.length); + *p += table.header.length; + *((u8*)*p) = 0; + (*p)++; + if (!string) { + *((u8*)*p) = 0; + (*p)++; + } + + (*nr_structs)++; + if (*p - (char *)header > *max_struct_size) + *max_struct_size = *p - (char *)header; + } + + if (start != *p) { + /* Mark that we've reported on this type */ + used_bitmap[(type >> 6) & 0x3] |= (1ULL << (type & 0x3f)); + return 1; + } + + return 0; +} + +int qemu_cfg_get_numa_nodes(void) +{ + u64 cnt; + + qemu_cfg_read_entry(&cnt, QEMU_CFG_NUMA, sizeof(cnt)); + + return (int)cnt; +} + +void qemu_cfg_get_numa_data(u64 *data, int n) +{ + int i; + + for (i = 0; i < n; i++) + qemu_cfg_read((u8*)(data + i), sizeof(u64)); +} + +u16 qemu_cfg_get_max_cpus(void) +{ + u16 cnt; + + if (!qemu_cfg_present) + return 0; + + qemu_cfg_read_entry(&cnt, QEMU_CFG_MAX_CPUS, sizeof(cnt)); + + return cnt; +} + +static QemuCfgFile LastFile; + +static u32 +__cfg_next_prefix_file(const char *prefix, int prefixlen, u32 prevselect) +{ + if (!qemu_cfg_present) + return 0; + + u32 count; + qemu_cfg_read_entry(&count, QEMU_CFG_FILE_DIR, sizeof(count)); + count = ntohl(count); + u32 e; + for (e = 0; e < count; e++) { + qemu_cfg_read((void*)&LastFile, sizeof(LastFile)); + u32 select = ntohs(LastFile.select); + if (select <= prevselect) + continue; + if (memcmp(prefix, LastFile.name, prefixlen) == 0) + return select; + } + return 0; +} + +u32 qemu_cfg_next_prefix_file(const char *prefix, u32 prevselect) +{ + return __cfg_next_prefix_file(prefix, strlen(prefix), prevselect); +} + +u32 qemu_cfg_find_file(const char *name) +{ + return __cfg_next_prefix_file(name, strlen(name) + 1, 0); +} + +static int +__qemu_cfg_set_file(u32 select) +{ + if (!qemu_cfg_present || !select) + return -1; + if (select == ntohs(LastFile.select)) + return 0; + + u32 count; + qemu_cfg_read_entry(&count, QEMU_CFG_FILE_DIR, sizeof(count)); + count = ntohl(count); + u32 e; + for (e = 0; e < count; e++) { + qemu_cfg_read((void*)&LastFile, sizeof(LastFile)); + if (select == ntohs(LastFile.select)) + return 0; + } + return -1; +} + +int qemu_cfg_size_file(u32 select) +{ + if (__qemu_cfg_set_file(select)) + return -1; + return ntohl(LastFile.size); +} + +const char* qemu_cfg_name_file(u32 select) +{ + if (__qemu_cfg_set_file(select)) + return NULL; + return LastFile.name; +} + +int qemu_cfg_read_file(u32 select, void *dst, u32 maxlen) +{ + if (__qemu_cfg_set_file(select)) + return -1; + int len = qemu_cfg_size_file(select); + if (len < 0 || len > maxlen) + return -1; + qemu_cfg_read_entry(dst, select, len); + return len; +} + +// Helper function to find, malloc_tmphigh, and copy a romfile. This +// function adds a trailing zero to the malloc'd copy. +void * +romfile_loadfile(const char *name, int *psize) +{ + u32 file = romfile_find(name); + if (!file) + return NULL; + + int filesize = romfile_size(file); + if (!filesize) + return NULL; + + char *data = malloc_tmphigh(filesize+1); + if (!data) { + warn_noalloc(); + return NULL; + } + + dprintf(5, "Copying romfile '%s' (len %d)\n", name, filesize); + romfile_copy(file, data, filesize); + if (psize) + *psize = filesize; + data[filesize] = '\0'; + return data; +} + +// Attempt to load an integer from the given file - return 'defval' +// if unsuccesful. +u64 +romfile_loadint(const char *name, u64 defval) +{ + u32 file = romfile_find(name); + if (!file) + return defval; + + int filesize = romfile_size(file); + if (!filesize || filesize > sizeof(u64) || (filesize & (filesize-1))) + // Doesn't look like a valid integer. + return defval; + + u64 val = 0; + romfile_copy(file, &val, sizeof(val)); + return val; +}