target-arm queue:

* Fix PC test for LDM (exception return)
  * Implement ARMv8.0-SB
  * Implement ARMv8.0-PredInv
  * Implement ARMv8.4-CondM
  * Implement ARMv8.5-CondM
  * Implement ARMv8.5-FRINT
  * hw/arm/stellaris: Implement watchdog timer
  * virt: support more than 255GB of RAM
 -----BEGIN PGP SIGNATURE-----
 
 iQJNBAABCAA3FiEE4aXFk81BneKOgxXPPCUl7RQ2DN4FAlx+qKsZHHBldGVyLm1h
 eWRlbGxAbGluYXJvLm9yZwAKCRA8JSXtFDYM3mAoD/93lBnewhnjwWh5/PH/aQK+
 guYrrNT8p+ZiSuODWKrXI2oyR8DLDoLIbeYG+DqkjwoZ8Mzm5AsfDjNmbXrWVxrH
 PYvEFVo3HsorYWaHWKBzUbBC2Rw0hv3JrJ1fUnxmQIJ0tX+jFOAIeq/7TM68CM3i
 +c0Ql/2kcAnfac0bv1yKR4OeY9xPC7SX4+ZFxdpT0rzt/ddhj9eQ+YQ6qPLtQs/5
 dPhswDjyFeALY5TmNrF560BiPrYjF7h0SeYx5I3BaiHPAVlT4foi2g+RXeimyZWu
 7VgOdgvpOSNaKdtBNXLQ2+7VnZXqZjpgK4qcMthCyjI/Dd+mdh4DBtMrVx3ZLzvm
 64H6QvlWRT/lsWWlxTICRohbq+2obZdV9unVmDkkhvzKOF6rT7SI3zia1jEJpJ74
 smjfAJ0gmRzqtrcTeKmO4U10HVkCsrqPBpJePnDw3hJmVzxgSjHCNdUxZqjTk0GQ
 jjpD0YCP0KF3MWl8Oc8nSOS8M0cTy84nWdV/PbedY8BrvwTI3u8QTd6vnLHT/h45
 Gr5n3XplL6T6u8G0g5Pt5LbKxn3bmO1RYtFYKEICmZaE9XARApbf1A+1B9PqXjsK
 pxaFgJu5qoGM3a9HNWFOgXh4ARmM/rHcKnEqiSviaLzQGT9Z5VSFxXfkQkkDRPGI
 E+1d2skV46/Nm8VFq2gp3A==
 =Ztdu
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/pmaydell/tags/pull-target-arm-20190305' into staging

target-arm queue:
 * Fix PC test for LDM (exception return)
 * Implement ARMv8.0-SB
 * Implement ARMv8.0-PredInv
 * Implement ARMv8.4-CondM
 * Implement ARMv8.5-CondM
 * Implement ARMv8.5-FRINT
 * hw/arm/stellaris: Implement watchdog timer
 * virt: support more than 255GB of RAM

# gpg: Signature made Tue 05 Mar 2019 16:49:47 GMT
# gpg:                using RSA key E1A5C593CD419DE28E8315CF3C2525ED14360CDE
# gpg:                issuer "peter.maydell@linaro.org"
# gpg: Good signature from "Peter Maydell <peter.maydell@linaro.org>" [ultimate]
# gpg:                 aka "Peter Maydell <pmaydell@gmail.com>" [ultimate]
# gpg:                 aka "Peter Maydell <pmaydell@chiark.greenend.org.uk>" [ultimate]
# Primary key fingerprint: E1A5 C593 CD41 9DE2 8E83  15CF 3C25 25ED 1436 0CDE

* remotes/pmaydell/tags/pull-target-arm-20190305: (22 commits)
  hw/arm/stellaris: Implement watchdog timer
  hw/arm/virt: Bump the 255GB initial RAM limit
  hw/arm/virt: Check the VCPU PA range in TCG mode
  hw/arm/virt: Implement kvm_type function for 4.0 machine
  hw/arm/virt: Dynamic memory map depending on RAM requirements
  vl: Set machine ram_size, maxram_size and ram_slots earlier
  kvm: add kvm_arm_get_max_vm_ipa_size
  hw/boards: Add a MachineState parameter to kvm_type callback
  hw/arm/virt: Split the memory map description
  hw/arm/virt: Rename highmem IO regions
  hw/arm/boot: introduce fdt_add_memory_node helper
  target/arm: Implement ARMv8.5-FRINT
  target/arm: Restructure handle_fp_1src_{single, double}
  target/arm: Implement ARMv8.5-CondM
  target/arm: Implement ARMv8.4-CondM
  target/arm: Rearrange disas_data_proc_reg
  target/arm: Add set/clear_pstate_bits, share gen_ss_advance
  target/arm: Split helper_msr_i_pstate into 3
  target/arm: Implement ARMv8.0-PredInv
  target/arm: Implement ARMv8.0-SB
  ...

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2019-03-05 17:23:25 +00:00
commit c99b58326d
29 changed files with 1032 additions and 274 deletions

View File

@ -1593,7 +1593,7 @@ static int kvm_init(MachineState *ms)
kvm_type = qemu_opt_get(qemu_get_machine_opts(), "kvm-type");
if (mc->kvm_type) {
type = mc->kvm_type(kvm_type);
type = mc->kvm_type(ms, kvm_type);
} else if (kvm_type) {
ret = -EINVAL;
fprintf(stderr, "Invalid argument kvm-type=%s\n", kvm_type);

View File

@ -423,6 +423,32 @@ static void set_kernel_args_old(const struct arm_boot_info *info,
}
}
static int fdt_add_memory_node(void *fdt, uint32_t acells, hwaddr mem_base,
uint32_t scells, hwaddr mem_len,
int numa_node_id)
{
char *nodename;
int ret;
nodename = g_strdup_printf("/memory@%" PRIx64, mem_base);
qemu_fdt_add_subnode(fdt, nodename);
qemu_fdt_setprop_string(fdt, nodename, "device_type", "memory");
ret = qemu_fdt_setprop_sized_cells(fdt, nodename, "reg", acells, mem_base,
scells, mem_len);
if (ret < 0) {
goto out;
}
/* only set the NUMA ID if it is specified */
if (numa_node_id >= 0) {
ret = qemu_fdt_setprop_cell(fdt, nodename,
"numa-node-id", numa_node_id);
}
out:
g_free(nodename);
return ret;
}
static void fdt_add_psci_node(void *fdt)
{
uint32_t cpu_suspend_fn;
@ -502,7 +528,6 @@ int arm_load_dtb(hwaddr addr, const struct arm_boot_info *binfo,
void *fdt = NULL;
int size, rc, n = 0;
uint32_t acells, scells;
char *nodename;
unsigned int i;
hwaddr mem_base, mem_len;
char **node_path;
@ -576,35 +601,24 @@ int arm_load_dtb(hwaddr addr, const struct arm_boot_info *binfo,
mem_base = binfo->loader_start;
for (i = 0; i < nb_numa_nodes; i++) {
mem_len = numa_info[i].node_mem;
nodename = g_strdup_printf("/memory@%" PRIx64, mem_base);
qemu_fdt_add_subnode(fdt, nodename);
qemu_fdt_setprop_string(fdt, nodename, "device_type", "memory");
rc = qemu_fdt_setprop_sized_cells(fdt, nodename, "reg",
acells, mem_base,
scells, mem_len);
rc = fdt_add_memory_node(fdt, acells, mem_base,
scells, mem_len, i);
if (rc < 0) {
fprintf(stderr, "couldn't set %s/reg for node %d\n", nodename,
i);
fprintf(stderr, "couldn't add /memory@%"PRIx64" node\n",
mem_base);
goto fail;
}
qemu_fdt_setprop_cell(fdt, nodename, "numa-node-id", i);
mem_base += mem_len;
g_free(nodename);
}
} else {
nodename = g_strdup_printf("/memory@%" PRIx64, binfo->loader_start);
qemu_fdt_add_subnode(fdt, nodename);
qemu_fdt_setprop_string(fdt, nodename, "device_type", "memory");
rc = qemu_fdt_setprop_sized_cells(fdt, nodename, "reg",
acells, binfo->loader_start,
scells, binfo->ram_size);
rc = fdt_add_memory_node(fdt, acells, binfo->loader_start,
scells, binfo->ram_size, -1);
if (rc < 0) {
fprintf(stderr, "couldn't set %s reg\n", nodename);
fprintf(stderr, "couldn't add /memory@%"PRIx64" node\n",
binfo->loader_start);
goto fail;
}
g_free(nodename);
}
rc = fdt_path_offset(fdt, "/chosen");

View File

@ -22,6 +22,7 @@
#include "sysemu/sysemu.h"
#include "hw/arm/armv7m.h"
#include "hw/char/pl011.h"
#include "hw/watchdog/cmsdk-apb-watchdog.h"
#include "hw/misc/unimp.h"
#include "cpu.h"
@ -1243,7 +1244,7 @@ static void stellaris_init(MachineState *ms, stellaris_board_info *board)
* Stellaris LM3S6965 Microcontroller Data Sheet (rev I)
* http://www.ti.com/lit/ds/symlink/lm3s6965.pdf
*
* 40000000 wdtimer (unimplemented)
* 40000000 wdtimer
* 40002000 i2c (unimplemented)
* 40004000 GPIO
* 40005000 GPIO
@ -1338,6 +1339,24 @@ static void stellaris_init(MachineState *ms, stellaris_board_info *board)
stellaris_sys_init(0x400fe000, qdev_get_gpio_in(nvic, 28),
board, nd_table[0].macaddr.a);
if (board->dc1 & (1 << 3)) { /* watchdog present */
dev = qdev_create(NULL, TYPE_LUMINARY_WATCHDOG);
/* system_clock_scale is valid now */
uint32_t mainclk = NANOSECONDS_PER_SECOND / system_clock_scale;
qdev_prop_set_uint32(dev, "wdogclk-frq", mainclk);
qdev_init_nofail(dev);
sysbus_mmio_map(SYS_BUS_DEVICE(dev),
0,
0x40000000u);
sysbus_connect_irq(SYS_BUS_DEVICE(dev),
0,
qdev_get_gpio_in(nvic, 18));
}
for (i = 0; i < 7; i++) {
if (board->dc4 & (1 << i)) {
gpio_dev[i] = sysbus_create_simple("pl061_luminary", gpio_addr[i],
@ -1431,7 +1450,6 @@ static void stellaris_init(MachineState *ms, stellaris_board_info *board)
/* Add dummy regions for the devices we don't implement yet,
* so guest accesses don't cause unlogged crashes.
*/
create_unimplemented_device("wdtimer", 0x40000000, 0x1000);
create_unimplemented_device("i2c-0", 0x40002000, 0x1000);
create_unimplemented_device("i2c-2", 0x40021000, 0x1000);
create_unimplemented_device("PWM", 0x40028000, 0x1000);

View File

@ -229,8 +229,8 @@ static void acpi_dsdt_add_pci(Aml *scope, const MemMapEntry *memmap,
size_pio));
if (use_highmem) {
hwaddr base_mmio_high = memmap[VIRT_PCIE_MMIO_HIGH].base;
hwaddr size_mmio_high = memmap[VIRT_PCIE_MMIO_HIGH].size;
hwaddr base_mmio_high = memmap[VIRT_HIGH_PCIE_MMIO].base;
hwaddr size_mmio_high = memmap[VIRT_HIGH_PCIE_MMIO].size;
aml_append(rbuf,
aml_qword_memory(AML_POS_DECODE, AML_MIN_FIXED, AML_MAX_FIXED,
@ -663,8 +663,10 @@ build_madt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
gicr = acpi_data_push(table_data, sizeof(*gicr));
gicr->type = ACPI_APIC_GENERIC_REDISTRIBUTOR;
gicr->length = sizeof(*gicr);
gicr->base_address = cpu_to_le64(memmap[VIRT_GIC_REDIST2].base);
gicr->range_length = cpu_to_le32(memmap[VIRT_GIC_REDIST2].size);
gicr->base_address =
cpu_to_le64(memmap[VIRT_HIGH_GIC_REDIST2].base);
gicr->range_length =
cpu_to_le32(memmap[VIRT_HIGH_GIC_REDIST2].size);
}
if (its_class_name() && !vmc->no_its) {

View File

@ -29,6 +29,7 @@
*/
#include "qemu/osdep.h"
#include "qemu/units.h"
#include "qapi/error.h"
#include "hw/sysbus.h"
#include "hw/arm/arm.h"
@ -58,6 +59,8 @@
#include "qapi/visitor.h"
#include "standard-headers/linux/input.h"
#include "hw/arm/smmuv3.h"
#include "hw/acpi/acpi.h"
#include "target/arm/internals.h"
#define DEFINE_VIRT_MACHINE_LATEST(major, minor, latest) \
static void virt_##major##_##minor##_class_init(ObjectClass *oc, \
@ -92,22 +95,9 @@
#define PLATFORM_BUS_NUM_IRQS 64
/* RAM limit in GB. Since VIRT_MEM starts at the 1GB mark, this means
* RAM can go up to the 256GB mark, leaving 256GB of the physical
* address space unallocated and free for future use between 256G and 512G.
* If we need to provide more RAM to VMs in the future then we need to:
* * allocate a second bank of RAM starting at 2TB and working up
* * fix the DT and ACPI table generation code in QEMU to correctly
* report two split lumps of RAM to the guest
* * fix KVM in the host kernel to allow guests with >40 bit address spaces
* (We don't want to fill all the way up to 512GB with RAM because
* we might want it for non-RAM purposes later. Conversely it seems
* reasonable to assume that anybody configuring a VM with a quarter
* of a terabyte of RAM will be doing it on a host with more than a
* terabyte of physical address space.)
*/
#define RAMLIMIT_GB 255
#define RAMLIMIT_BYTES (RAMLIMIT_GB * 1024ULL * 1024 * 1024)
/* Legacy RAM limit in GB (< version 4.0) */
#define LEGACY_RAMLIMIT_GB 255
#define LEGACY_RAMLIMIT_BYTES (LEGACY_RAMLIMIT_GB * GiB)
/* Addresses and sizes of our components.
* 0..128MB is space for a flash device so we can run bootrom code such as UEFI.
@ -121,7 +111,7 @@
* Note that devices should generally be placed at multiples of 0x10000,
* to accommodate guests using 64K pages.
*/
static const MemMapEntry a15memmap[] = {
static const MemMapEntry base_memmap[] = {
/* Space up to 0x8000000 is reserved for a boot ROM */
[VIRT_FLASH] = { 0, 0x08000000 },
[VIRT_CPUPERIPHS] = { 0x08000000, 0x00020000 },
@ -148,12 +138,26 @@ static const MemMapEntry a15memmap[] = {
[VIRT_PCIE_MMIO] = { 0x10000000, 0x2eff0000 },
[VIRT_PCIE_PIO] = { 0x3eff0000, 0x00010000 },
[VIRT_PCIE_ECAM] = { 0x3f000000, 0x01000000 },
[VIRT_MEM] = { 0x40000000, RAMLIMIT_BYTES },
/* Actual RAM size depends on initial RAM and device memory settings */
[VIRT_MEM] = { GiB, LEGACY_RAMLIMIT_BYTES },
};
/*
* Highmem IO Regions: This memory map is floating, located after the RAM.
* Each MemMapEntry base (GPA) will be dynamically computed, depending on the
* top of the RAM, so that its base get the same alignment as the size,
* ie. a 512GiB entry will be aligned on a 512GiB boundary. If there is
* less than 256GiB of RAM, the floating area starts at the 256GiB mark.
* Note the extended_memmap is sized so that it eventually also includes the
* base_memmap entries (VIRT_HIGH_GIC_REDIST2 index is greater than the last
* index of base_memmap).
*/
static MemMapEntry extended_memmap[] = {
/* Additional 64 MB redist region (can contain up to 512 redistributors) */
[VIRT_GIC_REDIST2] = { 0x4000000000ULL, 0x4000000 },
[VIRT_PCIE_ECAM_HIGH] = { 0x4010000000ULL, 0x10000000 },
/* Second PCIe window, 512GB wide at the 512GB boundary */
[VIRT_PCIE_MMIO_HIGH] = { 0x8000000000ULL, 0x8000000000ULL },
[VIRT_HIGH_GIC_REDIST2] = { 0x0, 64 * MiB },
[VIRT_HIGH_PCIE_ECAM] = { 0x0, 256 * MiB },
/* Second PCIe window */
[VIRT_HIGH_PCIE_MMIO] = { 0x0, 512 * GiB },
};
static const int a15irqmap[] = {
@ -431,12 +435,12 @@ static void fdt_add_gic_node(VirtMachineState *vms)
2, vms->memmap[VIRT_GIC_REDIST].size);
} else {
qemu_fdt_setprop_sized_cells(vms->fdt, nodename, "reg",
2, vms->memmap[VIRT_GIC_DIST].base,
2, vms->memmap[VIRT_GIC_DIST].size,
2, vms->memmap[VIRT_GIC_REDIST].base,
2, vms->memmap[VIRT_GIC_REDIST].size,
2, vms->memmap[VIRT_GIC_REDIST2].base,
2, vms->memmap[VIRT_GIC_REDIST2].size);
2, vms->memmap[VIRT_GIC_DIST].base,
2, vms->memmap[VIRT_GIC_DIST].size,
2, vms->memmap[VIRT_GIC_REDIST].base,
2, vms->memmap[VIRT_GIC_REDIST].size,
2, vms->memmap[VIRT_HIGH_GIC_REDIST2].base,
2, vms->memmap[VIRT_HIGH_GIC_REDIST2].size);
}
if (vms->virt) {
@ -584,7 +588,7 @@ static void create_gic(VirtMachineState *vms, qemu_irq *pic)
if (nb_redist_regions == 2) {
uint32_t redist1_capacity =
vms->memmap[VIRT_GIC_REDIST2].size / GICV3_REDIST_SIZE;
vms->memmap[VIRT_HIGH_GIC_REDIST2].size / GICV3_REDIST_SIZE;
qdev_prop_set_uint32(gicdev, "redist-region-count[1]",
MIN(smp_cpus - redist0_count, redist1_capacity));
@ -601,7 +605,8 @@ static void create_gic(VirtMachineState *vms, qemu_irq *pic)
if (type == 3) {
sysbus_mmio_map(gicbusdev, 1, vms->memmap[VIRT_GIC_REDIST].base);
if (nb_redist_regions == 2) {
sysbus_mmio_map(gicbusdev, 2, vms->memmap[VIRT_GIC_REDIST2].base);
sysbus_mmio_map(gicbusdev, 2,
vms->memmap[VIRT_HIGH_GIC_REDIST2].base);
}
} else {
sysbus_mmio_map(gicbusdev, 1, vms->memmap[VIRT_GIC_CPU].base);
@ -1088,8 +1093,8 @@ static void create_pcie(VirtMachineState *vms, qemu_irq *pic)
{
hwaddr base_mmio = vms->memmap[VIRT_PCIE_MMIO].base;
hwaddr size_mmio = vms->memmap[VIRT_PCIE_MMIO].size;
hwaddr base_mmio_high = vms->memmap[VIRT_PCIE_MMIO_HIGH].base;
hwaddr size_mmio_high = vms->memmap[VIRT_PCIE_MMIO_HIGH].size;
hwaddr base_mmio_high = vms->memmap[VIRT_HIGH_PCIE_MMIO].base;
hwaddr size_mmio_high = vms->memmap[VIRT_HIGH_PCIE_MMIO].size;
hwaddr base_pio = vms->memmap[VIRT_PCIE_PIO].base;
hwaddr size_pio = vms->memmap[VIRT_PCIE_PIO].size;
hwaddr base_ecam, size_ecam;
@ -1353,6 +1358,62 @@ static uint64_t virt_cpu_mp_affinity(VirtMachineState *vms, int idx)
return arm_cpu_mp_affinity(idx, clustersz);
}
static void virt_set_memmap(VirtMachineState *vms)
{
MachineState *ms = MACHINE(vms);
hwaddr base, device_memory_base, device_memory_size;
int i;
vms->memmap = extended_memmap;
for (i = 0; i < ARRAY_SIZE(base_memmap); i++) {
vms->memmap[i] = base_memmap[i];
}
if (ms->ram_slots > ACPI_MAX_RAM_SLOTS) {
error_report("unsupported number of memory slots: %"PRIu64,
ms->ram_slots);
exit(EXIT_FAILURE);
}
/*
* We compute the base of the high IO region depending on the
* amount of initial and device memory. The device memory start/size
* is aligned on 1GiB. We never put the high IO region below 256GiB
* so that if maxram_size is < 255GiB we keep the legacy memory map.
* The device region size assumes 1GiB page max alignment per slot.
*/
device_memory_base =
ROUND_UP(vms->memmap[VIRT_MEM].base + ms->ram_size, GiB);
device_memory_size = ms->maxram_size - ms->ram_size + ms->ram_slots * GiB;
/* Base address of the high IO region */
base = device_memory_base + ROUND_UP(device_memory_size, GiB);
if (base < device_memory_base) {
error_report("maxmem/slots too huge");
exit(EXIT_FAILURE);
}
if (base < vms->memmap[VIRT_MEM].base + LEGACY_RAMLIMIT_BYTES) {
base = vms->memmap[VIRT_MEM].base + LEGACY_RAMLIMIT_BYTES;
}
for (i = VIRT_LOWMEMMAP_LAST; i < ARRAY_SIZE(extended_memmap); i++) {
hwaddr size = extended_memmap[i].size;
base = ROUND_UP(base, size);
vms->memmap[i].base = base;
vms->memmap[i].size = size;
base += size;
}
vms->highest_gpa = base - 1;
if (device_memory_size > 0) {
ms->device_memory = g_malloc0(sizeof(*ms->device_memory));
ms->device_memory->base = device_memory_base;
memory_region_init(&ms->device_memory->mr, OBJECT(vms),
"device-memory", device_memory_size);
}
}
static void machvirt_init(MachineState *machine)
{
VirtMachineState *vms = VIRT_MACHINE(machine);
@ -1367,6 +1428,14 @@ static void machvirt_init(MachineState *machine)
bool firmware_loaded = bios_name || drive_get(IF_PFLASH, 0, 0);
bool aarch64 = true;
/*
* In accelerated mode, the memory map is computed earlier in kvm_type()
* to create a VM with the right number of IPA bits.
*/
if (!vms->memmap) {
virt_set_memmap(vms);
}
/* We can probe only here because during property set
* KVM is not available yet
*/
@ -1417,8 +1486,10 @@ static void machvirt_init(MachineState *machine)
* many redistributors we can fit into the memory map.
*/
if (vms->gic_version == 3) {
virt_max_cpus = vms->memmap[VIRT_GIC_REDIST].size / GICV3_REDIST_SIZE;
virt_max_cpus += vms->memmap[VIRT_GIC_REDIST2].size / GICV3_REDIST_SIZE;
virt_max_cpus =
vms->memmap[VIRT_GIC_REDIST].size / GICV3_REDIST_SIZE;
virt_max_cpus +=
vms->memmap[VIRT_HIGH_GIC_REDIST2].size / GICV3_REDIST_SIZE;
} else {
virt_max_cpus = GIC_NCPU;
}
@ -1432,11 +1503,6 @@ static void machvirt_init(MachineState *machine)
vms->smp_cpus = smp_cpus;
if (machine->ram_size > vms->memmap[VIRT_MEM].size) {
error_report("mach-virt: cannot model more than %dGB RAM", RAMLIMIT_GB);
exit(1);
}
if (vms->virt && kvm_enabled()) {
error_report("mach-virt: KVM does not support providing "
"Virtualization extensions to the guest CPU");
@ -1524,9 +1590,29 @@ static void machvirt_init(MachineState *machine)
fdt_add_timer_nodes(vms);
fdt_add_cpu_nodes(vms);
if (!kvm_enabled()) {
ARMCPU *cpu = ARM_CPU(first_cpu);
bool aarch64 = object_property_get_bool(OBJECT(cpu), "aarch64", NULL);
if (aarch64 && vms->highmem) {
int requested_pa_size, pamax = arm_pamax(cpu);
requested_pa_size = 64 - clz64(vms->highest_gpa);
if (pamax < requested_pa_size) {
error_report("VCPU supports less PA bits (%d) than requested "
"by the memory map (%d)", pamax, requested_pa_size);
exit(1);
}
}
}
memory_region_allocate_system_memory(ram, NULL, "mach-virt.ram",
machine->ram_size);
memory_region_add_subregion(sysmem, vms->memmap[VIRT_MEM].base, ram);
if (machine->device_memory) {
memory_region_add_subregion(sysmem, machine->device_memory->base,
&machine->device_memory->mr);
}
create_flash(vms, sysmem, secure_sysmem ? secure_sysmem : sysmem);
@ -1747,6 +1833,36 @@ static HotplugHandler *virt_machine_get_hotplug_handler(MachineState *machine,
return NULL;
}
/*
* for arm64 kvm_type [7-0] encodes the requested number of bits
* in the IPA address space
*/
static int virt_kvm_type(MachineState *ms, const char *type_str)
{
VirtMachineState *vms = VIRT_MACHINE(ms);
int max_vm_pa_size = kvm_arm_get_max_vm_ipa_size(ms);
int requested_pa_size;
/* we freeze the memory map to compute the highest gpa */
virt_set_memmap(vms);
requested_pa_size = 64 - clz64(vms->highest_gpa);
if (requested_pa_size > max_vm_pa_size) {
error_report("-m and ,maxmem option values "
"require an IPA range (%d bits) larger than "
"the one supported by the host (%d bits)",
requested_pa_size, max_vm_pa_size);
exit(1);
}
/*
* By default we return 0 which corresponds to an implicit legacy
* 40b IPA setting. Otherwise we return the actual requested PA
* logsize
*/
return requested_pa_size > 40 ? requested_pa_size : 0;
}
static void virt_machine_class_init(ObjectClass *oc, void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
@ -1771,6 +1887,7 @@ static void virt_machine_class_init(ObjectClass *oc, void *data)
mc->cpu_index_to_instance_props = virt_cpu_index_to_props;
mc->default_cpu_type = ARM_CPU_TYPE_NAME("cortex-a15");
mc->get_default_cpu_node_id = virt_get_default_cpu_node_id;
mc->kvm_type = virt_kvm_type;
assert(!mc->get_hotplug_handler);
mc->get_hotplug_handler = virt_machine_get_hotplug_handler;
hc->plug = virt_machine_device_plug_cb;
@ -1842,7 +1959,6 @@ static void virt_instance_init(Object *obj)
"Valid values are none and smmuv3",
NULL);
vms->memmap = a15memmap;
vms->irqmap = a15irqmap;
}

View File

@ -564,8 +564,7 @@ static char *core99_fw_dev_path(FWPathProvider *p, BusState *bus,
return NULL;
}
static int core99_kvm_type(const char *arg)
static int core99_kvm_type(MachineState *machine, const char *arg)
{
/* Always force PR KVM */
return 2;

View File

@ -420,7 +420,7 @@ static char *heathrow_fw_dev_path(FWPathProvider *p, BusState *bus,
return NULL;
}
static int heathrow_kvm_type(const char *arg)
static int heathrow_kvm_type(MachineState *machine, const char *arg)
{
/* Always force PR KVM */
return 2;

View File

@ -3023,7 +3023,7 @@ static void spapr_machine_init(MachineState *machine)
}
}
static int spapr_kvm_type(const char *vm_type)
static int spapr_kvm_type(MachineState *machine, const char *vm_type)
{
if (!vm_type) {
return 0;

View File

@ -14,6 +14,10 @@
* System Design Kit (CMSDK) and documented in the Cortex-M System
* Design Kit Technical Reference Manual (ARM DDI0479C):
* https://developer.arm.com/products/system-design/system-design-kits/cortex-m-system-design-kit
*
* We also support the variant of this device found in the TI
* Stellaris/Luminary boards and documented in:
* http://www.ti.com/lit/ds/symlink/lm3s6965.pdf
*/
#include "qemu/osdep.h"
@ -37,6 +41,7 @@ REG32(WDOGINTCLR, 0xc)
REG32(WDOGRIS, 0x10)
FIELD(WDOGRIS, INT, 0, 1)
REG32(WDOGMIS, 0x14)
REG32(WDOGTEST, 0x418) /* only in Stellaris/Luminary version of the device */
REG32(WDOGLOCK, 0xc00)
#define WDOG_UNLOCK_VALUE 0x1ACCE551
REG32(WDOGITCR, 0xf00)
@ -61,12 +66,18 @@ REG32(CID2, 0xff8)
REG32(CID3, 0xffc)
/* PID/CID values */
static const int watchdog_id[] = {
static const uint32_t cmsdk_apb_watchdog_id[] = {
0x04, 0x00, 0x00, 0x00, /* PID4..PID7 */
0x24, 0xb8, 0x1b, 0x00, /* PID0..PID3 */
0x0d, 0xf0, 0x05, 0xb1, /* CID0..CID3 */
};
static const uint32_t luminary_watchdog_id[] = {
0x00, 0x00, 0x00, 0x00, /* PID4..PID7 */
0x05, 0x18, 0x18, 0x01, /* PID0..PID3 */
0x0d, 0xf0, 0x05, 0xb1, /* CID0..CID3 */
};
static bool cmsdk_apb_watchdog_intstatus(CMSDKAPBWatchdog *s)
{
/* Return masked interrupt status */
@ -85,6 +96,10 @@ static void cmsdk_apb_watchdog_update(CMSDKAPBWatchdog *s)
bool wdogres;
if (s->itcr) {
/*
* Not checking that !s->is_luminary since s->itcr can't be written
* when s->is_luminary in the first place.
*/
wdogint = s->itop & R_WDOGITOP_WDOGINT_MASK;
wdogres = s->itop & R_WDOGITOP_WDOGRES_MASK;
} else {
@ -124,19 +139,34 @@ static uint64_t cmsdk_apb_watchdog_read(void *opaque, hwaddr offset,
r = s->lock;
break;
case A_WDOGITCR:
if (s->is_luminary) {
goto bad_offset;
}
r = s->itcr;
break;
case A_PID4 ... A_CID3:
r = watchdog_id[(offset - A_PID4) / 4];
r = s->id[(offset - A_PID4) / 4];
break;
case A_WDOGINTCLR:
case A_WDOGITOP:
if (s->is_luminary) {
goto bad_offset;
}
qemu_log_mask(LOG_GUEST_ERROR,
"CMSDK APB watchdog read: read of WO offset %x\n",
(int)offset);
r = 0;
break;
case A_WDOGTEST:
if (!s->is_luminary) {
goto bad_offset;
}
qemu_log_mask(LOG_UNIMP,
"Luminary watchdog read: stall not implemented\n");
r = 0;
break;
default:
bad_offset:
qemu_log_mask(LOG_GUEST_ERROR,
"CMSDK APB watchdog read: bad offset %x\n", (int)offset);
r = 0;
@ -170,6 +200,14 @@ static void cmsdk_apb_watchdog_write(void *opaque, hwaddr offset,
ptimer_run(s->timer, 0);
break;
case A_WDOGCONTROL:
if (s->is_luminary && 0 != (R_WDOGCONTROL_INTEN_MASK & s->control)) {
/*
* The Luminary version of this device ignores writes to
* this register after the guest has enabled interrupts
* (so they can only be disabled again via reset).
*/
break;
}
s->control = value & R_WDOGCONTROL_VALID_MASK;
cmsdk_apb_watchdog_update(s);
break;
@ -182,10 +220,16 @@ static void cmsdk_apb_watchdog_write(void *opaque, hwaddr offset,
s->lock = (value != WDOG_UNLOCK_VALUE);
break;
case A_WDOGITCR:
if (s->is_luminary) {
goto bad_offset;
}
s->itcr = value & R_WDOGITCR_VALID_MASK;
cmsdk_apb_watchdog_update(s);
break;
case A_WDOGITOP:
if (s->is_luminary) {
goto bad_offset;
}
s->itop = value & R_WDOGITOP_VALID_MASK;
cmsdk_apb_watchdog_update(s);
break;
@ -197,7 +241,15 @@ static void cmsdk_apb_watchdog_write(void *opaque, hwaddr offset,
"CMSDK APB watchdog write: write to RO offset 0x%x\n",
(int)offset);
break;
case A_WDOGTEST:
if (!s->is_luminary) {
goto bad_offset;
}
qemu_log_mask(LOG_UNIMP,
"Luminary watchdog write: stall not implemented\n");
break;
default:
bad_offset:
qemu_log_mask(LOG_GUEST_ERROR,
"CMSDK APB watchdog write: bad offset 0x%x\n",
(int)offset);
@ -256,6 +308,9 @@ static void cmsdk_apb_watchdog_init(Object *obj)
s, "cmsdk-apb-watchdog", 0x1000);
sysbus_init_mmio(sbd, &s->iomem);
sysbus_init_irq(sbd, &s->wdogint);
s->is_luminary = false;
s->id = cmsdk_apb_watchdog_id;
}
static void cmsdk_apb_watchdog_realize(DeviceState *dev, Error **errp)
@ -318,9 +373,24 @@ static const TypeInfo cmsdk_apb_watchdog_info = {
.class_init = cmsdk_apb_watchdog_class_init,
};
static void luminary_watchdog_init(Object *obj)
{
CMSDKAPBWatchdog *s = CMSDK_APB_WATCHDOG(obj);
s->is_luminary = true;
s->id = luminary_watchdog_id;
}
static const TypeInfo luminary_watchdog_info = {
.name = TYPE_LUMINARY_WATCHDOG,
.parent = TYPE_CMSDK_APB_WATCHDOG,
.instance_init = luminary_watchdog_init
};
static void cmsdk_apb_watchdog_register_types(void)
{
type_register_static(&cmsdk_apb_watchdog_info);
type_register_static(&luminary_watchdog_info);
}
type_init(cmsdk_apb_watchdog_register_types);

View File

@ -64,7 +64,6 @@ enum {
VIRT_GIC_VCPU,
VIRT_GIC_ITS,
VIRT_GIC_REDIST,
VIRT_GIC_REDIST2,
VIRT_SMMU,
VIRT_UART,
VIRT_MMIO,
@ -74,12 +73,18 @@ enum {
VIRT_PCIE_MMIO,
VIRT_PCIE_PIO,
VIRT_PCIE_ECAM,
VIRT_PCIE_ECAM_HIGH,
VIRT_PLATFORM_BUS,
VIRT_PCIE_MMIO_HIGH,
VIRT_GPIO,
VIRT_SECURE_UART,
VIRT_SECURE_MEM,
VIRT_LOWMEMMAP_LAST,
};
/* indices of IO regions located after the RAM */
enum {
VIRT_HIGH_GIC_REDIST2 = VIRT_LOWMEMMAP_LAST,
VIRT_HIGH_PCIE_ECAM,
VIRT_HIGH_PCIE_MMIO,
};
typedef enum VirtIOMMUType {
@ -116,7 +121,7 @@ typedef struct {
int32_t gic_version;
VirtIOMMUType iommu;
struct arm_boot_info bootinfo;
const MemMapEntry *memmap;
MemMapEntry *memmap;
const int *irqmap;
int smp_cpus;
void *fdt;
@ -126,9 +131,10 @@ typedef struct {
uint32_t msi_phandle;
uint32_t iommu_phandle;
int psci_conduit;
hwaddr highest_gpa;
} VirtMachineState;
#define VIRT_ECAM_ID(high) (high ? VIRT_PCIE_ECAM_HIGH : VIRT_PCIE_ECAM)
#define VIRT_ECAM_ID(high) (high ? VIRT_HIGH_PCIE_ECAM : VIRT_PCIE_ECAM)
#define TYPE_VIRT_MACHINE MACHINE_TYPE_NAME("virt")
#define VIRT_MACHINE(obj) \

View File

@ -156,6 +156,9 @@ typedef struct {
* should instead use "unimplemented-device" for all memory ranges where
* the guest will attempt to probe for a device that QEMU doesn't
* implement and a stub device is required.
* @kvm_type:
* Return the type of KVM corresponding to the kvm-type string option or
* computed based on other criteria such as the host kernel capabilities.
*/
struct MachineClass {
/*< private >*/
@ -171,7 +174,7 @@ struct MachineClass {
void (*init)(MachineState *state);
void (*reset)(void);
void (*hot_add_cpu)(const int64_t id, Error **errp);
int (*kvm_type)(const char *arg);
int (*kvm_type)(MachineState *machine, const char *arg);
BlockInterfaceType block_default_type;
int units_per_default_bus;

View File

@ -38,6 +38,12 @@
#define CMSDK_APB_WATCHDOG(obj) OBJECT_CHECK(CMSDKAPBWatchdog, (obj), \
TYPE_CMSDK_APB_WATCHDOG)
/*
* This shares the same struct (and cast macro) as the base
* cmsdk-apb-watchdog device.
*/
#define TYPE_LUMINARY_WATCHDOG "luminary-watchdog"
typedef struct CMSDKAPBWatchdog {
/*< private >*/
SysBusDevice parent_obj;
@ -46,6 +52,7 @@ typedef struct CMSDKAPBWatchdog {
MemoryRegion iomem;
qemu_irq wdogint;
uint32_t wdogclk_frq;
bool is_luminary;
struct ptimer_state *timer;
uint32_t control;
@ -54,6 +61,7 @@ typedef struct CMSDKAPBWatchdog {
uint32_t itcr;
uint32_t itop;
uint32_t resetstatus;
const uint32_t *id;
} CMSDKAPBWatchdog;
#endif

View File

@ -604,6 +604,8 @@ static uint32_t get_elf_hwcap(void)
GET_FEATURE_ID(aa64_pauth, ARM_HWCAP_A64_PACA | ARM_HWCAP_A64_PACG);
GET_FEATURE_ID(aa64_fhm, ARM_HWCAP_A64_ASIMDFHM);
GET_FEATURE_ID(aa64_jscvt, ARM_HWCAP_A64_JSCVT);
GET_FEATURE_ID(aa64_sb, ARM_HWCAP_A64_SB);
GET_FEATURE_ID(aa64_condm_4, ARM_HWCAP_A64_FLAGM);
#undef GET_FEATURE_ID

View File

@ -2021,6 +2021,8 @@ static void arm_max_initfn(Object *obj)
t = FIELD_DP32(t, ID_ISAR6, JSCVT, 1);
t = FIELD_DP32(t, ID_ISAR6, DP, 1);
t = FIELD_DP32(t, ID_ISAR6, FHM, 1);
t = FIELD_DP32(t, ID_ISAR6, SB, 1);
t = FIELD_DP32(t, ID_ISAR6, SPECRES, 1);
cpu->isar.id_isar6 = t;
t = cpu->id_mmfr4;

View File

@ -1060,7 +1060,8 @@ void pmu_init(ARMCPU *cpu);
#define SCTLR_R (1U << 9) /* up to v6; RAZ in v7 */
#define SCTLR_UMA (1U << 9) /* v8 onward, AArch64 only */
#define SCTLR_F (1U << 10) /* up to v6 */
#define SCTLR_SW (1U << 10) /* v7, RES0 in v8 */
#define SCTLR_SW (1U << 10) /* v7 */
#define SCTLR_EnRCTX (1U << 10) /* in v8.0-PredInv */
#define SCTLR_Z (1U << 11) /* in v7, RES1 in v8 */
#define SCTLR_EOS (1U << 11) /* v8.5-ExS */
#define SCTLR_I (1U << 12)
@ -3042,11 +3043,20 @@ static inline bool arm_sctlr_b(CPUARMState *env)
(env->cp15.sctlr_el[1] & SCTLR_B) != 0;
}
static inline uint64_t arm_sctlr(CPUARMState *env, int el)
{
if (el == 0) {
/* FIXME: ARMv8.1-VHE S2 translation regime. */
return env->cp15.sctlr_el[1];
} else {
return env->cp15.sctlr_el[el];
}
}
/* Return true if the processor is in big-endian mode. */
static inline bool arm_cpu_data_is_big_endian(CPUARMState *env)
{
int cur_el;
/* In 32bit endianness is determined by looking at CPSR's E bit */
if (!is_a64(env)) {
return
@ -3065,15 +3075,12 @@ static inline bool arm_cpu_data_is_big_endian(CPUARMState *env)
arm_sctlr_b(env) ||
#endif
((env->uncached_cpsr & CPSR_E) ? 1 : 0);
} else {
int cur_el = arm_current_el(env);
uint64_t sctlr = arm_sctlr(env, cur_el);
return (sctlr & (cur_el ? SCTLR_EE : SCTLR_E0E)) != 0;
}
cur_el = arm_current_el(env);
if (cur_el == 0) {
return (env->cp15.sctlr_el[1] & SCTLR_E0E) != 0;
}
return (env->cp15.sctlr_el[cur_el] & SCTLR_EE) != 0;
}
#include "exec/cpu-all.h"
@ -3301,6 +3308,16 @@ static inline bool isar_feature_aa32_fhm(const ARMISARegisters *id)
return FIELD_EX32(id->id_isar6, ID_ISAR6, FHM) != 0;
}
static inline bool isar_feature_aa32_sb(const ARMISARegisters *id)
{
return FIELD_EX32(id->id_isar6, ID_ISAR6, SB) != 0;
}
static inline bool isar_feature_aa32_predinv(const ARMISARegisters *id)
{
return FIELD_EX32(id->id_isar6, ID_ISAR6, SPECRES) != 0;
}
static inline bool isar_feature_aa32_fp16_arith(const ARMISARegisters *id)
{
/*
@ -3414,6 +3431,16 @@ static inline bool isar_feature_aa64_fhm(const ARMISARegisters *id)
return FIELD_EX64(id->id_aa64isar0, ID_AA64ISAR0, FHM) != 0;
}
static inline bool isar_feature_aa64_condm_4(const ARMISARegisters *id)
{
return FIELD_EX64(id->id_aa64isar0, ID_AA64ISAR0, TS) != 0;
}
static inline bool isar_feature_aa64_condm_5(const ARMISARegisters *id)
{
return FIELD_EX64(id->id_aa64isar0, ID_AA64ISAR0, TS) >= 2;
}
static inline bool isar_feature_aa64_jscvt(const ARMISARegisters *id)
{
return FIELD_EX64(id->id_aa64isar1, ID_AA64ISAR1, JSCVT) != 0;
@ -3439,6 +3466,21 @@ static inline bool isar_feature_aa64_pauth(const ARMISARegisters *id)
FIELD_DP64(0, ID_AA64ISAR1, GPI, 0xf))) != 0;
}
static inline bool isar_feature_aa64_sb(const ARMISARegisters *id)
{
return FIELD_EX64(id->id_aa64isar1, ID_AA64ISAR1, SB) != 0;
}
static inline bool isar_feature_aa64_predinv(const ARMISARegisters *id)
{
return FIELD_EX64(id->id_aa64isar1, ID_AA64ISAR1, SPECRES) != 0;
}
static inline bool isar_feature_aa64_frint(const ARMISARegisters *id)
{
return FIELD_EX64(id->id_aa64isar1, ID_AA64ISAR1, FRINTTS) != 0;
}
static inline bool isar_feature_aa64_fp16(const ARMISARegisters *id)
{
/* We always set the AdvSIMD and FP fields identically wrt FP16. */

View File

@ -309,6 +309,7 @@ static void aarch64_max_initfn(Object *obj)
t = FIELD_DP64(t, ID_AA64ISAR0, SM4, 1);
t = FIELD_DP64(t, ID_AA64ISAR0, DP, 1);
t = FIELD_DP64(t, ID_AA64ISAR0, FHM, 1);
t = FIELD_DP64(t, ID_AA64ISAR0, TS, 2); /* v8.5-CondM */
cpu->isar.id_aa64isar0 = t;
t = cpu->isar.id_aa64isar1;
@ -318,6 +319,9 @@ static void aarch64_max_initfn(Object *obj)
t = FIELD_DP64(t, ID_AA64ISAR1, API, 0);
t = FIELD_DP64(t, ID_AA64ISAR1, GPA, 1);
t = FIELD_DP64(t, ID_AA64ISAR1, GPI, 0);
t = FIELD_DP64(t, ID_AA64ISAR1, SB, 1);
t = FIELD_DP64(t, ID_AA64ISAR1, SPECRES, 1);
t = FIELD_DP64(t, ID_AA64ISAR1, FRINTTS, 1);
cpu->isar.id_aa64isar1 = t;
t = cpu->isar.id_aa64pfr0;
@ -349,6 +353,8 @@ static void aarch64_max_initfn(Object *obj)
u = FIELD_DP32(u, ID_ISAR6, JSCVT, 1);
u = FIELD_DP32(u, ID_ISAR6, DP, 1);
u = FIELD_DP32(u, ID_ISAR6, FHM, 1);
u = FIELD_DP32(u, ID_ISAR6, SB, 1);
u = FIELD_DP32(u, ID_ISAR6, SPECRES, 1);
cpu->isar.id_isar6 = u;
/*

View File

@ -61,6 +61,36 @@ uint64_t HELPER(rbit64)(uint64_t x)
return revbit64(x);
}
void HELPER(msr_i_spsel)(CPUARMState *env, uint32_t imm)
{
update_spsel(env, imm);
}
static void daif_check(CPUARMState *env, uint32_t op,
uint32_t imm, uintptr_t ra)
{
/* DAIF update to PSTATE. This is OK from EL0 only if UMA is set. */
if (arm_current_el(env) == 0 && !(env->cp15.sctlr_el[1] & SCTLR_UMA)) {
raise_exception_ra(env, EXCP_UDEF,
syn_aa64_sysregtrap(0, extract32(op, 0, 3),
extract32(op, 3, 3), 4,
imm, 0x1f, 0),
exception_target_el(env), ra);
}
}
void HELPER(msr_i_daifset)(CPUARMState *env, uint32_t imm)
{
daif_check(env, 0x1e, imm, GETPC());
env->daif |= (imm << 6) & PSTATE_DAIF;
}
void HELPER(msr_i_daifclear)(CPUARMState *env, uint32_t imm)
{
daif_check(env, 0x1f, imm, GETPC());
env->daif &= ~((imm << 6) & PSTATE_DAIF);
}
/* Convert a softfloat float_relation_ (as returned by
* the float*_compare functions) to the correct ARM
* NZCV flag state.

View File

@ -19,6 +19,9 @@
DEF_HELPER_FLAGS_2(udiv64, TCG_CALL_NO_RWG_SE, i64, i64, i64)
DEF_HELPER_FLAGS_2(sdiv64, TCG_CALL_NO_RWG_SE, s64, s64, s64)
DEF_HELPER_FLAGS_1(rbit64, TCG_CALL_NO_RWG_SE, i64, i64)
DEF_HELPER_2(msr_i_spsel, void, env, i32)
DEF_HELPER_2(msr_i_daifset, void, env, i32)
DEF_HELPER_2(msr_i_daifclear, void, env, i32)
DEF_HELPER_3(vfp_cmph_a64, i64, f16, f16, ptr)
DEF_HELPER_3(vfp_cmpeh_a64, i64, f16, f16, ptr)
DEF_HELPER_3(vfp_cmps_a64, i64, f32, f32, ptr)

View File

@ -5719,6 +5719,50 @@ static const ARMCPRegInfo pauth_reginfo[] = {
};
#endif
static CPAccessResult access_predinv(CPUARMState *env, const ARMCPRegInfo *ri,
bool isread)
{
int el = arm_current_el(env);
if (el == 0) {
uint64_t sctlr = arm_sctlr(env, el);
if (!(sctlr & SCTLR_EnRCTX)) {
return CP_ACCESS_TRAP;
}
} else if (el == 1) {
uint64_t hcr = arm_hcr_el2_eff(env);
if (hcr & HCR_NV) {
return CP_ACCESS_TRAP_EL2;
}
}
return CP_ACCESS_OK;
}
static const ARMCPRegInfo predinv_reginfo[] = {
{ .name = "CFP_RCTX", .state = ARM_CP_STATE_AA64,
.opc0 = 1, .opc1 = 3, .crn = 7, .crm = 3, .opc2 = 4,
.type = ARM_CP_NOP, .access = PL0_W, .accessfn = access_predinv },
{ .name = "DVP_RCTX", .state = ARM_CP_STATE_AA64,
.opc0 = 1, .opc1 = 3, .crn = 7, .crm = 3, .opc2 = 5,
.type = ARM_CP_NOP, .access = PL0_W, .accessfn = access_predinv },
{ .name = "CPP_RCTX", .state = ARM_CP_STATE_AA64,
.opc0 = 1, .opc1 = 3, .crn = 7, .crm = 3, .opc2 = 7,
.type = ARM_CP_NOP, .access = PL0_W, .accessfn = access_predinv },
/*
* Note the AArch32 opcodes have a different OPC1.
*/
{ .name = "CFPRCTX", .state = ARM_CP_STATE_AA32,
.cp = 15, .opc1 = 0, .crn = 7, .crm = 3, .opc2 = 4,
.type = ARM_CP_NOP, .access = PL0_W, .accessfn = access_predinv },
{ .name = "DVPRCTX", .state = ARM_CP_STATE_AA32,
.cp = 15, .opc1 = 0, .crn = 7, .crm = 3, .opc2 = 5,
.type = ARM_CP_NOP, .access = PL0_W, .accessfn = access_predinv },
{ .name = "CPPRCTX", .state = ARM_CP_STATE_AA32,
.cp = 15, .opc1 = 0, .crn = 7, .crm = 3, .opc2 = 7,
.type = ARM_CP_NOP, .access = PL0_W, .accessfn = access_predinv },
REGINFO_SENTINEL
};
void register_cp_regs_for_features(ARMCPU *cpu)
{
/* Register all the coprocessor registers based on feature bits */
@ -6618,6 +6662,17 @@ void register_cp_regs_for_features(ARMCPU *cpu)
define_arm_cp_regs(cpu, pauth_reginfo);
}
#endif
/*
* While all v8.0 cpus support aarch64, QEMU does have configurations
* that do not set ID_AA64ISAR1, e.g. user-only qemu-arm -cpu max,
* which will set ID_ISAR6.
*/
if (arm_feature(&cpu->env, ARM_FEATURE_AARCH64)
? cpu_isar_feature(aa64_predinv, cpu)
: cpu_isar_feature(aa32_predinv, cpu)) {
define_arm_cp_regs(cpu, predinv_reginfo);
}
}
void arm_cpu_register_gdb_regs_for_features(ARMCPU *cpu)
@ -12854,12 +12909,8 @@ void cpu_get_tb_cpu_state(CPUARMState *env, target_ulong *pc,
flags = FIELD_DP32(flags, TBFLAG_A64, ZCR_LEN, zcr_len);
}
if (current_el == 0) {
/* FIXME: ARMv8.1-VHE S2 translation regime. */
sctlr = env->cp15.sctlr_el[1];
} else {
sctlr = env->cp15.sctlr_el[current_el];
}
sctlr = arm_sctlr(env, current_el);
if (cpu_isar_feature(aa64_pauth, cpu)) {
/*
* In order to save space in flags, we record only whether

View File

@ -77,9 +77,6 @@ DEF_HELPER_2(get_cp_reg, i32, env, ptr)
DEF_HELPER_3(set_cp_reg64, void, env, ptr, i64)
DEF_HELPER_2(get_cp_reg64, i64, env, ptr)
DEF_HELPER_3(msr_i_pstate, void, env, i32, i32)
DEF_HELPER_1(clear_pstate_ss, void, env)
DEF_HELPER_2(get_r13_banked, i32, env, i32)
DEF_HELPER_3(set_r13_banked, void, env, i32, i32)
@ -686,6 +683,11 @@ DEF_HELPER_FLAGS_5(gvec_fmlal_idx_a32, TCG_CALL_NO_RWG,
DEF_HELPER_FLAGS_5(gvec_fmlal_idx_a64, TCG_CALL_NO_RWG,
void, ptr, ptr, ptr, ptr, i32)
DEF_HELPER_FLAGS_2(frint32_s, TCG_CALL_NO_RWG, f32, f32, ptr)
DEF_HELPER_FLAGS_2(frint64_s, TCG_CALL_NO_RWG, f32, f32, ptr)
DEF_HELPER_FLAGS_2(frint32_d, TCG_CALL_NO_RWG, f64, f64, ptr)
DEF_HELPER_FLAGS_2(frint64_d, TCG_CALL_NO_RWG, f64, f64, ptr)
#ifdef TARGET_AARCH64
#include "helper-a64.h"
#include "helper-sve.h"

View File

@ -968,4 +968,19 @@ ARMVAParameters aa64_va_parameters_both(CPUARMState *env, uint64_t va,
ARMVAParameters aa64_va_parameters(CPUARMState *env, uint64_t va,
ARMMMUIdx mmu_idx, bool data);
static inline int exception_target_el(CPUARMState *env)
{
int target_el = MAX(1, arm_current_el(env));
/*
* No such thing as secure EL1 if EL3 is aarch32,
* so update the target EL to EL3 in this case.
*/
if (arm_is_secure(env) && !arm_el_is_aa64(env, 3) && target_el == 1) {
target_el = 3;
}
return target_el;
}
#endif

View File

@ -18,6 +18,7 @@
#include "qemu/error-report.h"
#include "sysemu/sysemu.h"
#include "sysemu/kvm.h"
#include "sysemu/kvm_int.h"
#include "kvm_arm.h"
#include "cpu.h"
#include "trace.h"
@ -162,6 +163,15 @@ void kvm_arm_set_cpu_features_from_host(ARMCPU *cpu)
env->features = arm_host_cpu_features.features;
}
int kvm_arm_get_max_vm_ipa_size(MachineState *ms)
{
KVMState *s = KVM_STATE(ms->accelerator);
int ret;
ret = kvm_check_extension(s, KVM_CAP_ARM_VM_IPA_SIZE);
return ret > 0 ? ret : 40;
}
int kvm_arch_init(MachineState *ms, KVMState *s)
{
/* For ARM interrupt delivery is always asynchronous,

View File

@ -207,6 +207,14 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf);
*/
void kvm_arm_set_cpu_features_from_host(ARMCPU *cpu);
/**
* kvm_arm_get_max_vm_ipa_size - Returns the number of bits in the
* IPA address space supported by KVM
*
* @ms: Machine state handle
*/
int kvm_arm_get_max_vm_ipa_size(MachineState *ms);
/**
* kvm_arm_sync_mpstate_to_kvm
* @cpu: ARMCPU
@ -239,6 +247,11 @@ static inline void kvm_arm_set_cpu_features_from_host(ARMCPU *cpu)
cpu->host_cpu_probe_failed = true;
}
static inline int kvm_arm_get_max_vm_ipa_size(MachineState *ms)
{
return -ENOENT;
}
static inline int kvm_arm_vgic_probe(void)
{
return 0;

View File

@ -68,20 +68,6 @@ void raise_exception_ra(CPUARMState *env, uint32_t excp, uint32_t syndrome,
cpu_loop_exit_restore(cs, ra);
}
static int exception_target_el(CPUARMState *env)
{
int target_el = MAX(1, arm_current_el(env));
/* No such thing as secure EL1 if EL3 is aarch32, so update the target EL
* to EL3 in this case.
*/
if (arm_is_secure(env) && !arm_el_is_aa64(env, 3) && target_el == 1) {
target_el = 3;
}
return target_el;
}
uint32_t HELPER(neon_tbl)(uint32_t ireg, uint32_t def, void *vn,
uint32_t maxindex)
{
@ -875,39 +861,6 @@ uint64_t HELPER(get_cp_reg64)(CPUARMState *env, void *rip)
return res;
}
void HELPER(msr_i_pstate)(CPUARMState *env, uint32_t op, uint32_t imm)
{
/* MSR_i to update PSTATE. This is OK from EL0 only if UMA is set.
* Note that SPSel is never OK from EL0; we rely on handle_msr_i()
* to catch that case at translate time.
*/
if (arm_current_el(env) == 0 && !(env->cp15.sctlr_el[1] & SCTLR_UMA)) {
uint32_t syndrome = syn_aa64_sysregtrap(0, extract32(op, 0, 3),
extract32(op, 3, 3), 4,
imm, 0x1f, 0);
raise_exception(env, EXCP_UDEF, syndrome, exception_target_el(env));
}
switch (op) {
case 0x05: /* SPSel */
update_spsel(env, imm);
break;
case 0x1e: /* DAIFSet */
env->daif |= (imm << 6) & PSTATE_DAIF;
break;
case 0x1f: /* DAIFClear */
env->daif &= ~((imm << 6) & PSTATE_DAIF);
break;
default:
g_assert_not_reached();
}
}
void HELPER(clear_pstate_ss)(CPUARMState *env)
{
env->pstate &= ~PSTATE_SS;
}
void HELPER(pre_hvc)(CPUARMState *env)
{
ARMCPU *cpu = arm_env_get_cpu(env);

View File

@ -421,17 +421,6 @@ static void gen_exception_bkpt_insn(DisasContext *s, int offset,
s->base.is_jmp = DISAS_NORETURN;
}
static void gen_ss_advance(DisasContext *s)
{
/* If the singlestep state is Active-not-pending, advance to
* Active-pending.
*/
if (s->ss_active) {
s->pstate_ss = 0;
gen_helper_clear_pstate_ss(cpu_env);
}
}
static void gen_step_complete_exception(DisasContext *s)
{
/* We just completed step of an insn. Move from Active-not-pending
@ -1637,39 +1626,128 @@ static void handle_sync(DisasContext *s, uint32_t insn,
reset_btype(s);
gen_goto_tb(s, 0, s->pc);
return;
case 7: /* SB */
if (crm != 0 || !dc_isar_feature(aa64_sb, s)) {
goto do_unallocated;
}
/*
* TODO: There is no speculation barrier opcode for TCG;
* MB and end the TB instead.
*/
tcg_gen_mb(TCG_MO_ALL | TCG_BAR_SC);
gen_goto_tb(s, 0, s->pc);
return;
default:
do_unallocated:
unallocated_encoding(s);
return;
}
}
static void gen_xaflag(void)
{
TCGv_i32 z = tcg_temp_new_i32();
tcg_gen_setcondi_i32(TCG_COND_EQ, z, cpu_ZF, 0);
/*
* (!C & !Z) << 31
* (!(C | Z)) << 31
* ~((C | Z) << 31)
* ~-(C | Z)
* (C | Z) - 1
*/
tcg_gen_or_i32(cpu_NF, cpu_CF, z);
tcg_gen_subi_i32(cpu_NF, cpu_NF, 1);
/* !(Z & C) */
tcg_gen_and_i32(cpu_ZF, z, cpu_CF);
tcg_gen_xori_i32(cpu_ZF, cpu_ZF, 1);
/* (!C & Z) << 31 -> -(Z & ~C) */
tcg_gen_andc_i32(cpu_VF, z, cpu_CF);
tcg_gen_neg_i32(cpu_VF, cpu_VF);
/* C | Z */
tcg_gen_or_i32(cpu_CF, cpu_CF, z);
tcg_temp_free_i32(z);
}
static void gen_axflag(void)
{
tcg_gen_sari_i32(cpu_VF, cpu_VF, 31); /* V ? -1 : 0 */
tcg_gen_andc_i32(cpu_CF, cpu_CF, cpu_VF); /* C & !V */
/* !(Z | V) -> !(!ZF | V) -> ZF & !V -> ZF & ~VF */
tcg_gen_andc_i32(cpu_ZF, cpu_ZF, cpu_VF);
tcg_gen_movi_i32(cpu_NF, 0);
tcg_gen_movi_i32(cpu_VF, 0);
}
/* MSR (immediate) - move immediate to processor state field */
static void handle_msr_i(DisasContext *s, uint32_t insn,
unsigned int op1, unsigned int op2, unsigned int crm)
{
TCGv_i32 t1;
int op = op1 << 3 | op2;
/* End the TB by default, chaining is ok. */
s->base.is_jmp = DISAS_TOO_MANY;
switch (op) {
case 0x00: /* CFINV */
if (crm != 0 || !dc_isar_feature(aa64_condm_4, s)) {
goto do_unallocated;
}
tcg_gen_xori_i32(cpu_CF, cpu_CF, 1);
s->base.is_jmp = DISAS_NEXT;
break;
case 0x01: /* XAFlag */
if (crm != 0 || !dc_isar_feature(aa64_condm_5, s)) {
goto do_unallocated;
}
gen_xaflag();
s->base.is_jmp = DISAS_NEXT;
break;
case 0x02: /* AXFlag */
if (crm != 0 || !dc_isar_feature(aa64_condm_5, s)) {
goto do_unallocated;
}
gen_axflag();
s->base.is_jmp = DISAS_NEXT;
break;
case 0x05: /* SPSel */
if (s->current_el == 0) {
unallocated_encoding(s);
return;
goto do_unallocated;
}
/* fall through */
case 0x1e: /* DAIFSet */
case 0x1f: /* DAIFClear */
{
TCGv_i32 tcg_imm = tcg_const_i32(crm);
TCGv_i32 tcg_op = tcg_const_i32(op);
gen_a64_set_pc_im(s->pc - 4);
gen_helper_msr_i_pstate(cpu_env, tcg_op, tcg_imm);
tcg_temp_free_i32(tcg_imm);
tcg_temp_free_i32(tcg_op);
/* For DAIFClear, exit the cpu loop to re-evaluate pending IRQs. */
gen_a64_set_pc_im(s->pc);
s->base.is_jmp = (op == 0x1f ? DISAS_EXIT : DISAS_JUMP);
t1 = tcg_const_i32(crm & PSTATE_SP);
gen_helper_msr_i_spsel(cpu_env, t1);
tcg_temp_free_i32(t1);
break;
}
case 0x1e: /* DAIFSet */
t1 = tcg_const_i32(crm);
gen_helper_msr_i_daifset(cpu_env, t1);
tcg_temp_free_i32(t1);
break;
case 0x1f: /* DAIFClear */
t1 = tcg_const_i32(crm);
gen_helper_msr_i_daifclear(cpu_env, t1);
tcg_temp_free_i32(t1);
/* For DAIFClear, exit the cpu loop to re-evaluate pending IRQs. */
s->base.is_jmp = DISAS_UPDATE;
break;
default:
do_unallocated:
unallocated_encoding(s);
return;
}
@ -1698,7 +1776,6 @@ static void gen_get_nzcv(TCGv_i64 tcg_rt)
}
static void gen_set_nzcv(TCGv_i64 tcg_rt)
{
TCGv_i32 nzcv = tcg_temp_new_i32();
@ -4482,11 +4559,10 @@ static void disas_data_proc_3src(DisasContext *s, uint32_t insn)
}
/* Add/subtract (with carry)
* 31 30 29 28 27 26 25 24 23 22 21 20 16 15 10 9 5 4 0
* +--+--+--+------------------------+------+---------+------+-----+
* |sf|op| S| 1 1 0 1 0 0 0 0 | rm | opcode2 | Rn | Rd |
* +--+--+--+------------------------+------+---------+------+-----+
* [000000]
* 31 30 29 28 27 26 25 24 23 22 21 20 16 15 10 9 5 4 0
* +--+--+--+------------------------+------+-------------+------+-----+
* |sf|op| S| 1 1 0 1 0 0 0 0 | rm | 0 0 0 0 0 0 | Rn | Rd |
* +--+--+--+------------------------+------+-------------+------+-----+
*/
static void disas_adc_sbc(DisasContext *s, uint32_t insn)
@ -4494,11 +4570,6 @@ static void disas_adc_sbc(DisasContext *s, uint32_t insn)
unsigned int sf, op, setflags, rm, rn, rd;
TCGv_i64 tcg_y, tcg_rn, tcg_rd;
if (extract32(insn, 10, 6) != 0) {
unallocated_encoding(s);
return;
}
sf = extract32(insn, 31, 1);
op = extract32(insn, 30, 1);
setflags = extract32(insn, 29, 1);
@ -4523,6 +4594,84 @@ static void disas_adc_sbc(DisasContext *s, uint32_t insn)
}
}
/*
* Rotate right into flags
* 31 30 29 21 15 10 5 4 0
* +--+--+--+-----------------+--------+-----------+------+--+------+
* |sf|op| S| 1 1 0 1 0 0 0 0 | imm6 | 0 0 0 0 1 | Rn |o2| mask |
* +--+--+--+-----------------+--------+-----------+------+--+------+
*/
static void disas_rotate_right_into_flags(DisasContext *s, uint32_t insn)
{
int mask = extract32(insn, 0, 4);
int o2 = extract32(insn, 4, 1);
int rn = extract32(insn, 5, 5);
int imm6 = extract32(insn, 15, 6);
int sf_op_s = extract32(insn, 29, 3);
TCGv_i64 tcg_rn;
TCGv_i32 nzcv;
if (sf_op_s != 5 || o2 != 0 || !dc_isar_feature(aa64_condm_4, s)) {
unallocated_encoding(s);
return;
}
tcg_rn = read_cpu_reg(s, rn, 1);
tcg_gen_rotri_i64(tcg_rn, tcg_rn, imm6);
nzcv = tcg_temp_new_i32();
tcg_gen_extrl_i64_i32(nzcv, tcg_rn);
if (mask & 8) { /* N */
tcg_gen_shli_i32(cpu_NF, nzcv, 31 - 3);
}
if (mask & 4) { /* Z */
tcg_gen_not_i32(cpu_ZF, nzcv);
tcg_gen_andi_i32(cpu_ZF, cpu_ZF, 4);
}
if (mask & 2) { /* C */
tcg_gen_extract_i32(cpu_CF, nzcv, 1, 1);
}
if (mask & 1) { /* V */
tcg_gen_shli_i32(cpu_VF, nzcv, 31 - 0);
}
tcg_temp_free_i32(nzcv);
}
/*
* Evaluate into flags
* 31 30 29 21 15 14 10 5 4 0
* +--+--+--+-----------------+---------+----+---------+------+--+------+
* |sf|op| S| 1 1 0 1 0 0 0 0 | opcode2 | sz | 0 0 1 0 | Rn |o3| mask |
* +--+--+--+-----------------+---------+----+---------+------+--+------+
*/
static void disas_evaluate_into_flags(DisasContext *s, uint32_t insn)
{
int o3_mask = extract32(insn, 0, 5);
int rn = extract32(insn, 5, 5);
int o2 = extract32(insn, 15, 6);
int sz = extract32(insn, 14, 1);
int sf_op_s = extract32(insn, 29, 3);
TCGv_i32 tmp;
int shift;
if (sf_op_s != 1 || o2 != 0 || o3_mask != 0xd ||
!dc_isar_feature(aa64_condm_4, s)) {
unallocated_encoding(s);
return;
}
shift = sz ? 16 : 24; /* SETF16 or SETF8 */
tmp = tcg_temp_new_i32();
tcg_gen_extrl_i64_i32(tmp, cpu_reg(s, rn));
tcg_gen_shli_i32(cpu_NF, tmp, shift);
tcg_gen_shli_i32(cpu_VF, tmp, shift - 1);
tcg_gen_mov_i32(cpu_ZF, cpu_NF);
tcg_gen_xor_i32(cpu_VF, cpu_VF, cpu_NF);
tcg_temp_free_i32(tmp);
}
/* Conditional compare (immediate / register)
* 31 30 29 28 27 26 25 24 23 22 21 20 16 15 12 11 10 9 5 4 3 0
* +--+--+--+------------------------+--------+------+----+--+------+--+-----+
@ -5152,47 +5301,81 @@ static void disas_data_proc_2src(DisasContext *s, uint32_t insn)
}
}
/* Data processing - register */
/*
* Data processing - register
* 31 30 29 28 25 21 20 16 10 0
* +--+---+--+---+-------+-----+-------+-------+---------+
* | |op0| |op1| 1 0 1 | op2 | | op3 | |
* +--+---+--+---+-------+-----+-------+-------+---------+
*/
static void disas_data_proc_reg(DisasContext *s, uint32_t insn)
{
switch (extract32(insn, 24, 5)) {
case 0x0a: /* Logical (shifted register) */
disas_logic_reg(s, insn);
break;
case 0x0b: /* Add/subtract */
if (insn & (1 << 21)) { /* (extended register) */
disas_add_sub_ext_reg(s, insn);
int op0 = extract32(insn, 30, 1);
int op1 = extract32(insn, 28, 1);
int op2 = extract32(insn, 21, 4);
int op3 = extract32(insn, 10, 6);
if (!op1) {
if (op2 & 8) {
if (op2 & 1) {
/* Add/sub (extended register) */
disas_add_sub_ext_reg(s, insn);
} else {
/* Add/sub (shifted register) */
disas_add_sub_reg(s, insn);
}
} else {
disas_add_sub_reg(s, insn);
/* Logical (shifted register) */
disas_logic_reg(s, insn);
}
break;
case 0x1b: /* Data-processing (3 source) */
disas_data_proc_3src(s, insn);
break;
case 0x1a:
switch (extract32(insn, 21, 3)) {
case 0x0: /* Add/subtract (with carry) */
return;
}
switch (op2) {
case 0x0:
switch (op3) {
case 0x00: /* Add/subtract (with carry) */
disas_adc_sbc(s, insn);
break;
case 0x2: /* Conditional compare */
disas_cc(s, insn); /* both imm and reg forms */
case 0x01: /* Rotate right into flags */
case 0x21:
disas_rotate_right_into_flags(s, insn);
break;
case 0x4: /* Conditional select */
disas_cond_select(s, insn);
break;
case 0x6: /* Data-processing */
if (insn & (1 << 30)) { /* (1 source) */
disas_data_proc_1src(s, insn);
} else { /* (2 source) */
disas_data_proc_2src(s, insn);
}
case 0x02: /* Evaluate into flags */
case 0x12:
case 0x22:
case 0x32:
disas_evaluate_into_flags(s, insn);
break;
default:
unallocated_encoding(s);
break;
goto do_unallocated;
}
break;
case 0x2: /* Conditional compare */
disas_cc(s, insn); /* both imm and reg forms */
break;
case 0x4: /* Conditional select */
disas_cond_select(s, insn);
break;
case 0x6: /* Data-processing */
if (op0) { /* (1 source) */
disas_data_proc_1src(s, insn);
} else { /* (2 source) */
disas_data_proc_2src(s, insn);
}
break;
case 0x8 ... 0xf: /* (3 source) */
disas_data_proc_3src(s, insn);
break;
default:
do_unallocated:
unallocated_encoding(s);
break;
}
@ -5505,55 +5688,73 @@ static void handle_fp_1src_half(DisasContext *s, int opcode, int rd, int rn)
/* Floating-point data-processing (1 source) - single precision */
static void handle_fp_1src_single(DisasContext *s, int opcode, int rd, int rn)
{
void (*gen_fpst)(TCGv_i32, TCGv_i32, TCGv_ptr);
TCGv_i32 tcg_op, tcg_res;
TCGv_ptr fpst;
TCGv_i32 tcg_op;
TCGv_i32 tcg_res;
int rmode = -1;
fpst = get_fpstatus_ptr(false);
tcg_op = read_fp_sreg(s, rn);
tcg_res = tcg_temp_new_i32();
switch (opcode) {
case 0x0: /* FMOV */
tcg_gen_mov_i32(tcg_res, tcg_op);
break;
goto done;
case 0x1: /* FABS */
gen_helper_vfp_abss(tcg_res, tcg_op);
break;
goto done;
case 0x2: /* FNEG */
gen_helper_vfp_negs(tcg_res, tcg_op);
break;
goto done;
case 0x3: /* FSQRT */
gen_helper_vfp_sqrts(tcg_res, tcg_op, cpu_env);
break;
goto done;
case 0x8: /* FRINTN */
case 0x9: /* FRINTP */
case 0xa: /* FRINTM */
case 0xb: /* FRINTZ */
case 0xc: /* FRINTA */
{
TCGv_i32 tcg_rmode = tcg_const_i32(arm_rmode_to_sf(opcode & 7));
gen_helper_set_rmode(tcg_rmode, tcg_rmode, fpst);
gen_helper_rints(tcg_res, tcg_op, fpst);
gen_helper_set_rmode(tcg_rmode, tcg_rmode, fpst);
tcg_temp_free_i32(tcg_rmode);
rmode = arm_rmode_to_sf(opcode & 7);
gen_fpst = gen_helper_rints;
break;
}
case 0xe: /* FRINTX */
gen_helper_rints_exact(tcg_res, tcg_op, fpst);
gen_fpst = gen_helper_rints_exact;
break;
case 0xf: /* FRINTI */
gen_helper_rints(tcg_res, tcg_op, fpst);
gen_fpst = gen_helper_rints;
break;
case 0x10: /* FRINT32Z */
rmode = float_round_to_zero;
gen_fpst = gen_helper_frint32_s;
break;
case 0x11: /* FRINT32X */
gen_fpst = gen_helper_frint32_s;
break;
case 0x12: /* FRINT64Z */
rmode = float_round_to_zero;
gen_fpst = gen_helper_frint64_s;
break;
case 0x13: /* FRINT64X */
gen_fpst = gen_helper_frint64_s;
break;
default:
abort();
g_assert_not_reached();
}
write_fp_sreg(s, rd, tcg_res);
fpst = get_fpstatus_ptr(false);
if (rmode >= 0) {
TCGv_i32 tcg_rmode = tcg_const_i32(rmode);
gen_helper_set_rmode(tcg_rmode, tcg_rmode, fpst);
gen_fpst(tcg_res, tcg_op, fpst);
gen_helper_set_rmode(tcg_rmode, tcg_rmode, fpst);
tcg_temp_free_i32(tcg_rmode);
} else {
gen_fpst(tcg_res, tcg_op, fpst);
}
tcg_temp_free_ptr(fpst);
done:
write_fp_sreg(s, rd, tcg_res);
tcg_temp_free_i32(tcg_op);
tcg_temp_free_i32(tcg_res);
}
@ -5561,9 +5762,10 @@ static void handle_fp_1src_single(DisasContext *s, int opcode, int rd, int rn)
/* Floating-point data-processing (1 source) - double precision */
static void handle_fp_1src_double(DisasContext *s, int opcode, int rd, int rn)
{
void (*gen_fpst)(TCGv_i64, TCGv_i64, TCGv_ptr);
TCGv_i64 tcg_op, tcg_res;
TCGv_ptr fpst;
TCGv_i64 tcg_op;
TCGv_i64 tcg_res;
int rmode = -1;
switch (opcode) {
case 0x0: /* FMOV */
@ -5571,48 +5773,65 @@ static void handle_fp_1src_double(DisasContext *s, int opcode, int rd, int rn)
return;
}
fpst = get_fpstatus_ptr(false);
tcg_op = read_fp_dreg(s, rn);
tcg_res = tcg_temp_new_i64();
switch (opcode) {
case 0x1: /* FABS */
gen_helper_vfp_absd(tcg_res, tcg_op);
break;
goto done;
case 0x2: /* FNEG */
gen_helper_vfp_negd(tcg_res, tcg_op);
break;
goto done;
case 0x3: /* FSQRT */
gen_helper_vfp_sqrtd(tcg_res, tcg_op, cpu_env);
break;
goto done;
case 0x8: /* FRINTN */
case 0x9: /* FRINTP */
case 0xa: /* FRINTM */
case 0xb: /* FRINTZ */
case 0xc: /* FRINTA */
{
TCGv_i32 tcg_rmode = tcg_const_i32(arm_rmode_to_sf(opcode & 7));
gen_helper_set_rmode(tcg_rmode, tcg_rmode, fpst);
gen_helper_rintd(tcg_res, tcg_op, fpst);
gen_helper_set_rmode(tcg_rmode, tcg_rmode, fpst);
tcg_temp_free_i32(tcg_rmode);
rmode = arm_rmode_to_sf(opcode & 7);
gen_fpst = gen_helper_rintd;
break;
}
case 0xe: /* FRINTX */
gen_helper_rintd_exact(tcg_res, tcg_op, fpst);
gen_fpst = gen_helper_rintd_exact;
break;
case 0xf: /* FRINTI */
gen_helper_rintd(tcg_res, tcg_op, fpst);
gen_fpst = gen_helper_rintd;
break;
case 0x10: /* FRINT32Z */
rmode = float_round_to_zero;
gen_fpst = gen_helper_frint32_d;
break;
case 0x11: /* FRINT32X */
gen_fpst = gen_helper_frint32_d;
break;
case 0x12: /* FRINT64Z */
rmode = float_round_to_zero;
gen_fpst = gen_helper_frint64_d;
break;
case 0x13: /* FRINT64X */
gen_fpst = gen_helper_frint64_d;
break;
default:
abort();
g_assert_not_reached();
}
write_fp_dreg(s, rd, tcg_res);
fpst = get_fpstatus_ptr(false);
if (rmode >= 0) {
TCGv_i32 tcg_rmode = tcg_const_i32(rmode);
gen_helper_set_rmode(tcg_rmode, tcg_rmode, fpst);
gen_fpst(tcg_res, tcg_op, fpst);
gen_helper_set_rmode(tcg_rmode, tcg_rmode, fpst);
tcg_temp_free_i32(tcg_rmode);
} else {
gen_fpst(tcg_res, tcg_op, fpst);
}
tcg_temp_free_ptr(fpst);
done:
write_fp_dreg(s, rd, tcg_res);
tcg_temp_free_i64(tcg_op);
tcg_temp_free_i64(tcg_res);
}
@ -5731,6 +5950,13 @@ static void disas_fp_1src(DisasContext *s, uint32_t insn)
handle_fp_fcvt(s, opcode, rd, rn, dtype, type);
break;
}
case 0x10 ... 0x13: /* FRINT{32,64}{X,Z} */
if (type > 1 || !dc_isar_feature(aa64_frint, s)) {
unallocated_encoding(s);
return;
}
/* fall through */
case 0x0 ... 0x3:
case 0x8 ... 0xc:
case 0xe ... 0xf:
@ -5740,14 +5966,12 @@ static void disas_fp_1src(DisasContext *s, uint32_t insn)
if (!fp_access_check(s)) {
return;
}
handle_fp_1src_single(s, opcode, rd, rn);
break;
case 1:
if (!fp_access_check(s)) {
return;
}
handle_fp_1src_double(s, opcode, rd, rn);
break;
case 3:
@ -5759,13 +5983,13 @@ static void disas_fp_1src(DisasContext *s, uint32_t insn)
if (!fp_access_check(s)) {
return;
}
handle_fp_1src_half(s, opcode, rd, rn);
break;
default:
unallocated_encoding(s);
}
break;
default:
unallocated_encoding(s);
break;
@ -9293,6 +9517,14 @@ static void handle_2misc_64(DisasContext *s, int opcode, bool u,
case 0x59: /* FRINTX */
gen_helper_rintd_exact(tcg_rd, tcg_rn, tcg_fpstatus);
break;
case 0x1e: /* FRINT32Z */
case 0x5e: /* FRINT32X */
gen_helper_frint32_d(tcg_rd, tcg_rn, tcg_fpstatus);
break;
case 0x1f: /* FRINT64Z */
case 0x5f: /* FRINT64X */
gen_helper_frint64_d(tcg_rd, tcg_rn, tcg_fpstatus);
break;
default:
g_assert_not_reached();
}
@ -11943,8 +12175,7 @@ static void disas_simd_two_reg_misc(DisasContext *s, uint32_t insn)
}
break;
case 0xc ... 0xf:
case 0x16 ... 0x1d:
case 0x1f:
case 0x16 ... 0x1f:
{
/* Floating point: U, size[1] and opcode indicate operation;
* size[0] indicates single or double precision.
@ -12087,6 +12318,19 @@ static void disas_simd_two_reg_misc(DisasContext *s, uint32_t insn)
}
need_fpstatus = true;
break;
case 0x1e: /* FRINT32Z */
case 0x1f: /* FRINT64Z */
need_rmode = true;
rmode = FPROUNDING_ZERO;
/* fall through */
case 0x5e: /* FRINT32X */
case 0x5f: /* FRINT64X */
need_fpstatus = true;
if ((size == 3 && !is_q) || !dc_isar_feature(aa64_frint, s)) {
unallocated_encoding(s);
return;
}
break;
default:
unallocated_encoding(s);
return;
@ -12252,6 +12496,14 @@ static void disas_simd_two_reg_misc(DisasContext *s, uint32_t insn)
case 0x7c: /* URSQRTE */
gen_helper_rsqrte_u32(tcg_res, tcg_op, tcg_fpstatus);
break;
case 0x1e: /* FRINT32Z */
case 0x5e: /* FRINT32X */
gen_helper_frint32_s(tcg_res, tcg_op, tcg_fpstatus);
break;
case 0x1f: /* FRINT64Z */
case 0x5f: /* FRINT64X */
gen_helper_frint64_s(tcg_res, tcg_op, tcg_fpstatus);
break;
default:
g_assert_not_reached();
}

View File

@ -298,17 +298,6 @@ static void gen_exception(int excp, uint32_t syndrome, uint32_t target_el)
tcg_temp_free_i32(tcg_excp);
}
static void gen_ss_advance(DisasContext *s)
{
/* If the singlestep state is Active-not-pending, advance to
* Active-pending.
*/
if (s->ss_active) {
s->pstate_ss = 0;
gen_helper_clear_pstate_ss(cpu_env);
}
}
static void gen_step_complete_exception(DisasContext *s)
{
/* We just completed step of an insn. Move from Active-not-pending
@ -9282,6 +9271,17 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn)
*/
gen_goto_tb(s, 0, s->pc & ~1);
return;
case 7: /* sb */
if ((insn & 0xf) || !dc_isar_feature(aa32_sb, s)) {
goto illegal_op;
}
/*
* TODO: There is no speculation barrier opcode
* for TCG; MB and end the TB instead.
*/
tcg_gen_mb(TCG_MO_ALL | TCG_BAR_SC);
gen_goto_tb(s, 0, s->pc & ~1);
return;
default:
goto illegal_op;
}
@ -10612,7 +10612,7 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn)
} else if (i == rn) {
loaded_var = tmp;
loaded_base = 1;
} else if (rn == 15 && exc_return) {
} else if (i == 15 && exc_return) {
store_pc_exc_ret(s, tmp);
} else {
store_reg_from_load(s, i, tmp);
@ -11900,6 +11900,17 @@ static void disas_thumb2_insn(DisasContext *s, uint32_t insn)
*/
gen_goto_tb(s, 0, s->pc & ~1);
break;
case 7: /* sb */
if ((insn & 0xf) || !dc_isar_feature(aa32_sb, s)) {
goto illegal_op;
}
/*
* TODO: There is no speculation barrier opcode
* for TCG; MB and end the TB instead.
*/
tcg_gen_mb(TCG_MO_ALL | TCG_BAR_SC);
gen_goto_tb(s, 0, s->pc & ~1);
break;
default:
goto illegal_op;
}

View File

@ -202,6 +202,40 @@ static inline TCGv_i32 get_ahp_flag(void)
return ret;
}
/* Set bits within PSTATE. */
static inline void set_pstate_bits(uint32_t bits)
{
TCGv_i32 p = tcg_temp_new_i32();
tcg_debug_assert(!(bits & CACHED_PSTATE_BITS));
tcg_gen_ld_i32(p, cpu_env, offsetof(CPUARMState, pstate));
tcg_gen_ori_i32(p, p, bits);
tcg_gen_st_i32(p, cpu_env, offsetof(CPUARMState, pstate));
tcg_temp_free_i32(p);
}
/* Clear bits within PSTATE. */
static inline void clear_pstate_bits(uint32_t bits)
{
TCGv_i32 p = tcg_temp_new_i32();
tcg_debug_assert(!(bits & CACHED_PSTATE_BITS));
tcg_gen_ld_i32(p, cpu_env, offsetof(CPUARMState, pstate));
tcg_gen_andi_i32(p, p, ~bits);
tcg_gen_st_i32(p, cpu_env, offsetof(CPUARMState, pstate));
tcg_temp_free_i32(p);
}
/* If the singlestep state is Active-not-pending, advance to Active-pending. */
static inline void gen_ss_advance(DisasContext *s)
{
if (s->ss_active) {
s->pstate_ss = 0;
clear_pstate_bits(PSTATE_SS);
}
}
/* Vector operations shared between ARM and AArch64. */
extern const GVecGen3 bsl_op;

View File

@ -1174,3 +1174,99 @@ uint32_t HELPER(vjcvt)(float64 value, CPUARMState *env)
return result;
}
/* Round a float32 to an integer that fits in int32_t or int64_t. */
static float32 frint_s(float32 f, float_status *fpst, int intsize)
{
int old_flags = get_float_exception_flags(fpst);
uint32_t exp = extract32(f, 23, 8);
if (unlikely(exp == 0xff)) {
/* NaN or Inf. */
goto overflow;
}
/* Round and re-extract the exponent. */
f = float32_round_to_int(f, fpst);
exp = extract32(f, 23, 8);
/* Validate the range of the result. */
if (exp < 126 + intsize) {
/* abs(F) <= INT{N}_MAX */
return f;
}
if (exp == 126 + intsize) {
uint32_t sign = extract32(f, 31, 1);
uint32_t frac = extract32(f, 0, 23);
if (sign && frac == 0) {
/* F == INT{N}_MIN */
return f;
}
}
overflow:
/*
* Raise Invalid and return INT{N}_MIN as a float. Revert any
* inexact exception float32_round_to_int may have raised.
*/
set_float_exception_flags(old_flags | float_flag_invalid, fpst);
return (0x100u + 126u + intsize) << 23;
}
float32 HELPER(frint32_s)(float32 f, void *fpst)
{
return frint_s(f, fpst, 32);
}
float32 HELPER(frint64_s)(float32 f, void *fpst)
{
return frint_s(f, fpst, 64);
}
/* Round a float64 to an integer that fits in int32_t or int64_t. */
static float64 frint_d(float64 f, float_status *fpst, int intsize)
{
int old_flags = get_float_exception_flags(fpst);
uint32_t exp = extract64(f, 52, 11);
if (unlikely(exp == 0x7ff)) {
/* NaN or Inf. */
goto overflow;
}
/* Round and re-extract the exponent. */
f = float64_round_to_int(f, fpst);
exp = extract64(f, 52, 11);
/* Validate the range of the result. */
if (exp < 1022 + intsize) {
/* abs(F) <= INT{N}_MAX */
return f;
}
if (exp == 1022 + intsize) {
uint64_t sign = extract64(f, 63, 1);
uint64_t frac = extract64(f, 0, 52);
if (sign && frac == 0) {
/* F == INT{N}_MIN */
return f;
}
}
overflow:
/*
* Raise Invalid and return INT{N}_MIN as a float. Revert any
* inexact exception float64_round_to_int may have raised.
*/
set_float_exception_flags(old_flags | float_flag_invalid, fpst);
return (uint64_t)(0x800 + 1022 + intsize) << 52;
}
float64 HELPER(frint32_d)(float64 f, void *fpst)
{
return frint_d(f, fpst, 32);
}
float64 HELPER(frint64_d)(float64 f, void *fpst)
{
return frint_d(f, fpst, 64);
}

6
vl.c
View File

@ -4239,6 +4239,9 @@ int main(int argc, char **argv, char **envp)
machine_opts = qemu_get_machine_opts();
qemu_opt_foreach(machine_opts, machine_set_property, current_machine,
&error_fatal);
current_machine->ram_size = ram_size;
current_machine->maxram_size = maxram_size;
current_machine->ram_slots = ram_slots;
configure_accelerator(current_machine, argv[0]);
@ -4434,9 +4437,6 @@ int main(int argc, char **argv, char **envp)
replay_checkpoint(CHECKPOINT_INIT);
qdev_machine_init();
current_machine->ram_size = ram_size;
current_machine->maxram_size = maxram_size;
current_machine->ram_slots = ram_slots;
current_machine->boot_order = boot_order;
/* parse features once if machine provides default cpu_type */