示例#1
0
int pflash_cfi01_fdt_init(char *node_path, FDTMachineInfo *fdti, void *opaque)
{

    uint32_t flash_base = 0;
    uint32_t flash_size = 0;

    int be = *((int *)opaque);

    DriveInfo *dinfo;
    uint32_t bank_width;

    /* FIXME: respect #address and size cells */
    flash_base = qemu_fdt_getprop_cell(fdti->fdt, node_path, "reg", 0,
                                       false, &error_abort);
    flash_size = qemu_fdt_getprop_cell(fdti->fdt, node_path, "reg", 1,
                                       false, &error_abort);
    bank_width = qemu_fdt_getprop_cell(fdti->fdt, node_path, "bank-width",
                                       0, false, &error_abort);

    DB_PRINT_NP(0, "FLASH: baseaddr: 0x%x, size: 0x%x\n",
                flash_base, flash_size);

    dinfo = drive_get_next(IF_PFLASH);
    pflash_cfi01_register(flash_base, NULL, node_path, flash_size,
                            dinfo ? blk_by_legacy_dinfo(dinfo) : NULL,
                            FLASH_SECTOR_SIZE, flash_size/FLASH_SECTOR_SIZE,
                            bank_width, 0x89, 0x18, 0x0000, 0x0, be);
    return 0;
}
示例#2
0
static void vexpress_modify_dtb(const struct arm_boot_info *info, void *fdt)
{
    uint32_t acells, scells, intc;
    const VEDBoardInfo *daughterboard = (const VEDBoardInfo *)info;

    acells = qemu_fdt_getprop_cell(fdt, "/", "#address-cells");
    scells = qemu_fdt_getprop_cell(fdt, "/", "#size-cells");
    intc = find_int_controller(fdt);
    if (!intc) {
        /* Not fatal, we just won't provide virtio. This will
         * happen with older device tree blobs.
         */
        fprintf(stderr, "QEMU: warning: couldn't find interrupt controller in "
                "dtb; will not include virtio-mmio devices in the dtb.\n");
    } else {
        int i;
        const hwaddr *map = daughterboard->motherboard_map;

        /* We iterate backwards here because adding nodes
         * to the dtb puts them in last-first.
         */
        for (i = NUM_VIRTIO_TRANSPORTS - 1; i >= 0; i--) {
            add_virtio_mmio_node(fdt, acells, scells,
                                 map[VE_VIRTIO] + 0x200 * i,
                                 0x200, intc, 40 + i);
        }
    }
}
示例#3
0
static int uart16550_fdt_init(char *node_path, FDTMachineInfo *fdti,
    void *priv)
{
    /* FIXME: Pass in dynamically */
    MemoryRegion *address_space_mem = get_system_memory();
    hwaddr base;
    uint32_t baudrate;
    qemu_irq irqline;
    bool map_mode;
    char irq_info[1024];
    Error *err = NULL;

    /* FIXME: respect #address and size cells */
    base = qemu_fdt_getprop_cell(fdti->fdt, node_path, "reg", 0,
                                 false, &error_abort);
    base += qemu_fdt_getprop_cell(fdti->fdt, node_path, "reg-offset", 0,
                                  false, &error_abort);
    base &= ~3ULL; /* qemu uart16550 model starts with 3* 8bit offset */

    baudrate = qemu_fdt_getprop_cell(fdti->fdt, node_path, "current-speed",
                                     0, false, &err);
    if (err) {
        baudrate = 115200;
    }

    irqline = *fdt_get_irq_info(fdti, node_path, 0, irq_info, &map_mode);
    assert(!map_mode);
    DB_PRINT_NP(0, "UART16550a: baseaddr: 0x" TARGET_FMT_plx
                ", irq: %s, baud %d\n", base, irq_info, baudrate);

    /* it_shift = 2, reg-shift in DTS - for Xilnx IP is hardcoded */
    serial_mm_init(address_space_mem, base, 2, irqline, baudrate,
                   qemu_char_get_next_serial(), DEVICE_LITTLE_ENDIAN);
    return 0;
}
示例#4
0
static ram_addr_t get_dram_base(void *fdt)
{
    Error *errp = NULL;

    printf("DRAM base %08X, size %08X\n",
        qemu_fdt_getprop_cell(fdt, "/memory", "reg", 0, 0, &errp),
        qemu_fdt_getprop_cell(fdt, "/memory", "reg", 1, 0, &errp));

    return qemu_fdt_getprop_cell(fdt, "/memory", "reg", 0, 0, &errp);
}
示例#5
0
qemu_irq fdt_get_irq_info(FDTMachineInfo *fdti, char *node_path, int irq_idx,
        int *err, char *info) {
    void *fdt = fdti->fdt;
    int intc_phandle, intc_cells, idx, errl;
    char intc_node_path[DT_PATH_LENGTH];
    Error *errp = NULL;
    DeviceState *intc;

    if (!err) {
        err = &errl;
    }
    intc_phandle = qemu_fdt_getprop_cell(fdt, node_path, "interrupt-parent",
                                                                0, true, &errp);
    if (errp) {
        goto fail;
    }

    if (qemu_fdt_get_node_by_phandle(fdt, intc_node_path, intc_phandle)) {
        goto fail;
    }
    intc_cells = qemu_fdt_getprop_cell(fdt, intc_node_path,
                                       "#interrupt-cells", 0, false, &errp);
    if (errp) {
        goto fail;
    }
    idx = qemu_fdt_getprop_cell(fdt, node_path, "interrupts",
                                        intc_cells * irq_idx, false, &errp);
    if (errp) {
        goto fail;
    }

    while (!fdt_init_has_opaque(fdti, intc_node_path)) {
        fdt_init_yield(fdti);
    }
    intc = DEVICE(fdt_init_get_opaque(fdti, intc_node_path));
    if (!intc) {
        goto fail;
    }
    if (info) {
        char *node_name = qemu_fdt_get_node_name(fdt, intc_node_path);
        sprintf(info, "%d (%s)", idx, node_name);
        g_free((void *)node_name);
    }
    *err = 0;
    return qdev_get_gpio_in(intc, idx);
fail:
    *err = 1;
    if (info) {
        sprintf(info, "(none)");
    }
    return NULL;
}
示例#6
0
static void cpu_probe(FDTMachineInfo *fdti, const char *node_path, uint32_t offset)
{
    //int i;
    DeviceState *dev;
    Error *errp = NULL;

    Nios2CPU *cpu = cpu_nios2_init("nios2");

    qemu_register_reset(main_cpu_reset, cpu);

#if 0 /* TODO: Finish off the vectored-interrupt-controller */
    int reglen;
    const void *reg = qemu_fdt_getprop_offset(fdt, node, "reg", &reglen);
    uint32_t irq_addr = qemu_fdt_int_array_index(reg, 0) + offset;
    int nrIrqLen;
    const void *nrIrq =
        qemu_fdt_getprop_offset(fdt, node, "ALTR,num-intr-inputs",
                                    &nrIrqLen);
    uint32_t nrIrqs = qemu_fdt_int_array_index(nrIrq, 0);

    printf("  IRQ BASE %08X NIRQS %d\n", irq_addr, nrIrqs);

    fdti->irq_base = qdev_get_gpio_in(DEVICE(cpu), NIOS2_CPU_IRQ);
    dev = altera_vic_create(irq_addr, fdti->irq_base, 2);
#else
    /* Internal interrupt controller (IIC) */
    fdti->irq_base = qdev_get_gpio_in(DEVICE(cpu), NIOS2_CPU_IRQ);
    dev = altera_iic_create(cpu, fdti->irq_base, 2);
#endif

    /* TODO: use the entrypoint of the passed in elf file or
       the device-tree one */
#if 0
    cpu->env.reset_addr =
        qemu_fdt_getprop_cell(fdt, node_path, "ALTR,reset-addr", 0, 0, &errp);
#else
    cpu->env.reset_addr = 0xc0000000;
#endif

    cpu->env.exception_addr =
        qemu_fdt_getprop_cell(fdti->fdt, node_path, "ALTR,exception-addr", 0, 0, &errp);
    cpu->env.fast_tlb_miss_addr =
        qemu_fdt_getprop_cell(fdti->fdt, node_path, "ALTR,fast-tlb-miss-addr", 0, 0, &errp);

    /* reset again to use the new reset vector */
    cpu_reset(CPU(cpu));

    fdt_init_set_opaque(fdti, node_path, dev);
}
示例#7
0
hwaddr fdt_get_parent_base(const char *node_path,
                                       FDTMachineInfo *fdti)
{
    hwaddr base = fdti->sysbus_base;
    char parent[DT_PATH_LENGTH];
    if (!qemu_fdt_getparent(fdti->fdt, parent, node_path)) {
        do {
            Error *errp = NULL;
            int64_t parent_base = 0;
            parent_base = qemu_fdt_getprop_cell(fdti->fdt, parent, "reg",
                                                    0, false, &errp);
            if (errp == NULL) {
                base += (hwaddr)parent_base;
            }
        } while (!qemu_fdt_getparent(fdti->fdt, parent, parent));
    }

    return base;
}
示例#8
0
static int fdt_init_qdev(char *node_path, FDTMachineInfo *fdti, char *compat)
{
    int err;
    qemu_irq irq;
    hwaddr base;
    int offset;
    DeviceState *dev;
    char *dev_type = NULL;
    int is_intc;
    int i;

    dev = fdt_create_qdev_from_compat(compat, &dev_type);
    if (!dev) {
        DB_PRINT("no match found for %s\n", compat);
        return 1;
    }
    /* FIXME: attach to the sysbus instead */
    object_property_add_child(container_get(qdev_get_machine(), "/unattached"),
                              qemu_fdt_get_node_name(fdti->fdt, node_path),
                              OBJECT(dev), NULL);

    fdt_init_set_opaque(fdti, node_path, dev);

    /* connect nic if appropriate */
    static int nics;
    if (object_property_find(OBJECT(dev), "mac", NULL)) {
        qdev_set_nic_properties(dev, &nd_table[nics]);
        if (nd_table[nics].instantiated) {
            DB_PRINT("NIC instantiated: %s\n", dev_type);
            nics++;
        }
    }

    offset = fdt_path_offset(fdti->fdt, node_path);
    for (offset = fdt_first_property_offset(fdti->fdt, offset);
            offset != -FDT_ERR_NOTFOUND;
            offset = fdt_next_property_offset(fdti->fdt, offset)) {
        const char *propname;
        int len;
        const void *val = fdt_getprop_by_offset(fdti->fdt, offset,
                                                    &propname, &len);

        propname = trim_vendor(propname);
        ObjectProperty *p = object_property_find(OBJECT(dev), propname, NULL);
        if (p) {
            DB_PRINT("matched property: %s of type %s, len %d\n",
                                            propname, p->type, len);
        }
        if (!p) {
            continue;
        }

        /* FIXME: handle generically using accessors and stuff */
        if (!strcmp(p->type, "uint8") || !strcmp(p->type, "uint16") ||
                !strcmp(p->type, "uint32") || !strcmp(p->type, "uint64")) {
            uint64_t offset = (!strcmp(propname, "reg")) ?
                              fdt_get_parent_base(node_path, fdti) : 0;
            object_property_set_int(OBJECT(dev), get_int_be(val, len) + offset,
                                    propname, &error_abort);
            DB_PRINT("set property %s to %#llx\n", propname,
                                            (long long unsigned int)get_int_be(val, len));
        } else if (!strcmp(p->type, "bool")) {
            object_property_set_bool(OBJECT(dev), !!get_int_be(val, len),
                        propname, &error_abort);
            DB_PRINT("set property %s to %#llx\n", propname,
                                            (long long unsigned int)get_int_be(val, len));
        } else if (!strncmp(p->type, "link", 4)) {
            char target_node_path[DT_PATH_LENGTH];
            DeviceState *linked_dev;

            if (qemu_fdt_get_node_by_phandle(fdti->fdt, target_node_path,
                                                get_int_be(val, len))) {
                abort();
            }
            while (!fdt_init_has_opaque(fdti, target_node_path)) {
                fdt_init_yield(fdti);
            }
            linked_dev = fdt_init_get_opaque(fdti, target_node_path);
            object_property_set_link(OBJECT(dev), OBJECT(linked_dev), propname,
                                        &error_abort);
        } else if (!strcmp(p->type, "string")) {
            object_property_set_str(OBJECT(dev), strndup(val, len), propname, &error_abort);
	}
    }

    qdev_init_nofail(dev);
    /* map slave attachment */
    base = qemu_fdt_getprop_cell(fdti->fdt, node_path, "reg", 0, false, &error_abort);

    base += fdt_get_parent_base(node_path, fdti);
    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);

    {
        int len;
        fdt_get_property(fdti->fdt, fdt_path_offset(fdti->fdt, node_path),
                                "interrupt-controller", &len);
        is_intc = len >= 0;
        DB_PRINT("is interrupt controller: %c\n", is_intc ? 'y' : 'n');
    }
    /* connect irq */
    for (i = 0; ; ++i) {
        char irq_info[1024];
        irq = fdt_get_irq_info(fdti, node_path, i, &err, irq_info);
        /* INTCs inferr their top level, if no IRQ connection specified */
        if (err && is_intc) {
            irq = fdti->irq_base;
            sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq);
            fprintf(stderr, "FDT: (%s) connected top level irq %s\n", dev_type,
                        irq_info);
            break;
        }
        if (!err) {
            sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, irq);
            fprintf(stderr, "FDT: (%s) connected irq %s\n", dev_type, irq_info);
        } else {
            break;
        }
    }

    if (dev_type) {
        g_free(dev_type);
    }

    return 0;
}
示例#9
0
qemu_irq *fdt_get_irq_info(FDTMachineInfo *fdti, char *node_path, int irq_idx,
                          char *info, bool *map_mode) {
    void *fdt = fdti->fdt;
    uint32_t intc_phandle, intc_cells, cells[32];
    char intc_node_path[DT_PATH_LENGTH];
    qemu_irq *ret = NULL;
    int i;
    Error *errp = NULL;

    intc_phandle = qemu_fdt_getprop_cell(fdt, node_path, "interrupt-parent",
                                                                0, true, &errp);
    if (errp) {
        errp = NULL;
        intc_cells = qemu_fdt_getprop_cell(fdt, node_path,
                                           "#interrupt-cells", 0, true, &errp);
        if (errp) {
            goto fail;
        }
        *map_mode = true;
    } else {
        if (qemu_devtree_get_node_by_phandle(fdt, intc_node_path,
                                             intc_phandle)) {
            goto fail;
        }
        intc_cells = qemu_fdt_getprop_cell(fdt, intc_node_path,
                                           "#interrupt-cells", 0, true, &errp);
        if (errp) {
            goto fail;
        }
        *map_mode = false;
    }

    DB_PRINT_NP(2, "%s intc_phandle: %d\n", node_path, intc_phandle);

    for (i = 0; i < intc_cells; ++i) {
        cells[i] = qemu_fdt_getprop_cell(fdt, node_path, "interrupts",
                                         intc_cells * irq_idx + i, false, &errp);
        if (errp) {
            goto fail;
        }
    }

    if (*map_mode) {
        int k;
        ret = g_new0(qemu_irq, 1);
        int num_matches = 0;
        int len;
        uint32_t imap_mask[intc_cells];
        uint32_t *imap_p;
        uint32_t *imap;
        bool use_parent = false;

        for (k = 0; k < intc_cells; ++k) {
            imap_mask[k] = qemu_fdt_getprop_cell(fdt, node_path,
                                                 "interrupt-map-mask", k + 2,
                                                 true, &errp);
            if (errp) {
                goto fail;
            }
        }

        /* Check if the device has an interrupt-map property */
        imap = qemu_fdt_getprop(fdt, node_path, "interrupt-map", &len,
                                  use_parent, &errp);

        if (!imap || errp) {
            /* If the device doesn't have an interrupt-map, try again with
             * inheritance. This will return the parents interrupt-map
             */
            use_parent = true;
            errp = NULL;

            imap_p = qemu_fdt_getprop(fdt, node_path, "interrupt-map",
                                      &len, use_parent, &errp);
            if (!imap_cached) {
                memcpy(imap_cache, imap_p, len);
                imap_cached = true;
            }
            imap = imap_cache;

            if (errp) {
                goto fail;
            }
        }

        len /= sizeof(uint32_t);

        i = 0;
        assert(imap);
        while (i < len) {
            if (!use_parent) {
                /* Only re-sync the interrupt-map when the device has it's
                 * own map, to save time.
                 */
                imap = qemu_fdt_getprop(fdt, node_path, "interrupt-map", &len,
                                          use_parent, &errp);

                if (errp) {
                    goto fail;
                }

                len /= sizeof(uint32_t);
            }

            bool match = true;
            uint32_t new_intc_cells, new_cells[32];
            i++; i++; /* FIXME: do address cells properly */
            for (k = 0; k < intc_cells; ++k) {
                uint32_t  map_val = be32_to_cpu(imap[i++]);
                if ((cells[k] ^ map_val) & imap_mask[k]) {
                    match = false;
                }
            }
            /* when caching, we hackishly store the number of cells for
             * the parent in the MSB. +1, so zero MSB means non cachd
             * and the full lookup is needed.
             */
            intc_phandle = be32_to_cpu(imap[i++]);
            if (intc_phandle & (0xffu << 24)) {
                new_intc_cells = (intc_phandle >> 24) - 1;
            } else {
                if (qemu_devtree_get_node_by_phandle(fdt, intc_node_path,
                                                     intc_phandle)) {
                    goto fail;
                }
                new_intc_cells = qemu_fdt_getprop_cell(fdt, intc_node_path,
                                                       "#interrupt-cells", 0,
                                                       false, &errp);
                imap[i - 1] = cpu_to_be32(intc_phandle |
                                            (new_intc_cells + 1) << 24);
                if (errp) {
                    goto fail;
                }
            }
            for (k = 0; k < new_intc_cells; ++k) {
                new_cells[k] = be32_to_cpu(imap[i++]);
            }
            if (match) {
                num_matches++;
                ret = g_renew(qemu_irq, ret, num_matches + 1);
                if (intc_phandle & (0xffu << 24)) {
                    if (qemu_devtree_get_node_by_phandle(fdt, intc_node_path,
                                                         intc_phandle &
                                                         ((1 << 24) - 1))) {
                        goto fail;
                    }
                }

                DB_PRINT_NP(2, "Getting IRQ information: %s -> 0x%x (%s)\n",
                            node_path, intc_phandle, intc_node_path);

                memset(&ret[num_matches], 0, sizeof(*ret));
                fdt_get_irq_info_from_intc(fdti, &ret[num_matches-1], intc_node_path,
                                           new_cells, new_intc_cells, 1, &errp);
                if (info) {
                   sprintf(info, "%s", intc_node_path);
                   info += strlen(info) + 1;
                }
                if (errp) {
                    goto fail;
                }
            }
        }
示例#10
0
static qemu_irq fdt_get_gpio(FDTMachineInfo *fdti, char *node_path,
                             int* cur_cell, qemu_irq input,
                             const FDTGenericGPIOSet *gpio_set,
                             const char *debug_success, bool *end) {
    void *fdt = fdti->fdt;
    uint32_t parent_phandle, parent_cells = 0, cells[32];
    char parent_node_path[DT_PATH_LENGTH];
    DeviceState *parent;
    int i;
    Error *errp = NULL;
    const char *reason;
    bool free_reason = false;
    const char *propname = gpio_set->names->propname;
    const char *cells_propname = gpio_set->names->cells_propname;

    cells[0] = 0;

    parent_phandle = qemu_fdt_getprop_cell(fdt, node_path, propname,
                                           (*cur_cell)++, false, &errp);
    if (errp) {
        reason = g_strdup_printf("Cant get phandle from \"%s\" property\n",
                                 propname);
        *end = true;
        free_reason = true;
        goto fail_silent;
    }
    if (qemu_devtree_get_node_by_phandle(fdt, parent_node_path,
                                         parent_phandle)) {
        *end = true;
        reason = "cant get node from phandle\n";
        goto fail;
    }
    parent_cells = qemu_fdt_getprop_cell(fdt, parent_node_path,
                                         cells_propname, 0, false, &errp);
    if (errp) {
        *end = true;
        reason = g_strdup_printf("cant get the property \"%s\" from the " \
                                 "parent \"%s\"\n",
                                 cells_propname, parent_node_path);
        free_reason = true;
        goto fail;
    }

    for (i = 0; i < parent_cells; ++i) {
        cells[i] = qemu_fdt_getprop_cell(fdt, node_path, propname,
                                         (*cur_cell)++, false, &errp);
        if (errp) {
            *end = true;
            reason = "cant get cell value";
            goto fail;
        }
    }

    while (!fdt_init_has_opaque(fdti, parent_node_path)) {
        fdt_init_yield(fdti);
    }
    parent = DEVICE(fdt_init_get_opaque(fdti, parent_node_path));

    if (!parent) {
        reason = "parent is not a device";
        goto fail_silent;
    }

    while (!parent->realized) {
        fdt_init_yield(fdti);
    }

    {
        const FDTGenericGPIOConnection *fgg_con = NULL;
        uint16_t range, idx;
        const char *gpio_name = NULL;
        qemu_irq ret;

        if (object_dynamic_cast(OBJECT(parent), TYPE_FDT_GENERIC_GPIO)) {
            const FDTGenericGPIOSet *set;
            FDTGenericGPIOClass *parent_fggc =
                        FDT_GENERIC_GPIO_GET_CLASS(parent);

            for (set = parent_fggc->controller_gpios; set && set->names;
                 set++) {
                if (!strcmp(gpio_set->names->cells_propname,
                            set->names->cells_propname)) {
                    fgg_con = set->gpios;
                    break;
                }
            }
        }

        /* FIXME: cells[0] is not always the fdt indexing match system */
        idx = cells[0] & ~(1ul << 31);
        if (fgg_con) {
            range = fgg_con->range ? fgg_con->range : 1;
            while (!(idx >= fgg_con->fdt_index
                     && idx < (fgg_con->fdt_index + range))
                   && fgg_con->name) {
                fgg_con++;
            }
            if (!fgg_con) {
                goto fail;
            }

            idx -= fgg_con->fdt_index;
            gpio_name = fgg_con->name;
        }

        if (input) {
            FDTIRQConnection *irq = g_new0(FDTIRQConnection, 1);
            bool (*merge_fn)(bool *, int) = qemu_irq_shared_or_handler;

            /* FIXME: I am kind of stealing here. Use the msb of the first
             * cell to indicate the merge function. This needs to be discussed
             * with device-tree community on how this should be done properly.
             */
            if (cells[0] & (1 << 31)) {
                merge_fn = qemu_irq_shared_and_handler;
            }

            DB_PRINT_NP(1, "%s GPIO output %s[%d] on %s\n", debug_success,
                        gpio_name ? gpio_name : "unnamed", idx,
                        parent_node_path);
            *irq = (FDTIRQConnection) {
                .dev = parent,
                .name = gpio_name,
                .merge_fn = merge_fn,
                .i = idx,
                .irq = input,
                .sink_info = NULL, /* FIMXE */
                .next = fdti->irqs
            };
            fdti->irqs = irq;
        }
        ret = qdev_get_gpio_in_named(parent, gpio_name, idx);

        if (ret) {
            DB_PRINT_NP(1, "wiring GPIO input %s on %s ... \n",
                        fgg_con ? fgg_con->name : "unnamed", parent_node_path);
        }
        return ret;
    }
fail:
    fprintf(stderr, "%s Failed: %s\n", node_path, reason);
fail_silent:
    if (free_reason) {
        g_free((void *)reason);
    }
    return NULL;
}

static void fdt_get_irq_info_from_intc(FDTMachineInfo *fdti, qemu_irq *ret,
                                       char *intc_node_path,
                                       uint32_t *cells, uint32_t num_cells,
                                       uint32_t max, Error **errp)
{
    FDTGenericIntcClass *intc_fdt_class;
    DeviceState *intc;

    while (!fdt_init_has_opaque(fdti, intc_node_path)) {
        fdt_init_yield(fdti);
    }
    intc = DEVICE(fdt_init_get_opaque(fdti, intc_node_path));

    if (!intc) {
        goto fail;
    }

    while (!intc->realized) {
        fdt_init_yield(fdti);
    }

    intc_fdt_class = FDT_GENERIC_INTC_GET_CLASS(intc);
    if (!intc_fdt_class) {
        goto fail;
    }

    intc_fdt_class->get_irq(FDT_GENERIC_INTC(intc), ret, cells, num_cells,
                            max, errp);
    return;
fail:
    error_setg(errp, "%s", __func__);
}
static void
microblaze_generic_fdt_init(MachineState *machine)
{
    CPUState *cpu;
    ram_addr_t ram_kernel_base = 0, ram_kernel_size = 0;
    void *fdt = NULL;
    const char *dtb_arg, *hw_dtb_arg;
    QemuOpts *machine_opts;
    int fdt_size;

    /* for memory node */
    char node_path[DT_PATH_LENGTH];
    FDTMachineInfo *fdti;
    MemoryRegion *main_mem;

    /* For DMA node */
    char dma_path[DT_PATH_LENGTH] = { 0 };
    uint32_t memory_phandle;

    /* For Ethernet nodes */
    char **eth_paths;
    char *phy_path;
    char *mdio_path;
    uint32_t n_eth;
    uint32_t prop_val;

    machine_opts = qemu_opts_find(qemu_find_opts("machine"), 0);
    if (!machine_opts) {
        goto no_dtb_arg;
    }
    dtb_arg = qemu_opt_get(machine_opts, "dtb");
    hw_dtb_arg = qemu_opt_get(machine_opts, "hw-dtb");
    if (!dtb_arg && !hw_dtb_arg) {
        goto no_dtb_arg;
    }

    /* If the user only provided a -dtb, use it as the hw description.  */
    if (!hw_dtb_arg) {
        hw_dtb_arg = dtb_arg;
    }

    fdt = load_device_tree(hw_dtb_arg, &fdt_size);
    if (!fdt) {
        hw_error("Error: Unable to load Device Tree %s\n", hw_dtb_arg);
        return;
    }

    if (IS_PETALINUX_MACHINE) {
        /* Mark the simple-bus as incompatible as it breaks the Microblaze
         * PetaLinux boot
         */
        add_to_compat_table(NULL, "compatible:simple-bus", NULL);
    }

    /* find memory node or add new one if needed */
    while (qemu_fdt_get_node_by_name(fdt, node_path, "memory")) {
        qemu_fdt_add_subnode(fdt, "/memory@0");
        qemu_fdt_setprop_cells(fdt, "/memory@0", "reg", 0, machine->ram_size);
    }

    if (!qemu_fdt_getprop(fdt, "/memory", "compatible", NULL, 0, NULL)) {
        qemu_fdt_setprop_string(fdt, "/memory", "compatible",
                                "qemu:memory-region");
        qemu_fdt_setprop_cells(fdt, "/memory", "qemu,ram", 1);
    }

    if (IS_PETALINUX_MACHINE) {
        /* If using a *-plnx machine, the AXI DMA memory links are not included
         * in the DTB by default. To avoid seg faults, add the links in here if
         * they have not already been added by the user
         */
        qemu_fdt_get_node_by_name(fdt, dma_path, "dma");

        if (strcmp(dma_path, "") != 0) {
            memory_phandle = qemu_fdt_check_phandle(fdt, node_path);

            if (!memory_phandle) {
                memory_phandle = qemu_fdt_alloc_phandle(fdt);

                qemu_fdt_setprop_cells(fdt, "/memory", "linux,phandle",
                                       memory_phandle);
                qemu_fdt_setprop_cells(fdt, "/memory", "phandle",
                                       memory_phandle);
            }

            if (!qemu_fdt_getprop(fdt, dma_path, "sg", NULL, 0, NULL)) {
                qemu_fdt_setprop_phandle(fdt, dma_path, "sg", node_path);
            }

            if (!qemu_fdt_getprop(fdt, dma_path, "s2mm", NULL, 0, NULL)) {
                qemu_fdt_setprop_phandle(fdt, dma_path, "s2mm", node_path);
            }

            if (!qemu_fdt_getprop(fdt, dma_path, "mm2s", NULL, 0, NULL)) {
                qemu_fdt_setprop_phandle(fdt, dma_path, "mm2s", node_path);
            }
        }

        /* Copy phyaddr value from phy node reg property */
        n_eth = qemu_fdt_get_n_nodes_by_name(fdt, &eth_paths, "ethernet");

        while (n_eth--) {
            mdio_path = qemu_fdt_get_child_by_name(fdt, eth_paths[n_eth],
                                                       "mdio");
            if (mdio_path) {
                phy_path = qemu_fdt_get_child_by_name(fdt, mdio_path,
                                                          "phy");
                if (phy_path) {
                    prop_val = qemu_fdt_getprop_cell(fdt, phy_path, "reg", NULL, 0,
                                                     NULL, &error_abort);
                    qemu_fdt_setprop_cell(fdt, eth_paths[n_eth], "xlnx,phyaddr",
                                          prop_val);
                    g_free(phy_path);
                } else {
                    qemu_log_mask(LOG_GUEST_ERROR, "phy not found in %s",
                                  mdio_path);
                }
                g_free(mdio_path);
            }
            g_free(eth_paths[n_eth]);
        }
        g_free(eth_paths);
    }

    /* Instantiate peripherals from the FDT.  */
    fdti = fdt_generic_create_machine(fdt, NULL);
    main_mem = MEMORY_REGION(object_resolve_path(node_path, NULL));

    ram_kernel_base = object_property_get_int(OBJECT(main_mem), "addr", NULL);
    ram_kernel_size = object_property_get_int(OBJECT(main_mem), "size", NULL);

    if (!memory_region_is_mapped(main_mem)) {
        /* If the memory region is not mapped, map it here.
         * It has to be mapped somewhere, so guess that the base address
         * is where the kernel starts
         */
        memory_region_add_subregion(get_system_memory(), ram_kernel_base,
                                    main_mem);

        if (ram_kernel_base && IS_PETALINUX_MACHINE) {
            /* If the memory added is at an offset from zero QEMU will error
             * when an ISR/exception is triggered. Add a small amount of hack
             * RAM to handle this.
             */
            MemoryRegion *hack_ram = g_new(MemoryRegion, 1);
            memory_region_init_ram(hack_ram, NULL, "hack_ram", 0x1000,
                                   &error_abort);
            vmstate_register_ram_global(hack_ram);
            memory_region_add_subregion(get_system_memory(), 0, hack_ram);
        }
    }

    fdt_init_destroy_fdti(fdti);

    fdt_g = fdt;
    microblaze_load_kernel(MICROBLAZE_CPU(first_cpu), ram_kernel_base,
                           ram_kernel_size, machine->initrd_filename, NULL,
                           microblaze_generic_fdt_reset, 0, fdt, fdt_size);

    /* Register FDT to prop mapper for secondary cores.  */
    cpu = CPU_NEXT(first_cpu);
    while (cpu) {
        qemu_register_reset(secondary_cpu_reset, cpu);
        cpu = CPU_NEXT(cpu);
    }

    return;
no_dtb_arg:
    if (!QTEST_RUNNING) {
        hw_error("DTB must be specified for %s machine model\n", MACHINE_NAME);
    }
    return;
}