mirror of
https://github.com/izzy2lost/xemu.git
synced 2026-07-06 00:20:22 -07:00
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:
+1
-1
@@ -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);
|
||||
|
||||
+34
-20
@@ -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");
|
||||
|
||||
+20
-2
@@ -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);
|
||||
|
||||
@@ -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) {
|
||||
|
||||
+156
-40
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
+1
-1
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
+11
-5
@@ -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) \
|
||||
|
||||
+4
-1
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
+53
-11
@@ -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. */
|
||||
|
||||
@@ -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;
|
||||
|
||||
/*
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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)
|
||||
|
||||
+57
-6
@@ -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
|
||||
|
||||
+5
-3
@@ -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"
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user