通过上一篇的分析,知道了
- mac_newworld中的 TYPE_U3_AGP_HOST_BRIDGE; TYPE_UNI_NORTH_AGP_HOST_BRIDGE;TYPE_UNI_NORTH_INTERNAL_PCI_HOST_BRIDGE;TYPE_UNI_NORTH_PCI_HOST_BRIDGE;其实本质上都是UNINHostState (这个有点像C++的从一个类实例化出不同的对象)
- sysbus_mmio_map和 memory_region_add_subregion(get_system_memory(), 0xf2000000,sysbus_mmio_get_region(s, 3));完成了向CPU可以直接访问到的空间进行的映射。
- UNINHostState具体的实现关联,是如何添加的到system_memory中的
#define UNI_NORTH_PCI_HOST_BRIDGE(obj) \
OBJECT_CHECK(UNINHostState, (obj), TYPE_UNI_NORTH_PCI_HOST_BRIDGE)
#define UNI_NORTH_AGP_HOST_BRIDGE(obj) \
OBJECT_CHECK(UNINHostState, (obj), TYPE_UNI_NORTH_AGP_HOST_BRIDGE)
#define UNI_NORTH_INTERNAL_PCI_HOST_BRIDGE(obj) \
OBJECT_CHECK(UNINHostState, (obj), TYPE_UNI_NORTH_INTERNAL_PCI_HOST_BRIDGE)
#define U3_AGP_HOST_BRIDGE(obj) \
OBJECT_CHECK(UNINHostState, (obj), TYPE_U3_AGP_HOST_BRIDGE)
今天就让我们继续往后分析吧
macIO
/* init basic PC hardware */
pci_bus = PCI_HOST_BRIDGE(uninorth_pci)->bus;
/* MacIO */
macio = NEWWORLD_MACIO(pci_create(pci_bus, -1, TYPE_NEWWORLD_MACIO));
dev = DEVICE(macio);
qdev_prop_set_uint64(dev, "frequency", tbfreq);
qdev_prop_set_bit(dev, "has-pmu", has_pmu);
qdev_prop_set_bit(dev, "has-adb", has_adb);
object_property_set_link(OBJECT(macio), OBJECT(pic_dev), "pic",
&error_abort);
qdev_init_nofail(dev);
PCI_HOST_BRIDGE(uninorth_pci)将UNINHostState强制转换成PCIHostState,并让pci_bus等于这个PCIHostState中的PCIBus *bus
struct PCIHostState {
SysBusDevice busdev;
MemoryRegion conf_mem;
MemoryRegion data_mem;
MemoryRegion mmcfg;
uint32_t config_reg;
PCIBus *bus;
QLIST_ENTRY(PCIHostState) next;
};
macio是建立在pci_bus上的一个PCIDevice
=> PCIDevice *pci_create(PCIBus *bus, int devfn, const char *name)
=> PCIDevice *pci_create_multifunction(PCIBus *bus, int devfn, bool multifunction,
const char *name)
pci_create_multifunction(bus, devfn, false, name);
==> dev = qdev_create(&bus->qbus, name);
===> dev = qdev_try_create(bus, name);
然后就是对这个设备的创建了,会调用到TYPE_NEWWORLD_MACIO其的instance_init和class_init
#define NEWWORLD_MACIO(obj) \
OBJECT_CHECK(NewWorldMacIOState, (obj), TYPE_NEWWORLD_MACIO)
typedef struct NewWorldMacIOState {
/*< private >*/
MacIOState parent_obj;
/*< public >*/
bool has_pmu;
bool has_adb;
OpenPICState *pic;
MACIOIDEState ide[2];
MacIOGPIOState gpio;
} NewWorldMacIOState;
-
static void macio_newworld_init(Object *obj)
static void macio_newworld_init(Object *obj)
{
MacIOState *s = MACIO(obj);
NewWorldMacIOState *ns = NEWWORLD_MACIO(obj);
int i;
object_property_add_link(obj, "pic", TYPE_OPENPIC,
(Object **) &ns->pic,
qdev_prop_allow_set_link_before_realize,
0, NULL);
sysbus_init_child_obj(obj, "gpio", &ns->gpio, sizeof(ns->gpio),
TYPE_MACIO_GPIO);
for (i = 0; i < 2; i++) {
macio_init_ide(s, &ns->ide[i], sizeof(ns->ide[i]), i);
}
}
可以从这段代码中看出:
- 首先添加了pic的属性(所以后面的epic可以在这里修改)
- 初始化了孩子对象 sysbus_init_child_obj(obj, "gpio", &ns->gpio, sizeof(ns->gpio), TYPE_MACIO_GPIO);
#define TYPE_MACIO_GPIO "macio-gpio"
#define MACIO_GPIO(obj) OBJECT_CHECK(MacIOGPIOState, (obj), TYPE_MACIO_GPIO)
typedef struct MacIOGPIOState {
/*< private >*/
SysBusDevice parent;
/*< public >*/
OpenPICState *pic;
MemoryRegion gpiomem;
qemu_irq gpio_extirqs[10];
uint8_t gpio_levels[8];
uint8_t gpio_regs[36]; /* XXX Check count */
} MacIOGPIOState;
static const TypeInfo macio_gpio_init_info = {
.name = TYPE_MACIO_GPIO,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(MacIOGPIOState),
.instance_init = macio_gpio_init,
.class_init = macio_gpio_class_init,
.interfaces = (InterfaceInfo[]) {
{ TYPE_NMI },
{ }
},
};
static void macio_gpio_init(Object *obj)
{
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
MacIOGPIOState *s = MACIO_GPIO(obj);
object_property_add_link(obj, "pic", TYPE_OPENPIC,
(Object **) &s->pic,
qdev_prop_allow_set_link_before_realize,
0, NULL);
memory_region_init_io(&s->gpiomem, OBJECT(s), &macio_gpio_ops, obj,
"gpio", 0x30);
sysbus_init_mmio(sbd, &s->gpiomem);
}
从上面可以看出,这里是通过
memory_region_init_io(&s->gpiomem, OBJECT(s), &macio_gpio_ops, obj,
"gpio", 0x30);
sysbus_init_mmio(sbd, &s->gpiomem);
完成了mmio_init(就想上一篇所说的一样)
-
macio_gpio_ops
static const MemoryRegionOps macio_gpio_ops = {
.read = macio_gpio_read,
.write = macio_gpio_write,
.endianness = DEVICE_LITTLE_ENDIAN,
.impl = {
.min_access_size = 1,
.max_access_size = 1,
},
};
//macio_gpio_read
static uint64_t macio_gpio_read(void *opaque, hwaddr addr, unsigned size)
{
MacIOGPIOState *s = opaque;
uint64_t val = 0;
/* Levels regs */
if (addr < 8) {
val = s->gpio_levels[addr];
} else {
addr -= 8;
if (addr < 36) {
val = s->gpio_regs[addr];
}
}
trace_macio_gpio_write(addr, val);
return val;
}
//macio_gpio_write
static void macio_gpio_write(void *opaque, hwaddr addr, uint64_t value,
unsigned size)
{
MacIOGPIOState *s = opaque;
uint8_t ibit;
trace_macio_gpio_write(addr, value);
/* Levels regs are read-only */
if (addr < 8) {
return;
}
addr -= 8;
if (addr < 36) {
value &= ~2;
if (value & 4) {
ibit = (value & 1) << 1;
} else {
ibit = s->gpio_regs[addr] & 2;
}
s->gpio_regs[addr] = value | ibit;
}
}
- sysbus_init_child_obj(obj, "gpio", &ns->gpio, sizeof(ns->gpio), TYPE_MACIO_GPIO);
void sysbus_init_child_obj(Object *parent, const char *childname, void *child,
size_t childsize, const char *childtype)
{
object_initialize_child(parent, childname, child, childsize, childtype,
&error_abort, NULL);
qdev_set_parent_bus(DEVICE(child), sysbus_get_default());
}
void object_initialize_child(Object *parentobj, const char *propname,
void *childobj, size_t size, const char *type,
Error **errp, ...)
{
va_list vargs;
va_start(vargs, errp);
object_initialize_childv(parentobj, propname, childobj, size, type, errp,
vargs);
va_end(vargs);
}
void object_initialize_childv(Object *parentobj, const char *propname,
void *childobj, size_t size, const char *type,
Error **errp, va_list vargs)
{
Error *local_err = NULL;
Object *obj;
object_initialize(childobj, size, type);
obj = OBJECT(childobj);
object_set_propv(obj, &local_err, vargs);
if (local_err) {
goto out;
}
object_property_add_child(parentobj, propname, obj, &local_err);
if (local_err) {
goto out;
}
if (object_dynamic_cast(obj, TYPE_USER_CREATABLE)) {
user_creatable_complete(obj, &local_err);
if (local_err) {
object_unparent(obj);
goto out;
}
}
/*
* Since object_property_add_child added a reference to the child object,
* we can drop the reference added by object_initialize(), so the child
* property will own the only reference to the object.
*/
object_unref(obj);
out:
if (local_err) {
error_propagate(errp, local_err);
object_unref(obj);
}
}
通过这句话object_initialize(childobj, size, type);完成对象的初始化
通过qdev_set_parent_bus(DEVICE(child), sysbus_get_default());把这个设备添加到main_system_bus上,所以这些MACIO是在sysbus上的设备
让我们继续看macio_init_ide
for (i = 0; i < 2; i++) {
macio_init_ide(s, &ns->ide[i], sizeof(ns->ide[i]), i);
}
static void macio_init_ide(MacIOState *s, MACIOIDEState *ide, size_t ide_size,
int index)
{
gchar *name = g_strdup_printf("ide[%i]", index);
sysbus_init_child_obj(OBJECT(s), name, ide, ide_size, TYPE_MACIO_IDE);
memory_region_add_subregion(&s->bar, 0x1f000 + ((index + 1) * 0x1000),
&ide->mem);
g_free(name);
}
typedef struct MACIOIDEState {
/*< private >*/
SysBusDevice parent_obj;
/*< public >*/
uint32_t channel;
qemu_irq real_ide_irq;
qemu_irq real_dma_irq;
qemu_irq ide_irq;
qemu_irq dma_irq;
MemoryRegion mem;
IDEBus bus;
IDEDMA dma;
void *dbdma;
bool dma_active;
uint32_t timing_reg;
uint32_t irq_reg;
} MACIOIDEState;
这里注意IDE是sysbusdevice!
typedef struct MacIOState {
/*< private >*/
PCIDevice parent;
/*< public >*/
MemoryRegion bar;
CUDAState cuda;
PMUState pmu;
DBDMAState dbdma;
ESCCState escc;
uint64_t frequency;
} MacIOState;
在bar中添加了两块IDE中的MemoryRegion&ide->mem
再来看看macio_newwold的class_init
static void macio_newworld_class_init(ObjectClass *oc, void *data)
{
PCIDeviceClass *pdc = PCI_DEVICE_CLASS(oc);
DeviceClass *dc = DEVICE_CLASS(oc);
pdc->realize = macio_newworld_realize;
pdc->device_id = PCI_DEVICE_ID_APPLE_UNI_N_KEYL;
dc->vmsd = &vmstate_macio_newworld;
dc->props = macio_newworld_properties;
大致是这样一个函数调用关系吧
在macio完成实现之后:
/* We only emulate 2 out of 3 IDE controllers for now */
ide_drive_get(hd, ARRAY_SIZE(hd));
macio_ide = MACIO_IDE(object_resolve_path_component(OBJECT(macio),
"ide[0]"));
macio_ide_init_drives(macio_ide, hd);
macio_ide = MACIO_IDE(object_resolve_path_component(OBJECT(macio),
"ide[1]"));
macio_ide_init_drives(macio_ide, &hd[MAX_IDE_DEVS]);
这些函数,最后实现了macio_ide的驱动初始化
总结一下:
- MACIO里面实现了一个BAR, 里面完成了关于DBDMA , TIMER, OPENPIC等功能,很像这张图:
后续的思路,是看Tsi107的手册,重点看地址映射,PCI配置寄存器以及DMA的部分