diff options
Diffstat (limited to 'hw')
-rw-r--r-- | hw/arm/armv7m.c | 8 | ||||
-rw-r--r-- | hw/arm/boot.c | 7 | ||||
-rw-r--r-- | hw/arm/stellaris.c | 3 | ||||
-rw-r--r-- | hw/arm/virt.c | 31 | ||||
-rw-r--r-- | hw/core/loader.c | 48 |
5 files changed, 86 insertions, 11 deletions
diff --git a/hw/arm/armv7m.c b/hw/arm/armv7m.c index 397e8dfb37..aedef13002 100644 --- a/hw/arm/armv7m.c +++ b/hw/arm/armv7m.c @@ -166,7 +166,7 @@ static void armv7m_reset(void *opaque) flash_size and sram_size are in kb. Returns the NVIC array. */ -qemu_irq *armv7m_init(MemoryRegion *address_space_mem, +qemu_irq *armv7m_init(MemoryRegion *system_memory, int flash_size, int sram_size, const char *kernel_filename, const char *cpu_model) { @@ -213,10 +213,10 @@ qemu_irq *armv7m_init(MemoryRegion *address_space_mem, memory_region_init_ram(flash, NULL, "armv7m.flash", flash_size); vmstate_register_ram_global(flash); memory_region_set_readonly(flash, true); - memory_region_add_subregion(address_space_mem, 0, flash); + memory_region_add_subregion(system_memory, 0, flash); memory_region_init_ram(sram, NULL, "armv7m.sram", sram_size); vmstate_register_ram_global(sram); - memory_region_add_subregion(address_space_mem, 0x20000000, sram); + memory_region_add_subregion(system_memory, 0x20000000, sram); armv7m_bitband_init(); nvic = qdev_create(NULL, "armv7m_nvic"); @@ -257,7 +257,7 @@ qemu_irq *armv7m_init(MemoryRegion *address_space_mem, when returning from an exception. */ memory_region_init_ram(hack, NULL, "armv7m.hack", 0x1000); vmstate_register_ram_global(hack); - memory_region_add_subregion(address_space_mem, 0xfffff000, hack); + memory_region_add_subregion(system_memory, 0xfffff000, hack); qemu_register_reset(armv7m_reset, cpu); return pic; diff --git a/hw/arm/boot.c b/hw/arm/boot.c index 12417617a3..e32f2f4158 100644 --- a/hw/arm/boot.c +++ b/hw/arm/boot.c @@ -514,6 +514,13 @@ void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info) kernel_size = load_uimage(info->kernel_filename, &entry, NULL, &is_linux); } + /* On aarch64, it's the bootloader's job to uncompress the kernel. */ + if (arm_feature(&cpu->env, ARM_FEATURE_AARCH64) && kernel_size < 0) { + entry = info->loader_start + kernel_load_offset; + kernel_size = load_image_gzipped(info->kernel_filename, entry, + info->ram_size - kernel_load_offset); + is_linux = 1; + } if (kernel_size < 0) { entry = info->loader_start + kernel_load_offset; kernel_size = load_image_targphys(info->kernel_filename, entry, diff --git a/hw/arm/stellaris.c b/hw/arm/stellaris.c index 80028e80cf..64bd4b4c4b 100644 --- a/hw/arm/stellaris.c +++ b/hw/arm/stellaris.c @@ -1208,7 +1208,6 @@ static void stellaris_init(const char *kernel_filename, const char *cpu_model, 0x40024000, 0x40025000, 0x40026000}; static const int gpio_irq[7] = {0, 1, 2, 3, 4, 30, 31}; - MemoryRegion *address_space_mem = get_system_memory(); qemu_irq *pic; DeviceState *gpio_dev[7]; qemu_irq gpio_in[7][8]; @@ -1223,7 +1222,7 @@ static void stellaris_init(const char *kernel_filename, const char *cpu_model, flash_size = ((board->dc0 & 0xffff) + 1) << 1; sram_size = (board->dc0 >> 18) + 1; - pic = armv7m_init(address_space_mem, + pic = armv7m_init(get_system_memory(), flash_size, sram_size, kernel_filename, cpu_model); if (board->dc1 & (1 << 16)) { diff --git a/hw/arm/virt.c b/hw/arm/virt.c index ba94298555..bd206a019a 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -194,20 +194,41 @@ static void fdt_add_psci_node(const VirtBoardInfo *vbi) /* No PSCI for TCG yet */ if (kvm_enabled()) { + uint32_t cpu_suspend_fn; + uint32_t cpu_off_fn; + uint32_t cpu_on_fn; + uint32_t migrate_fn; + qemu_fdt_add_subnode(fdt, "/psci"); if (armcpu->psci_version == 2) { const char comp[] = "arm,psci-0.2\0arm,psci"; qemu_fdt_setprop(fdt, "/psci", "compatible", comp, sizeof(comp)); + + cpu_off_fn = QEMU_PSCI_0_2_FN_CPU_OFF; + if (arm_feature(&armcpu->env, ARM_FEATURE_AARCH64)) { + cpu_suspend_fn = QEMU_PSCI_0_2_FN64_CPU_SUSPEND; + cpu_on_fn = QEMU_PSCI_0_2_FN64_CPU_ON; + migrate_fn = QEMU_PSCI_0_2_FN64_MIGRATE; + } else { + cpu_suspend_fn = QEMU_PSCI_0_2_FN_CPU_SUSPEND; + cpu_on_fn = QEMU_PSCI_0_2_FN_CPU_ON; + migrate_fn = QEMU_PSCI_0_2_FN_MIGRATE; + } } else { qemu_fdt_setprop_string(fdt, "/psci", "compatible", "arm,psci"); + + cpu_suspend_fn = QEMU_PSCI_0_1_FN_CPU_SUSPEND; + cpu_off_fn = QEMU_PSCI_0_1_FN_CPU_OFF; + cpu_on_fn = QEMU_PSCI_0_1_FN_CPU_ON; + migrate_fn = QEMU_PSCI_0_1_FN_MIGRATE; } qemu_fdt_setprop_string(fdt, "/psci", "method", "hvc"); - qemu_fdt_setprop_cell(fdt, "/psci", "cpu_suspend", - PSCI_FN_CPU_SUSPEND); - qemu_fdt_setprop_cell(fdt, "/psci", "cpu_off", PSCI_FN_CPU_OFF); - qemu_fdt_setprop_cell(fdt, "/psci", "cpu_on", PSCI_FN_CPU_ON); - qemu_fdt_setprop_cell(fdt, "/psci", "migrate", PSCI_FN_MIGRATE); + + qemu_fdt_setprop_cell(fdt, "/psci", "cpu_suspend", cpu_suspend_fn); + qemu_fdt_setprop_cell(fdt, "/psci", "cpu_off", cpu_off_fn); + qemu_fdt_setprop_cell(fdt, "/psci", "cpu_on", cpu_on_fn); + qemu_fdt_setprop_cell(fdt, "/psci", "migrate", migrate_fn); } } diff --git a/hw/core/loader.c b/hw/core/loader.c index 1a53f0fd90..193f0f8400 100644 --- a/hw/core/loader.c +++ b/hw/core/loader.c @@ -577,6 +577,54 @@ int load_ramdisk(const char *filename, hwaddr addr, uint64_t max_sz) return load_uboot_image(filename, NULL, &addr, NULL, IH_TYPE_RAMDISK); } +/* This simply prevents g_malloc in the function below from allocating + * a huge amount of memory, by placing a limit on the maximum + * uncompressed image size that load_image_gzipped will read. + */ +#define LOAD_IMAGE_MAX_GUNZIP_BYTES (256 << 20) + +/* Load a gzip-compressed kernel. */ +int load_image_gzipped(const char *filename, hwaddr addr, uint64_t max_sz) +{ + uint8_t *compressed_data = NULL; + uint8_t *data = NULL; + gsize len; + ssize_t bytes; + int ret = -1; + + if (!g_file_get_contents(filename, (char **) &compressed_data, &len, + NULL)) { + goto out; + } + + /* Is it a gzip-compressed file? */ + if (len < 2 || + compressed_data[0] != 0x1f || + compressed_data[1] != 0x8b) { + goto out; + } + + if (max_sz > LOAD_IMAGE_MAX_GUNZIP_BYTES) { + max_sz = LOAD_IMAGE_MAX_GUNZIP_BYTES; + } + + data = g_malloc(max_sz); + bytes = gunzip(data, max_sz, compressed_data, len); + if (bytes < 0) { + fprintf(stderr, "%s: unable to decompress gzipped kernel file\n", + filename); + goto out; + } + + rom_add_blob_fixed(filename, data, bytes, addr); + ret = bytes; + + out: + g_free(compressed_data); + g_free(data); + return ret; +} + /* * Functions for reboot-persistent memory regions. * - used for vga bios and option roms. |