Пример #1
0
static int add_virtio_mmio_node(void *fdt, uint32_t acells, uint32_t scells,
                                hwaddr addr, hwaddr size, uint32_t intc,
                                int irq)
{
    /* Add a virtio_mmio node to the device tree blob:
     *   virtio_mmio@ADDRESS {
     *       compatible = "virtio,mmio";
     *       reg = <ADDRESS, SIZE>;
     *       interrupt-parent = <&intc>;
     *       interrupts = <0, irq, 1>;
     *   }
     * (Note that the format of the interrupts property is dependent on the
     * interrupt controller that interrupt-parent points to; these are for
     * the ARM GIC and indicate an SPI interrupt, rising-edge-triggered.)
     */
    int rc;
    char *nodename = g_strdup_printf("/virtio_mmio@%" PRIx64, addr);

    rc = qemu_devtree_add_subnode(fdt, nodename);
    rc |= qemu_devtree_setprop_string(fdt, nodename,
                                      "compatible", "virtio,mmio");
    rc |= qemu_devtree_setprop_sized_cells(fdt, nodename, "reg",
                                           acells, addr, scells, size);
    qemu_devtree_setprop_cells(fdt, nodename, "interrupt-parent", intc);
    qemu_devtree_setprop_cells(fdt, nodename, "interrupts", 0, irq, 1);
    g_free(nodename);
    if (rc) {
        return -1;
    }
    return 0;
}
static int labx_load_device_tree(hwaddr addr,
                                 uint32_t ramsize,
                                 hwaddr initrd_base,
                                 hwaddr initrd_size,
                                 const char *kernel_cmdline)
{
    int fdt_size;
    void *fdt;
    int r;

    fdt = get_device_tree(&fdt_size);

    if (!fdt) {
        return 0;
    }

    if (kernel_cmdline && strlen(kernel_cmdline)) {
        r = qemu_devtree_setprop_string(fdt, "/chosen", "bootargs",
                                        kernel_cmdline);
        if (r < 0) {
            fprintf(stderr, "couldn't set /chosen/bootargs\n");
        }
    }
    cpu_physical_memory_write(addr, (void *)fdt, fdt_size);

    return fdt_size;
}
Пример #3
0
static int bamboo_load_device_tree(target_phys_addr_t addr,
                                   uint32_t ramsize,
                                   target_phys_addr_t initrd_base,
                                   target_phys_addr_t initrd_size,
                                   const char *kernel_cmdline)
{
    int ret = -1;
#ifdef CONFIG_FDT
    uint32_t mem_reg_property[] = { 0, 0, ramsize };
    char *filename;
    int fdt_size;
    void *fdt;

    filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, BINARY_DEVICE_TREE_FILE);
    if (!filename) {
        goto out;
    }
    fdt = load_device_tree(filename, &fdt_size);
    g_free(filename);
    if (fdt == NULL) {
        goto out;
    }

    /* Manipulate device tree in memory. */

    ret = qemu_devtree_setprop(fdt, "/memory", "reg", mem_reg_property,
                               sizeof(mem_reg_property));
    if (ret < 0)
        fprintf(stderr, "couldn't set /memory/reg\n");

    ret = qemu_devtree_setprop_cell(fdt, "/chosen", "linux,initrd-start",
                                    initrd_base);
    if (ret < 0)
        fprintf(stderr, "couldn't set /chosen/linux,initrd-start\n");

    ret = qemu_devtree_setprop_cell(fdt, "/chosen", "linux,initrd-end",
                                    (initrd_base + initrd_size));
    if (ret < 0)
        fprintf(stderr, "couldn't set /chosen/linux,initrd-end\n");

    ret = qemu_devtree_setprop_string(fdt, "/chosen", "bootargs",
                                      kernel_cmdline);
    if (ret < 0)
        fprintf(stderr, "couldn't set /chosen/bootargs\n");

    if (kvm_enabled())
        kvmppc_fdt_update(fdt);

    ret = rom_add_blob_fixed(BINARY_DEVICE_TREE_FILE, fdt, fdt_size, addr);
    g_free(fdt);

out:
#endif

    return ret;
}
Пример #4
0
static void *bamboo_load_device_tree(target_phys_addr_t addr,
                                     uint32_t ramsize,
                                     target_phys_addr_t initrd_base,
                                     target_phys_addr_t initrd_size,
                                     const char *kernel_cmdline)
{
    void *fdt = NULL;
#ifdef HAVE_FDT
    uint32_t mem_reg_property[] = { 0, 0, ramsize };
    char *path;
    int fdt_size;
    int pathlen;
    int ret;

    pathlen = snprintf(NULL, 0, "%s/%s", bios_dir, BINARY_DEVICE_TREE_FILE) + 1;
    path = qemu_malloc(pathlen);

    snprintf(path, pathlen, "%s/%s", bios_dir, BINARY_DEVICE_TREE_FILE);

    fdt = load_device_tree(path, &fdt_size);
    free(path);
    if (fdt == NULL)
        goto out;

    /* Manipulate device tree in memory. */

    ret = qemu_devtree_setprop(fdt, "/memory", "reg", mem_reg_property,
                               sizeof(mem_reg_property));
    if (ret < 0)
        fprintf(stderr, "couldn't set /memory/reg\n");

    ret = qemu_devtree_setprop_cell(fdt, "/chosen", "linux,initrd-start",
                                    initrd_base);
    if (ret < 0)
        fprintf(stderr, "couldn't set /chosen/linux,initrd-start\n");

    ret = qemu_devtree_setprop_cell(fdt, "/chosen", "linux,initrd-end",
                                    (initrd_base + initrd_size));
    if (ret < 0)
        fprintf(stderr, "couldn't set /chosen/linux,initrd-end\n");

    ret = qemu_devtree_setprop_string(fdt, "/chosen", "bootargs",
                                      kernel_cmdline);
    if (ret < 0)
        fprintf(stderr, "couldn't set /chosen/bootargs\n");

    if (kvm_enabled())
        kvmppc_fdt_update(fdt);

    cpu_physical_memory_write (addr, (void *)fdt, fdt_size);

out:
#endif

    return fdt;
}
Пример #5
0
static void dt_serial_create(void *fdt, unsigned long long offset,
                             const char *soc, const char *mpic,
                             const char *alias, int idx, bool defcon)
{
    char ser[128];

    snprintf(ser, sizeof(ser), "%s/serial@%llx", soc, offset);
    qemu_devtree_add_subnode(fdt, ser);
    qemu_devtree_setprop_string(fdt, ser, "device_type", "serial");
    qemu_devtree_setprop_string(fdt, ser, "compatible", "ns16550");
    qemu_devtree_setprop_cells(fdt, ser, "reg", offset, 0x100);
    qemu_devtree_setprop_cell(fdt, ser, "cell-index", idx);
    qemu_devtree_setprop_cell(fdt, ser, "clock-frequency", 0);
    qemu_devtree_setprop_cells(fdt, ser, "interrupts", 42, 2);
    qemu_devtree_setprop_phandle(fdt, ser, "interrupt-parent", mpic);
    qemu_devtree_setprop_string(fdt, "/aliases", alias, ser);

    if (defcon) {
        qemu_devtree_setprop_string(fdt, "/chosen", "linux,stdout-path", ser);
    }
}
Пример #6
0
static int petalogix_load_device_tree(target_phys_addr_t addr,
                                      uint32_t ramsize,
                                      target_phys_addr_t initrd_base,
                                      target_phys_addr_t initrd_size,
                                      const char *kernel_cmdline)
{
#ifdef HAVE_FDT
    void *fdt;
    int r;
#endif
    char *path;
    int fdt_size;

#ifdef HAVE_FDT
    /* Try the local "mb.dtb" override.  */
    fdt = load_device_tree("mb.dtb", &fdt_size);
    if (!fdt) {
        path = qemu_find_file(QEMU_FILE_TYPE_BIOS, BINARY_DEVICE_TREE_FILE);
        if (path) {
            fdt = load_device_tree(path, &fdt_size);
            qemu_free(path);
        }
        if (!fdt)
            return 0;
    }

    r = qemu_devtree_setprop_string(fdt, "/chosen", "bootargs", kernel_cmdline);
    if (r < 0)
        fprintf(stderr, "couldn't set /chosen/bootargs\n");
    cpu_physical_memory_write (addr, (void *)fdt, fdt_size);
#else
    /* We lack libfdt so we cannot manipulate the fdt. Just pass on the blob
       to the kernel.  */
    fdt_size = load_image_targphys("mb.dtb", addr, 0x10000);
    if (fdt_size < 0) {
        path = qemu_find_file(QEMU_FILE_TYPE_BIOS, BINARY_DEVICE_TREE_FILE);
        if (path) {
            fdt_size = load_image_targphys(path, addr, 0x10000);
	    qemu_free(path);
        }
    }

    if (kernel_cmdline) {
        fprintf(stderr,
                "Warning: missing libfdt, cannot pass cmdline to kernel!\n");
    }
#endif
    return fdt_size;
}
Пример #7
0
static int mpc8544_load_device_tree(CPUPPCState *env,
                                    target_phys_addr_t addr,
                                    uint32_t ramsize,
                                    target_phys_addr_t initrd_base,
                                    target_phys_addr_t initrd_size,
                                    const char *kernel_cmdline)
{
    int ret = -1;
#ifdef CONFIG_FDT
    uint32_t mem_reg_property[] = {0, cpu_to_be32(ramsize)};
    char *filename;
    int fdt_size;
    void *fdt;
    uint8_t hypercall[16];
    uint32_t clock_freq = 400000000;
    uint32_t tb_freq = 400000000;
    int i;

    filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, BINARY_DEVICE_TREE_FILE);
    if (!filename) {
        goto out;
    }
    fdt = load_device_tree(filename, &fdt_size);
    g_free(filename);
    if (fdt == NULL) {
        goto out;
    }

    /* Manipulate device tree in memory. */
    ret = qemu_devtree_setprop(fdt, "/memory", "reg", mem_reg_property,
                               sizeof(mem_reg_property));
    if (ret < 0)
        fprintf(stderr, "couldn't set /memory/reg\n");

    if (initrd_size) {
        ret = qemu_devtree_setprop_cell(fdt, "/chosen", "linux,initrd-start",
                                        initrd_base);
        if (ret < 0) {
            fprintf(stderr, "couldn't set /chosen/linux,initrd-start\n");
        }

        ret = qemu_devtree_setprop_cell(fdt, "/chosen", "linux,initrd-end",
                                        (initrd_base + initrd_size));
        if (ret < 0) {
            fprintf(stderr, "couldn't set /chosen/linux,initrd-end\n");
        }
    }

    ret = qemu_devtree_setprop_string(fdt, "/chosen", "bootargs",
                                      kernel_cmdline);
    if (ret < 0)
        fprintf(stderr, "couldn't set /chosen/bootargs\n");

    if (kvm_enabled()) {
        /* Read out host's frequencies */
        clock_freq = kvmppc_get_clockfreq();
        tb_freq = kvmppc_get_tbfreq();

        /* indicate KVM hypercall interface */
        qemu_devtree_setprop_string(fdt, "/hypervisor", "compatible",
                                    "linux,kvm");
        kvmppc_get_hypercall(env, hypercall, sizeof(hypercall));
        qemu_devtree_setprop(fdt, "/hypervisor", "hcall-instructions",
                             hypercall, sizeof(hypercall));
    }

    /* We need to generate the cpu nodes in reverse order, so Linux can pick
       the first node as boot node and be happy */
    for (i = smp_cpus - 1; i >= 0; i--) {
        char cpu_name[128];
        uint64_t cpu_release_addr = cpu_to_be64(MPC8544_SPIN_BASE + (i * 0x20));

        for (env = first_cpu; env != NULL; env = env->next_cpu) {
            if (env->cpu_index == i) {
                break;
            }
        }

        if (!env) {
            continue;
        }

        snprintf(cpu_name, sizeof(cpu_name), "/cpus/PowerPC,8544@%x", env->cpu_index);
        qemu_devtree_add_subnode(fdt, cpu_name);
        qemu_devtree_setprop_cell(fdt, cpu_name, "clock-frequency", clock_freq);
        qemu_devtree_setprop_cell(fdt, cpu_name, "timebase-frequency", tb_freq);
        qemu_devtree_setprop_string(fdt, cpu_name, "device_type", "cpu");
        qemu_devtree_setprop_cell(fdt, cpu_name, "reg", env->cpu_index);
        qemu_devtree_setprop_cell(fdt, cpu_name, "d-cache-line-size",
                                  env->dcache_line_size);
        qemu_devtree_setprop_cell(fdt, cpu_name, "i-cache-line-size",
                                  env->icache_line_size);
        qemu_devtree_setprop_cell(fdt, cpu_name, "d-cache-size", 0x8000);
        qemu_devtree_setprop_cell(fdt, cpu_name, "i-cache-size", 0x8000);
        qemu_devtree_setprop_cell(fdt, cpu_name, "bus-frequency", 0);
        if (env->cpu_index) {
            qemu_devtree_setprop_string(fdt, cpu_name, "status", "disabled");
            qemu_devtree_setprop_string(fdt, cpu_name, "enable-method", "spin-table");
            qemu_devtree_setprop(fdt, cpu_name, "cpu-release-addr",
                                 &cpu_release_addr, sizeof(cpu_release_addr));
        } else {
            qemu_devtree_setprop_string(fdt, cpu_name, "status", "okay");
        }
    }

    ret = rom_add_blob_fixed(BINARY_DEVICE_TREE_FILE, fdt, fdt_size, addr);
    g_free(fdt);

out:
#endif

    return ret;
}
Пример #8
0
static int ppce500_load_device_tree(CPUPPCState *env,
                                    PPCE500Params *params,
                                    hwaddr addr,
                                    hwaddr initrd_base,
                                    hwaddr initrd_size)
{
    int ret = -1;
    uint64_t mem_reg_property[] = { 0, cpu_to_be64(params->ram_size) };
    int fdt_size;
    void *fdt;
    uint8_t hypercall[16];
    uint32_t clock_freq = 400000000;
    uint32_t tb_freq = 400000000;
    int i;
    const char *toplevel_compat = NULL; /* user override */
    char compatible_sb[] = "fsl,mpc8544-immr\0simple-bus";
    char soc[128];
    char mpic[128];
    uint32_t mpic_ph;
    uint32_t msi_ph;
    char gutil[128];
    char pci[128];
    char msi[128];
    uint32_t *pci_map = NULL;
    int len;
    uint32_t pci_ranges[14] =
        {
            0x2000000, 0x0, 0xc0000000,
            0x0, 0xc0000000,
            0x0, 0x20000000,

            0x1000000, 0x0, 0x0,
            0x0, 0xe1000000,
            0x0, 0x10000,
        };
    QemuOpts *machine_opts;
    const char *dtb_file = NULL;

    machine_opts = qemu_opts_find(qemu_find_opts("machine"), 0);
    if (machine_opts) {
        dtb_file = qemu_opt_get(machine_opts, "dtb");
        toplevel_compat = qemu_opt_get(machine_opts, "dt_compatible");
    }

    if (dtb_file) {
        char *filename;
        filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, dtb_file);
        if (!filename) {
            goto out;
        }

        fdt = load_device_tree(filename, &fdt_size);
        if (!fdt) {
            goto out;
        }
        goto done;
    }

    fdt = create_device_tree(&fdt_size);
    if (fdt == NULL) {
        goto out;
    }

    /* Manipulate device tree in memory. */
    qemu_devtree_setprop_cell(fdt, "/", "#address-cells", 2);
    qemu_devtree_setprop_cell(fdt, "/", "#size-cells", 2);

    qemu_devtree_add_subnode(fdt, "/memory");
    qemu_devtree_setprop_string(fdt, "/memory", "device_type", "memory");
    qemu_devtree_setprop(fdt, "/memory", "reg", mem_reg_property,
                         sizeof(mem_reg_property));

    qemu_devtree_add_subnode(fdt, "/chosen");
    if (initrd_size) {
        ret = qemu_devtree_setprop_cell(fdt, "/chosen", "linux,initrd-start",
                                        initrd_base);
        if (ret < 0) {
            fprintf(stderr, "couldn't set /chosen/linux,initrd-start\n");
        }

        ret = qemu_devtree_setprop_cell(fdt, "/chosen", "linux,initrd-end",
                                        (initrd_base + initrd_size));
        if (ret < 0) {
            fprintf(stderr, "couldn't set /chosen/linux,initrd-end\n");
        }
    }

    ret = qemu_devtree_setprop_string(fdt, "/chosen", "bootargs",
                                      params->kernel_cmdline);
    if (ret < 0)
        fprintf(stderr, "couldn't set /chosen/bootargs\n");

    if (kvm_enabled()) {
        /* Read out host's frequencies */
        clock_freq = kvmppc_get_clockfreq();
        tb_freq = kvmppc_get_tbfreq();

        /* indicate KVM hypercall interface */
        qemu_devtree_add_subnode(fdt, "/hypervisor");
        qemu_devtree_setprop_string(fdt, "/hypervisor", "compatible",
                                    "linux,kvm");
        kvmppc_get_hypercall(env, hypercall, sizeof(hypercall));
        qemu_devtree_setprop(fdt, "/hypervisor", "hcall-instructions",
                             hypercall, sizeof(hypercall));
    }

    /* Create CPU nodes */
    qemu_devtree_add_subnode(fdt, "/cpus");
    qemu_devtree_setprop_cell(fdt, "/cpus", "#address-cells", 1);
    qemu_devtree_setprop_cell(fdt, "/cpus", "#size-cells", 0);

    /* We need to generate the cpu nodes in reverse order, so Linux can pick
       the first node as boot node and be happy */
    for (i = smp_cpus - 1; i >= 0; i--) {
        char cpu_name[128];
        uint64_t cpu_release_addr = MPC8544_SPIN_BASE + (i * 0x20);

        for (env = first_cpu; env != NULL; env = env->next_cpu) {
            if (env->cpu_index == i) {
                break;
            }
        }

        if (!env) {
            continue;
        }

        snprintf(cpu_name, sizeof(cpu_name), "/cpus/PowerPC,8544@%x", env->cpu_index);
        qemu_devtree_add_subnode(fdt, cpu_name);
        qemu_devtree_setprop_cell(fdt, cpu_name, "clock-frequency", clock_freq);
        qemu_devtree_setprop_cell(fdt, cpu_name, "timebase-frequency", tb_freq);
        qemu_devtree_setprop_string(fdt, cpu_name, "device_type", "cpu");
        qemu_devtree_setprop_cell(fdt, cpu_name, "reg", env->cpu_index);
        qemu_devtree_setprop_cell(fdt, cpu_name, "d-cache-line-size",
                                  env->dcache_line_size);
        qemu_devtree_setprop_cell(fdt, cpu_name, "i-cache-line-size",
                                  env->icache_line_size);
        qemu_devtree_setprop_cell(fdt, cpu_name, "d-cache-size", 0x8000);
        qemu_devtree_setprop_cell(fdt, cpu_name, "i-cache-size", 0x8000);
        qemu_devtree_setprop_cell(fdt, cpu_name, "bus-frequency", 0);
        if (env->cpu_index) {
            qemu_devtree_setprop_string(fdt, cpu_name, "status", "disabled");
            qemu_devtree_setprop_string(fdt, cpu_name, "enable-method", "spin-table");
            qemu_devtree_setprop_u64(fdt, cpu_name, "cpu-release-addr",
                                     cpu_release_addr);
        } else {
            qemu_devtree_setprop_string(fdt, cpu_name, "status", "okay");
        }
    }

    qemu_devtree_add_subnode(fdt, "/aliases");
    /* XXX These should go into their respective devices' code */
    snprintf(soc, sizeof(soc), "/soc@%llx", MPC8544_CCSRBAR_BASE);
    qemu_devtree_add_subnode(fdt, soc);
    qemu_devtree_setprop_string(fdt, soc, "device_type", "soc");
    qemu_devtree_setprop(fdt, soc, "compatible", compatible_sb,
                         sizeof(compatible_sb));
    qemu_devtree_setprop_cell(fdt, soc, "#address-cells", 1);
    qemu_devtree_setprop_cell(fdt, soc, "#size-cells", 1);
    qemu_devtree_setprop_cells(fdt, soc, "ranges", 0x0,
                               MPC8544_CCSRBAR_BASE >> 32, MPC8544_CCSRBAR_BASE,
                               MPC8544_CCSRBAR_SIZE);
    /* XXX should contain a reasonable value */
    qemu_devtree_setprop_cell(fdt, soc, "bus-frequency", 0);

    snprintf(mpic, sizeof(mpic), "%s/pic@%llx", soc, MPC8544_MPIC_REGS_OFFSET);
    qemu_devtree_add_subnode(fdt, mpic);
    qemu_devtree_setprop_string(fdt, mpic, "device_type", "open-pic");
    qemu_devtree_setprop_string(fdt, mpic, "compatible", "chrp,open-pic");
    qemu_devtree_setprop_cells(fdt, mpic, "reg", MPC8544_MPIC_REGS_OFFSET,
                               0x40000);
    qemu_devtree_setprop_cell(fdt, mpic, "#address-cells", 0);
    qemu_devtree_setprop_cell(fdt, mpic, "#interrupt-cells", 2);
    mpic_ph = qemu_devtree_alloc_phandle(fdt);
    qemu_devtree_setprop_cell(fdt, mpic, "phandle", mpic_ph);
    qemu_devtree_setprop_cell(fdt, mpic, "linux,phandle", mpic_ph);
    qemu_devtree_setprop(fdt, mpic, "interrupt-controller", NULL, 0);

    /*
     * We have to generate ser1 first, because Linux takes the first
     * device it finds in the dt as serial output device. And we generate
     * devices in reverse order to the dt.
     */
    dt_serial_create(fdt, MPC8544_SERIAL1_REGS_OFFSET,
                     soc, mpic, "serial1", 1, false);
    dt_serial_create(fdt, MPC8544_SERIAL0_REGS_OFFSET,
                     soc, mpic, "serial0", 0, true);

    snprintf(gutil, sizeof(gutil), "%s/global-utilities@%llx", soc,
             MPC8544_UTIL_OFFSET);
    qemu_devtree_add_subnode(fdt, gutil);
    qemu_devtree_setprop_string(fdt, gutil, "compatible", "fsl,mpc8544-guts");
    qemu_devtree_setprop_cells(fdt, gutil, "reg", MPC8544_UTIL_OFFSET, 0x1000);
    qemu_devtree_setprop(fdt, gutil, "fsl,has-rstcr", NULL, 0);

    snprintf(msi, sizeof(msi), "/%s/msi@%llx", soc, MPC8544_MSI_REGS_OFFSET);
    qemu_devtree_add_subnode(fdt, msi);
    qemu_devtree_setprop_string(fdt, msi, "compatible", "fsl,mpic-msi");
    qemu_devtree_setprop_cells(fdt, msi, "reg", MPC8544_MSI_REGS_OFFSET, 0x200);
    msi_ph = qemu_devtree_alloc_phandle(fdt);
    qemu_devtree_setprop_cells(fdt, msi, "msi-available-ranges", 0x0, 0x100);
    qemu_devtree_setprop_phandle(fdt, msi, "interrupt-parent", mpic);
    qemu_devtree_setprop_cells(fdt, msi, "interrupts",
        0xe0, 0x0,
        0xe1, 0x0,
        0xe2, 0x0,
        0xe3, 0x0,
        0xe4, 0x0,
        0xe5, 0x0,
        0xe6, 0x0,
        0xe7, 0x0);
    qemu_devtree_setprop_cell(fdt, msi, "phandle", msi_ph);
    qemu_devtree_setprop_cell(fdt, msi, "linux,phandle", msi_ph);

    snprintf(pci, sizeof(pci), "/pci@%llx", MPC8544_PCI_REGS_BASE);
    qemu_devtree_add_subnode(fdt, pci);
    qemu_devtree_setprop_cell(fdt, pci, "cell-index", 0);
    qemu_devtree_setprop_string(fdt, pci, "compatible", "fsl,mpc8540-pci");
    qemu_devtree_setprop_string(fdt, pci, "device_type", "pci");
    qemu_devtree_setprop_cells(fdt, pci, "interrupt-map-mask", 0xf800, 0x0,
                               0x0, 0x7);
    pci_map = pci_map_create(fdt, qemu_devtree_get_phandle(fdt, mpic),
                             params->pci_first_slot, params->pci_nr_slots,
                             &len);
    qemu_devtree_setprop(fdt, pci, "interrupt-map", pci_map, len);
    qemu_devtree_setprop_phandle(fdt, pci, "interrupt-parent", mpic);
    qemu_devtree_setprop_cells(fdt, pci, "interrupts", 24, 2);
    qemu_devtree_setprop_cells(fdt, pci, "bus-range", 0, 255);
    for (i = 0; i < 14; i++) {
        pci_ranges[i] = cpu_to_be32(pci_ranges[i]);
    }
    qemu_devtree_setprop_cell(fdt, pci, "fsl,msi", msi_ph);
    qemu_devtree_setprop(fdt, pci, "ranges", pci_ranges, sizeof(pci_ranges));
    qemu_devtree_setprop_cells(fdt, pci, "reg", MPC8544_PCI_REGS_BASE >> 32,
                               MPC8544_PCI_REGS_BASE, 0, 0x1000);
    qemu_devtree_setprop_cell(fdt, pci, "clock-frequency", 66666666);
    qemu_devtree_setprop_cell(fdt, pci, "#interrupt-cells", 1);
    qemu_devtree_setprop_cell(fdt, pci, "#size-cells", 2);
    qemu_devtree_setprop_cell(fdt, pci, "#address-cells", 3);
    qemu_devtree_setprop_string(fdt, "/aliases", "pci0", pci);

    params->fixup_devtree(params, fdt);

    if (toplevel_compat) {
        qemu_devtree_setprop(fdt, "/", "compatible", toplevel_compat,
                             strlen(toplevel_compat) + 1);
    }

done:
    qemu_devtree_dumpdtb(fdt, fdt_size);
    ret = rom_add_blob_fixed(BINARY_DEVICE_TREE_FILE, fdt, fdt_size, addr);
    if (ret < 0) {
        goto out;
    }
    g_free(fdt);
    ret = fdt_size;

out:
    g_free(pci_map);

    return ret;
}
Пример #9
0
static int mpc8544_load_device_tree(target_phys_addr_t addr,
                                     uint32_t ramsize,
                                     target_phys_addr_t initrd_base,
                                     target_phys_addr_t initrd_size,
                                     const char *kernel_cmdline)
{
    int ret = -1;
#ifdef CONFIG_FDT
    uint32_t mem_reg_property[] = {0, ramsize};
    char *filename;
    int fdt_size;
    void *fdt;

    filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, BINARY_DEVICE_TREE_FILE);
    if (!filename) {
        goto out;
    }
    fdt = load_device_tree(filename, &fdt_size);
    qemu_free(filename);
    if (fdt == NULL) {
        goto out;
    }

    /* Manipulate device tree in memory. */
    ret = qemu_devtree_setprop(fdt, "/memory", "reg", mem_reg_property,
                               sizeof(mem_reg_property));
    if (ret < 0)
        fprintf(stderr, "couldn't set /memory/reg\n");

    ret = qemu_devtree_setprop_cell(fdt, "/chosen", "linux,initrd-start",
                                    initrd_base);
    if (ret < 0)
        fprintf(stderr, "couldn't set /chosen/linux,initrd-start\n");

    ret = qemu_devtree_setprop_cell(fdt, "/chosen", "linux,initrd-end",
                                    (initrd_base + initrd_size));
    if (ret < 0)
        fprintf(stderr, "couldn't set /chosen/linux,initrd-end\n");

    ret = qemu_devtree_setprop_string(fdt, "/chosen", "bootargs",
                                      kernel_cmdline);
    if (ret < 0)
        fprintf(stderr, "couldn't set /chosen/bootargs\n");

    if (kvm_enabled()) {
        struct dirent *dirp;
        DIR *dp;
        char buf[128];

        if ((dp = opendir("/proc/device-tree/cpus/")) == NULL) {
            printf("Can't open directory /proc/device-tree/cpus/\n");
            ret = -1;
            goto out;
        }

        buf[0] = '\0';
        while ((dirp = readdir(dp)) != NULL) {
            if (strncmp(dirp->d_name, "PowerPC", 7) == 0) {
                snprintf(buf, 128, "/cpus/%s", dirp->d_name);
                break;
            }
        }
        closedir(dp);
        if (buf[0] == '\0') {
            printf("Unknow host!\n");
            ret = -1;
            goto out;
        }

        mpc8544_copy_soc_cell(fdt, buf, "clock-frequency");
        mpc8544_copy_soc_cell(fdt, buf, "timebase-frequency");
    }

    ret = rom_add_blob_fixed(BINARY_DEVICE_TREE_FILE, fdt, fdt_size, addr);
    qemu_free(fdt);

out:
#endif

    return ret;
}
Пример #10
0
static int bamboo_load_device_tree(hwaddr addr,
                                     uint32_t ramsize,
                                     hwaddr initrd_base,
                                     hwaddr initrd_size,
                                     const char *kernel_cmdline)
{
    int ret = -1;
    uint32_t mem_reg_property[] = { 0, 0, cpu_to_be32(ramsize) };
    char *filename;
    int fdt_size;
    void *fdt;
    uint32_t tb_freq = 400000000;
    uint32_t clock_freq = 400000000;

    filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, BINARY_DEVICE_TREE_FILE);
    if (!filename) {
        goto out;
    }
    fdt = load_device_tree(filename, &fdt_size);
    g_free(filename);
    if (fdt == NULL) {
        goto out;
    }

    /* Manipulate device tree in memory. */

    ret = qemu_devtree_setprop(fdt, "/memory", "reg", mem_reg_property,
                               sizeof(mem_reg_property));
    if (ret < 0)
        fprintf(stderr, "couldn't set /memory/reg\n");

    ret = qemu_devtree_setprop_cell(fdt, "/chosen", "linux,initrd-start",
                                    initrd_base);
    if (ret < 0)
        fprintf(stderr, "couldn't set /chosen/linux,initrd-start\n");

    ret = qemu_devtree_setprop_cell(fdt, "/chosen", "linux,initrd-end",
                                    (initrd_base + initrd_size));
    if (ret < 0)
        fprintf(stderr, "couldn't set /chosen/linux,initrd-end\n");

    ret = qemu_devtree_setprop_string(fdt, "/chosen", "bootargs",
                                      kernel_cmdline);
    if (ret < 0)
        fprintf(stderr, "couldn't set /chosen/bootargs\n");

    /* Copy data from the host device tree into the guest. Since the guest can
     * directly access the timebase without host involvement, we must expose
     * the correct frequencies. */
    if (kvm_enabled()) {
        tb_freq = kvmppc_get_tbfreq();
        clock_freq = kvmppc_get_clockfreq();
    }

    qemu_devtree_setprop_cell(fdt, "/cpus/cpu@0", "clock-frequency",
                              clock_freq);
    qemu_devtree_setprop_cell(fdt, "/cpus/cpu@0", "timebase-frequency",
                              tb_freq);

    rom_add_blob_fixed(BINARY_DEVICE_TREE_FILE, fdt, fdt_size, addr);
    g_free(fdt);
    return 0;

out:

    return ret;
}
Пример #11
0
static void fdt_init_node(void *args)
{

    struct FDTInitNodeArgs *a = args;
    char *node_path = a->node_path;
    FDTMachineInfo *fdti = a->fdti;
    g_free(a);

    char *all_compats = NULL, *compat, *node_name, *next_compat;
    int compat_len;

#ifdef FDT_GENERIC_UTIL_ERR_DEBUG
    static int entry_index;
    int this_entry = entry_index++;
#endif
    DB_PRINT("enter %d %s\n", this_entry, node_path);

    /* try instance binding first */
    node_name = qemu_devtree_get_node_name(fdti->fdt, node_path);
    if (!node_name) {
        fprintf(stderr, "FDT: ERROR: nameless node: %s\n", node_path);
    }
    if (!fdt_init_inst_bind(node_path, fdti, node_name)) {
        goto exit;
    }

    /* fallback to compatibility binding */
    all_compats = qemu_devtree_getprop(fdti->fdt, node_path,
        "compatible", &compat_len, false, NULL);
    if (!all_compats) {
        fprintf(stderr, "FDT: ERROR: no compatibility found for node %s/%s\n", node_path,
            node_name);
        DB_PRINT("exit %d\n", this_entry);
        fdti->routinesPending--;
        return;
    }
    compat = all_compats;

try_next_compat:
    if (compat_len == 0) {
        goto invalidate;
    }
    if (!fdt_init_compat(node_path, fdti, compat)) {
        goto exit;
    }
    if (!fdt_init_qdev(node_path, fdti, compat)) {
        goto exit;
    }
    next_compat = rawmemchr(compat, '\0');
    compat_len -= (next_compat + 1 - compat);
    if (compat_len > 0) {
        *next_compat = ' ';
    }
    compat = next_compat+1;
    goto try_next_compat;
invalidate:
    fprintf(stderr, "FDT: Unsupported peripheral invalidated %s compatibilities %s\n",
        node_name, all_compats);
    qemu_devtree_setprop_string(fdti->fdt, node_path, "compatible",
        "invalidated");
exit:

    DB_PRINT("exit %d\n", this_entry);

    if (!fdt_init_has_opaque(fdti, node_path)) {
        fdt_init_set_opaque(fdti, node_path, NULL);
    }
    g_free(node_path);
    g_free(all_compats);
    fdti->routinesPending--;
    return;
}