在qemu/hw/arm/virt-apci-build.c 中会创建传给guest的acpi table。这里我们以组建spcr为例
virt_acpi_build->build_spcr
static void
build_spcr(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
{
AcpiSerialPortConsoleRedirection *spcr;
const MemMapEntry *uart_memmap = &vms->memmap[VIRT_UART];
int irq = vms->irqmap[VIRT_UART] + ARM_SPI_BASE;
int spcr_start = table_data->len;
#得到spcr的首地址指针
spcr = acpi_data_push(table_data, sizeof(*spcr));
#下面就是spcr的个个成员变量的赋值
spcr->interface_type = 0x3; /* ARM PL011 UART */
spcr->base_address.space_id = AML_SYSTEM_MEMORY;
spcr->base_address.bit_width = 8;
spcr->base_address.bit_offset = 0;
spcr->base_address.access_width = 1;
spcr->base_address.address = cpu_to_le64(uart_memmap->base);
spcr->interrupt_types = (1 << 3); /* Bit[3] ARMH GIC interrupt */
spcr->gsi = cpu_to_le32(irq); /* Global System Interrupt */
spcr->baud = 3; /* Baud Rate: 3 = 9600 */
spcr->parity = 0; /* No Parity */
spcr->stopbits = 1; /* 1 Stop bit */
spcr->flowctrl = (1 << 1); /* Bit[1] = RTS/CTS hardware flow control */
spcr->term_type = 0; /* Terminal Type: 0 = VT100 */
spcr->pci_device_id = 0xffff; /* PCI Device ID: not a PCI device */
spcr->pci_vendor_id = 0xffff; /* PCI Vendor ID: not a PCI device */
#将创建spcr table 的头信息
build_header(linker, table_data, (void *)(table_data->data + spcr_start),
"SPCR", table_data->len - spcr_start, 2, NULL, NULL);
}
build_header(BIOSLinker *linker, GArray *table_data,
AcpiTableHeader *h, const char *sig, int len, uint8_t rev,
const char *oem_id, const char *oem_table_id)
{
unsigned tbl_offset = (char *)h - table_data->data;
unsigned checksum_offset = (char *)&h->checksum - table_data->data;
memcpy(&h->signature, sig, 4);
h->length = cpu_to_le32(len);
h->revision = rev;
#scpr是否包括oem id
if (oem_id) {
strncpy((char *)h->oem_id, oem_id, sizeof h->oem_id);
} else {
memcpy(h->oem_id, ACPI_BUILD_APPNAME6, 6);
}
if (oem_table_id) {
strncpy((char *)h->oem_table_id, oem_table_id, sizeof(h->oem_table_id));
} else {
memcpy(h->oem_table_id, ACPI_BUILD_APPNAME4, 4);
memcpy(h->oem_table_id + 4, sig, 4);
}
h->oem_revision = cpu_to_le32(1);
memcpy(h->asl_compiler_id, ACPI_BUILD_APPNAME4, 4);
h->asl_compiler_revision = cpu_to_le32(1);
/* Checksum to be filled in by Guest linker */
ask guest to add checksum of ACPI * table in the specified file at the specified offset.
#在表中加入check sum信息,这段组建spcr table的逻辑和bios中的类似
bios_linker_loader_add_checksum(linker, ACPI_BUILD_TABLE_FILE,
tbl_offset, len, checksum_offset);
}