Commit 549c272b authored by Anthony Liguori's avatar Anthony Liguori
Browse files

Merge remote-tracking branch 'pmaydell/tags/pull-arm-devs-20130722' into staging



arm-devs queue

# gpg: Signature made Mon 22 Jul 2013 06:38:52 AM CDT using RSA key ID 14360CDE
# gpg: Can't check signature: public key not found

# By Peter Maydell (8) and Soren Brinkmann (2)
# Via Peter Maydell
* pmaydell/tags/pull-arm-devs-20130722:
  hw/arm: Use 'load_ramdisk()' for loading ramdisks w/ U-Boot header
  hw/loader: Support ramdisk with u-boot header
  vexpress: Add virtio-mmio transports
  vexpress: Make VEDBoardInfo extend arm_boot_info
  arm/boot: Allow boards to modify the FDT blob
  virtio: Implement MMIO based virtio transport
  virtio: Support transports which can specify the vring alignment
  virtio: Add support for guest setting of queue size
  arm/boot: Use qemu_devtree_setprop_sized_cells()
  device_tree: Add qemu_devtree_setprop_sized_cells() utility functions

Message-id: 1374493427-3254-1-git-send-email-peter.maydell@linaro.org
Signed-off-by: default avatarAnthony Liguori <aliguori@us.ibm.com>
parents c9fea5d7 fd76663e
Loading
Loading
Loading
Loading
+33 −0
Original line number Diff line number Diff line
@@ -308,3 +308,36 @@ void qemu_devtree_dumpdtb(void *fdt, int size)
        exit(g_file_set_contents(dumpdtb, fdt, size, NULL) ? 0 : 1);
    }
}

int qemu_devtree_setprop_sized_cells_from_array(void *fdt,
                                                const char *node_path,
                                                const char *property,
                                                int numvalues,
                                                uint64_t *values)
{
    uint32_t *propcells;
    uint64_t value;
    int cellnum, vnum, ncells;
    uint32_t hival;

    propcells = g_new0(uint32_t, numvalues * 2);

    cellnum = 0;
    for (vnum = 0; vnum < numvalues; vnum++) {
        ncells = values[vnum * 2];
        if (ncells != 1 && ncells != 2) {
            return -1;
        }
        value = values[vnum * 2 + 1];
        hival = cpu_to_be32(value >> 32);
        if (ncells > 1) {
            propcells[cellnum++] = hival;
        } else if (hival != 0) {
            return -1;
        }
        propcells[cellnum++] = cpu_to_be32(value);
    }

    return qemu_devtree_setprop(fdt, node_path, property, propcells,
                                cellnum * sizeof(uint32_t));
}
+23 −25
Original line number Diff line number Diff line
@@ -227,12 +227,10 @@ static void set_kernel_args_old(const struct arm_boot_info *info)

static int load_dtb(hwaddr addr, const struct arm_boot_info *binfo)
{
    uint32_t *mem_reg_property;
    uint32_t mem_reg_propsize;
    void *fdt = NULL;
    char *filename;
    int size, rc;
    uint32_t acells, scells, hival;
    uint32_t acells, scells;

    filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, binfo->dtb_filename);
    if (!filename) {
@@ -255,29 +253,18 @@ static int load_dtb(hwaddr addr, const struct arm_boot_info *binfo)
        goto fail;
    }

    mem_reg_propsize = acells + scells;
    mem_reg_property = g_new0(uint32_t, mem_reg_propsize);
    mem_reg_property[acells - 1] = cpu_to_be32(binfo->loader_start);
    hival = cpu_to_be32(binfo->loader_start >> 32);
    if (acells > 1) {
        mem_reg_property[acells - 2] = hival;
    } else if (hival != 0) {
        fprintf(stderr, "qemu: dtb file not compatible with "
                "RAM start address > 4GB\n");
        goto fail;
    }
    mem_reg_property[acells + scells - 1] = cpu_to_be32(binfo->ram_size);
    hival = cpu_to_be32(binfo->ram_size >> 32);
    if (scells > 1) {
        mem_reg_property[acells + scells - 2] = hival;
    } else if (hival != 0) {
    if (scells < 2 && binfo->ram_size >= (1ULL << 32)) {
        /* This is user error so deserves a friendlier error message
         * than the failure of setprop_sized_cells would provide
         */
        fprintf(stderr, "qemu: dtb file not compatible with "
                "RAM size > 4GB\n");
        goto fail;
    }

    rc = qemu_devtree_setprop(fdt, "/memory", "reg", mem_reg_property,
                              mem_reg_propsize * sizeof(uint32_t));
    rc = qemu_devtree_setprop_sized_cells(fdt, "/memory", "reg",
                                          acells, binfo->loader_start,
                                          scells, binfo->ram_size);
    if (rc < 0) {
        fprintf(stderr, "couldn't set /memory/reg\n");
        goto fail;
@@ -307,6 +294,11 @@ static int load_dtb(hwaddr addr, const struct arm_boot_info *binfo)
            goto fail;
        }
    }

    if (binfo->modify_dtb) {
        binfo->modify_dtb(binfo, fdt);
    }

    qemu_devtree_dumpdtb(fdt, size);

    cpu_physical_memory_write(addr, fdt, size);
@@ -419,10 +411,16 @@ void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info)
    info->entry = entry;
    if (is_linux) {
        if (info->initrd_filename) {
            initrd_size = load_ramdisk(info->initrd_filename,
                                       info->initrd_start,
                                       info->ram_size -
                                       info->initrd_start);
            if (initrd_size < 0) {
                initrd_size = load_image_targphys(info->initrd_filename,
                                                  info->initrd_start,
                                                  info->ram_size -
                                                  info->initrd_start);
            }
            if (initrd_size < 0) {
                fprintf(stderr, "qemu: could not load initrd '%s'\n",
                        info->initrd_filename);
+113 −15
Original line number Diff line number Diff line
@@ -31,12 +31,17 @@
#include "exec/address-spaces.h"
#include "sysemu/blockdev.h"
#include "hw/block/flash.h"
#include "sysemu/device_tree.h"
#include <libfdt.h>

#define VEXPRESS_BOARD_ID 0x8e0
#define VEXPRESS_FLASH_SIZE (64 * 1024 * 1024)
#define VEXPRESS_FLASH_SECT_SIZE (256 * 1024)

static struct arm_boot_info vexpress_binfo;
/* Number of virtio transports to create (0..8; limited by
 * number of available IRQ lines).
 */
#define NUM_VIRTIO_TRANSPORTS 4

/* Address maps for peripherals:
 * the Versatile Express motherboard has two possible maps,
@@ -73,6 +78,7 @@ enum {
    VE_ETHERNET,
    VE_USB,
    VE_DAPROM,
    VE_VIRTIO,
};

static hwaddr motherboard_legacy_map[] = {
@@ -91,6 +97,7 @@ static hwaddr motherboard_legacy_map[] = {
    [VE_WDT] = 0x1000f000,
    [VE_TIMER01] = 0x10011000,
    [VE_TIMER23] = 0x10012000,
    [VE_VIRTIO] = 0x10013000,
    [VE_SERIALDVI] = 0x10016000,
    [VE_RTC] = 0x10017000,
    [VE_COMPACTFLASH] = 0x1001a000,
@@ -137,6 +144,7 @@ static hwaddr motherboard_aseries_map[] = {
    [VE_WDT] = 0x1c0f0000,
    [VE_TIMER01] = 0x1c110000,
    [VE_TIMER23] = 0x1c120000,
    [VE_VIRTIO] = 0x1c130000,
    [VE_SERIALDVI] = 0x1c160000,
    [VE_RTC] = 0x1c170000,
    [VE_COMPACTFLASH] = 0x1c1a0000,
@@ -153,6 +161,7 @@ typedef void DBoardInitFn(const VEDBoardInfo *daughterboard,
                          qemu_irq *pic);

struct VEDBoardInfo {
    struct arm_boot_info bootinfo;
    const hwaddr *motherboard_map;
    hwaddr loader_start;
    const hwaddr gic_cpu_if_addr;
@@ -272,7 +281,7 @@ static const uint32_t a9_clocks[] = {
    66670000, /* Test chip reference clock: 66.67MHz */
};

static const VEDBoardInfo a9_daughterboard = {
static VEDBoardInfo a9_daughterboard = {
    .motherboard_map = motherboard_legacy_map,
    .loader_start = 0x60000000,
    .gic_cpu_if_addr = 0x1e000100,
@@ -384,7 +393,7 @@ static const uint32_t a15_clocks[] = {
    40000000, /* OSCCLK8: 40MHz : DDR2 PLL reference */
};

static const VEDBoardInfo a15_daughterboard = {
static VEDBoardInfo a15_daughterboard = {
    .motherboard_map = motherboard_aseries_map,
    .loader_start = 0x80000000,
    .gic_cpu_if_addr = 0x2c002000,
@@ -396,7 +405,86 @@ static const VEDBoardInfo a15_daughterboard = {
    .init = a15_daughterboard_init,
};

static void vexpress_common_init(const VEDBoardInfo *daughterboard,
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 uint32_t find_int_controller(void *fdt)
{
    /* Find the FDT node corresponding to the interrupt controller
     * for virtio-mmio devices. We do this by scanning the fdt for
     * a node with the right compatibility, since we know there is
     * only one GIC on a vexpress board.
     * We return the phandle of the node, or 0 if none was found.
     */
    const char *compat = "arm,cortex-a9-gic";
    int offset;

    offset = fdt_node_offset_by_compatible(fdt, -1, compat);
    if (offset >= 0) {
        return fdt_get_phandle(fdt, offset);
    }
    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_devtree_getprop_cell(fdt, "/", "#address-cells");
    scells = qemu_devtree_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 void vexpress_common_init(VEDBoardInfo *daughterboard,
                                 QEMUMachineInitArgs *args)
{
    DeviceState *dev, *sysctl, *pl041;
@@ -524,17 +612,27 @@ static void vexpress_common_init(const VEDBoardInfo *daughterboard,

    /* VE_DAPROM: not modelled */

    vexpress_binfo.ram_size = args->ram_size;
    vexpress_binfo.kernel_filename = args->kernel_filename;
    vexpress_binfo.kernel_cmdline = args->kernel_cmdline;
    vexpress_binfo.initrd_filename = args->initrd_filename;
    vexpress_binfo.nb_cpus = smp_cpus;
    vexpress_binfo.board_id = VEXPRESS_BOARD_ID;
    vexpress_binfo.loader_start = daughterboard->loader_start;
    vexpress_binfo.smp_loader_start = map[VE_SRAM];
    vexpress_binfo.smp_bootreg_addr = map[VE_SYSREGS] + 0x30;
    vexpress_binfo.gic_cpu_if_addr = daughterboard->gic_cpu_if_addr;
    arm_load_kernel(ARM_CPU(first_cpu), &vexpress_binfo);
    /* Create mmio transports, so the user can create virtio backends
     * (which will be automatically plugged in to the transports). If
     * no backend is created the transport will just sit harmlessly idle.
     */
    for (i = 0; i < NUM_VIRTIO_TRANSPORTS; i++) {
        sysbus_create_simple("virtio-mmio", map[VE_VIRTIO] + 0x200 * i,
                             pic[40 + i]);
    }

    daughterboard->bootinfo.ram_size = args->ram_size;
    daughterboard->bootinfo.kernel_filename = args->kernel_filename;
    daughterboard->bootinfo.kernel_cmdline = args->kernel_cmdline;
    daughterboard->bootinfo.initrd_filename = args->initrd_filename;
    daughterboard->bootinfo.nb_cpus = smp_cpus;
    daughterboard->bootinfo.board_id = VEXPRESS_BOARD_ID;
    daughterboard->bootinfo.loader_start = daughterboard->loader_start;
    daughterboard->bootinfo.smp_loader_start = map[VE_SRAM];
    daughterboard->bootinfo.smp_bootreg_addr = map[VE_SYSREGS] + 0x30;
    daughterboard->bootinfo.gic_cpu_if_addr = daughterboard->gic_cpu_if_addr;
    daughterboard->bootinfo.modify_dtb = vexpress_modify_dtb;
    arm_load_kernel(ARM_CPU(first_cpu), &daughterboard->bootinfo);
}

static void vexpress_a9_init(QEMUMachineInitArgs *args)
+59 −25
Original line number Diff line number Diff line
@@ -434,15 +434,17 @@ static ssize_t gunzip(void *dst, size_t dstlen, uint8_t *src,
}

/* Load a U-Boot image.  */
int load_uimage(const char *filename, hwaddr *ep,
                hwaddr *loadaddr, int *is_linux)
static int load_uboot_image(const char *filename, hwaddr *ep, hwaddr *loadaddr,
                            int *is_linux, uint8_t image_type)
{
    int fd;
    int size;
    hwaddr address;
    uboot_image_header_t h;
    uboot_image_header_t *hdr = &h;
    uint8_t *data = NULL;
    int ret = -1;
    int do_uncompress = 0;

    fd = open(filename, O_RDONLY | O_BINARY);
    if (fd < 0)
@@ -457,15 +459,25 @@ int load_uimage(const char *filename, hwaddr *ep,
    if (hdr->ih_magic != IH_MAGIC)
        goto out;

    /* TODO: Implement other image types.  */
    if (hdr->ih_type != IH_TYPE_KERNEL) {
        fprintf(stderr, "Can only load u-boot image type \"kernel\"\n");
    if (hdr->ih_type != image_type) {
        fprintf(stderr, "Wrong image type %d, expected %d\n", hdr->ih_type,
                image_type);
        goto out;
    }

    /* TODO: Implement other image types.  */
    switch (hdr->ih_type) {
    case IH_TYPE_KERNEL:
        address = hdr->ih_load;
        if (loadaddr) {
            *loadaddr = hdr->ih_load;
        }

        switch (hdr->ih_comp) {
        case IH_COMP_NONE:
            break;
        case IH_COMP_GZIP:
            do_uncompress = 1;
            break;
        default:
            fprintf(stderr,
@@ -474,15 +486,28 @@ int load_uimage(const char *filename, hwaddr *ep,
            goto out;
        }

        if (ep) {
            *ep = hdr->ih_ep;
        }

        /* TODO: Check CPU type.  */
        if (is_linux) {
        if (hdr->ih_os == IH_OS_LINUX)
            if (hdr->ih_os == IH_OS_LINUX) {
                *is_linux = 1;
        else
            } else {
                *is_linux = 0;
            }
        }

        break;
    case IH_TYPE_RAMDISK:
        address = *loadaddr;
        break;
    default:
        fprintf(stderr, "Unsupported u-boot image type %d\n", hdr->ih_type);
        goto out;
    }

    *ep = hdr->ih_ep;
    data = g_malloc(hdr->ih_size);

    if (read(fd, data, hdr->ih_size) != hdr->ih_size) {
@@ -490,7 +515,7 @@ int load_uimage(const char *filename, hwaddr *ep,
        goto out;
    }

    if (hdr->ih_comp == IH_COMP_GZIP) {
    if (do_uncompress) {
        uint8_t *compressed_data;
        size_t max_bytes;
        ssize_t bytes;
@@ -508,10 +533,7 @@ int load_uimage(const char *filename, hwaddr *ep,
        hdr->ih_size = bytes;
    }

    rom_add_blob_fixed(filename, data, hdr->ih_size, hdr->ih_load);

    if (loadaddr)
        *loadaddr = hdr->ih_load;
    rom_add_blob_fixed(filename, data, hdr->ih_size, address);

    ret = hdr->ih_size;

@@ -522,6 +544,18 @@ out:
    return ret;
}

int load_uimage(const char *filename, hwaddr *ep, hwaddr *loadaddr,
                int *is_linux)
{
    return load_uboot_image(filename, ep, loadaddr, is_linux, IH_TYPE_KERNEL);
}

/* Load a ramdisk.  */
int load_ramdisk(const char *filename, hwaddr addr, uint64_t max_sz)
{
    return load_uboot_image(filename, NULL, &addr, NULL, IH_TYPE_RAMDISK);
}

/*
 * Functions for reboot-persistent memory regions.
 *  - used for vga bios and option roms.
+1 −0
Original line number Diff line number Diff line
common-obj-y += virtio-rng.o
common-obj-$(CONFIG_VIRTIO_PCI) += virtio-pci.o
common-obj-y += virtio-bus.o
common-obj-y += virtio-mmio.o
common-obj-$(CONFIG_VIRTIO_BLK_DATA_PLANE) += dataplane/

obj-y += virtio.o virtio-balloon.o 
Loading