+ *(ssdt_ptr++) = getHex(i >> 4);
+ *(ssdt_ptr++) = getHex(i);
+ *(ssdt_ptr++) = 0x69; // Arg1Op
+ }
+
+ // build "Name(CPON, Package() { One, One, ..., Zero, Zero, ... })"
+ *(ssdt_ptr++) = 0x08; // NameOp
+ *(ssdt_ptr++) = 'C';
+ *(ssdt_ptr++) = 'P';
+ *(ssdt_ptr++) = 'O';
+ *(ssdt_ptr++) = 'N';
+ *(ssdt_ptr++) = 0x12; // PackageOp
+ ssdt_ptr = encodeLen(ssdt_ptr, 2+1+(1*acpi_cpus), 2);
+ *(ssdt_ptr++) = acpi_cpus;
+ for (i=0; i<acpi_cpus; i++)
+ *(ssdt_ptr++) = (i < CountCPUs) ? 0x01 : 0x00;
+
+ build_header((void*)ssdt, SSDT_SIGNATURE, ssdt_ptr - ssdt, 1);
+
+ //hexdump(ssdt, ssdt_ptr - ssdt);
+
+ return ssdt;
+}
+
+#include "ssdt-pcihp.hex"
+
+#define PCI_RMV_BASE 0xae0c
+
+extern void link_time_assertion(void);
+
+static void* build_pcihp(void)
+{
+ u32 rmvc_pcrm;
+ int i;
+
+ u8 *ssdt = malloc_high(sizeof ssdp_pcihp_aml);
+ memcpy(ssdt, ssdp_pcihp_aml, sizeof ssdp_pcihp_aml);
+
+ /* Runtime patching of EJ0: to disable hotplug for a slot,
+ * replace the method name: _EJ0 by EJ0_. */
+ if (ARRAY_SIZE(aml_ej0_name) != ARRAY_SIZE(aml_adr_dword)) {
+ link_time_assertion();
+ }
+
+ rmvc_pcrm = inl(PCI_RMV_BASE);
+ for (i = 0; i < ARRAY_SIZE(aml_ej0_name); ++i) {
+ /* Slot is in byte 2 in _ADR */
+ u8 slot = ssdp_pcihp_aml[aml_adr_dword[i] + 2] & 0x1F;
+ /* Sanity check */
+ if (memcmp(ssdp_pcihp_aml + aml_ej0_name[i], "_EJ0", 4)) {
+ warn_internalerror();
+ free(ssdt);
+ return NULL;
+ }
+ if (!(rmvc_pcrm & (0x1 << slot))) {
+ memcpy(ssdt + aml_ej0_name[i], "EJ0_", 4);
+ }
+ }
+
+ return ssdt;
+}
+
+#define HPET_SIGNATURE 0x54455048 // HPET
+static void*
+build_hpet(void)
+{
+ struct acpi_20_hpet *hpet;
+ const void *hpet_base = (void *)BUILD_HPET_ADDRESS;
+ u32 hpet_vendor = readl(hpet_base + HPET_ID) >> 16;
+ u32 hpet_period = readl(hpet_base + HPET_PERIOD);
+
+ if (hpet_vendor == 0 || hpet_vendor == 0xffff ||
+ hpet_period == 0 || hpet_period > 100000000)
+ return NULL;
+
+ hpet = malloc_high(sizeof(*hpet));
+ if (!hpet) {
+ warn_noalloc();
+ return NULL;
+ }
+
+ memset(hpet, 0, sizeof(*hpet));
+ /* Note timer_block_id value must be kept in sync with value advertised by
+ * emulated hpet
+ */
+ hpet->timer_block_id = cpu_to_le32(0x8086a201);
+ hpet->addr.address = cpu_to_le32(BUILD_HPET_ADDRESS);
+ build_header((void*)hpet, HPET_SIGNATURE, sizeof(*hpet), 1);
+
+ return hpet;
+}
+
+static void
+acpi_build_srat_memory(struct srat_memory_affinity *numamem,
+ u64 base, u64 len, int node, int enabled)
+{
+ numamem->type = SRAT_MEMORY;
+ numamem->length = sizeof(*numamem);
+ memset(numamem->proximity, 0 ,4);
+ numamem->proximity[0] = node;
+ numamem->flags = cpu_to_le32(!!enabled);
+ numamem->base_addr_low = base & 0xFFFFFFFF;
+ numamem->base_addr_high = base >> 32;
+ numamem->length_low = len & 0xFFFFFFFF;
+ numamem->length_high = len >> 32;
+}
+
+#define SRAT_SIGNATURE 0x54415253 // SRAT
+static void *
+build_srat(void)
+{
+ int nb_numa_nodes = qemu_cfg_get_numa_nodes();
+
+ if (nb_numa_nodes == 0)
+ return NULL;
+
+ u64 *numadata = malloc_tmphigh(sizeof(u64) * (MaxCountCPUs + nb_numa_nodes));
+ if (!numadata) {
+ warn_noalloc();
+ return NULL;
+ }
+
+ qemu_cfg_get_numa_data(numadata, MaxCountCPUs + nb_numa_nodes);
+
+ struct system_resource_affinity_table *srat;
+ int srat_size = sizeof(*srat) +
+ sizeof(struct srat_processor_affinity) * MaxCountCPUs +
+ sizeof(struct srat_memory_affinity) * (nb_numa_nodes + 2);
+
+ srat = malloc_high(srat_size);
+ if (!srat) {
+ warn_noalloc();
+ free(numadata);
+ return NULL;
+ }
+
+ memset(srat, 0, srat_size);
+ srat->reserved1=1;
+ struct srat_processor_affinity *core = (void*)(srat + 1);
+ int i;
+ u64 curnode;
+
+ for (i = 0; i < MaxCountCPUs; ++i) {
+ core->type = SRAT_PROCESSOR;
+ core->length = sizeof(*core);
+ core->local_apic_id = i;
+ curnode = *numadata++;
+ core->proximity_lo = curnode;
+ memset(core->proximity_hi, 0, 3);
+ core->local_sapic_eid = 0;
+ if (i < CountCPUs)
+ core->flags = cpu_to_le32(1);