用qemu实现tsi107桥摸索(三)

通过上一篇的分析,知道了

  • 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的部分

猜你喜欢

转载自blog.csdn.net/weixin_38171577/article/details/84920795
107