本文主要是介绍qemu对acpi的模拟,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
在qemu/hw/acpi 这个目录下是qemu对acpi的模拟,从其中的Makefile.objs 中可以看到x86支持两种类型的ACPI 硬件
common-obj-$(CONFIG_ACPI_X86) += core.o piix4.o pcihp.o
common-obj-$(CONFIG_ACPI_X86_ICH) += ich9.o tco.o
这里我们piix4.c 为例,其设备初始化代码如下:
static const TypeInfo piix4_pm_info = {.name = TYPE_PIIX4_PM,.parent = TYPE_PCI_DEVICE,.instance_size = sizeof(PIIX4PMState),.class_init = piix4_pm_class_init,.interfaces = (InterfaceInfo[]) {{ TYPE_HOTPLUG_HANDLER },{ TYPE_ACPI_DEVICE_IF },{ INTERFACE_CONVENTIONAL_PCI_DEVICE },{ }}
};
初始化代码在piix4_pm_class_init中
static void piix4_pm_class_init(ObjectClass *klass, void *data)
{DeviceClass *dc = DEVICE_CLASS(klass);PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(klass);AcpiDeviceIfClass *adevc = ACPI_DEVICE_IF_CLASS(klass);k->realize = piix4_pm_realize;k->config_write = pm_write_config;k->vendor_id = PCI_VENDOR_ID_INTEL;k->device_id = PCI_DEVICE_ID_INTEL_82371AB_3;k->revision = 0x03;k->class_id = PCI_CLASS_BRIDGE_OTHER;
}
从piix4_pm_class_init中创建piix4的设备函数piix4_pm_realize,我们可以知道对于ACPI的操作
是映射到内存,然后直接操作内存
static void piix4_pm_realize(PCIDevice *dev, Error **errp)
{memory_region_init(&s->io, OBJECT(s), "piix4-pm", 64);
#内存操作默认没有使能处于disable状态memory_region_set_enabled(&s->io, false);memory_region_add_subregion(pci_address_space_io(dev),0, &s->io);acpi_pm_tmr_init(&s->ar, pm_tmr_timer, &s->io);acpi_pm1_evt_init(&s->ar, pm_tmr_timer, &s->io);acpi_pm1_cnt_init(&s->ar, &s->io, s->disable_s3, s->disable_s4, s->s4_val);acpi_gpe_init(&s->ar, GPE_LEN);s->powerdown_notifier.notify = piix4_pm_powerdown_req;qemu_register_powerdown_notifier(&s->powerdown_notifier);s->machine_ready.notify = piix4_pm_machine_ready;qemu_add_machine_init_done_notifier(&s->machine_ready);piix4_acpi_system_hot_add_init(pci_address_space_io(dev),pci_get_bus(dev), s);qbus_set_hotplug_handler(BUS(pci_get_bus(dev)), OBJECT(s));piix4_pm_add_propeties(s);
}
具体的使能在pm_write_config
static void pm_write_config(PCIDevice *d,uint32_t address, uint32_t val, int len)
{pci_default_write_config(d, address, val, len);if (range_covers_byte(address, len, 0x80) ||ranges_overlap(address, len, 0x40, 4)) {pm_io_space_update((PIIX4PMState *)d);}if (range_covers_byte(address, len, 0xd2) ||ranges_overlap(address, len, 0x90, 4)) {smbus_io_space_update((PIIX4PMState *)d);}
}
这里调用pm_io_space_update
static void pm_io_space_update(PIIX4PMState *s)
{PCIDevice *d = PCI_DEVICE(s);s->io_base = le32_to_cpu(*(uint32_t *)(d->config + 0x40));s->io_base &= 0xffc0;memory_region_transaction_begin();memory_region_set_enabled(&s->io, d->config[0x80] & 1);memory_region_set_address(&s->io, s->io_base);memory_region_transaction_commit();
}
可见这里是往offset为0x80里面写入1即可使能内存操作。系统起来后,可以通过cat /proc/ioports
命令来得到ACPI的控制内存的首地址.
这篇关于qemu对acpi的模拟的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!