/* * Starting with version 2.1 qemu provides a full set of smbios tables * for the virtual hardware emulated, except type 0 (bios information). * * What we are going to do here is find the type0 table, keep it, and * override everything else generated by coreboot with the qemu smbios * tables. * * It's a bit hackish, but qemu is a special case (compared to real * hardware) and this way we don't need special qemu support in the * generic smbios code. */ unsigned long fw_cfg_smbios_tables(int *handle, unsigned long *current) { struct smbios_type0 *t0; unsigned long start, end; int len, ret, i, count = 1; char *str; len = fw_cfg_check_file("etc/smbios/smbios-tables"); if (len < 0) return 0; printk(BIOS_DEBUG, "QEMU: found smbios tables in fw_cfg (len %d).\n", len); /* * Search backwards for "coreboot" (first string in type0 table, * see src/arch/x86/boot/smbios.c), then find type0 table. */ for (i = 0; i < 16384; i++) { str = (char*)(*current - i); if (strcmp(str, "coreboot") == 0) break; } if (i == 16384) return 0; i += sizeof(struct smbios_type0) - 2; t0 = (struct smbios_type0*)(*current - i); if (t0->type != SMBIOS_BIOS_INFORMATION || t0->handle != 0) return 0; printk(BIOS_DEBUG, "QEMU: coreboot type0 table found at 0x%lx.\n", *current - i); start = smbios_next(*current - i); /* * Fetch smbios tables from qemu, go find the end marker. * We'll exclude the end marker as coreboot will add one. */ printk(BIOS_DEBUG, "QEMU: loading smbios tables to 0x%lx\n", start); fw_cfg_load_file("etc/smbios/smbios-tables", (void*)start); end = start; do { t0 = (struct smbios_type0*)end; if (t0->type == SMBIOS_END_OF_TABLE) break; end = smbios_next(end); count++; } while (end < start + len); /* final fixups. */ ret = end - *current; *current = end; *handle = count; return ret; }
static void cpu_pci_domain_read_resources(struct device *dev) { u16 nbid = pci_read_config16(dev_find_slot(0, 0), PCI_DEVICE_ID); int i440fx = (nbid == 0x1237); int q35 = (nbid == 0x29c0); struct resource *res; unsigned long tomk = 0, high; int idx = 10; int size; pci_domain_read_resources(dev); size = fw_cfg_check_file("etc/e820"); if (size > 0) { /* supported by qemu 1.7+ */ FwCfgE820Entry *list = malloc(size); int i; fw_cfg_load_file("etc/e820", list); for (i = 0; i < size/sizeof(*list); i++) { switch (list[i].type) { case 1: /* ram */ printk(BIOS_DEBUG, "QEMU: e820/ram: 0x%08llx +0x%08llx\n", list[i].address, list[i].length); if (list[i].address == 0) { tomk = list[i].length / 1024; ram_resource(dev, idx++, 0, 640); ram_resource(dev, idx++, 768, tomk - 768); } else { ram_resource(dev, idx++, list[i].address / 1024, list[i].length / 1024); } break; case 2: /* reserved */ printk(BIOS_DEBUG, "QEMU: e820/res: 0x%08llx +0x%08llx\n", list[i].address, list[i].length); res = new_resource(dev, idx++); res->base = list[i].address; res->size = list[i].length; res->limit = 0xffffffff; res->flags = IORESOURCE_MEM | IORESOURCE_FIXED | IORESOURCE_STORED | IORESOURCE_ASSIGNED; break; default: /* skip unknown */ break; } } free(list); } if (!tomk) { /* qemu older than 1.7, or reading etc/e820 failed. Fallback to cmos. */ tomk = qemu_get_memory_size(); high = qemu_get_high_memory_size(); printk(BIOS_DEBUG, "QEMU: cmos: %lu MiB RAM below 4G.\n", tomk / 1024); printk(BIOS_DEBUG, "QEMU: cmos: %lu MiB RAM above 4G.\n", high / 1024); /* Report the memory regions. */ ram_resource(dev, idx++, 0, 640); ram_resource(dev, idx++, 768, tomk - 768); if (high) ram_resource(dev, idx++, 4 * 1024 * 1024, high); } /* Reserve I/O ports used by QEMU */ qemu_reserve_ports(dev, idx++, 0x0510, 0x02, "firmware-config"); qemu_reserve_ports(dev, idx++, 0x5658, 0x01, "vmware-port"); if (i440fx) { qemu_reserve_ports(dev, idx++, 0xae00, 0x10, "pci-hotplug"); qemu_reserve_ports(dev, idx++, 0xaf00, 0x20, "cpu-hotplug"); qemu_reserve_ports(dev, idx++, 0xafe0, 0x04, "piix4-gpe0"); } if (inb(CONFIG_CONSOLE_QEMU_DEBUGCON_PORT) == 0xe9) { qemu_reserve_ports(dev, idx++, CONFIG_CONSOLE_QEMU_DEBUGCON_PORT, 1, "debugcon"); } if (q35 && ((tomk * 1024) < 0xb0000000)) { /* * Reserve the region between top-of-ram and the * mmconf xbar (ar 0xb0000000), so coreboot doesn't * place pci bars there. The region isn't declared as * pci io window in the acpi tables (\_SB.PCI0._CRS). */ res = new_resource(dev, idx++); res->base = tomk * 1024; res->size = 0xb0000000 - tomk * 1024; res->limit = 0xffffffff; res->flags = IORESOURCE_MEM | IORESOURCE_FIXED | IORESOURCE_STORED | IORESOURCE_ASSIGNED; } if (i440fx) { /* Reserve space for the IOAPIC. This should be in * the southbridge, but I couldn't tell which device * to put it in. */ res = new_resource(dev, 2); res->base = IO_APIC_ADDR; res->size = 0x100000UL; res->limit = 0xffffffffUL; res->flags = IORESOURCE_MEM | IORESOURCE_FIXED | IORESOURCE_STORED | IORESOURCE_ASSIGNED; } /* Reserve space for the LAPIC. There's one in every processor, but * the space only needs to be reserved once, so we do it here. */ res = new_resource(dev, 3); res->base = LOCAL_APIC_ADDR; res->size = 0x10000UL; res->limit = 0xffffffffUL; res->flags = IORESOURCE_MEM | IORESOURCE_FIXED | IORESOURCE_STORED | IORESOURCE_ASSIGNED; }
unsigned long fw_cfg_acpi_tables(unsigned long start) { BiosLinkerLoaderEntry *s; unsigned long *addrs, current; uint8_t *ptr; int rc, i, j, src, dst, max; rc = fw_cfg_check_file("etc/table-loader"); if (rc < 0) return 0; printk(BIOS_DEBUG, "QEMU: found ACPI tables in fw_cfg.\n"); max = rc / sizeof(*s); s = malloc(rc); addrs = malloc(max * sizeof(*addrs)); fw_cfg_load_file("etc/table-loader", s); current = start; for (i = 0; i < max && s[i].command != 0; i++) { void *cksum_data; uint32_t cksum; uint32_t addr4; uint64_t addr8; switch (s[i].command) { case BIOS_LINKER_LOADER_COMMAND_ALLOCATE: current = ALIGN(current, s[i].alloc.align); rc = fw_cfg_check_file(s[i].alloc.file); if (rc < 0) goto err; printk(BIOS_DEBUG, "QEMU: loading \"%s\" to 0x%lx (len %d)\n", s[i].alloc.file, current, rc); fw_cfg_load_file(s[i].alloc.file, (void*)current); addrs[i] = current; current += rc; break; case BIOS_LINKER_LOADER_COMMAND_ADD_POINTER: src = -1; dst = -1; for (j = 0; j < i; j++) { if (s[j].command != BIOS_LINKER_LOADER_COMMAND_ALLOCATE) continue; if (strcmp(s[j].alloc.file, s[i].pointer.dest_file) == 0) dst = j; if (strcmp(s[j].alloc.file, s[i].pointer.src_file) == 0) src = j; } if (src == -1 || dst == -1) goto err; switch (s[i].pointer.size) { case 4: ptr = (uint8_t *)addrs[dst]; ptr += s[i].pointer.offset; addr4 = read_le32(ptr); addr4 += addrs[src]; write_le32(ptr, addr4); break; case 8: ptr = (uint8_t *)addrs[dst]; ptr += s[i].pointer.offset; addr8 = read_le64(ptr); addr8 += addrs[src]; write_le64(ptr, addr8); break; default: /* * Should not happen. ACPI knows 1 and 2 byte ptrs * too, but we are operating with 32bit offsets which * would simply not fit in there ... */ printk(BIOS_DEBUG, "QEMU: acpi: unimplemented ptr size %d\n", s[i].pointer.size); goto err; } break; case BIOS_LINKER_LOADER_COMMAND_ADD_CHECKSUM: dst = -1; for (j = 0; j < i; j++) { if (s[j].command != BIOS_LINKER_LOADER_COMMAND_ALLOCATE) continue; if (strcmp(s[j].alloc.file, s[i].cksum.file) == 0) dst = j; } if (dst == -1) goto err; ptr = (uint8_t *)(addrs[dst] + s[i].cksum.offset); cksum_data = (void *)(addrs[dst] + s[i].cksum.start); cksum = acpi_checksum(cksum_data, s[i].cksum.length); write_le8(ptr, cksum); break; default: printk(BIOS_DEBUG, "QEMU: acpi: unknown script cmd 0x%x @ %p\n", s[i].command, s+i); goto err; }; } printk(BIOS_DEBUG, "QEMU: loaded ACPI tables from fw_cfg.\n"); free(s); free(addrs); return ALIGN(current, 16); err: printk(BIOS_DEBUG, "QEMU: loading ACPI tables from fw_cfg failed.\n"); free(s); free(addrs); return 0; }