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; }
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); } } }
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; }
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); }
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; }
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", ®len); 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); }
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; }
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; }
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; } } }
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, ð_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; }