diff options
Diffstat (limited to 'hw')
| -rw-r--r-- | hw/arm/armsse.c | 58 | ||||
| -rw-r--r-- | hw/arm/armv7m.c | 18 | ||||
| -rw-r--r-- | hw/arm/boot.c | 83 | ||||
| -rw-r--r-- | hw/arm/musca.c | 8 | ||||
| -rw-r--r-- | hw/intc/arm_gicv3_dist.c | 12 | ||||
| -rw-r--r-- | hw/intc/arm_gicv3_redist.c | 4 |
6 files changed, 145 insertions, 38 deletions
diff --git a/hw/arm/armsse.c b/hw/arm/armsse.c index 47d13312dc..b5c614cc3a 100644 --- a/hw/arm/armsse.c +++ b/hw/arm/armsse.c @@ -38,6 +38,33 @@ struct ARMSSEInfo { bool has_cachectrl; bool has_cpusecctrl; bool has_cpuid; + Property *props; +}; + +static Property iotkit_properties[] = { + DEFINE_PROP_LINK("memory", ARMSSE, board_memory, TYPE_MEMORY_REGION, + MemoryRegion *), + DEFINE_PROP_UINT32("EXP_NUMIRQ", ARMSSE, exp_numirq, 64), + DEFINE_PROP_UINT32("MAINCLK", ARMSSE, mainclk_frq, 0), + DEFINE_PROP_UINT32("SRAM_ADDR_WIDTH", ARMSSE, sram_addr_width, 15), + DEFINE_PROP_UINT32("init-svtor", ARMSSE, init_svtor, 0x10000000), + DEFINE_PROP_BOOL("CPU0_FPU", ARMSSE, cpu_fpu[0], true), + DEFINE_PROP_BOOL("CPU0_DSP", ARMSSE, cpu_dsp[0], true), + DEFINE_PROP_END_OF_LIST() +}; + +static Property armsse_properties[] = { + DEFINE_PROP_LINK("memory", ARMSSE, board_memory, TYPE_MEMORY_REGION, + MemoryRegion *), + DEFINE_PROP_UINT32("EXP_NUMIRQ", ARMSSE, exp_numirq, 64), + DEFINE_PROP_UINT32("MAINCLK", ARMSSE, mainclk_frq, 0), + DEFINE_PROP_UINT32("SRAM_ADDR_WIDTH", ARMSSE, sram_addr_width, 15), + DEFINE_PROP_UINT32("init-svtor", ARMSSE, init_svtor, 0x10000000), + DEFINE_PROP_BOOL("CPU0_FPU", ARMSSE, cpu_fpu[0], false), + DEFINE_PROP_BOOL("CPU0_DSP", ARMSSE, cpu_dsp[0], false), + DEFINE_PROP_BOOL("CPU1_FPU", ARMSSE, cpu_fpu[1], true), + DEFINE_PROP_BOOL("CPU1_DSP", ARMSSE, cpu_dsp[1], true), + DEFINE_PROP_END_OF_LIST() }; static const ARMSSEInfo armsse_variants[] = { @@ -53,6 +80,7 @@ static const ARMSSEInfo armsse_variants[] = { .has_cachectrl = false, .has_cpusecctrl = false, .has_cpuid = false, + .props = iotkit_properties, }, { .name = TYPE_SSE200, @@ -66,6 +94,7 @@ static const ARMSSEInfo armsse_variants[] = { .has_cachectrl = true, .has_cpusecctrl = true, .has_cpuid = true, + .props = armsse_properties, }, }; @@ -533,6 +562,20 @@ static void armsse_realize(DeviceState *dev, Error **errp) return; } } + if (!s->cpu_fpu[i]) { + object_property_set_bool(cpuobj, false, "vfp", &err); + if (err) { + error_propagate(errp, err); + return; + } + } + if (!s->cpu_dsp[i]) { + object_property_set_bool(cpuobj, false, "dsp", &err); + if (err) { + error_propagate(errp, err); + return; + } + } if (i > 0) { memory_region_add_subregion_overlap(&s->cpu_container[i], 0, @@ -1222,16 +1265,6 @@ static const VMStateDescription armsse_vmstate = { } }; -static Property armsse_properties[] = { - DEFINE_PROP_LINK("memory", ARMSSE, board_memory, TYPE_MEMORY_REGION, - MemoryRegion *), - DEFINE_PROP_UINT32("EXP_NUMIRQ", ARMSSE, exp_numirq, 64), - DEFINE_PROP_UINT32("MAINCLK", ARMSSE, mainclk_frq, 0), - DEFINE_PROP_UINT32("SRAM_ADDR_WIDTH", ARMSSE, sram_addr_width, 15), - DEFINE_PROP_UINT32("init-svtor", ARMSSE, init_svtor, 0x10000000), - DEFINE_PROP_END_OF_LIST() -}; - static void armsse_reset(DeviceState *dev) { ARMSSE *s = ARMSSE(dev); @@ -1244,13 +1277,14 @@ static void armsse_class_init(ObjectClass *klass, void *data) DeviceClass *dc = DEVICE_CLASS(klass); IDAUInterfaceClass *iic = IDAU_INTERFACE_CLASS(klass); ARMSSEClass *asc = ARMSSE_CLASS(klass); + const ARMSSEInfo *info = data; dc->realize = armsse_realize; dc->vmsd = &armsse_vmstate; - dc->props = armsse_properties; + dc->props = info->props; dc->reset = armsse_reset; iic->check = armsse_idau_check; - asc->info = data; + asc->info = info; } static const TypeInfo armsse_info = { diff --git a/hw/arm/armv7m.c b/hw/arm/armv7m.c index 1a8a6c8bf9..b9efad6bac 100644 --- a/hw/arm/armv7m.c +++ b/hw/arm/armv7m.c @@ -190,6 +190,22 @@ static void armv7m_realize(DeviceState *dev, Error **errp) return; } } + if (object_property_find(OBJECT(s->cpu), "vfp", NULL)) { + object_property_set_bool(OBJECT(s->cpu), s->vfp, + "vfp", &err); + if (err != NULL) { + error_propagate(errp, err); + return; + } + } + if (object_property_find(OBJECT(s->cpu), "dsp", NULL)) { + object_property_set_bool(OBJECT(s->cpu), s->dsp, + "dsp", &err); + if (err != NULL) { + error_propagate(errp, err); + return; + } + } /* * Tell the CPU where the NVIC is; it will fail realize if it doesn't @@ -260,6 +276,8 @@ static Property armv7m_properties[] = { DEFINE_PROP_BOOL("enable-bitband", ARMv7MState, enable_bitband, false), DEFINE_PROP_BOOL("start-powered-off", ARMv7MState, start_powered_off, false), + DEFINE_PROP_BOOL("vfp", ARMv7MState, vfp, true), + DEFINE_PROP_BOOL("dsp", ARMv7MState, dsp, true), DEFINE_PROP_END_OF_LIST(), }; diff --git a/hw/arm/boot.c b/hw/arm/boot.c index 0261fdabab..b2f93f6bef 100644 --- a/hw/arm/boot.c +++ b/hw/arm/boot.c @@ -911,6 +911,7 @@ static uint64_t load_aarch64_image(const char *filename, hwaddr mem_base, hwaddr *entry, AddressSpace *as) { hwaddr kernel_load_offset = KERNEL64_LOAD_ADDR; + uint64_t kernel_size = 0; uint8_t *buffer; int size; @@ -938,7 +939,10 @@ static uint64_t load_aarch64_image(const char *filename, hwaddr mem_base, * is only valid if the image_size is non-zero. */ memcpy(&hdrvals, buffer + ARM64_TEXT_OFFSET_OFFSET, sizeof(hdrvals)); - if (hdrvals[1] != 0) { + + kernel_size = le64_to_cpu(hdrvals[1]); + + if (kernel_size != 0) { kernel_load_offset = le64_to_cpu(hdrvals[0]); /* @@ -956,12 +960,21 @@ static uint64_t load_aarch64_image(const char *filename, hwaddr mem_base, } } + /* + * Kernels before v3.17 don't populate the image_size field, and + * raw images have no header. For those our best guess at the size + * is the size of the Image file itself. + */ + if (kernel_size == 0) { + kernel_size = size; + } + *entry = mem_base + kernel_load_offset; rom_add_blob_fixed_as(filename, buffer, size, *entry, as); g_free(buffer); - return size; + return kernel_size; } static void arm_setup_direct_kernel_boot(ARMCPU *cpu, @@ -977,6 +990,7 @@ static void arm_setup_direct_kernel_boot(ARMCPU *cpu, int elf_machine; hwaddr entry; static const ARMInsnFixup *primary_loader; + uint64_t ram_end = info->loader_start + info->ram_size; if (arm_feature(&cpu->env, ARM_FEATURE_AARCH64)) { primary_loader = bootloader_aarch64; @@ -999,20 +1013,6 @@ static void arm_setup_direct_kernel_boot(ARMCPU *cpu, if (info->nb_cpus == 0) info->nb_cpus = 1; - /* - * We want to put the initrd far enough into RAM that when the - * kernel is uncompressed it will not clobber the initrd. However - * on boards without much RAM we must ensure that we still leave - * enough room for a decent sized initrd, and on boards with large - * amounts of RAM we must avoid the initrd being so far up in RAM - * that it is outside lowmem and inaccessible to the kernel. - * So for boards with less than 256MB of RAM we put the initrd - * halfway into RAM, and for boards with 256MB of RAM or more we put - * the initrd at 128MB. - */ - info->initrd_start = info->loader_start + - MIN(info->ram_size / 2, 128 * 1024 * 1024); - /* Assume that raw images are linux kernels, and ELF images are not. */ kernel_size = arm_load_elf(info, &elf_entry, &elf_low_addr, &elf_high_addr, elf_machine, as); @@ -1048,27 +1048,59 @@ static void arm_setup_direct_kernel_boot(ARMCPU *cpu, /* 32-bit ARM */ entry = info->loader_start + KERNEL_LOAD_ADDR; kernel_size = load_image_targphys_as(info->kernel_filename, entry, - info->ram_size - KERNEL_LOAD_ADDR, - as); + ram_end - KERNEL_LOAD_ADDR, as); is_linux = 1; } if (kernel_size < 0) { error_report("could not load kernel '%s'", info->kernel_filename); exit(1); } + + if (kernel_size > info->ram_size) { + error_report("kernel '%s' is too large to fit in RAM " + "(kernel size %d, RAM size %" PRId64 ")", + info->kernel_filename, kernel_size, info->ram_size); + exit(1); + } + info->entry = entry; + + /* + * We want to put the initrd far enough into RAM that when the + * kernel is uncompressed it will not clobber the initrd. However + * on boards without much RAM we must ensure that we still leave + * enough room for a decent sized initrd, and on boards with large + * amounts of RAM we must avoid the initrd being so far up in RAM + * that it is outside lowmem and inaccessible to the kernel. + * So for boards with less than 256MB of RAM we put the initrd + * halfway into RAM, and for boards with 256MB of RAM or more we put + * the initrd at 128MB. + * We also refuse to put the initrd somewhere that will definitely + * overlay the kernel we just loaded, though for kernel formats which + * don't tell us their exact size (eg self-decompressing 32-bit kernels) + * we might still make a bad choice here. + */ + info->initrd_start = info->loader_start + + MAX(MIN(info->ram_size / 2, 128 * 1024 * 1024), kernel_size); + info->initrd_start = TARGET_PAGE_ALIGN(info->initrd_start); + if (is_linux) { uint32_t fixupcontext[FIXUP_MAX]; if (info->initrd_filename) { + + if (info->initrd_start >= ram_end) { + error_report("not enough space after kernel to load initrd"); + exit(1); + } + initrd_size = load_ramdisk_as(info->initrd_filename, info->initrd_start, - info->ram_size - info->initrd_start, - as); + ram_end - info->initrd_start, as); if (initrd_size < 0) { initrd_size = load_image_targphys_as(info->initrd_filename, info->initrd_start, - info->ram_size - + ram_end - info->initrd_start, as); } @@ -1077,6 +1109,11 @@ static void arm_setup_direct_kernel_boot(ARMCPU *cpu, info->initrd_filename); exit(1); } + if (info->initrd_start + initrd_size > info->ram_size) { + error_report("could not load initrd '%s': " + "too big to fit into RAM after the kernel", + info->initrd_filename); + } } else { initrd_size = 0; } @@ -1112,6 +1149,10 @@ static void arm_setup_direct_kernel_boot(ARMCPU *cpu, /* Place the DTB after the initrd in memory with alignment. */ info->dtb_start = QEMU_ALIGN_UP(info->initrd_start + initrd_size, align); + if (info->dtb_start >= ram_end) { + error_report("Not enough space for DTB after kernel/initrd"); + exit(1); + } fixupcontext[FIXUP_ARGPTR_LO] = info->dtb_start; fixupcontext[FIXUP_ARGPTR_HI] = info->dtb_start >> 32; } else { diff --git a/hw/arm/musca.c b/hw/arm/musca.c index 825d80e75a..ddd8842732 100644 --- a/hw/arm/musca.c +++ b/hw/arm/musca.c @@ -385,6 +385,14 @@ static void musca_init(MachineState *machine) qdev_prop_set_uint32(ssedev, "init-svtor", mmc->init_svtor); qdev_prop_set_uint32(ssedev, "SRAM_ADDR_WIDTH", mmc->sram_addr_width); qdev_prop_set_uint32(ssedev, "MAINCLK", SYSCLK_FRQ); + /* + * Musca-A takes the default SSE-200 FPU/DSP settings (ie no for + * CPU0 and yes for CPU1); Musca-B1 explicitly enables them for CPU0. + */ + if (mmc->type == MUSCA_B1) { + qdev_prop_set_bit(ssedev, "CPU0_FPU", true); + qdev_prop_set_bit(ssedev, "CPU0_DSP", true); + } object_property_set_bool(OBJECT(&mms->sse), true, "realized", &error_fatal); diff --git a/hw/intc/arm_gicv3_dist.c b/hw/intc/arm_gicv3_dist.c index 53c55c5729..b65f56f903 100644 --- a/hw/intc/arm_gicv3_dist.c +++ b/hw/intc/arm_gicv3_dist.c @@ -378,8 +378,14 @@ static MemTxResult gicd_readl(GICv3State *s, hwaddr offset, * ITLinesNumber == (num external irqs / 32) - 1 */ int itlinesnumber = ((s->num_irq - GIC_INTERNAL) / 32) - 1; + /* + * SecurityExtn must be RAZ if GICD_CTLR.DS == 1, and + * "security extensions not supported" always implies DS == 1, + * so we only need to check the DS bit. + */ + bool sec_extn = !(s->gicd_ctlr & GICD_CTLR_DS); - *data = (1 << 25) | (1 << 24) | (s->security_extn << 10) | + *data = (1 << 25) | (1 << 24) | (sec_extn << 10) | (0xf << 19) | itlinesnumber; return MEMTX_OK; } @@ -533,7 +539,7 @@ static MemTxResult gicd_readl(GICv3State *s, hwaddr offset, } return MEMTX_OK; } - case GICD_IDREGS ... GICD_IDREGS + 0x1f: + case GICD_IDREGS ... GICD_IDREGS + 0x2f: /* ID registers */ *data = gicv3_idreg(offset - GICD_IDREGS); return MEMTX_OK; @@ -744,7 +750,7 @@ static MemTxResult gicd_writel(GICv3State *s, hwaddr offset, gicd_write_irouter(s, attrs, irq, r); return MEMTX_OK; } - case GICD_IDREGS ... GICD_IDREGS + 0x1f: + case GICD_IDREGS ... GICD_IDREGS + 0x2f: case GICD_TYPER: case GICD_IIDR: /* RO registers, ignore the write */ diff --git a/hw/intc/arm_gicv3_redist.c b/hw/intc/arm_gicv3_redist.c index 3b0ba6de1a..8645220d61 100644 --- a/hw/intc/arm_gicv3_redist.c +++ b/hw/intc/arm_gicv3_redist.c @@ -233,7 +233,7 @@ static MemTxResult gicr_readl(GICv3CPUState *cs, hwaddr offset, } *data = cs->gicr_nsacr; return MEMTX_OK; - case GICR_IDREGS ... GICR_IDREGS + 0x1f: + case GICR_IDREGS ... GICR_IDREGS + 0x2f: *data = gicv3_idreg(offset - GICR_IDREGS); return MEMTX_OK; default: @@ -363,7 +363,7 @@ static MemTxResult gicr_writel(GICv3CPUState *cs, hwaddr offset, return MEMTX_OK; case GICR_IIDR: case GICR_TYPER: - case GICR_IDREGS ... GICR_IDREGS + 0x1f: + case GICR_IDREGS ... GICR_IDREGS + 0x2f: /* RO registers, ignore the write */ qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid guest write to RO register at offset " |