/* RSDP */ static GArray * build_rsdp(GArray *rsdp_table, GArray *linker, unsigned rsdt) { AcpiRsdpDescriptor *rsdp = acpi_data_push(rsdp_table, sizeof *rsdp); bios_linker_loader_alloc(linker, ACPI_BUILD_RSDP_FILE, 16, true /* fseg memory */); memcpy(&rsdp->signature, "RSD PTR ", sizeof(rsdp->signature)); memcpy(rsdp->oem_id, ACPI_BUILD_APPNAME6, sizeof(rsdp->oem_id)); rsdp->length = cpu_to_le32(sizeof(*rsdp)); rsdp->revision = 0x02; /* Point to RSDT */ rsdp->rsdt_physical_address = cpu_to_le32(rsdt); /* Address to be filled by Guest linker */ bios_linker_loader_add_pointer(linker, ACPI_BUILD_RSDP_FILE, ACPI_BUILD_TABLE_FILE, rsdp_table, &rsdp->rsdt_physical_address, sizeof rsdp->rsdt_physical_address); rsdp->checksum = 0; /* Checksum to be filled by Guest linker */ bios_linker_loader_add_checksum(linker, ACPI_BUILD_RSDP_FILE, rsdp_table, rsdp, sizeof *rsdp, &rsdp->checksum); return rsdp_table; }
static void virt_acpi_build(VirtGuestInfo *guest_info, AcpiBuildTables *tables) { GArray *table_offsets; unsigned dsdt, rsdt; GArray *tables_blob = tables->table_data; table_offsets = g_array_new(false, true /* clear */, sizeof(uint32_t)); bios_linker_loader_alloc(tables->linker, ACPI_BUILD_TABLE_FILE, tables_blob, 64, false /* high memory */); /* * The ACPI v5.1 tables for Hardware-reduced ACPI platform are: * RSDP * RSDT * FADT * GTDT * MADT * MCFG * DSDT */ /* DSDT is pointed to by FADT */ dsdt = tables_blob->len; build_dsdt(tables_blob, tables->linker, guest_info); /* FADT MADT GTDT MCFG SPCR pointed to by RSDT */ acpi_add_table(table_offsets, tables_blob); build_fadt(tables_blob, tables->linker, dsdt); acpi_add_table(table_offsets, tables_blob); build_madt(tables_blob, tables->linker, guest_info); acpi_add_table(table_offsets, tables_blob); build_gtdt(tables_blob, tables->linker); acpi_add_table(table_offsets, tables_blob); build_mcfg(tables_blob, tables->linker, guest_info); acpi_add_table(table_offsets, tables_blob); build_spcr(tables_blob, tables->linker, guest_info); if (nb_numa_nodes > 0) { acpi_add_table(table_offsets, tables_blob); build_srat(tables_blob, tables->linker, guest_info); } /* RSDT is pointed to by RSDP */ rsdt = tables_blob->len; build_rsdt(tables_blob, tables->linker, table_offsets, NULL, NULL); /* RSDP is in FSEG memory, so allocate it separately */ build_rsdp(tables->rsdp, tables->linker, rsdt); /* Cleanup memory that's no longer used. */ g_array_free(table_offsets, true); }
/* RSDP */ static GArray * build_rsdp(GArray *rsdp_table, BIOSLinker *linker, unsigned rsdt_tbl_offset) { AcpiRsdpDescriptor *rsdp = acpi_data_push(rsdp_table, sizeof *rsdp); unsigned rsdt_pa_size = sizeof(rsdp->rsdt_physical_address); unsigned rsdt_pa_offset = (char *)&rsdp->rsdt_physical_address - rsdp_table->data; bios_linker_loader_alloc(linker, ACPI_BUILD_RSDP_FILE, rsdp_table, 16, true /* fseg memory */); memcpy(&rsdp->signature, "RSD PTR ", sizeof(rsdp->signature)); memcpy(rsdp->oem_id, ACPI_BUILD_APPNAME6, sizeof(rsdp->oem_id)); rsdp->length = cpu_to_le32(sizeof(*rsdp)); rsdp->revision = 0x02; /* Address to be filled by Guest linker */ bios_linker_loader_add_pointer(linker, ACPI_BUILD_RSDP_FILE, rsdt_pa_offset, rsdt_pa_size, ACPI_BUILD_TABLE_FILE, rsdt_tbl_offset); /* Checksum to be filled by Guest linker */ bios_linker_loader_add_checksum(linker, ACPI_BUILD_RSDP_FILE, (char *)rsdp - rsdp_table->data, sizeof *rsdp, (char *)&rsdp->checksum - rsdp_table->data); return rsdp_table; }
static GArray * build_rsdp(GArray *rsdp_table, GArray *linker, unsigned rsdt) { AcpiRsdpDescriptor *rsdp = acpi_data_push(rsdp_table, sizeof *rsdp); bios_linker_loader_alloc(linker, ACPI_BUILD_RSDP_FILE, 1, true /* fseg memory */); rsdp->signature = cpu_to_le64(ACPI_RSDP_SIGNATURE); memcpy(rsdp->oem_id, ACPI_BUILD_APPNAME6, 6); rsdp->rsdt_physical_address = cpu_to_le32(rsdt); /* Address to be filled by Guest linker */ bios_linker_loader_add_pointer(linker, ACPI_BUILD_RSDP_FILE, ACPI_BUILD_TABLE_FILE, rsdp_table, &rsdp->rsdt_physical_address, sizeof rsdp->rsdt_physical_address); rsdp->checksum = 0; /* Checksum to be filled by Guest linker */ bios_linker_loader_add_checksum(linker, ACPI_BUILD_RSDP_FILE, rsdp, rsdp, sizeof *rsdp, &rsdp->checksum); return rsdp_table; }
static void acpi_build(PcGuestInfo *guest_info, AcpiBuildTables *tables) { GArray *table_offsets; unsigned facs, dsdt, rsdt; AcpiCpuInfo cpu; AcpiPmInfo pm; AcpiMiscInfo misc; AcpiMcfgInfo mcfg; PcPciInfo pci; uint8_t *u; acpi_get_cpu_info(&cpu); acpi_get_pm_info(&pm); acpi_get_dsdt(&misc); acpi_get_misc_info(&misc); acpi_get_pci_info(&pci); table_offsets = g_array_new(false, true /* clear */, sizeof(uint32_t)); ACPI_BUILD_DPRINTF(3, "init ACPI tables\n"); bios_linker_loader_alloc(tables->linker, ACPI_BUILD_TABLE_FILE, 64 /* Ensure FACS is aligned */, false /* high memory */); /* * FACS is pointed to by FADT. * We place it first since it's the only table that has alignment * requirements. */ facs = tables->table_data->len; build_facs(tables->table_data, tables->linker, guest_info); /* DSDT is pointed to by FADT */ dsdt = tables->table_data->len; build_dsdt(tables->table_data, tables->linker, &misc); /* ACPI tables pointed to by RSDT */ acpi_add_table(table_offsets, tables->table_data); build_fadt(tables->table_data, tables->linker, &pm, facs, dsdt); acpi_add_table(table_offsets, tables->table_data); build_ssdt(tables->table_data, tables->linker, &cpu, &pm, &misc, &pci, guest_info); acpi_add_table(table_offsets, tables->table_data); build_madt(tables->table_data, tables->linker, &cpu, guest_info); acpi_add_table(table_offsets, tables->table_data); if (misc.has_hpet) { build_hpet(tables->table_data, tables->linker); } if (guest_info->numa_nodes) { acpi_add_table(table_offsets, tables->table_data); build_srat(tables->table_data, tables->linker, &cpu, guest_info); } if (acpi_get_mcfg(&mcfg)) { acpi_add_table(table_offsets, tables->table_data); build_mcfg_q35(tables->table_data, tables->linker, &mcfg); } /* Add tables supplied by user (if any) */ for (u = acpi_table_first(); u; u = acpi_table_next(u)) { unsigned len = acpi_table_len(u); acpi_add_table(table_offsets, tables->table_data); g_array_append_vals(tables->table_data, u, len); } /* RSDT is pointed to by RSDP */ rsdt = tables->table_data->len; build_rsdt(tables->table_data, tables->linker, table_offsets); /* RSDP is in FSEG memory, so allocate it separately */ build_rsdp(tables->rsdp, tables->linker, rsdt); /* We'll expose it all to Guest so align size to reduce * chance of size changes. * RSDP is small so it's easy to keep it immutable, no need to * bother with alignment. */ acpi_align_size(tables->table_data, 0x1000); acpi_align_size(tables->linker, 0x1000); /* Cleanup memory that's no longer used. */ g_array_free(table_offsets, true); }