target-arm queue:
* New board type max78000fthr * Enable use of CXL on Arm 'virt' board * Some more tidyup of ID register handling * Refactor AT insns and PMU regs into separate source files * Don't enforce NSE,NS check for EL3->EL3 returns * hw/arm/fsl-imx8mp: Wire VIRQ and VFIQ * Allow nested-virtualization with KVM on the 'virt' board * system/qdev: Remove pointless NULL check in qdev_device_add_from_qdict * hw/arm/virt-acpi-build: Don't create ITS id mappings by default * target/arm: Remove unused helper_sme2_luti4_4b -----BEGIN PGP SIGNATURE----- iQJNBAABCAA3FiEE4aXFk81BneKOgxXPPCUl7RQ2DN4FAmhxEcoZHHBldGVyLm1h eWRlbGxAbGluYXJvLm9yZwAKCRA8JSXtFDYM3j5yEACWYnNeqo8Yph6/EJExE6eV r0tC6FBb5ShPgA6kDxhpOc1lI6uXGh8+D7bL9BePEdz/brCf1QDfs2Z4q/hb5ysX D0H6VI5Gr1j6MjkFRBo3+vvYz4Yh++XLn5Q9lZv8zaSEdraq/ay2kxnuhRCK+4Ar +QoGtKrGMJ7UCpfiRlvNnd1UjgORZf10EE/bRImX13sxeDomP3CZhFzAyJyShOP9 JA7bAd4rYJ4oj8R33y8Yaxjwm4FOndj740B0zwpO8mpjzFiE5zbqsaO+mEgYSflc OQisCu/KRFpyIR+UqP+4gNaJLfKQW5Y4r61zEaiJWV/c4RdKNnbK1f7MX11fNhOk k1paF3GIXp6f794Hb14vtsYnKHF2eeNSmRkAomXxLgUSYzLezL+yj7cdYmRJhgYU thc1PSiEmHYhjRmOaMC9+dkMtvIexWyDNYNFTygoOE5/kTMSazeTFQpFmw+ZuTee 9pjKsYRZJgTa64IkJy1L34jc2gds48Q20KpQsqZ22KQcjwt4PW4eQXkvMylawSut mArHVH6AAxIK+defeEmnQCJ0OccyGCENjRDuWyWMMGoP/ggZpO47rGWmCUOK8xz8 IfGdPeF/9xsKSKWvjpiHyyKa48wuO2bVC+5bISS6IPA2uGneS2DpmjkHU+gHBqpk GNlvEnXZfavZOHejE7/L/Q== =hJ4/ -----END PGP SIGNATURE----- Merge tag 'pull-target-arm-20250711' of https://gitlab.com/pm215/qemu into staging target-arm queue: * New board type max78000fthr * Enable use of CXL on Arm 'virt' board * Some more tidyup of ID register handling * Refactor AT insns and PMU regs into separate source files * Don't enforce NSE,NS check for EL3->EL3 returns * hw/arm/fsl-imx8mp: Wire VIRQ and VFIQ * Allow nested-virtualization with KVM on the 'virt' board * system/qdev: Remove pointless NULL check in qdev_device_add_from_qdict * hw/arm/virt-acpi-build: Don't create ITS id mappings by default * target/arm: Remove unused helper_sme2_luti4_4b # -----BEGIN PGP SIGNATURE----- # # iQJNBAABCAA3FiEE4aXFk81BneKOgxXPPCUl7RQ2DN4FAmhxEcoZHHBldGVyLm1h # eWRlbGxAbGluYXJvLm9yZwAKCRA8JSXtFDYM3j5yEACWYnNeqo8Yph6/EJExE6eV # r0tC6FBb5ShPgA6kDxhpOc1lI6uXGh8+D7bL9BePEdz/brCf1QDfs2Z4q/hb5ysX # D0H6VI5Gr1j6MjkFRBo3+vvYz4Yh++XLn5Q9lZv8zaSEdraq/ay2kxnuhRCK+4Ar # +QoGtKrGMJ7UCpfiRlvNnd1UjgORZf10EE/bRImX13sxeDomP3CZhFzAyJyShOP9 # JA7bAd4rYJ4oj8R33y8Yaxjwm4FOndj740B0zwpO8mpjzFiE5zbqsaO+mEgYSflc # OQisCu/KRFpyIR+UqP+4gNaJLfKQW5Y4r61zEaiJWV/c4RdKNnbK1f7MX11fNhOk # k1paF3GIXp6f794Hb14vtsYnKHF2eeNSmRkAomXxLgUSYzLezL+yj7cdYmRJhgYU # thc1PSiEmHYhjRmOaMC9+dkMtvIexWyDNYNFTygoOE5/kTMSazeTFQpFmw+ZuTee # 9pjKsYRZJgTa64IkJy1L34jc2gds48Q20KpQsqZ22KQcjwt4PW4eQXkvMylawSut # mArHVH6AAxIK+defeEmnQCJ0OccyGCENjRDuWyWMMGoP/ggZpO47rGWmCUOK8xz8 # IfGdPeF/9xsKSKWvjpiHyyKa48wuO2bVC+5bISS6IPA2uGneS2DpmjkHU+gHBqpk # GNlvEnXZfavZOHejE7/L/Q== # =hJ4/ # -----END PGP SIGNATURE----- # gpg: Signature made Fri 11 Jul 2025 09:29:46 EDT # gpg: using RSA key E1A5C593CD419DE28E8315CF3C2525ED14360CDE # gpg: issuer "peter.maydell@linaro.org" # gpg: Good signature from "Peter Maydell <peter.maydell@linaro.org>" [full] # gpg: aka "Peter Maydell <pmaydell@gmail.com>" [full] # gpg: aka "Peter Maydell <pmaydell@chiark.greenend.org.uk>" [full] # gpg: aka "Peter Maydell <peter@archaic.org.uk>" [unknown] # Primary key fingerprint: E1A5 C593 CD41 9DE2 8E83 15CF 3C25 25ED 1436 0CDE * tag 'pull-target-arm-20250711' of https://gitlab.com/pm215/qemu: (36 commits) tests/functional: Add a test for the MAX78000 arm machine docs/system: arm: Add max78000 board description target/arm: Remove helper_sme2_luti4_4b hw/arm/virt-acpi-build: Don't create ITS id mappings by default system/qdev: Remove pointless NULL check in qdev_device_add_from_qdict hw/arm/virt: Allow virt extensions with KVM hw/arm/arm_gicv3_kvm: Add a migration blocker with kvm nested virt target/arm: Enable feature ARM_FEATURE_EL2 if EL2 is supported target/arm/kvm: Add helper to detect EL2 when using KVM hw/arm: Allow setting KVM vGIC maintenance IRQ hw/arm/fsl-imx8mp: Wire VIRQ and VFIQ target/arm: Don't enforce NSE,NS check for EL3->EL3 returns target/arm: Split out performance monitor regs to cpregs-pmu.c target/arm: Split out AT insns to tcg/cpregs-at.c target/arm: Drop stub for define_tlb_insn_regs arm/kvm: shorten one overly long line arm/cpu: store clidr into the idregs array arm/cpu: fix trailing ',' for SET_IDREG arm/cpu: store id_aa64afr{0,1} into the idregs array arm/cpu: store id_afr0 into the idregs array ... Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
This commit is contained in:
commit
0edc2afe0c
62 changed files with 4300 additions and 2010 deletions
37
docs/system/arm/max78000.rst
Normal file
37
docs/system/arm/max78000.rst
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
.. SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
Analog Devices max78000 board (``max78000fthr``)
|
||||
================================================
|
||||
|
||||
The max78000 is a Cortex-M4 based SOC with a RISC-V coprocessor. The RISC-V coprocessor is not supported.
|
||||
|
||||
Supported devices
|
||||
-----------------
|
||||
|
||||
* Instruction Cache Controller
|
||||
* UART
|
||||
* Global Control Register
|
||||
* True Random Number Generator
|
||||
* AES
|
||||
|
||||
Notable unsupported devices
|
||||
---------------------------
|
||||
|
||||
* I2C
|
||||
* CNN
|
||||
* CRC
|
||||
* SPI
|
||||
|
||||
Boot options
|
||||
------------
|
||||
|
||||
The max78000 can be started using the ``-kernel`` option to load a
|
||||
firmware at address 0 as the ROM. As the ROM normally jumps to software loaded
|
||||
from the internal flash at address 0x10000000, loading your program there is
|
||||
generally advisable. If you don't have a copy of the ROM, the interrupt
|
||||
vector table from user firmware will do.
|
||||
Example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ qemu-system-arm -machine max78000fthr -kernel max78000.bin -device loader,file=max78000.bin,addr=0x10000000
|
||||
|
|
@ -31,6 +31,7 @@ Supported devices
|
|||
The virt board supports:
|
||||
|
||||
- PCI/PCIe devices
|
||||
- CXL Fixed memory windows, root bridges and devices.
|
||||
- Flash memory
|
||||
- Either one or two PL011 UARTs for the NonSecure World
|
||||
- An RTC
|
||||
|
|
@ -189,6 +190,14 @@ ras
|
|||
acpi
|
||||
Set ``on``/``off``/``auto`` to enable/disable ACPI.
|
||||
|
||||
cxl
|
||||
Set ``on``/``off`` to enable/disable CXL. More details in
|
||||
:doc:`../devices/cxl`. The default is off.
|
||||
|
||||
cxl-fmw
|
||||
Array of CXL fixed memory windows describing fixed address routing to
|
||||
target CXL host bridges. See :doc:`../devices/cxl`.
|
||||
|
||||
dtb-randomness
|
||||
Set ``on``/``off`` to pass random seeds via the guest DTB
|
||||
rng-seed and kaslr-seed nodes (in both "/chosen" and
|
||||
|
|
|
|||
|
|
@ -384,6 +384,17 @@ An example of 4 devices below a switch suitable for 1, 2 or 4 way interleave::
|
|||
-device cxl-type3,bus=swport3,persistent-memdev=cxl-mem3,lsa=cxl-lsa3,id=cxl-pmem3,sn=0x4 \
|
||||
-M cxl-fmw.0.targets.0=cxl.1,cxl-fmw.0.size=4G,cxl-fmw.0.interleave-granularity=4k
|
||||
|
||||
A simple arm/virt example featuring a single direct connected CXL Type 3
|
||||
Volatile Memory device::
|
||||
|
||||
qemu-system-aarch64 -M virt,gic-version=3,cxl=on -m 4g,maxmem=8g,slots=4 -cpu max -smp 4 \
|
||||
...
|
||||
-object memory-backend-ram,id=vmem0,share=on,size=256M \
|
||||
-device pxb-cxl,bus_nr=12,bus=pcie.0,id=cxl.1 \
|
||||
-device cxl-rp,port=0,bus=cxl.1,id=root_port13,chassis=0,slot=2 \
|
||||
-device cxl-type3,bus=root_port13,volatile-memdev=vmem0,id=cxl-vmem0 \
|
||||
-M cxl-fmw.0.targets.0=cxl.1,cxl-fmw.0.size=4G
|
||||
|
||||
Deprecations
|
||||
------------
|
||||
|
||||
|
|
|
|||
|
|
@ -71,6 +71,7 @@ Board-specific documentation
|
|||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
arm/max78000
|
||||
arm/integratorcp
|
||||
arm/mps2
|
||||
arm/musca
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@
|
|||
#include "hw/pci/pci_bridge.h"
|
||||
#include "hw/pci/pci_host.h"
|
||||
#include "hw/cxl/cxl.h"
|
||||
#include "hw/cxl/cxl_host.h"
|
||||
#include "hw/mem/memory-device.h"
|
||||
#include "hw/acpi/acpi.h"
|
||||
#include "hw/acpi/aml-build.h"
|
||||
|
|
@ -135,55 +136,52 @@ static void cedt_build_chbs(GArray *table_data, PXBCXLDev *cxl)
|
|||
* Interleave ways encoding in CXL 2.0 ECN: 3, 6, 12 and 16-way memory
|
||||
* interleaving.
|
||||
*/
|
||||
static void cedt_build_cfmws(GArray *table_data, CXLState *cxls)
|
||||
static void cedt_build_cfmws(CXLFixedWindow *fw, Aml *cedt)
|
||||
{
|
||||
GList *it;
|
||||
GArray *table_data = cedt->buf;
|
||||
int i;
|
||||
|
||||
for (it = cxls->fixed_windows; it; it = it->next) {
|
||||
CXLFixedWindow *fw = it->data;
|
||||
int i;
|
||||
/* Type */
|
||||
build_append_int_noprefix(table_data, 1, 1);
|
||||
|
||||
/* Type */
|
||||
build_append_int_noprefix(table_data, 1, 1);
|
||||
/* Reserved */
|
||||
build_append_int_noprefix(table_data, 0, 1);
|
||||
|
||||
/* Reserved */
|
||||
build_append_int_noprefix(table_data, 0, 1);
|
||||
/* Record Length */
|
||||
build_append_int_noprefix(table_data, 36 + 4 * fw->num_targets, 2);
|
||||
|
||||
/* Record Length */
|
||||
build_append_int_noprefix(table_data, 36 + 4 * fw->num_targets, 2);
|
||||
/* Reserved */
|
||||
build_append_int_noprefix(table_data, 0, 4);
|
||||
|
||||
/* Reserved */
|
||||
build_append_int_noprefix(table_data, 0, 4);
|
||||
/* Base HPA */
|
||||
build_append_int_noprefix(table_data, fw->mr.addr, 8);
|
||||
|
||||
/* Base HPA */
|
||||
build_append_int_noprefix(table_data, fw->mr.addr, 8);
|
||||
/* Window Size */
|
||||
build_append_int_noprefix(table_data, fw->size, 8);
|
||||
|
||||
/* Window Size */
|
||||
build_append_int_noprefix(table_data, fw->size, 8);
|
||||
/* Host Bridge Interleave Ways */
|
||||
build_append_int_noprefix(table_data, fw->enc_int_ways, 1);
|
||||
|
||||
/* Host Bridge Interleave Ways */
|
||||
build_append_int_noprefix(table_data, fw->enc_int_ways, 1);
|
||||
/* Host Bridge Interleave Arithmetic */
|
||||
build_append_int_noprefix(table_data, 0, 1);
|
||||
|
||||
/* Host Bridge Interleave Arithmetic */
|
||||
build_append_int_noprefix(table_data, 0, 1);
|
||||
/* Reserved */
|
||||
build_append_int_noprefix(table_data, 0, 2);
|
||||
|
||||
/* Reserved */
|
||||
build_append_int_noprefix(table_data, 0, 2);
|
||||
/* Host Bridge Interleave Granularity */
|
||||
build_append_int_noprefix(table_data, fw->enc_int_gran, 4);
|
||||
|
||||
/* Host Bridge Interleave Granularity */
|
||||
build_append_int_noprefix(table_data, fw->enc_int_gran, 4);
|
||||
/* Window Restrictions */
|
||||
build_append_int_noprefix(table_data, 0x0f, 2);
|
||||
|
||||
/* Window Restrictions */
|
||||
build_append_int_noprefix(table_data, 0x0f, 2); /* No restrictions */
|
||||
/* QTG ID */
|
||||
build_append_int_noprefix(table_data, 0, 2);
|
||||
|
||||
/* QTG ID */
|
||||
build_append_int_noprefix(table_data, 0, 2);
|
||||
|
||||
/* Host Bridge List (list of UIDs - currently bus_nr) */
|
||||
for (i = 0; i < fw->num_targets; i++) {
|
||||
g_assert(fw->target_hbs[i]);
|
||||
build_append_int_noprefix(table_data, PXB_DEV(fw->target_hbs[i])->bus_nr, 4);
|
||||
}
|
||||
/* Host Bridge List (list of UIDs - currently bus_nr) */
|
||||
for (i = 0; i < fw->num_targets; i++) {
|
||||
g_assert(fw->target_hbs[i]);
|
||||
build_append_int_noprefix(table_data,
|
||||
PXB_DEV(fw->target_hbs[i])->bus_nr, 4);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -202,6 +200,7 @@ void cxl_build_cedt(GArray *table_offsets, GArray *table_data,
|
|||
BIOSLinker *linker, const char *oem_id,
|
||||
const char *oem_table_id, CXLState *cxl_state)
|
||||
{
|
||||
GSList *cfmws_list, *iter;
|
||||
Aml *cedt;
|
||||
AcpiTable table = { .sig = "CEDT", .rev = 1, .oem_id = oem_id,
|
||||
.oem_table_id = oem_table_id };
|
||||
|
|
@ -213,7 +212,12 @@ void cxl_build_cedt(GArray *table_offsets, GArray *table_data,
|
|||
/* reserve space for CEDT header */
|
||||
|
||||
object_child_foreach_recursive(object_get_root(), cxl_foreach_pxb_hb, cedt);
|
||||
cedt_build_cfmws(cedt->buf, cxl_state);
|
||||
|
||||
cfmws_list = cxl_fmws_get_all_sorted();
|
||||
for (iter = cfmws_list; iter; iter = iter->next) {
|
||||
cedt_build_cfmws(CXL_FMW(iter->data), cedt);
|
||||
}
|
||||
g_slist_free(cfmws_list);
|
||||
|
||||
/* copy AML table into ACPI tables blob and patch header there */
|
||||
g_array_append_vals(table_data, cedt->buf->data, cedt->buf->len);
|
||||
|
|
|
|||
|
|
@ -95,6 +95,12 @@ config INTEGRATOR
|
|||
select PL181 # display
|
||||
select SMC91C111
|
||||
|
||||
config MAX78000FTHR
|
||||
bool
|
||||
default y
|
||||
depends on TCG && ARM
|
||||
select MAX78000_SOC
|
||||
|
||||
config MPS3R
|
||||
bool
|
||||
default y
|
||||
|
|
@ -357,6 +363,15 @@ config ALLWINNER_R40
|
|||
select USB_EHCI_SYSBUS
|
||||
select SD
|
||||
|
||||
config MAX78000_SOC
|
||||
bool
|
||||
select ARM_V7M
|
||||
select MAX78000_ICC
|
||||
select MAX78000_UART
|
||||
select MAX78000_GCR
|
||||
select MAX78000_TRNG
|
||||
select MAX78000_AES
|
||||
|
||||
config RASPI
|
||||
bool
|
||||
default y
|
||||
|
|
|
|||
|
|
@ -356,6 +356,10 @@ static void fsl_imx8mp_realize(DeviceState *dev, Error **errp)
|
|||
qdev_get_gpio_in(cpudev, ARM_CPU_IRQ));
|
||||
sysbus_connect_irq(gicsbd, i + ms->smp.cpus,
|
||||
qdev_get_gpio_in(cpudev, ARM_CPU_FIQ));
|
||||
sysbus_connect_irq(gicsbd, i + 2 * ms->smp.cpus,
|
||||
qdev_get_gpio_in(cpudev, ARM_CPU_VIRQ));
|
||||
sysbus_connect_irq(gicsbd, i + 3 * ms->smp.cpus,
|
||||
qdev_get_gpio_in(cpudev, ARM_CPU_VFIQ));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
232
hw/arm/max78000_soc.c
Normal file
232
hw/arm/max78000_soc.c
Normal file
|
|
@ -0,0 +1,232 @@
|
|||
/*
|
||||
* MAX78000 SOC
|
||||
*
|
||||
* Copyright (c) 2025 Jackson Donaldson <jcksn@duck.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*
|
||||
* Implementation based on stm32f205 and Max78000 user guide at
|
||||
* https://www.analog.com/media/en/technical-documentation/user-guides/max78000-user-guide.pdf
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qapi/error.h"
|
||||
#include "system/address-spaces.h"
|
||||
#include "system/system.h"
|
||||
#include "hw/arm/max78000_soc.h"
|
||||
#include "hw/qdev-clock.h"
|
||||
#include "hw/misc/unimp.h"
|
||||
|
||||
static const uint32_t max78000_icc_addr[] = {0x4002a000, 0x4002a800};
|
||||
static const uint32_t max78000_uart_addr[] = {0x40042000, 0x40043000,
|
||||
0x40044000};
|
||||
|
||||
static const int max78000_uart_irq[] = {14, 15, 34};
|
||||
|
||||
static void max78000_soc_initfn(Object *obj)
|
||||
{
|
||||
MAX78000State *s = MAX78000_SOC(obj);
|
||||
int i;
|
||||
|
||||
object_initialize_child(obj, "armv7m", &s->armv7m, TYPE_ARMV7M);
|
||||
|
||||
object_initialize_child(obj, "gcr", &s->gcr, TYPE_MAX78000_GCR);
|
||||
|
||||
for (i = 0; i < MAX78000_NUM_ICC; i++) {
|
||||
g_autofree char *name = g_strdup_printf("icc%d", i);
|
||||
object_initialize_child(obj, name, &s->icc[i], TYPE_MAX78000_ICC);
|
||||
}
|
||||
|
||||
for (i = 0; i < MAX78000_NUM_UART; i++) {
|
||||
g_autofree char *name = g_strdup_printf("uart%d", i);
|
||||
object_initialize_child(obj, name, &s->uart[i],
|
||||
TYPE_MAX78000_UART);
|
||||
}
|
||||
|
||||
object_initialize_child(obj, "trng", &s->trng, TYPE_MAX78000_TRNG);
|
||||
|
||||
object_initialize_child(obj, "aes", &s->aes, TYPE_MAX78000_AES);
|
||||
|
||||
s->sysclk = qdev_init_clock_in(DEVICE(s), "sysclk", NULL, NULL, 0);
|
||||
}
|
||||
|
||||
static void max78000_soc_realize(DeviceState *dev_soc, Error **errp)
|
||||
{
|
||||
MAX78000State *s = MAX78000_SOC(dev_soc);
|
||||
MemoryRegion *system_memory = get_system_memory();
|
||||
DeviceState *dev, *gcrdev, *armv7m;
|
||||
SysBusDevice *busdev;
|
||||
Error *err = NULL;
|
||||
int i;
|
||||
|
||||
if (!clock_has_source(s->sysclk)) {
|
||||
error_setg(errp, "sysclk clock must be wired up by the board code");
|
||||
return;
|
||||
}
|
||||
|
||||
memory_region_init_rom(&s->flash, OBJECT(dev_soc), "MAX78000.flash",
|
||||
FLASH_SIZE, &err);
|
||||
if (err != NULL) {
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
}
|
||||
|
||||
memory_region_add_subregion(system_memory, FLASH_BASE_ADDRESS, &s->flash);
|
||||
|
||||
memory_region_init_ram(&s->sram, NULL, "MAX78000.sram", SRAM_SIZE,
|
||||
&err);
|
||||
|
||||
gcrdev = DEVICE(&s->gcr);
|
||||
object_property_set_link(OBJECT(gcrdev), "sram", OBJECT(&s->sram),
|
||||
&err);
|
||||
|
||||
if (err != NULL) {
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
}
|
||||
memory_region_add_subregion(system_memory, SRAM_BASE_ADDRESS, &s->sram);
|
||||
|
||||
armv7m = DEVICE(&s->armv7m);
|
||||
|
||||
/*
|
||||
* The MAX78000 user guide's Interrupt Vector Table section
|
||||
* suggests that there are 120 IRQs in the text, while only listing
|
||||
* 104 in table 5-1. Implement the more generous of the two.
|
||||
* This has not been tested in hardware.
|
||||
*/
|
||||
qdev_prop_set_uint32(armv7m, "num-irq", 120);
|
||||
qdev_prop_set_uint8(armv7m, "num-prio-bits", 3);
|
||||
qdev_prop_set_string(armv7m, "cpu-type", ARM_CPU_TYPE_NAME("cortex-m4"));
|
||||
qdev_prop_set_bit(armv7m, "enable-bitband", true);
|
||||
qdev_connect_clock_in(armv7m, "cpuclk", s->sysclk);
|
||||
object_property_set_link(OBJECT(&s->armv7m), "memory",
|
||||
OBJECT(system_memory), &error_abort);
|
||||
if (!sysbus_realize(SYS_BUS_DEVICE(&s->armv7m), errp)) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < MAX78000_NUM_ICC; i++) {
|
||||
dev = DEVICE(&(s->icc[i]));
|
||||
sysbus_realize(SYS_BUS_DEVICE(dev), errp);
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, max78000_icc_addr[i]);
|
||||
}
|
||||
|
||||
for (i = 0; i < MAX78000_NUM_UART; i++) {
|
||||
g_autofree char *link = g_strdup_printf("uart%d", i);
|
||||
dev = DEVICE(&(s->uart[i]));
|
||||
qdev_prop_set_chr(dev, "chardev", serial_hd(i));
|
||||
if (!sysbus_realize(SYS_BUS_DEVICE(&s->uart[i]), errp)) {
|
||||
return;
|
||||
}
|
||||
|
||||
object_property_set_link(OBJECT(gcrdev), link, OBJECT(dev),
|
||||
&err);
|
||||
|
||||
busdev = SYS_BUS_DEVICE(dev);
|
||||
sysbus_mmio_map(busdev, 0, max78000_uart_addr[i]);
|
||||
sysbus_connect_irq(busdev, 0, qdev_get_gpio_in(armv7m,
|
||||
max78000_uart_irq[i]));
|
||||
}
|
||||
|
||||
dev = DEVICE(&s->trng);
|
||||
sysbus_realize(SYS_BUS_DEVICE(dev), errp);
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0x4004d000);
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, qdev_get_gpio_in(armv7m, 4));
|
||||
|
||||
object_property_set_link(OBJECT(gcrdev), "trng", OBJECT(dev), &err);
|
||||
|
||||
dev = DEVICE(&s->aes);
|
||||
sysbus_realize(SYS_BUS_DEVICE(dev), errp);
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0x40007400);
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, qdev_get_gpio_in(armv7m, 5));
|
||||
|
||||
object_property_set_link(OBJECT(gcrdev), "aes", OBJECT(dev), &err);
|
||||
|
||||
dev = DEVICE(&s->gcr);
|
||||
sysbus_realize(SYS_BUS_DEVICE(dev), errp);
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0x40000000);
|
||||
|
||||
create_unimplemented_device("systemInterface", 0x40000400, 0x400);
|
||||
create_unimplemented_device("functionControl", 0x40000800, 0x400);
|
||||
create_unimplemented_device("watchdogTimer0", 0x40003000, 0x400);
|
||||
create_unimplemented_device("dynamicVoltScale", 0x40003c00, 0x40);
|
||||
create_unimplemented_device("SIMO", 0x40004400, 0x400);
|
||||
create_unimplemented_device("trimSystemInit", 0x40005400, 0x400);
|
||||
create_unimplemented_device("generalCtrlFunc", 0x40005800, 0x400);
|
||||
create_unimplemented_device("wakeupTimer", 0x40006400, 0x400);
|
||||
create_unimplemented_device("powerSequencer", 0x40006800, 0x400);
|
||||
create_unimplemented_device("miscControl", 0x40006c00, 0x400);
|
||||
|
||||
create_unimplemented_device("gpio0", 0x40008000, 0x1000);
|
||||
create_unimplemented_device("gpio1", 0x40009000, 0x1000);
|
||||
|
||||
create_unimplemented_device("parallelCamInterface", 0x4000e000, 0x1000);
|
||||
create_unimplemented_device("CRC", 0x4000f000, 0x1000);
|
||||
|
||||
create_unimplemented_device("timer0", 0x40010000, 0x1000);
|
||||
create_unimplemented_device("timer1", 0x40011000, 0x1000);
|
||||
create_unimplemented_device("timer2", 0x40012000, 0x1000);
|
||||
create_unimplemented_device("timer3", 0x40013000, 0x1000);
|
||||
|
||||
create_unimplemented_device("i2c0", 0x4001d000, 0x1000);
|
||||
create_unimplemented_device("i2c1", 0x4001e000, 0x1000);
|
||||
create_unimplemented_device("i2c2", 0x4001f000, 0x1000);
|
||||
|
||||
create_unimplemented_device("standardDMA", 0x40028000, 0x1000);
|
||||
create_unimplemented_device("flashController0", 0x40029000, 0x400);
|
||||
|
||||
create_unimplemented_device("adc", 0x40034000, 0x1000);
|
||||
create_unimplemented_device("pulseTrainEngine", 0x4003c000, 0xa0);
|
||||
create_unimplemented_device("oneWireMaster", 0x4003d000, 0x1000);
|
||||
create_unimplemented_device("semaphore", 0x4003e000, 0x1000);
|
||||
|
||||
create_unimplemented_device("spi1", 0x40046000, 0x2000);
|
||||
create_unimplemented_device("i2s", 0x40060000, 0x1000);
|
||||
create_unimplemented_device("lowPowerControl", 0x40080000, 0x400);
|
||||
create_unimplemented_device("gpio2", 0x40080400, 0x200);
|
||||
create_unimplemented_device("lowPowerWatchdogTimer", 0x40080800, 0x400);
|
||||
create_unimplemented_device("lowPowerTimer4", 0x40080c00, 0x400);
|
||||
|
||||
create_unimplemented_device("lowPowerTimer5", 0x40081000, 0x400);
|
||||
create_unimplemented_device("lowPowerUART0", 0x40081400, 0x400);
|
||||
create_unimplemented_device("lowPowerComparator", 0x40088000, 0x400);
|
||||
|
||||
create_unimplemented_device("spi0", 0x400be000, 0x400);
|
||||
|
||||
/*
|
||||
* The MAX78000 user guide's base address map lists the CNN TX FIFO as
|
||||
* beginning at 0x400c0400 and ending at 0x400c0400. Given that CNN_FIFO
|
||||
* is listed as having data accessible up to offset 0x1000, the user
|
||||
* guide is likely incorrect.
|
||||
*/
|
||||
create_unimplemented_device("cnnTxFIFO", 0x400c0400, 0x2000);
|
||||
|
||||
create_unimplemented_device("cnnGlobalControl", 0x50000000, 0x10000);
|
||||
create_unimplemented_device("cnnx16quad0", 0x50100000, 0x40000);
|
||||
create_unimplemented_device("cnnx16quad1", 0x50500000, 0x40000);
|
||||
create_unimplemented_device("cnnx16quad2", 0x50900000, 0x40000);
|
||||
create_unimplemented_device("cnnx16quad3", 0x50d00000, 0x40000);
|
||||
|
||||
}
|
||||
|
||||
static void max78000_soc_class_init(ObjectClass *klass, const void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
||||
dc->realize = max78000_soc_realize;
|
||||
}
|
||||
|
||||
static const TypeInfo max78000_soc_info = {
|
||||
.name = TYPE_MAX78000_SOC,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(MAX78000State),
|
||||
.instance_init = max78000_soc_initfn,
|
||||
.class_init = max78000_soc_class_init,
|
||||
};
|
||||
|
||||
static void max78000_soc_types(void)
|
||||
{
|
||||
type_register_static(&max78000_soc_info);
|
||||
}
|
||||
|
||||
type_init(max78000_soc_types)
|
||||
50
hw/arm/max78000fthr.c
Normal file
50
hw/arm/max78000fthr.c
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* MAX78000FTHR Evaluation Board
|
||||
*
|
||||
* Copyright (c) 2025 Jackson Donaldson <jcksn@duck.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qapi/error.h"
|
||||
#include "hw/boards.h"
|
||||
#include "hw/qdev-properties.h"
|
||||
#include "hw/qdev-clock.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "hw/arm/max78000_soc.h"
|
||||
#include "hw/arm/boot.h"
|
||||
|
||||
/* 60MHz is the default, but other clocks can be selected. */
|
||||
#define SYSCLK_FRQ 60000000ULL
|
||||
static void max78000_init(MachineState *machine)
|
||||
{
|
||||
DeviceState *dev;
|
||||
Clock *sysclk;
|
||||
|
||||
sysclk = clock_new(OBJECT(machine), "SYSCLK");
|
||||
clock_set_hz(sysclk, SYSCLK_FRQ);
|
||||
|
||||
dev = qdev_new(TYPE_MAX78000_SOC);
|
||||
object_property_add_child(OBJECT(machine), "soc", OBJECT(dev));
|
||||
qdev_connect_clock_in(dev, "sysclk", sysclk);
|
||||
sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
|
||||
|
||||
armv7m_load_kernel(ARM_CPU(first_cpu),
|
||||
machine->kernel_filename,
|
||||
0x00000000, FLASH_SIZE);
|
||||
}
|
||||
|
||||
static void max78000_machine_init(MachineClass *mc)
|
||||
{
|
||||
static const char * const valid_cpu_types[] = {
|
||||
ARM_CPU_TYPE_NAME("cortex-m4"),
|
||||
NULL
|
||||
};
|
||||
|
||||
mc->desc = "MAX78000FTHR Board (Cortex-M4 / (Unimplemented) RISC-V)";
|
||||
mc->init = max78000_init;
|
||||
mc->valid_cpu_types = valid_cpu_types;
|
||||
}
|
||||
|
||||
DEFINE_MACHINE("max78000fthr", max78000_machine_init)
|
||||
|
|
@ -27,6 +27,7 @@ arm_common_ss.add(when: 'CONFIG_OMAP', if_true: files('omap1.c'))
|
|||
arm_common_ss.add(when: 'CONFIG_ALLWINNER_A10', if_true: files('allwinner-a10.c', 'cubieboard.c'))
|
||||
arm_common_ss.add(when: 'CONFIG_ALLWINNER_H3', if_true: files('allwinner-h3.c', 'orangepi.c'))
|
||||
arm_common_ss.add(when: 'CONFIG_ALLWINNER_R40', if_true: files('allwinner-r40.c', 'bananapi_m2u.c'))
|
||||
arm_common_ss.add(when: 'CONFIG_MAX78000_SOC', if_true: files('max78000_soc.c'))
|
||||
arm_ss.add(when: 'CONFIG_RASPI', if_true: files('bcm2836.c', 'raspi.c'))
|
||||
arm_common_ss.add(when: ['CONFIG_RASPI', 'TARGET_AARCH64'], if_true: files('bcm2838.c', 'raspi4b.c'))
|
||||
arm_common_ss.add(when: 'CONFIG_STM32F100_SOC', if_true: files('stm32f100_soc.c'))
|
||||
|
|
@ -71,6 +72,7 @@ arm_ss.add(when: 'CONFIG_XEN', if_true: files(
|
|||
arm_common_ss.add(when: 'CONFIG_ARM_SMMUV3', if_true: files('smmu-common.c'))
|
||||
arm_common_ss.add(when: 'CONFIG_COLLIE', if_true: files('collie.c'))
|
||||
arm_common_ss.add(when: 'CONFIG_EXYNOS4', if_true: files('exynos4_boards.c'))
|
||||
arm_common_ss.add(when: 'CONFIG_MAX78000FTHR', if_true: files('max78000fthr.c'))
|
||||
arm_common_ss.add(when: 'CONFIG_NETDUINO2', if_true: files('netduino2.c'))
|
||||
arm_common_ss.add(when: 'CONFIG_RASPI', if_true: files('bcm2835_peripherals.c'))
|
||||
arm_common_ss.add(when: 'CONFIG_RASPI', if_true: files('bcm2838_peripherals.c'))
|
||||
|
|
|
|||
|
|
@ -39,10 +39,12 @@
|
|||
#include "hw/acpi/aml-build.h"
|
||||
#include "hw/acpi/utils.h"
|
||||
#include "hw/acpi/pci.h"
|
||||
#include "hw/acpi/cxl.h"
|
||||
#include "hw/acpi/memory_hotplug.h"
|
||||
#include "hw/acpi/generic_event_device.h"
|
||||
#include "hw/acpi/tpm.h"
|
||||
#include "hw/acpi/hmat.h"
|
||||
#include "hw/cxl/cxl.h"
|
||||
#include "hw/pci/pcie_host.h"
|
||||
#include "hw/pci/pci.h"
|
||||
#include "hw/pci/pci_bus.h"
|
||||
|
|
@ -119,10 +121,29 @@ static void acpi_dsdt_add_flash(Aml *scope, const MemMapEntry *flash_memmap)
|
|||
aml_append(scope, dev);
|
||||
}
|
||||
|
||||
static void build_acpi0017(Aml *table)
|
||||
{
|
||||
Aml *dev, *scope, *method;
|
||||
|
||||
scope = aml_scope("_SB");
|
||||
dev = aml_device("CXLM");
|
||||
aml_append(dev, aml_name_decl("_HID", aml_string("ACPI0017")));
|
||||
|
||||
method = aml_method("_STA", 0, AML_NOTSERIALIZED);
|
||||
aml_append(method, aml_return(aml_int(0x0B)));
|
||||
aml_append(dev, method);
|
||||
build_cxl_dsm_method(dev);
|
||||
|
||||
aml_append(scope, dev);
|
||||
aml_append(table, scope);
|
||||
}
|
||||
|
||||
static void acpi_dsdt_add_pci(Aml *scope, const MemMapEntry *memmap,
|
||||
uint32_t irq, VirtMachineState *vms)
|
||||
{
|
||||
int ecam_id = VIRT_ECAM_ID(vms->highmem_ecam);
|
||||
bool cxl_present = false;
|
||||
PCIBus *bus = vms->bus;
|
||||
struct GPEXConfig cfg = {
|
||||
.mmio32 = memmap[VIRT_PCIE_MMIO],
|
||||
.pio = memmap[VIRT_PCIE_PIO],
|
||||
|
|
@ -136,6 +157,14 @@ static void acpi_dsdt_add_pci(Aml *scope, const MemMapEntry *memmap,
|
|||
}
|
||||
|
||||
acpi_dsdt_add_gpex(scope, &cfg);
|
||||
QLIST_FOREACH(bus, &vms->bus->child, sibling) {
|
||||
if (pci_bus_is_cxl(bus)) {
|
||||
cxl_present = true;
|
||||
}
|
||||
}
|
||||
if (cxl_present) {
|
||||
build_acpi0017(scope);
|
||||
}
|
||||
}
|
||||
|
||||
static void acpi_dsdt_add_gpio(Aml *scope, const MemMapEntry *gpio_memmap,
|
||||
|
|
@ -329,12 +358,6 @@ build_iort(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
|
|||
/* Sort the smmu idmap by input_base */
|
||||
g_array_sort(rc_smmu_idmaps, iort_idmap_compare);
|
||||
|
||||
/*
|
||||
* Knowing the ID ranges from the RC to the SMMU, it's possible to
|
||||
* determine the ID ranges from RC that are directed to the ITS.
|
||||
*/
|
||||
create_rc_its_idmaps(rc_its_idmaps, rc_smmu_idmaps);
|
||||
|
||||
nb_nodes = 2; /* RC and SMMUv3 */
|
||||
rc_mapping_count = rc_smmu_idmaps->len;
|
||||
|
||||
|
|
@ -1027,6 +1050,11 @@ void virt_acpi_build(VirtMachineState *vms, AcpiBuildTables *tables)
|
|||
}
|
||||
}
|
||||
|
||||
if (vms->cxl_devices_state.is_enabled) {
|
||||
cxl_build_cedt(table_offsets, tables_blob, tables->linker,
|
||||
vms->oem_id, vms->oem_table_id, &vms->cxl_devices_state);
|
||||
}
|
||||
|
||||
if (ms->nvdimms_state->is_enabled) {
|
||||
nvdimm_build_acpi(table_offsets, tables_blob, tables->linker,
|
||||
ms->nvdimms_state, ms->ram_slots, vms->oem_id,
|
||||
|
|
|
|||
|
|
@ -57,6 +57,7 @@
|
|||
#include "qemu/error-report.h"
|
||||
#include "qemu/module.h"
|
||||
#include "hw/pci-host/gpex.h"
|
||||
#include "hw/pci-bridge/pci_expander_bridge.h"
|
||||
#include "hw/virtio/virtio-pci.h"
|
||||
#include "hw/core/sysbus-fdt.h"
|
||||
#include "hw/platform-bus.h"
|
||||
|
|
@ -86,6 +87,8 @@
|
|||
#include "hw/virtio/virtio-md-pci.h"
|
||||
#include "hw/virtio/virtio-iommu.h"
|
||||
#include "hw/char/pl011.h"
|
||||
#include "hw/cxl/cxl.h"
|
||||
#include "hw/cxl/cxl_host.h"
|
||||
#include "qemu/guest-random.h"
|
||||
|
||||
static GlobalProperty arm_virt_compat[] = {
|
||||
|
|
@ -220,9 +223,11 @@ static const MemMapEntry base_memmap[] = {
|
|||
static MemMapEntry extended_memmap[] = {
|
||||
/* Additional 64 MB redist region (can contain up to 512 redistributors) */
|
||||
[VIRT_HIGH_GIC_REDIST2] = { 0x0, 64 * MiB },
|
||||
[VIRT_CXL_HOST] = { 0x0, 64 * KiB * 16 }, /* 16 UID */
|
||||
[VIRT_HIGH_PCIE_ECAM] = { 0x0, 256 * MiB },
|
||||
/* Second PCIe window */
|
||||
[VIRT_HIGH_PCIE_MMIO] = { 0x0, DEFAULT_HIGH_PCIE_MMIO_SIZE },
|
||||
/* Any CXL Fixed memory windows come here */
|
||||
};
|
||||
|
||||
static const int a15irqmap[] = {
|
||||
|
|
@ -792,6 +797,13 @@ static void create_gic(VirtMachineState *vms, MemoryRegion *mem)
|
|||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
|
||||
if (kvm_enabled() && vms->virt &&
|
||||
(revision != 3 || !kvm_irqchip_in_kernel())) {
|
||||
error_report("KVM EL2 is only supported with in-kernel GICv3");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
vms->gic = qdev_new(gictype);
|
||||
qdev_prop_set_uint32(vms->gic, "revision", revision);
|
||||
qdev_prop_set_uint32(vms->gic, "num-cpu", smp_cpus);
|
||||
|
|
@ -828,6 +840,9 @@ static void create_gic(VirtMachineState *vms, MemoryRegion *mem)
|
|||
OBJECT(mem), &error_fatal);
|
||||
qdev_prop_set_bit(vms->gic, "has-lpi", true);
|
||||
}
|
||||
} else if (vms->virt) {
|
||||
qdev_prop_set_uint32(vms->gic, "maintenance-interrupt-id",
|
||||
ARCH_GIC_MAINT_IRQ);
|
||||
}
|
||||
} else {
|
||||
if (!kvm_irqchip_in_kernel()) {
|
||||
|
|
@ -1623,6 +1638,17 @@ static void create_pcie(VirtMachineState *vms)
|
|||
}
|
||||
}
|
||||
|
||||
static void create_cxl_host_reg_region(VirtMachineState *vms)
|
||||
{
|
||||
MemoryRegion *sysmem = get_system_memory();
|
||||
MemoryRegion *mr = &vms->cxl_devices_state.host_mr;
|
||||
|
||||
memory_region_init(mr, OBJECT(vms), "cxl_host_reg",
|
||||
vms->memmap[VIRT_CXL_HOST].size);
|
||||
memory_region_add_subregion(sysmem, vms->memmap[VIRT_CXL_HOST].base, mr);
|
||||
vms->highmem_cxl = true;
|
||||
}
|
||||
|
||||
static void create_platform_bus(VirtMachineState *vms)
|
||||
{
|
||||
DeviceState *dev;
|
||||
|
|
@ -1739,6 +1765,12 @@ void virt_machine_done(Notifier *notifier, void *data)
|
|||
struct arm_boot_info *info = &vms->bootinfo;
|
||||
AddressSpace *as = arm_boot_address_space(cpu, info);
|
||||
|
||||
cxl_hook_up_pxb_registers(vms->bus, &vms->cxl_devices_state,
|
||||
&error_fatal);
|
||||
|
||||
if (vms->cxl_devices_state.is_enabled) {
|
||||
cxl_fmws_link_targets(&error_fatal);
|
||||
}
|
||||
/*
|
||||
* If the user provided a dtb, we assume the dynamic sysbus nodes
|
||||
* already are integrated there. This corresponds to a use case where
|
||||
|
|
@ -1785,6 +1817,7 @@ static inline bool *virt_get_high_memmap_enabled(VirtMachineState *vms,
|
|||
{
|
||||
bool *enabled_array[] = {
|
||||
&vms->highmem_redists,
|
||||
&vms->highmem_cxl,
|
||||
&vms->highmem_ecam,
|
||||
&vms->highmem_mmio,
|
||||
};
|
||||
|
|
@ -1892,6 +1925,9 @@ static void virt_set_memmap(VirtMachineState *vms, int pa_bits)
|
|||
if (device_memory_size > 0) {
|
||||
machine_memory_devices_init(ms, device_memory_base, device_memory_size);
|
||||
}
|
||||
vms->highest_gpa = cxl_fmws_set_memmap(ROUND_UP(vms->highest_gpa + 1,
|
||||
256 * MiB),
|
||||
BIT_ULL(pa_bits)) - 1;
|
||||
}
|
||||
|
||||
static VirtGICType finalize_gic_version_do(const char *accel_name,
|
||||
|
|
@ -2063,6 +2099,10 @@ static void virt_post_cpus_gic_realized(VirtMachineState *vms,
|
|||
memory_region_init_ram(pvtime, NULL, "pvtime", pvtime_size, NULL);
|
||||
memory_region_add_subregion(sysmem, pvtime_reg_base, pvtime);
|
||||
}
|
||||
if (!aarch64 && vms->virt) {
|
||||
error_report("KVM does not support EL2 on an AArch32 vCPU");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
CPU_FOREACH(cpu) {
|
||||
if (pmu) {
|
||||
|
|
@ -2208,7 +2248,13 @@ static void machvirt_init(MachineState *machine)
|
|||
exit(1);
|
||||
}
|
||||
|
||||
if (vms->virt && !tcg_enabled() && !qtest_enabled()) {
|
||||
if (vms->virt && kvm_enabled() && !kvm_arm_el2_supported()) {
|
||||
error_report("mach-virt: host kernel KVM does not support providing "
|
||||
"Virtualization extensions to the guest CPU");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (vms->virt && !kvm_enabled() && !tcg_enabled() && !qtest_enabled()) {
|
||||
error_report("mach-virt: %s does not support providing "
|
||||
"Virtualization extensions to the guest CPU",
|
||||
current_accel_name());
|
||||
|
|
@ -2343,6 +2389,8 @@ static void machvirt_init(MachineState *machine)
|
|||
memory_region_add_subregion(sysmem, vms->memmap[VIRT_MEM].base,
|
||||
machine->ram);
|
||||
|
||||
cxl_fmws_update_mmio();
|
||||
|
||||
virt_flash_fdt(vms, sysmem, secure_sysmem ?: sysmem);
|
||||
|
||||
create_gic(vms, sysmem);
|
||||
|
|
@ -2398,6 +2446,7 @@ static void machvirt_init(MachineState *machine)
|
|||
create_rtc(vms);
|
||||
|
||||
create_pcie(vms);
|
||||
create_cxl_host_reg_region(vms);
|
||||
|
||||
if (has_ged && aarch64 && firmware_loaded && virt_is_acpi_enabled(vms)) {
|
||||
vms->acpi_dev = create_acpi_ged(vms);
|
||||
|
|
@ -3364,6 +3413,7 @@ static void virt_instance_init(Object *obj)
|
|||
|
||||
vms->oem_id = g_strndup(ACPI_BUILD_APPNAME6, 6);
|
||||
vms->oem_table_id = g_strndup(ACPI_BUILD_APPNAME8, 8);
|
||||
cxl_machine_init(obj, &vms->cxl_devices_state);
|
||||
}
|
||||
|
||||
static const TypeInfo virt_machine_info = {
|
||||
|
|
|
|||
|
|
@ -48,6 +48,9 @@ config VIRTIO_SERIAL
|
|||
default y
|
||||
depends on VIRTIO
|
||||
|
||||
config MAX78000_UART
|
||||
bool
|
||||
|
||||
config STM32F2XX_USART
|
||||
bool
|
||||
|
||||
|
|
|
|||
285
hw/char/max78000_uart.c
Normal file
285
hw/char/max78000_uart.c
Normal file
|
|
@ -0,0 +1,285 @@
|
|||
/*
|
||||
* MAX78000 UART
|
||||
*
|
||||
* Copyright (c) 2025 Jackson Donaldson <jcksn@duck.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/char/max78000_uart.h"
|
||||
#include "hw/irq.h"
|
||||
#include "hw/qdev-properties.h"
|
||||
#include "hw/qdev-properties-system.h"
|
||||
#include "qemu/log.h"
|
||||
#include "qemu/module.h"
|
||||
#include "migration/vmstate.h"
|
||||
#include "trace.h"
|
||||
|
||||
|
||||
static int max78000_uart_can_receive(void *opaque)
|
||||
{
|
||||
Max78000UartState *s = opaque;
|
||||
if (!(s->ctrl & UART_BCLKEN)) {
|
||||
return 0;
|
||||
}
|
||||
return fifo8_num_free(&s->rx_fifo);
|
||||
}
|
||||
|
||||
static void max78000_update_irq(Max78000UartState *s)
|
||||
{
|
||||
int interrupt_level;
|
||||
|
||||
interrupt_level = s->int_fl & s->int_en;
|
||||
qemu_set_irq(s->irq, interrupt_level);
|
||||
}
|
||||
|
||||
static void max78000_uart_receive(void *opaque, const uint8_t *buf, int size)
|
||||
{
|
||||
Max78000UartState *s = opaque;
|
||||
|
||||
assert(size <= fifo8_num_free(&s->rx_fifo));
|
||||
|
||||
fifo8_push_all(&s->rx_fifo, buf, size);
|
||||
|
||||
uint32_t rx_threshold = s->ctrl & 0xf;
|
||||
|
||||
if (fifo8_num_used(&s->rx_fifo) >= rx_threshold) {
|
||||
s->int_fl |= UART_RX_THD;
|
||||
}
|
||||
|
||||
max78000_update_irq(s);
|
||||
}
|
||||
|
||||
static void max78000_uart_reset_hold(Object *obj, ResetType type)
|
||||
{
|
||||
Max78000UartState *s = MAX78000_UART(obj);
|
||||
|
||||
s->ctrl = 0;
|
||||
s->status = UART_TX_EM | UART_RX_EM;
|
||||
s->int_en = 0;
|
||||
s->int_fl = 0;
|
||||
s->osr = 0;
|
||||
s->txpeek = 0;
|
||||
s->pnr = UART_RTS;
|
||||
s->fifo = 0;
|
||||
s->dma = 0;
|
||||
s->wken = 0;
|
||||
s->wkfl = 0;
|
||||
fifo8_reset(&s->rx_fifo);
|
||||
}
|
||||
|
||||
static uint64_t max78000_uart_read(void *opaque, hwaddr addr,
|
||||
unsigned int size)
|
||||
{
|
||||
Max78000UartState *s = opaque;
|
||||
uint64_t retvalue = 0;
|
||||
switch (addr) {
|
||||
case UART_CTRL:
|
||||
retvalue = s->ctrl;
|
||||
break;
|
||||
case UART_STATUS:
|
||||
retvalue = (fifo8_num_used(&s->rx_fifo) << UART_RX_LVL) |
|
||||
UART_TX_EM |
|
||||
(fifo8_is_empty(&s->rx_fifo) ? UART_RX_EM : 0);
|
||||
break;
|
||||
case UART_INT_EN:
|
||||
retvalue = s->int_en;
|
||||
break;
|
||||
case UART_INT_FL:
|
||||
retvalue = s->int_fl;
|
||||
break;
|
||||
case UART_CLKDIV:
|
||||
retvalue = s->clkdiv;
|
||||
break;
|
||||
case UART_OSR:
|
||||
retvalue = s->osr;
|
||||
break;
|
||||
case UART_TXPEEK:
|
||||
if (!fifo8_is_empty(&s->rx_fifo)) {
|
||||
retvalue = fifo8_peek(&s->rx_fifo);
|
||||
}
|
||||
break;
|
||||
case UART_PNR:
|
||||
retvalue = s->pnr;
|
||||
break;
|
||||
case UART_FIFO:
|
||||
if (!fifo8_is_empty(&s->rx_fifo)) {
|
||||
retvalue = fifo8_pop(&s->rx_fifo);
|
||||
max78000_update_irq(s);
|
||||
}
|
||||
break;
|
||||
case UART_DMA:
|
||||
/* DMA not implemented */
|
||||
retvalue = s->dma;
|
||||
break;
|
||||
case UART_WKEN:
|
||||
retvalue = s->wken;
|
||||
break;
|
||||
case UART_WKFL:
|
||||
retvalue = s->wkfl;
|
||||
break;
|
||||
default:
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"%s: Bad offset 0x%"HWADDR_PRIx"\n", __func__, addr);
|
||||
break;
|
||||
}
|
||||
|
||||
return retvalue;
|
||||
}
|
||||
|
||||
static void max78000_uart_write(void *opaque, hwaddr addr,
|
||||
uint64_t val64, unsigned int size)
|
||||
{
|
||||
Max78000UartState *s = opaque;
|
||||
|
||||
uint32_t value = val64;
|
||||
uint8_t data;
|
||||
|
||||
switch (addr) {
|
||||
case UART_CTRL:
|
||||
if (value & UART_FLUSH_RX) {
|
||||
fifo8_reset(&s->rx_fifo);
|
||||
}
|
||||
if (value & UART_BCLKEN) {
|
||||
value = value | UART_BCLKRDY;
|
||||
}
|
||||
s->ctrl = value & ~(UART_FLUSH_RX | UART_FLUSH_TX);
|
||||
|
||||
/*
|
||||
* Software can manage UART flow control manually by setting hfc_en
|
||||
* in UART_CTRL. This would require emulating uart at a lower level,
|
||||
* and is currently unimplemented.
|
||||
*/
|
||||
|
||||
return;
|
||||
case UART_STATUS:
|
||||
/* UART_STATUS is read only */
|
||||
return;
|
||||
case UART_INT_EN:
|
||||
s->int_en = value;
|
||||
return;
|
||||
case UART_INT_FL:
|
||||
s->int_fl = s->int_fl & ~(value);
|
||||
max78000_update_irq(s);
|
||||
return;
|
||||
case UART_CLKDIV:
|
||||
s->clkdiv = value;
|
||||
return;
|
||||
case UART_OSR:
|
||||
s->osr = value;
|
||||
return;
|
||||
case UART_PNR:
|
||||
s->pnr = value;
|
||||
return;
|
||||
case UART_FIFO:
|
||||
data = value & 0xff;
|
||||
/*
|
||||
* XXX this blocks entire thread. Rewrite to use
|
||||
* qemu_chr_fe_write and background I/O callbacks
|
||||
*/
|
||||
qemu_chr_fe_write_all(&s->chr, &data, 1);
|
||||
|
||||
/* TX is always empty */
|
||||
s->int_fl |= UART_TX_HE;
|
||||
max78000_update_irq(s);
|
||||
|
||||
return;
|
||||
case UART_DMA:
|
||||
/* DMA not implemented */
|
||||
s->dma = value;
|
||||
return;
|
||||
case UART_WKEN:
|
||||
s->wken = value;
|
||||
return;
|
||||
case UART_WKFL:
|
||||
s->wkfl = value;
|
||||
return;
|
||||
default:
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%"
|
||||
HWADDR_PRIx "\n", __func__, addr);
|
||||
}
|
||||
}
|
||||
|
||||
static const MemoryRegionOps max78000_uart_ops = {
|
||||
.read = max78000_uart_read,
|
||||
.write = max78000_uart_write,
|
||||
.endianness = DEVICE_LITTLE_ENDIAN,
|
||||
.valid.min_access_size = 4,
|
||||
.valid.max_access_size = 4,
|
||||
};
|
||||
|
||||
static const Property max78000_uart_properties[] = {
|
||||
DEFINE_PROP_CHR("chardev", Max78000UartState, chr),
|
||||
};
|
||||
|
||||
static const VMStateDescription max78000_uart_vmstate = {
|
||||
.name = TYPE_MAX78000_UART,
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT32(ctrl, Max78000UartState),
|
||||
VMSTATE_UINT32(status, Max78000UartState),
|
||||
VMSTATE_UINT32(int_en, Max78000UartState),
|
||||
VMSTATE_UINT32(int_fl, Max78000UartState),
|
||||
VMSTATE_UINT32(clkdiv, Max78000UartState),
|
||||
VMSTATE_UINT32(osr, Max78000UartState),
|
||||
VMSTATE_UINT32(txpeek, Max78000UartState),
|
||||
VMSTATE_UINT32(pnr, Max78000UartState),
|
||||
VMSTATE_UINT32(fifo, Max78000UartState),
|
||||
VMSTATE_UINT32(dma, Max78000UartState),
|
||||
VMSTATE_UINT32(wken, Max78000UartState),
|
||||
VMSTATE_UINT32(wkfl, Max78000UartState),
|
||||
VMSTATE_FIFO8(rx_fifo, Max78000UartState),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
static void max78000_uart_init(Object *obj)
|
||||
{
|
||||
Max78000UartState *s = MAX78000_UART(obj);
|
||||
fifo8_create(&s->rx_fifo, 8);
|
||||
|
||||
sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->irq);
|
||||
|
||||
memory_region_init_io(&s->mmio, obj, &max78000_uart_ops, s,
|
||||
TYPE_MAX78000_UART, 0x400);
|
||||
sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio);
|
||||
}
|
||||
|
||||
static void max78000_uart_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
Max78000UartState *s = MAX78000_UART(dev);
|
||||
|
||||
qemu_chr_fe_set_handlers(&s->chr, max78000_uart_can_receive,
|
||||
max78000_uart_receive, NULL, NULL,
|
||||
s, NULL, true);
|
||||
}
|
||||
|
||||
static void max78000_uart_class_init(ObjectClass *klass, const void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
ResettableClass *rc = RESETTABLE_CLASS(klass);
|
||||
|
||||
rc->phases.hold = max78000_uart_reset_hold;
|
||||
|
||||
device_class_set_props(dc, max78000_uart_properties);
|
||||
dc->realize = max78000_uart_realize;
|
||||
|
||||
dc->vmsd = &max78000_uart_vmstate;
|
||||
}
|
||||
|
||||
static const TypeInfo max78000_uart_info = {
|
||||
.name = TYPE_MAX78000_UART,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(Max78000UartState),
|
||||
.instance_init = max78000_uart_init,
|
||||
.class_init = max78000_uart_class_init,
|
||||
};
|
||||
|
||||
static void max78000_uart_register_types(void)
|
||||
{
|
||||
type_register_static(&max78000_uart_info);
|
||||
}
|
||||
|
||||
type_init(max78000_uart_register_types)
|
||||
|
|
@ -26,6 +26,7 @@ system_ss.add(when: 'CONFIG_AVR_USART', if_true: files('avr_usart.c'))
|
|||
system_ss.add(when: 'CONFIG_COLDFIRE', if_true: files('mcf_uart.c'))
|
||||
system_ss.add(when: 'CONFIG_DIGIC', if_true: files('digic-uart.c'))
|
||||
system_ss.add(when: 'CONFIG_EXYNOS4', if_true: files('exynos4210_uart.c'))
|
||||
system_ss.add(when: 'CONFIG_MAX78000_UART', if_true: files('max78000_uart.c'))
|
||||
system_ss.add(when: 'CONFIG_OMAP', if_true: files('omap_uart.c'))
|
||||
system_ss.add(when: 'CONFIG_RASPI', if_true: files('bcm2835_aux.c'))
|
||||
system_ss.add(when: 'CONFIG_RENESAS_SCI', if_true: files('renesas_sci.c'))
|
||||
|
|
|
|||
|
|
@ -8,8 +8,13 @@
|
|||
#include "hw/cxl/cxl.h"
|
||||
#include "hw/cxl/cxl_host.h"
|
||||
|
||||
void cxl_fmws_link_targets(CXLState *stat, Error **errp) {};
|
||||
void cxl_fmws_link_targets(Error **errp) {};
|
||||
void cxl_machine_init(Object *obj, CXLState *state) {};
|
||||
void cxl_hook_up_pxb_registers(PCIBus *bus, CXLState *state, Error **errp) {};
|
||||
hwaddr cxl_fmws_set_memmap(hwaddr base, hwaddr max_addr)
|
||||
{
|
||||
return base;
|
||||
};
|
||||
void cxl_fmws_update_mmio(void) {};
|
||||
|
||||
const MemoryRegionOps cfmws_ops;
|
||||
|
|
|
|||
|
|
@ -22,15 +22,17 @@
|
|||
#include "hw/pci/pcie_port.h"
|
||||
#include "hw/pci-bridge/pci_expander_bridge.h"
|
||||
|
||||
static void cxl_fixed_memory_window_config(CXLState *cxl_state,
|
||||
CXLFixedMemoryWindowOptions *object,
|
||||
Error **errp)
|
||||
static void cxl_fixed_memory_window_config(CXLFixedMemoryWindowOptions *object,
|
||||
int index, Error **errp)
|
||||
{
|
||||
ERRP_GUARD();
|
||||
g_autofree CXLFixedWindow *fw = g_malloc0(sizeof(*fw));
|
||||
DeviceState *dev = qdev_new(TYPE_CXL_FMW);
|
||||
CXLFixedWindow *fw = CXL_FMW(dev);
|
||||
strList *target;
|
||||
int i;
|
||||
|
||||
fw->index = index;
|
||||
|
||||
for (target = object->targets; target; target = target->next) {
|
||||
fw->num_targets++;
|
||||
}
|
||||
|
|
@ -65,35 +67,39 @@ static void cxl_fixed_memory_window_config(CXLState *cxl_state,
|
|||
fw->targets[i] = g_strdup(target->value);
|
||||
}
|
||||
|
||||
cxl_state->fixed_windows = g_list_append(cxl_state->fixed_windows,
|
||||
g_steal_pointer(&fw));
|
||||
sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), errp);
|
||||
}
|
||||
|
||||
void cxl_fmws_link_targets(CXLState *cxl_state, Error **errp)
|
||||
static int cxl_fmws_link(Object *obj, void *opaque)
|
||||
{
|
||||
if (cxl_state && cxl_state->fixed_windows) {
|
||||
GList *it;
|
||||
struct CXLFixedWindow *fw;
|
||||
int i;
|
||||
|
||||
for (it = cxl_state->fixed_windows; it; it = it->next) {
|
||||
CXLFixedWindow *fw = it->data;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < fw->num_targets; i++) {
|
||||
Object *o;
|
||||
bool ambig;
|
||||
|
||||
o = object_resolve_path_type(fw->targets[i],
|
||||
TYPE_PXB_CXL_DEV,
|
||||
&ambig);
|
||||
if (!o) {
|
||||
error_setg(errp, "Could not resolve CXLFM target %s",
|
||||
fw->targets[i]);
|
||||
return;
|
||||
}
|
||||
fw->target_hbs[i] = PXB_CXL_DEV(o);
|
||||
}
|
||||
}
|
||||
if (!object_dynamic_cast(obj, TYPE_CXL_FMW)) {
|
||||
return 0;
|
||||
}
|
||||
fw = CXL_FMW(obj);
|
||||
|
||||
for (i = 0; i < fw->num_targets; i++) {
|
||||
Object *o;
|
||||
bool ambig;
|
||||
|
||||
o = object_resolve_path_type(fw->targets[i], TYPE_PXB_CXL_DEV,
|
||||
&ambig);
|
||||
if (!o) {
|
||||
error_setg(&error_fatal, "Could not resolve CXLFM target %s",
|
||||
fw->targets[i]);
|
||||
return 1;
|
||||
}
|
||||
fw->target_hbs[i] = PXB_CXL_DEV(o);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void cxl_fmws_link_targets(Error **errp)
|
||||
{
|
||||
/* Order doesn't matter for this, so no need to build list */
|
||||
object_child_foreach_recursive(object_get_root(), cxl_fmws_link, NULL);
|
||||
}
|
||||
|
||||
static bool cxl_hdm_find_target(uint32_t *cache_mem, hwaddr addr,
|
||||
|
|
@ -325,14 +331,15 @@ static void machine_set_cfmw(Object *obj, Visitor *v, const char *name,
|
|||
CXLState *state = opaque;
|
||||
CXLFixedMemoryWindowOptionsList *cfmw_list = NULL;
|
||||
CXLFixedMemoryWindowOptionsList *it;
|
||||
int index;
|
||||
|
||||
visit_type_CXLFixedMemoryWindowOptionsList(v, name, &cfmw_list, errp);
|
||||
if (!cfmw_list) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (it = cfmw_list; it; it = it->next) {
|
||||
cxl_fixed_memory_window_config(state, it->value, errp);
|
||||
for (it = cfmw_list, index = 0; it; it = it->next, index++) {
|
||||
cxl_fixed_memory_window_config(it->value, index, errp);
|
||||
}
|
||||
state->cfmw_list = cfmw_list;
|
||||
}
|
||||
|
|
@ -370,3 +377,110 @@ void cxl_hook_up_pxb_registers(PCIBus *bus, CXLState *state, Error **errp)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int cxl_fmws_find(Object *obj, void *opaque)
|
||||
{
|
||||
GSList **list = opaque;
|
||||
|
||||
if (!object_dynamic_cast(obj, TYPE_CXL_FMW)) {
|
||||
return 0;
|
||||
}
|
||||
*list = g_slist_prepend(*list, obj);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static GSList *cxl_fmws_get_all(void)
|
||||
{
|
||||
GSList *list = NULL;
|
||||
|
||||
object_child_foreach_recursive(object_get_root(), cxl_fmws_find, &list);
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
static gint cfmws_cmp(gconstpointer a, gconstpointer b, gpointer d)
|
||||
{
|
||||
const struct CXLFixedWindow *ap = a;
|
||||
const struct CXLFixedWindow *bp = b;
|
||||
|
||||
return ap->index > bp->index;
|
||||
}
|
||||
|
||||
GSList *cxl_fmws_get_all_sorted(void)
|
||||
{
|
||||
return g_slist_sort_with_data(cxl_fmws_get_all(), cfmws_cmp, NULL);
|
||||
}
|
||||
|
||||
static int cxl_fmws_mmio_map(Object *obj, void *opaque)
|
||||
{
|
||||
struct CXLFixedWindow *fw;
|
||||
|
||||
if (!object_dynamic_cast(obj, TYPE_CXL_FMW)) {
|
||||
return 0;
|
||||
}
|
||||
fw = CXL_FMW(obj);
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(fw), 0, fw->base);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void cxl_fmws_update_mmio(void)
|
||||
{
|
||||
/* Ordering is not required for this */
|
||||
object_child_foreach_recursive(object_get_root(), cxl_fmws_mmio_map, NULL);
|
||||
}
|
||||
|
||||
hwaddr cxl_fmws_set_memmap(hwaddr base, hwaddr max_addr)
|
||||
{
|
||||
GSList *cfmws_list, *iter;
|
||||
CXLFixedWindow *fw;
|
||||
|
||||
cfmws_list = cxl_fmws_get_all_sorted();
|
||||
for (iter = cfmws_list; iter; iter = iter->next) {
|
||||
fw = CXL_FMW(iter->data);
|
||||
if (base + fw->size <= max_addr) {
|
||||
fw->base = base;
|
||||
base += fw->size;
|
||||
}
|
||||
}
|
||||
g_slist_free(cfmws_list);
|
||||
|
||||
return base;
|
||||
}
|
||||
|
||||
static void cxl_fmw_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
CXLFixedWindow *fw = CXL_FMW(dev);
|
||||
|
||||
memory_region_init_io(&fw->mr, OBJECT(dev), &cfmws_ops, fw,
|
||||
"cxl-fixed-memory-region", fw->size);
|
||||
sysbus_init_mmio(SYS_BUS_DEVICE(dev), &fw->mr);
|
||||
}
|
||||
|
||||
/*
|
||||
* Note: Fixed memory windows represent fixed address decoders on the host and
|
||||
* as such have no dynamic state to reset or migrate
|
||||
*/
|
||||
static void cxl_fmw_class_init(ObjectClass *klass, const void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
||||
dc->desc = "CXL Fixed Memory Window";
|
||||
dc->realize = cxl_fmw_realize;
|
||||
/* Reason - created by machines as tightly coupled to machine memory map */
|
||||
dc->user_creatable = false;
|
||||
}
|
||||
|
||||
static const TypeInfo cxl_fmw_info = {
|
||||
.name = TYPE_CXL_FMW,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(CXLFixedWindow),
|
||||
.class_init = cxl_fmw_class_init,
|
||||
};
|
||||
|
||||
static void cxl_host_register_types(void)
|
||||
{
|
||||
type_register_static(&cxl_fmw_info);
|
||||
}
|
||||
type_init(cxl_host_register_types)
|
||||
|
|
|
|||
50
hw/i386/pc.c
50
hw/i386/pc.c
|
|
@ -609,7 +609,7 @@ void pc_machine_done(Notifier *notifier, void *data)
|
|||
&error_fatal);
|
||||
|
||||
if (pcms->cxl_devices_state.is_enabled) {
|
||||
cxl_fmws_link_targets(&pcms->cxl_devices_state, &error_fatal);
|
||||
cxl_fmws_link_targets(&error_fatal);
|
||||
}
|
||||
|
||||
/* set the number of CPUs */
|
||||
|
|
@ -718,20 +718,28 @@ static uint64_t pc_get_cxl_range_start(PCMachineState *pcms)
|
|||
return cxl_base;
|
||||
}
|
||||
|
||||
static int cxl_get_fmw_end(Object *obj, void *opaque)
|
||||
{
|
||||
struct CXLFixedWindow *fw;
|
||||
uint64_t *start = opaque;
|
||||
|
||||
if (!object_dynamic_cast(obj, TYPE_CXL_FMW)) {
|
||||
return 0;
|
||||
}
|
||||
fw = CXL_FMW(obj);
|
||||
|
||||
*start += fw->size;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint64_t pc_get_cxl_range_end(PCMachineState *pcms)
|
||||
{
|
||||
uint64_t start = pc_get_cxl_range_start(pcms) + MiB;
|
||||
|
||||
if (pcms->cxl_devices_state.fixed_windows) {
|
||||
GList *it;
|
||||
|
||||
start = ROUND_UP(start, 256 * MiB);
|
||||
for (it = pcms->cxl_devices_state.fixed_windows; it; it = it->next) {
|
||||
CXLFixedWindow *fw = it->data;
|
||||
start += fw->size;
|
||||
}
|
||||
}
|
||||
|
||||
/* Ordering doesn't matter so no need to build a sorted list */
|
||||
object_child_foreach_recursive(object_get_root(), cxl_get_fmw_end,
|
||||
&start);
|
||||
return start;
|
||||
}
|
||||
|
||||
|
|
@ -933,23 +941,9 @@ void pc_memory_init(PCMachineState *pcms,
|
|||
cxl_base = pc_get_cxl_range_start(pcms);
|
||||
memory_region_init(mr, OBJECT(machine), "cxl_host_reg", cxl_size);
|
||||
memory_region_add_subregion(system_memory, cxl_base, mr);
|
||||
cxl_resv_end = cxl_base + cxl_size;
|
||||
if (pcms->cxl_devices_state.fixed_windows) {
|
||||
hwaddr cxl_fmw_base;
|
||||
GList *it;
|
||||
|
||||
cxl_fmw_base = ROUND_UP(cxl_base + cxl_size, 256 * MiB);
|
||||
for (it = pcms->cxl_devices_state.fixed_windows; it; it = it->next) {
|
||||
CXLFixedWindow *fw = it->data;
|
||||
|
||||
fw->base = cxl_fmw_base;
|
||||
memory_region_init_io(&fw->mr, OBJECT(machine), &cfmws_ops, fw,
|
||||
"cxl-fixed-memory-region", fw->size);
|
||||
memory_region_add_subregion(system_memory, fw->base, &fw->mr);
|
||||
cxl_fmw_base += fw->size;
|
||||
cxl_resv_end = cxl_fmw_base;
|
||||
}
|
||||
}
|
||||
cxl_base = ROUND_UP(cxl_base + cxl_size, 256 * MiB);
|
||||
cxl_resv_end = cxl_fmws_set_memmap(cxl_base, maxphysaddr);
|
||||
cxl_fmws_update_mmio();
|
||||
}
|
||||
|
||||
/* Initialize PC system firmware */
|
||||
|
|
|
|||
|
|
@ -612,6 +612,7 @@ static const Property arm_gicv3_common_properties[] = {
|
|||
DEFINE_PROP_BOOL("has-lpi", GICv3State, lpi_enable, 0),
|
||||
DEFINE_PROP_BOOL("has-nmi", GICv3State, nmi_support, 0),
|
||||
DEFINE_PROP_BOOL("has-security-extensions", GICv3State, security_extn, 0),
|
||||
DEFINE_PROP_UINT32("maintenance-interrupt-id", GICv3State, maint_irq, 0),
|
||||
/*
|
||||
* Compatibility property: force 8 bits of physical priority, even
|
||||
* if the CPU being emulated should have fewer.
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@
|
|||
#include "qemu/osdep.h"
|
||||
#include "qapi/error.h"
|
||||
#include "hw/intc/arm_gicv3_common.h"
|
||||
#include "hw/arm/virt.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "qemu/module.h"
|
||||
#include "system/kvm.h"
|
||||
|
|
@ -825,6 +826,34 @@ static void kvm_arm_gicv3_realize(DeviceState *dev, Error **errp)
|
|||
return;
|
||||
}
|
||||
|
||||
if (s->maint_irq) {
|
||||
Error *kvm_nv_migration_blocker = NULL;
|
||||
int ret;
|
||||
|
||||
error_setg(&kvm_nv_migration_blocker,
|
||||
"Live migration disabled because KVM nested virt is enabled");
|
||||
if (migrate_add_blocker(&kvm_nv_migration_blocker, errp)) {
|
||||
error_free(kvm_nv_migration_blocker);
|
||||
return;
|
||||
}
|
||||
|
||||
ret = kvm_device_check_attr(s->dev_fd,
|
||||
KVM_DEV_ARM_VGIC_GRP_MAINT_IRQ, 0);
|
||||
if (!ret) {
|
||||
error_setg_errno(errp, errno,
|
||||
"VGICv3 setting maintenance IRQ is not "
|
||||
"supported by this host kernel");
|
||||
return;
|
||||
}
|
||||
|
||||
ret = kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_MAINT_IRQ, 0,
|
||||
&s->maint_irq, true, errp);
|
||||
if (ret) {
|
||||
error_setg_errno(errp, errno, "Failed to set VGIC maintenance IRQ");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
multiple_redist_region_allowed =
|
||||
kvm_device_check_attr(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
|
||||
KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION);
|
||||
|
|
|
|||
|
|
@ -1279,7 +1279,7 @@ static uint32_t nvic_readl(NVICState *s, uint32_t offset, MemTxAttrs attrs)
|
|||
if (!arm_feature(&cpu->env, ARM_FEATURE_M_MAIN)) {
|
||||
goto bad_offset;
|
||||
}
|
||||
return cpu->id_afr0;
|
||||
return GET_IDREG(isar, ID_AFR0);
|
||||
case 0xd50: /* MMFR0. */
|
||||
if (!arm_feature(&cpu->env, ARM_FEATURE_M_MAIN)) {
|
||||
goto bad_offset;
|
||||
|
|
@ -1331,7 +1331,7 @@ static uint32_t nvic_readl(NVICState *s, uint32_t offset, MemTxAttrs attrs)
|
|||
}
|
||||
return GET_IDREG(&cpu->isar, ID_ISAR5);
|
||||
case 0xd78: /* CLIDR */
|
||||
return cpu->clidr;
|
||||
return GET_IDREG(&cpu->isar, CLIDR);
|
||||
case 0xd7c: /* CTR */
|
||||
return cpu->ctr;
|
||||
case 0xd80: /* CSSIDR */
|
||||
|
|
|
|||
|
|
@ -47,6 +47,18 @@ config A9SCU
|
|||
config ARM11SCU
|
||||
bool
|
||||
|
||||
config MAX78000_AES
|
||||
bool
|
||||
|
||||
config MAX78000_GCR
|
||||
bool
|
||||
|
||||
config MAX78000_ICC
|
||||
bool
|
||||
|
||||
config MAX78000_TRNG
|
||||
bool
|
||||
|
||||
config MOS6522
|
||||
bool
|
||||
|
||||
|
|
|
|||
223
hw/misc/max78000_aes.c
Normal file
223
hw/misc/max78000_aes.c
Normal file
|
|
@ -0,0 +1,223 @@
|
|||
/*
|
||||
* MAX78000 AES
|
||||
*
|
||||
* Copyright (c) 2025 Jackson Donaldson <jcksn@duck.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/log.h"
|
||||
#include "trace.h"
|
||||
#include "hw/irq.h"
|
||||
#include "migration/vmstate.h"
|
||||
#include "hw/misc/max78000_aes.h"
|
||||
#include "crypto/aes.h"
|
||||
|
||||
static void max78000_aes_set_status(Max78000AesState *s)
|
||||
{
|
||||
s->status = 0;
|
||||
if (s->result_index >= 16) {
|
||||
s->status |= OUTPUT_FULL;
|
||||
}
|
||||
if (s->result_index == 0) {
|
||||
s->status |= OUTPUT_EMPTY;
|
||||
}
|
||||
if (s->data_index >= 16) {
|
||||
s->status |= INPUT_FULL;
|
||||
}
|
||||
if (s->data_index == 0) {
|
||||
s->status |= INPUT_EMPTY;
|
||||
}
|
||||
}
|
||||
|
||||
static uint64_t max78000_aes_read(void *opaque, hwaddr addr,
|
||||
unsigned int size)
|
||||
{
|
||||
Max78000AesState *s = opaque;
|
||||
switch (addr) {
|
||||
case CTRL:
|
||||
return s->ctrl;
|
||||
|
||||
case STATUS:
|
||||
return s->status;
|
||||
|
||||
case INTFL:
|
||||
return s->intfl;
|
||||
|
||||
case INTEN:
|
||||
return s->inten;
|
||||
|
||||
case FIFO:
|
||||
if (s->result_index >= 4) {
|
||||
s->intfl &= ~DONE;
|
||||
s->result_index -= 4;
|
||||
max78000_aes_set_status(s);
|
||||
return ldl_be_p(&s->result[s->result_index]);
|
||||
} else{
|
||||
return 0;
|
||||
}
|
||||
|
||||
default:
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%"
|
||||
HWADDR_PRIx "\n", __func__, addr);
|
||||
break;
|
||||
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void max78000_aes_do_crypto(Max78000AesState *s)
|
||||
{
|
||||
int keylen = 256;
|
||||
uint8_t *keydata = s->key;
|
||||
if ((s->ctrl & KEY_SIZE) == 0) {
|
||||
keylen = 128;
|
||||
keydata += 16;
|
||||
} else if ((s->ctrl & KEY_SIZE) == 1 << 6) {
|
||||
keylen = 192;
|
||||
keydata += 8;
|
||||
}
|
||||
|
||||
AES_KEY key;
|
||||
if ((s->ctrl & TYPE) == 0) {
|
||||
AES_set_encrypt_key(keydata, keylen, &key);
|
||||
AES_set_decrypt_key(keydata, keylen, &s->internal_key);
|
||||
AES_encrypt(s->data, s->result, &key);
|
||||
s->result_index = 16;
|
||||
} else if ((s->ctrl & TYPE) == 1 << 8) {
|
||||
AES_set_decrypt_key(keydata, keylen, &key);
|
||||
AES_set_decrypt_key(keydata, keylen, &s->internal_key);
|
||||
AES_decrypt(s->data, s->result, &key);
|
||||
s->result_index = 16;
|
||||
} else{
|
||||
AES_decrypt(s->data, s->result, &s->internal_key);
|
||||
s->result_index = 16;
|
||||
}
|
||||
s->intfl |= DONE;
|
||||
}
|
||||
|
||||
static void max78000_aes_write(void *opaque, hwaddr addr,
|
||||
uint64_t val64, unsigned int size)
|
||||
{
|
||||
Max78000AesState *s = opaque;
|
||||
uint32_t val = val64;
|
||||
switch (addr) {
|
||||
case CTRL:
|
||||
if (val & OUTPUT_FLUSH) {
|
||||
s->result_index = 0;
|
||||
val &= ~OUTPUT_FLUSH;
|
||||
}
|
||||
if (val & INPUT_FLUSH) {
|
||||
s->data_index = 0;
|
||||
val &= ~INPUT_FLUSH;
|
||||
}
|
||||
if (val & START) {
|
||||
max78000_aes_do_crypto(s);
|
||||
}
|
||||
|
||||
/* Hardware appears to stay enabled even if 0 written */
|
||||
s->ctrl = val | (s->ctrl & AES_EN);
|
||||
break;
|
||||
|
||||
case FIFO:
|
||||
assert(s->data_index <= 12);
|
||||
stl_be_p(&s->data[12 - s->data_index], val);
|
||||
s->data_index += 4;
|
||||
if (s->data_index >= 16) {
|
||||
s->data_index = 0;
|
||||
max78000_aes_do_crypto(s);
|
||||
}
|
||||
break;
|
||||
|
||||
case KEY_BASE ... KEY_END - 4:
|
||||
stl_be_p(&s->key[(KEY_END - KEY_BASE - 4) - (addr - KEY_BASE)], val);
|
||||
break;
|
||||
|
||||
default:
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%"
|
||||
HWADDR_PRIx "\n", __func__, addr);
|
||||
break;
|
||||
|
||||
}
|
||||
max78000_aes_set_status(s);
|
||||
}
|
||||
|
||||
static void max78000_aes_reset_hold(Object *obj, ResetType type)
|
||||
{
|
||||
Max78000AesState *s = MAX78000_AES(obj);
|
||||
s->ctrl = 0;
|
||||
s->status = 0;
|
||||
s->intfl = 0;
|
||||
s->inten = 0;
|
||||
|
||||
s->data_index = 0;
|
||||
s->result_index = 0;
|
||||
|
||||
memset(s->data, 0, sizeof(s->data));
|
||||
memset(s->key, 0, sizeof(s->key));
|
||||
memset(s->result, 0, sizeof(s->result));
|
||||
memset(&s->internal_key, 0, sizeof(s->internal_key));
|
||||
}
|
||||
|
||||
static const MemoryRegionOps max78000_aes_ops = {
|
||||
.read = max78000_aes_read,
|
||||
.write = max78000_aes_write,
|
||||
.endianness = DEVICE_LITTLE_ENDIAN,
|
||||
.valid.min_access_size = 4,
|
||||
.valid.max_access_size = 4,
|
||||
};
|
||||
|
||||
static const VMStateDescription vmstate_max78000_aes = {
|
||||
.name = TYPE_MAX78000_AES,
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.fields = (const VMStateField[]) {
|
||||
VMSTATE_UINT32(ctrl, Max78000AesState),
|
||||
VMSTATE_UINT32(status, Max78000AesState),
|
||||
VMSTATE_UINT32(intfl, Max78000AesState),
|
||||
VMSTATE_UINT32(inten, Max78000AesState),
|
||||
VMSTATE_UINT8_ARRAY(data, Max78000AesState, 16),
|
||||
VMSTATE_UINT8_ARRAY(key, Max78000AesState, 32),
|
||||
VMSTATE_UINT8_ARRAY(result, Max78000AesState, 16),
|
||||
VMSTATE_UINT32_ARRAY(internal_key.rd_key, Max78000AesState, 60),
|
||||
VMSTATE_INT32(internal_key.rounds, Max78000AesState),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
static void max78000_aes_init(Object *obj)
|
||||
{
|
||||
Max78000AesState *s = MAX78000_AES(obj);
|
||||
sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->irq);
|
||||
|
||||
memory_region_init_io(&s->mmio, obj, &max78000_aes_ops, s,
|
||||
TYPE_MAX78000_AES, 0xc00);
|
||||
sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio);
|
||||
|
||||
}
|
||||
|
||||
static void max78000_aes_class_init(ObjectClass *klass, const void *data)
|
||||
{
|
||||
ResettableClass *rc = RESETTABLE_CLASS(klass);
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
||||
rc->phases.hold = max78000_aes_reset_hold;
|
||||
dc->vmsd = &vmstate_max78000_aes;
|
||||
|
||||
}
|
||||
|
||||
static const TypeInfo max78000_aes_info = {
|
||||
.name = TYPE_MAX78000_AES,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(Max78000AesState),
|
||||
.instance_init = max78000_aes_init,
|
||||
.class_init = max78000_aes_class_init,
|
||||
};
|
||||
|
||||
static void max78000_aes_register_types(void)
|
||||
{
|
||||
type_register_static(&max78000_aes_info);
|
||||
}
|
||||
|
||||
type_init(max78000_aes_register_types)
|
||||
351
hw/misc/max78000_gcr.c
Normal file
351
hw/misc/max78000_gcr.c
Normal file
|
|
@ -0,0 +1,351 @@
|
|||
/*
|
||||
* MAX78000 Global Control Registers
|
||||
*
|
||||
* Copyright (c) 2025 Jackson Donaldson <jcksn@duck.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/log.h"
|
||||
#include "trace.h"
|
||||
#include "hw/irq.h"
|
||||
#include "system/runstate.h"
|
||||
#include "migration/vmstate.h"
|
||||
#include "hw/qdev-properties.h"
|
||||
#include "hw/char/max78000_uart.h"
|
||||
#include "hw/misc/max78000_trng.h"
|
||||
#include "hw/misc/max78000_aes.h"
|
||||
#include "hw/misc/max78000_gcr.h"
|
||||
|
||||
|
||||
static void max78000_gcr_reset_hold(Object *obj, ResetType type)
|
||||
{
|
||||
DeviceState *dev = DEVICE(obj);
|
||||
Max78000GcrState *s = MAX78000_GCR(dev);
|
||||
s->sysctrl = 0x21002;
|
||||
s->rst0 = 0;
|
||||
/* All clocks are always ready */
|
||||
s->clkctrl = 0x3e140008;
|
||||
s->pm = 0x3f000;
|
||||
s->pclkdiv = 0;
|
||||
s->pclkdis0 = 0xffffffff;
|
||||
s->memctrl = 0x5;
|
||||
s->memz = 0;
|
||||
s->sysst = 0;
|
||||
s->rst1 = 0;
|
||||
s->pckdis1 = 0xffffffff;
|
||||
s->eventen = 0;
|
||||
s->revision = 0xa1;
|
||||
s->sysie = 0;
|
||||
s->eccerr = 0;
|
||||
s->ecced = 0;
|
||||
s->eccie = 0;
|
||||
s->eccaddr = 0;
|
||||
}
|
||||
|
||||
static uint64_t max78000_gcr_read(void *opaque, hwaddr addr,
|
||||
unsigned int size)
|
||||
{
|
||||
Max78000GcrState *s = opaque;
|
||||
|
||||
switch (addr) {
|
||||
case SYSCTRL:
|
||||
return s->sysctrl;
|
||||
|
||||
case RST0:
|
||||
return s->rst0;
|
||||
|
||||
case CLKCTRL:
|
||||
return s->clkctrl;
|
||||
|
||||
case PM:
|
||||
return s->pm;
|
||||
|
||||
case PCLKDIV:
|
||||
return s->pclkdiv;
|
||||
|
||||
case PCLKDIS0:
|
||||
return s->pclkdis0;
|
||||
|
||||
case MEMCTRL:
|
||||
return s->memctrl;
|
||||
|
||||
case MEMZ:
|
||||
return s->memz;
|
||||
|
||||
case SYSST:
|
||||
return s->sysst;
|
||||
|
||||
case RST1:
|
||||
return s->rst1;
|
||||
|
||||
case PCKDIS1:
|
||||
return s->pckdis1;
|
||||
|
||||
case EVENTEN:
|
||||
return s->eventen;
|
||||
|
||||
case REVISION:
|
||||
return s->revision;
|
||||
|
||||
case SYSIE:
|
||||
return s->sysie;
|
||||
|
||||
case ECCERR:
|
||||
return s->eccerr;
|
||||
|
||||
case ECCED:
|
||||
return s->ecced;
|
||||
|
||||
case ECCIE:
|
||||
return s->eccie;
|
||||
|
||||
case ECCADDR:
|
||||
return s->eccaddr;
|
||||
|
||||
default:
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%"
|
||||
HWADDR_PRIx "\n", __func__, addr);
|
||||
return 0;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
static void max78000_gcr_write(void *opaque, hwaddr addr,
|
||||
uint64_t val64, unsigned int size)
|
||||
{
|
||||
Max78000GcrState *s = opaque;
|
||||
uint32_t val = val64;
|
||||
uint8_t zero[0xc000] = {0};
|
||||
switch (addr) {
|
||||
case SYSCTRL:
|
||||
/* Checksum calculations always pass immediately */
|
||||
s->sysctrl = (val & 0x30000) | 0x1002;
|
||||
break;
|
||||
|
||||
case RST0:
|
||||
if (val & SYSTEM_RESET) {
|
||||
qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
|
||||
}
|
||||
if (val & PERIPHERAL_RESET) {
|
||||
/*
|
||||
* Peripheral reset resets all peripherals. The CPU
|
||||
* retains its state. The GPIO, watchdog timers, AoD,
|
||||
* RAM retention, and general control registers (GCR),
|
||||
* including the clock configuration, are unaffected.
|
||||
*/
|
||||
val = UART2_RESET | UART1_RESET | UART0_RESET |
|
||||
ADC_RESET | CNN_RESET | TRNG_RESET |
|
||||
RTC_RESET | I2C0_RESET | SPI1_RESET |
|
||||
TMR3_RESET | TMR2_RESET | TMR1_RESET |
|
||||
TMR0_RESET | WDT0_RESET | DMA_RESET;
|
||||
}
|
||||
if (val & SOFT_RESET) {
|
||||
/* Soft reset also resets GPIO */
|
||||
val = UART2_RESET | UART1_RESET | UART0_RESET |
|
||||
ADC_RESET | CNN_RESET | TRNG_RESET |
|
||||
RTC_RESET | I2C0_RESET | SPI1_RESET |
|
||||
TMR3_RESET | TMR2_RESET | TMR1_RESET |
|
||||
TMR0_RESET | GPIO1_RESET | GPIO0_RESET |
|
||||
DMA_RESET;
|
||||
}
|
||||
if (val & UART2_RESET) {
|
||||
device_cold_reset(s->uart2);
|
||||
}
|
||||
if (val & UART1_RESET) {
|
||||
device_cold_reset(s->uart1);
|
||||
}
|
||||
if (val & UART0_RESET) {
|
||||
device_cold_reset(s->uart0);
|
||||
}
|
||||
if (val & TRNG_RESET) {
|
||||
device_cold_reset(s->trng);
|
||||
}
|
||||
if (val & AES_RESET) {
|
||||
device_cold_reset(s->aes);
|
||||
}
|
||||
/* TODO: As other devices are implemented, add them here */
|
||||
break;
|
||||
|
||||
case CLKCTRL:
|
||||
s->clkctrl = val | SYSCLK_RDY;
|
||||
break;
|
||||
|
||||
case PM:
|
||||
s->pm = val;
|
||||
break;
|
||||
|
||||
case PCLKDIV:
|
||||
s->pclkdiv = val;
|
||||
break;
|
||||
|
||||
case PCLKDIS0:
|
||||
s->pclkdis0 = val;
|
||||
break;
|
||||
|
||||
case MEMCTRL:
|
||||
s->memctrl = val;
|
||||
break;
|
||||
|
||||
case MEMZ:
|
||||
if (val & ram0) {
|
||||
address_space_write(&s->sram_as, SYSRAM0_START,
|
||||
MEMTXATTRS_UNSPECIFIED, zero, 0x8000);
|
||||
}
|
||||
if (val & ram1) {
|
||||
address_space_write(&s->sram_as, SYSRAM1_START,
|
||||
MEMTXATTRS_UNSPECIFIED, zero, 0x8000);
|
||||
}
|
||||
if (val & ram2) {
|
||||
address_space_write(&s->sram_as, SYSRAM2_START,
|
||||
MEMTXATTRS_UNSPECIFIED, zero, 0xC000);
|
||||
}
|
||||
if (val & ram3) {
|
||||
address_space_write(&s->sram_as, SYSRAM3_START,
|
||||
MEMTXATTRS_UNSPECIFIED, zero, 0x4000);
|
||||
}
|
||||
break;
|
||||
|
||||
case SYSST:
|
||||
s->sysst = val;
|
||||
break;
|
||||
|
||||
case RST1:
|
||||
/* TODO: As other devices are implemented, add them here */
|
||||
s->rst1 = val;
|
||||
break;
|
||||
|
||||
case PCKDIS1:
|
||||
s->pckdis1 = val;
|
||||
break;
|
||||
|
||||
case EVENTEN:
|
||||
s->eventen = val;
|
||||
break;
|
||||
|
||||
case REVISION:
|
||||
s->revision = val;
|
||||
break;
|
||||
|
||||
case SYSIE:
|
||||
s->sysie = val;
|
||||
break;
|
||||
|
||||
case ECCERR:
|
||||
s->eccerr = val;
|
||||
break;
|
||||
|
||||
case ECCED:
|
||||
s->ecced = val;
|
||||
break;
|
||||
|
||||
case ECCIE:
|
||||
s->eccie = val;
|
||||
break;
|
||||
|
||||
case ECCADDR:
|
||||
s->eccaddr = val;
|
||||
break;
|
||||
|
||||
default:
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n",
|
||||
__func__, addr);
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
static const Property max78000_gcr_properties[] = {
|
||||
DEFINE_PROP_LINK("sram", Max78000GcrState, sram,
|
||||
TYPE_MEMORY_REGION, MemoryRegion*),
|
||||
DEFINE_PROP_LINK("uart0", Max78000GcrState, uart0,
|
||||
TYPE_MAX78000_UART, DeviceState*),
|
||||
DEFINE_PROP_LINK("uart1", Max78000GcrState, uart1,
|
||||
TYPE_MAX78000_UART, DeviceState*),
|
||||
DEFINE_PROP_LINK("uart2", Max78000GcrState, uart2,
|
||||
TYPE_MAX78000_UART, DeviceState*),
|
||||
DEFINE_PROP_LINK("trng", Max78000GcrState, trng,
|
||||
TYPE_MAX78000_TRNG, DeviceState*),
|
||||
DEFINE_PROP_LINK("aes", Max78000GcrState, aes,
|
||||
TYPE_MAX78000_AES, DeviceState*),
|
||||
};
|
||||
|
||||
static const MemoryRegionOps max78000_gcr_ops = {
|
||||
.read = max78000_gcr_read,
|
||||
.write = max78000_gcr_write,
|
||||
.endianness = DEVICE_LITTLE_ENDIAN,
|
||||
.valid.min_access_size = 4,
|
||||
.valid.max_access_size = 4,
|
||||
};
|
||||
|
||||
static const VMStateDescription vmstate_max78000_gcr = {
|
||||
.name = TYPE_MAX78000_GCR,
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.fields = (const VMStateField[]) {
|
||||
VMSTATE_UINT32(sysctrl, Max78000GcrState),
|
||||
VMSTATE_UINT32(rst0, Max78000GcrState),
|
||||
VMSTATE_UINT32(clkctrl, Max78000GcrState),
|
||||
VMSTATE_UINT32(pm, Max78000GcrState),
|
||||
VMSTATE_UINT32(pclkdiv, Max78000GcrState),
|
||||
VMSTATE_UINT32(pclkdis0, Max78000GcrState),
|
||||
VMSTATE_UINT32(memctrl, Max78000GcrState),
|
||||
VMSTATE_UINT32(memz, Max78000GcrState),
|
||||
VMSTATE_UINT32(sysst, Max78000GcrState),
|
||||
VMSTATE_UINT32(rst1, Max78000GcrState),
|
||||
VMSTATE_UINT32(pckdis1, Max78000GcrState),
|
||||
VMSTATE_UINT32(eventen, Max78000GcrState),
|
||||
VMSTATE_UINT32(revision, Max78000GcrState),
|
||||
VMSTATE_UINT32(sysie, Max78000GcrState),
|
||||
VMSTATE_UINT32(eccerr, Max78000GcrState),
|
||||
VMSTATE_UINT32(ecced, Max78000GcrState),
|
||||
VMSTATE_UINT32(eccie, Max78000GcrState),
|
||||
VMSTATE_UINT32(eccaddr, Max78000GcrState),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
static void max78000_gcr_init(Object *obj)
|
||||
{
|
||||
Max78000GcrState *s = MAX78000_GCR(obj);
|
||||
|
||||
memory_region_init_io(&s->mmio, obj, &max78000_gcr_ops, s,
|
||||
TYPE_MAX78000_GCR, 0x400);
|
||||
sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio);
|
||||
|
||||
}
|
||||
|
||||
static void max78000_gcr_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
Max78000GcrState *s = MAX78000_GCR(dev);
|
||||
|
||||
address_space_init(&s->sram_as, s->sram, "sram");
|
||||
}
|
||||
|
||||
static void max78000_gcr_class_init(ObjectClass *klass, const void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
ResettableClass *rc = RESETTABLE_CLASS(klass);
|
||||
|
||||
device_class_set_props(dc, max78000_gcr_properties);
|
||||
|
||||
dc->realize = max78000_gcr_realize;
|
||||
dc->vmsd = &vmstate_max78000_gcr;
|
||||
rc->phases.hold = max78000_gcr_reset_hold;
|
||||
}
|
||||
|
||||
static const TypeInfo max78000_gcr_info = {
|
||||
.name = TYPE_MAX78000_GCR,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(Max78000GcrState),
|
||||
.instance_init = max78000_gcr_init,
|
||||
.class_init = max78000_gcr_class_init,
|
||||
};
|
||||
|
||||
static void max78000_gcr_register_types(void)
|
||||
{
|
||||
type_register_static(&max78000_gcr_info);
|
||||
}
|
||||
|
||||
type_init(max78000_gcr_register_types)
|
||||
120
hw/misc/max78000_icc.c
Normal file
120
hw/misc/max78000_icc.c
Normal file
|
|
@ -0,0 +1,120 @@
|
|||
/*
|
||||
* MAX78000 Instruction Cache
|
||||
*
|
||||
* Copyright (c) 2025 Jackson Donaldson <jcksn@duck.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/log.h"
|
||||
#include "trace.h"
|
||||
#include "hw/irq.h"
|
||||
#include "migration/vmstate.h"
|
||||
#include "hw/misc/max78000_icc.h"
|
||||
|
||||
|
||||
static uint64_t max78000_icc_read(void *opaque, hwaddr addr,
|
||||
unsigned int size)
|
||||
{
|
||||
Max78000IccState *s = opaque;
|
||||
switch (addr) {
|
||||
case ICC_INFO:
|
||||
return s->info;
|
||||
|
||||
case ICC_SZ:
|
||||
return s->sz;
|
||||
|
||||
case ICC_CTRL:
|
||||
return s->ctrl;
|
||||
|
||||
default:
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"%s: Bad offset 0x%" HWADDR_PRIx "\n",
|
||||
__func__, addr);
|
||||
return 0;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
static void max78000_icc_write(void *opaque, hwaddr addr,
|
||||
uint64_t val64, unsigned int size)
|
||||
{
|
||||
Max78000IccState *s = opaque;
|
||||
|
||||
switch (addr) {
|
||||
case ICC_CTRL:
|
||||
s->ctrl = 0x10000 | (val64 & 1);
|
||||
break;
|
||||
|
||||
case ICC_INVALIDATE:
|
||||
break;
|
||||
|
||||
default:
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"%s: Bad offset 0x%" HWADDR_PRIx "\n",
|
||||
__func__, addr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static const MemoryRegionOps max78000_icc_ops = {
|
||||
.read = max78000_icc_read,
|
||||
.write = max78000_icc_write,
|
||||
.endianness = DEVICE_LITTLE_ENDIAN,
|
||||
.valid.min_access_size = 4,
|
||||
.valid.max_access_size = 4,
|
||||
};
|
||||
|
||||
static const VMStateDescription max78000_icc_vmstate = {
|
||||
.name = TYPE_MAX78000_ICC,
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.fields = (const VMStateField[]) {
|
||||
VMSTATE_UINT32(info, Max78000IccState),
|
||||
VMSTATE_UINT32(sz, Max78000IccState),
|
||||
VMSTATE_UINT32(ctrl, Max78000IccState),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
static void max78000_icc_reset_hold(Object *obj, ResetType type)
|
||||
{
|
||||
Max78000IccState *s = MAX78000_ICC(obj);
|
||||
s->info = 0;
|
||||
s->sz = 0x10000010;
|
||||
s->ctrl = 0x10000;
|
||||
}
|
||||
|
||||
static void max78000_icc_init(Object *obj)
|
||||
{
|
||||
Max78000IccState *s = MAX78000_ICC(obj);
|
||||
|
||||
memory_region_init_io(&s->mmio, obj, &max78000_icc_ops, s,
|
||||
TYPE_MAX78000_ICC, 0x800);
|
||||
sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio);
|
||||
}
|
||||
|
||||
static void max78000_icc_class_init(ObjectClass *klass, const void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
ResettableClass *rc = RESETTABLE_CLASS(klass);
|
||||
|
||||
rc->phases.hold = max78000_icc_reset_hold;
|
||||
dc->vmsd = &max78000_icc_vmstate;
|
||||
}
|
||||
|
||||
static const TypeInfo max78000_icc_info = {
|
||||
.name = TYPE_MAX78000_ICC,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(Max78000IccState),
|
||||
.instance_init = max78000_icc_init,
|
||||
.class_init = max78000_icc_class_init,
|
||||
};
|
||||
|
||||
static void max78000_icc_register_types(void)
|
||||
{
|
||||
type_register_static(&max78000_icc_info);
|
||||
}
|
||||
|
||||
type_init(max78000_icc_register_types)
|
||||
139
hw/misc/max78000_trng.c
Normal file
139
hw/misc/max78000_trng.c
Normal file
|
|
@ -0,0 +1,139 @@
|
|||
/*
|
||||
* MAX78000 True Random Number Generator
|
||||
*
|
||||
* Copyright (c) 2025 Jackson Donaldson <jcksn@duck.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/log.h"
|
||||
#include "trace.h"
|
||||
#include "hw/irq.h"
|
||||
#include "migration/vmstate.h"
|
||||
#include "hw/misc/max78000_trng.h"
|
||||
#include "qemu/guest-random.h"
|
||||
|
||||
static uint64_t max78000_trng_read(void *opaque, hwaddr addr,
|
||||
unsigned int size)
|
||||
{
|
||||
uint32_t data;
|
||||
|
||||
Max78000TrngState *s = opaque;
|
||||
switch (addr) {
|
||||
case CTRL:
|
||||
return s->ctrl;
|
||||
|
||||
case STATUS:
|
||||
return 1;
|
||||
|
||||
case DATA:
|
||||
/*
|
||||
* When interrupts are enabled, reading random data should cause a
|
||||
* new interrupt to be generated; since there's always a random number
|
||||
* available, we could qemu_set_irq(s->irq, s->ctrl & RND_IE). Because
|
||||
* of how trng_write is set up, this is always a noop, so don't
|
||||
*/
|
||||
qemu_guest_getrandom_nofail(&data, sizeof(data));
|
||||
return data;
|
||||
|
||||
default:
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%"
|
||||
HWADDR_PRIx "\n", __func__, addr);
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void max78000_trng_write(void *opaque, hwaddr addr,
|
||||
uint64_t val64, unsigned int size)
|
||||
{
|
||||
Max78000TrngState *s = opaque;
|
||||
uint32_t val = val64;
|
||||
switch (addr) {
|
||||
case CTRL:
|
||||
/* TODO: implement AES keygen */
|
||||
s->ctrl = val;
|
||||
|
||||
/*
|
||||
* This device models random number generation as taking 0 time.
|
||||
* A new random number is always available, so the condition for the
|
||||
* RND interrupt is always fulfilled; we can just set irq to 1.
|
||||
*/
|
||||
if (val & RND_IE) {
|
||||
qemu_set_irq(s->irq, 1);
|
||||
} else{
|
||||
qemu_set_irq(s->irq, 0);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%"
|
||||
HWADDR_PRIx "\n", __func__, addr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void max78000_trng_reset_hold(Object *obj, ResetType type)
|
||||
{
|
||||
Max78000TrngState *s = MAX78000_TRNG(obj);
|
||||
s->ctrl = 0;
|
||||
s->status = 0;
|
||||
s->data = 0;
|
||||
}
|
||||
|
||||
static const MemoryRegionOps max78000_trng_ops = {
|
||||
.read = max78000_trng_read,
|
||||
.write = max78000_trng_write,
|
||||
.endianness = DEVICE_LITTLE_ENDIAN,
|
||||
.valid.min_access_size = 4,
|
||||
.valid.max_access_size = 4,
|
||||
};
|
||||
|
||||
static const VMStateDescription max78000_trng_vmstate = {
|
||||
.name = TYPE_MAX78000_TRNG,
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.fields = (const VMStateField[]) {
|
||||
VMSTATE_UINT32(ctrl, Max78000TrngState),
|
||||
VMSTATE_UINT32(status, Max78000TrngState),
|
||||
VMSTATE_UINT32(data, Max78000TrngState),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
static void max78000_trng_init(Object *obj)
|
||||
{
|
||||
Max78000TrngState *s = MAX78000_TRNG(obj);
|
||||
sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->irq);
|
||||
|
||||
memory_region_init_io(&s->mmio, obj, &max78000_trng_ops, s,
|
||||
TYPE_MAX78000_TRNG, 0x1000);
|
||||
sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio);
|
||||
|
||||
}
|
||||
|
||||
static void max78000_trng_class_init(ObjectClass *klass, const void *data)
|
||||
{
|
||||
ResettableClass *rc = RESETTABLE_CLASS(klass);
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
||||
rc->phases.hold = max78000_trng_reset_hold;
|
||||
dc->vmsd = &max78000_trng_vmstate;
|
||||
|
||||
}
|
||||
|
||||
static const TypeInfo max78000_trng_info = {
|
||||
.name = TYPE_MAX78000_TRNG,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(Max78000TrngState),
|
||||
.instance_init = max78000_trng_init,
|
||||
.class_init = max78000_trng_class_init,
|
||||
};
|
||||
|
||||
static void max78000_trng_register_types(void)
|
||||
{
|
||||
type_register_static(&max78000_trng_info);
|
||||
}
|
||||
|
||||
type_init(max78000_trng_register_types)
|
||||
|
|
@ -70,6 +70,10 @@ system_ss.add(when: 'CONFIG_IMX', if_true: files(
|
|||
'imx_ccm.c',
|
||||
'imx_rngc.c',
|
||||
))
|
||||
system_ss.add(when: 'CONFIG_MAX78000_AES', if_true: files('max78000_aes.c'))
|
||||
system_ss.add(when: 'CONFIG_MAX78000_GCR', if_true: files('max78000_gcr.c'))
|
||||
system_ss.add(when: 'CONFIG_MAX78000_ICC', if_true: files('max78000_icc.c'))
|
||||
system_ss.add(when: 'CONFIG_MAX78000_TRNG', if_true: files('max78000_trng.c'))
|
||||
system_ss.add(when: 'CONFIG_NPCM7XX', if_true: files(
|
||||
'npcm_clk.c',
|
||||
'npcm_gcr.c',
|
||||
|
|
|
|||
50
include/hw/arm/max78000_soc.h
Normal file
50
include/hw/arm/max78000_soc.h
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* MAX78000 SOC
|
||||
*
|
||||
* Copyright (c) 2025 Jackson Donaldson <jcksn@duck.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef HW_ARM_MAX78000_SOC_H
|
||||
#define HW_ARM_MAX78000_SOC_H
|
||||
|
||||
#include "hw/or-irq.h"
|
||||
#include "hw/arm/armv7m.h"
|
||||
#include "hw/misc/max78000_aes.h"
|
||||
#include "hw/misc/max78000_gcr.h"
|
||||
#include "hw/misc/max78000_icc.h"
|
||||
#include "hw/char/max78000_uart.h"
|
||||
#include "hw/misc/max78000_trng.h"
|
||||
#include "qom/object.h"
|
||||
|
||||
#define TYPE_MAX78000_SOC "max78000-soc"
|
||||
OBJECT_DECLARE_SIMPLE_TYPE(MAX78000State, MAX78000_SOC)
|
||||
|
||||
#define FLASH_BASE_ADDRESS 0x10000000
|
||||
#define FLASH_SIZE (512 * 1024)
|
||||
#define SRAM_BASE_ADDRESS 0x20000000
|
||||
#define SRAM_SIZE (128 * 1024)
|
||||
|
||||
/* The MAX78k has 2 instruction caches; only icc0 matters, icc1 is for RISC */
|
||||
#define MAX78000_NUM_ICC 2
|
||||
#define MAX78000_NUM_UART 3
|
||||
|
||||
struct MAX78000State {
|
||||
SysBusDevice parent_obj;
|
||||
|
||||
ARMv7MState armv7m;
|
||||
|
||||
MemoryRegion sram;
|
||||
MemoryRegion flash;
|
||||
|
||||
Max78000GcrState gcr;
|
||||
Max78000IccState icc[MAX78000_NUM_ICC];
|
||||
Max78000UartState uart[MAX78000_NUM_UART];
|
||||
Max78000TrngState trng;
|
||||
Max78000AesState aes;
|
||||
|
||||
Clock *sysclk;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -36,6 +36,7 @@
|
|||
#include "hw/arm/boot.h"
|
||||
#include "hw/arm/bsa.h"
|
||||
#include "hw/block/flash.h"
|
||||
#include "hw/cxl/cxl.h"
|
||||
#include "system/kvm.h"
|
||||
#include "hw/intc/arm_gicv3_common.h"
|
||||
#include "qom/object.h"
|
||||
|
|
@ -85,6 +86,7 @@ enum {
|
|||
/* indices of IO regions located after the RAM */
|
||||
enum {
|
||||
VIRT_HIGH_GIC_REDIST2 = VIRT_LOWMEMMAP_LAST,
|
||||
VIRT_CXL_HOST,
|
||||
VIRT_HIGH_PCIE_ECAM,
|
||||
VIRT_HIGH_PCIE_MMIO,
|
||||
};
|
||||
|
|
@ -140,6 +142,7 @@ struct VirtMachineState {
|
|||
bool secure;
|
||||
bool highmem;
|
||||
bool highmem_compact;
|
||||
bool highmem_cxl;
|
||||
bool highmem_ecam;
|
||||
bool highmem_mmio;
|
||||
bool highmem_redists;
|
||||
|
|
@ -174,6 +177,7 @@ struct VirtMachineState {
|
|||
char *oem_id;
|
||||
char *oem_table_id;
|
||||
bool ns_el2_virt_timer_irq;
|
||||
CXLState cxl_devices_state;
|
||||
};
|
||||
|
||||
#define VIRT_ECAM_ID(high) (high ? VIRT_HIGH_PCIE_ECAM : VIRT_PCIE_ECAM)
|
||||
|
|
|
|||
78
include/hw/char/max78000_uart.h
Normal file
78
include/hw/char/max78000_uart.h
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
/*
|
||||
* MAX78000 UART
|
||||
*
|
||||
* Copyright (c) 2025 Jackson Donaldson <jcksn@duck.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef HW_MAX78000_UART_H
|
||||
#define HW_MAX78000_UART_H
|
||||
|
||||
#include "hw/sysbus.h"
|
||||
#include "chardev/char-fe.h"
|
||||
#include "qemu/fifo8.h"
|
||||
#include "qom/object.h"
|
||||
|
||||
#define UART_CTRL 0x0
|
||||
#define UART_STATUS 0x4
|
||||
#define UART_INT_EN 0x8
|
||||
#define UART_INT_FL 0xc
|
||||
#define UART_CLKDIV 0x10
|
||||
#define UART_OSR 0x14
|
||||
#define UART_TXPEEK 0x18
|
||||
#define UART_PNR 0x1c
|
||||
#define UART_FIFO 0x20
|
||||
#define UART_DMA 0x30
|
||||
#define UART_WKEN 0x34
|
||||
#define UART_WKFL 0x38
|
||||
|
||||
/* CTRL */
|
||||
#define UART_CTF_DIS (1 << 7)
|
||||
#define UART_FLUSH_TX (1 << 8)
|
||||
#define UART_FLUSH_RX (1 << 9)
|
||||
#define UART_BCLKEN (1 << 15)
|
||||
#define UART_BCLKRDY (1 << 19)
|
||||
|
||||
/* STATUS */
|
||||
#define UART_RX_LVL 8
|
||||
#define UART_TX_EM (1 << 6)
|
||||
#define UART_RX_FULL (1 << 5)
|
||||
#define UART_RX_EM (1 << 4)
|
||||
|
||||
/* PNR (Pin Control Register) */
|
||||
#define UART_CTS 1
|
||||
#define UART_RTS (1 << 1)
|
||||
|
||||
/* INT_EN / INT_FL */
|
||||
#define UART_RX_THD (1 << 4)
|
||||
#define UART_TX_HE (1 << 6)
|
||||
|
||||
#define UART_RXBUFLEN 0x100
|
||||
#define TYPE_MAX78000_UART "max78000-uart"
|
||||
OBJECT_DECLARE_SIMPLE_TYPE(Max78000UartState, MAX78000_UART)
|
||||
|
||||
struct Max78000UartState {
|
||||
SysBusDevice parent_obj;
|
||||
|
||||
MemoryRegion mmio;
|
||||
|
||||
uint32_t ctrl;
|
||||
uint32_t status;
|
||||
uint32_t int_en;
|
||||
uint32_t int_fl;
|
||||
uint32_t clkdiv;
|
||||
uint32_t osr;
|
||||
uint32_t txpeek;
|
||||
uint32_t pnr;
|
||||
uint32_t fifo;
|
||||
uint32_t dma;
|
||||
uint32_t wken;
|
||||
uint32_t wkfl;
|
||||
|
||||
Fifo8 rx_fifo;
|
||||
|
||||
CharBackend chr;
|
||||
qemu_irq irq;
|
||||
};
|
||||
#endif /* HW_STM32F2XX_USART_H */
|
||||
|
|
@ -27,6 +27,8 @@
|
|||
typedef struct PXBCXLDev PXBCXLDev;
|
||||
|
||||
typedef struct CXLFixedWindow {
|
||||
SysBusDevice parent_obj;
|
||||
int index;
|
||||
uint64_t size;
|
||||
char **targets;
|
||||
PXBCXLDev *target_hbs[16];
|
||||
|
|
@ -37,12 +39,13 @@ typedef struct CXLFixedWindow {
|
|||
MemoryRegion mr;
|
||||
hwaddr base;
|
||||
} CXLFixedWindow;
|
||||
#define TYPE_CXL_FMW "cxl-fmw"
|
||||
OBJECT_DECLARE_SIMPLE_TYPE(CXLFixedWindow, CXL_FMW)
|
||||
|
||||
typedef struct CXLState {
|
||||
bool is_enabled;
|
||||
MemoryRegion host_mr;
|
||||
unsigned int next_mr_idx;
|
||||
GList *fixed_windows;
|
||||
CXLFixedMemoryWindowOptionsList *cfmw_list;
|
||||
} CXLState;
|
||||
|
||||
|
|
|
|||
|
|
@ -14,8 +14,11 @@
|
|||
#define CXL_HOST_H
|
||||
|
||||
void cxl_machine_init(Object *obj, CXLState *state);
|
||||
void cxl_fmws_link_targets(CXLState *stat, Error **errp);
|
||||
void cxl_fmws_link_targets(Error **errp);
|
||||
void cxl_hook_up_pxb_registers(PCIBus *bus, CXLState *state, Error **errp);
|
||||
hwaddr cxl_fmws_set_memmap(hwaddr base, hwaddr max_addr);
|
||||
void cxl_fmws_update_mmio(void);
|
||||
GSList *cxl_fmws_get_all_sorted(void);
|
||||
|
||||
extern const MemoryRegionOps cfmws_ops;
|
||||
|
||||
|
|
|
|||
|
|
@ -231,6 +231,7 @@ struct GICv3State {
|
|||
uint32_t num_cpu;
|
||||
uint32_t num_irq;
|
||||
uint32_t revision;
|
||||
uint32_t maint_irq;
|
||||
bool lpi_enable;
|
||||
bool nmi_support;
|
||||
bool security_extn;
|
||||
|
|
|
|||
68
include/hw/misc/max78000_aes.h
Normal file
68
include/hw/misc/max78000_aes.h
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* MAX78000 AES
|
||||
*
|
||||
* Copyright (c) 2025 Jackson Donaldson <jcksn@duck.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
#ifndef HW_MAX78000_AES_H
|
||||
#define HW_MAX78000_AES_H
|
||||
|
||||
#include "hw/sysbus.h"
|
||||
#include "crypto/aes.h"
|
||||
#include "qom/object.h"
|
||||
|
||||
#define TYPE_MAX78000_AES "max78000-aes"
|
||||
OBJECT_DECLARE_SIMPLE_TYPE(Max78000AesState, MAX78000_AES)
|
||||
|
||||
#define CTRL 0
|
||||
#define STATUS 4
|
||||
#define INTFL 8
|
||||
#define INTEN 0xc
|
||||
#define FIFO 0x10
|
||||
|
||||
#define KEY_BASE 0x400
|
||||
#define KEY_END 0x420
|
||||
|
||||
/* CTRL */
|
||||
#define TYPE (1 << 9 | 1 << 8)
|
||||
#define KEY_SIZE (1 << 7 | 1 << 6)
|
||||
#define OUTPUT_FLUSH (1 << 5)
|
||||
#define INPUT_FLUSH (1 << 4)
|
||||
#define START (1 << 3)
|
||||
|
||||
#define AES_EN (1 << 0)
|
||||
|
||||
/* STATUS */
|
||||
#define OUTPUT_FULL (1 << 4)
|
||||
#define OUTPUT_EMPTY (1 << 3)
|
||||
#define INPUT_FULL (1 << 2)
|
||||
#define INPUT_EMPTY (1 << 1)
|
||||
#define BUSY (1 << 0)
|
||||
|
||||
/* INTFL*/
|
||||
#define DONE (1 << 0)
|
||||
|
||||
struct Max78000AesState {
|
||||
SysBusDevice parent_obj;
|
||||
|
||||
MemoryRegion mmio;
|
||||
|
||||
uint32_t ctrl;
|
||||
uint32_t status;
|
||||
uint32_t intfl;
|
||||
uint32_t inten;
|
||||
uint32_t data_index;
|
||||
uint8_t data[16];
|
||||
|
||||
uint8_t key[32];
|
||||
AES_KEY internal_key;
|
||||
|
||||
uint32_t result_index;
|
||||
uint8_t result[16];
|
||||
|
||||
|
||||
qemu_irq irq;
|
||||
};
|
||||
|
||||
#endif
|
||||
131
include/hw/misc/max78000_gcr.h
Normal file
131
include/hw/misc/max78000_gcr.h
Normal file
|
|
@ -0,0 +1,131 @@
|
|||
/*
|
||||
* MAX78000 Global Control Register
|
||||
*
|
||||
* Copyright (c) 2025 Jackson Donaldson <jcksn@duck.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
#ifndef HW_MAX78000_GCR_H
|
||||
#define HW_MAX78000_GCR_H
|
||||
|
||||
#include "hw/sysbus.h"
|
||||
#include "qom/object.h"
|
||||
|
||||
#define TYPE_MAX78000_GCR "max78000-gcr"
|
||||
OBJECT_DECLARE_SIMPLE_TYPE(Max78000GcrState, MAX78000_GCR)
|
||||
|
||||
#define SYSCTRL 0x0
|
||||
#define RST0 0x4
|
||||
#define CLKCTRL 0x8
|
||||
#define PM 0xc
|
||||
#define PCLKDIV 0x18
|
||||
#define PCLKDIS0 0x24
|
||||
#define MEMCTRL 0x28
|
||||
#define MEMZ 0x2c
|
||||
#define SYSST 0x40
|
||||
#define RST1 0x44
|
||||
#define PCKDIS1 0x48
|
||||
#define EVENTEN 0x4c
|
||||
#define REVISION 0x50
|
||||
#define SYSIE 0x54
|
||||
#define ECCERR 0x64
|
||||
#define ECCED 0x68
|
||||
#define ECCIE 0x6c
|
||||
#define ECCADDR 0x70
|
||||
|
||||
/* RST0 */
|
||||
#define SYSTEM_RESET (1 << 31)
|
||||
#define PERIPHERAL_RESET (1 << 30)
|
||||
#define SOFT_RESET (1 << 29)
|
||||
#define UART2_RESET (1 << 28)
|
||||
|
||||
#define ADC_RESET (1 << 26)
|
||||
#define CNN_RESET (1 << 25)
|
||||
#define TRNG_RESET (1 << 24)
|
||||
|
||||
#define RTC_RESET (1 << 17)
|
||||
#define I2C0_RESET (1 << 16)
|
||||
|
||||
#define SPI1_RESET (1 << 13)
|
||||
#define UART1_RESET (1 << 12)
|
||||
#define UART0_RESET (1 << 11)
|
||||
|
||||
#define TMR3_RESET (1 << 8)
|
||||
#define TMR2_RESET (1 << 7)
|
||||
#define TMR1_RESET (1 << 6)
|
||||
#define TMR0_RESET (1 << 5)
|
||||
|
||||
#define GPIO1_RESET (1 << 3)
|
||||
#define GPIO0_RESET (1 << 2)
|
||||
#define WDT0_RESET (1 << 1)
|
||||
#define DMA_RESET (1 << 0)
|
||||
|
||||
/* CLKCTRL */
|
||||
#define SYSCLK_RDY (1 << 13)
|
||||
|
||||
/* MEMZ */
|
||||
#define ram0 (1 << 0)
|
||||
#define ram1 (1 << 1)
|
||||
#define ram2 (1 << 2)
|
||||
#define ram3 (1 << 3)
|
||||
|
||||
/* RST1 */
|
||||
#define CPU1_RESET (1 << 31)
|
||||
|
||||
#define SIMO_RESET (1 << 25)
|
||||
#define DVS_RESET (1 << 24)
|
||||
|
||||
#define I2C2_RESET (1 << 20)
|
||||
#define I2S_RESET (1 << 19)
|
||||
|
||||
#define SMPHR_RESET (1 << 16)
|
||||
|
||||
#define SPI0_RESET (1 << 11)
|
||||
#define AES_RESET (1 << 10)
|
||||
#define CRC_RESET (1 << 9)
|
||||
|
||||
#define PT_RESET (1 << 1)
|
||||
#define I2C1_RESET (1 << 0)
|
||||
|
||||
|
||||
#define SYSRAM0_START 0x20000000
|
||||
#define SYSRAM1_START 0x20008000
|
||||
#define SYSRAM2_START 0x20010000
|
||||
#define SYSRAM3_START 0x2001C000
|
||||
|
||||
struct Max78000GcrState {
|
||||
SysBusDevice parent_obj;
|
||||
|
||||
MemoryRegion mmio;
|
||||
|
||||
uint32_t sysctrl;
|
||||
uint32_t rst0;
|
||||
uint32_t clkctrl;
|
||||
uint32_t pm;
|
||||
uint32_t pclkdiv;
|
||||
uint32_t pclkdis0;
|
||||
uint32_t memctrl;
|
||||
uint32_t memz;
|
||||
uint32_t sysst;
|
||||
uint32_t rst1;
|
||||
uint32_t pckdis1;
|
||||
uint32_t eventen;
|
||||
uint32_t revision;
|
||||
uint32_t sysie;
|
||||
uint32_t eccerr;
|
||||
uint32_t ecced;
|
||||
uint32_t eccie;
|
||||
uint32_t eccaddr;
|
||||
|
||||
MemoryRegion *sram;
|
||||
AddressSpace sram_as;
|
||||
|
||||
DeviceState *uart0;
|
||||
DeviceState *uart1;
|
||||
DeviceState *uart2;
|
||||
DeviceState *trng;
|
||||
DeviceState *aes;
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
33
include/hw/misc/max78000_icc.h
Normal file
33
include/hw/misc/max78000_icc.h
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* MAX78000 Instruction Cache
|
||||
*
|
||||
* Copyright (c) 2025 Jackson Donaldson <jcksn@duck.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef HW_MAX78000_ICC_H
|
||||
#define HW_MAX78000_ICC_H
|
||||
|
||||
#include "hw/sysbus.h"
|
||||
#include "qom/object.h"
|
||||
|
||||
#define TYPE_MAX78000_ICC "max78000-icc"
|
||||
OBJECT_DECLARE_SIMPLE_TYPE(Max78000IccState, MAX78000_ICC)
|
||||
|
||||
#define ICC_INFO 0x0
|
||||
#define ICC_SZ 0x4
|
||||
#define ICC_CTRL 0x100
|
||||
#define ICC_INVALIDATE 0x700
|
||||
|
||||
struct Max78000IccState {
|
||||
SysBusDevice parent_obj;
|
||||
|
||||
MemoryRegion mmio;
|
||||
|
||||
uint32_t info;
|
||||
uint32_t sz;
|
||||
uint32_t ctrl;
|
||||
};
|
||||
|
||||
#endif
|
||||
35
include/hw/misc/max78000_trng.h
Normal file
35
include/hw/misc/max78000_trng.h
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* MAX78000 True Random Number Generator
|
||||
*
|
||||
* Copyright (c) 2025 Jackson Donaldson <jcksn@duck.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
#ifndef HW_MAX78000_TRNG_H
|
||||
#define HW_MAX78000_TRNG_H
|
||||
|
||||
#include "hw/sysbus.h"
|
||||
#include "qom/object.h"
|
||||
|
||||
#define TYPE_MAX78000_TRNG "max78000-trng"
|
||||
OBJECT_DECLARE_SIMPLE_TYPE(Max78000TrngState, MAX78000_TRNG)
|
||||
|
||||
#define CTRL 0
|
||||
#define STATUS 4
|
||||
#define DATA 8
|
||||
|
||||
#define RND_IE (1 << 1)
|
||||
|
||||
struct Max78000TrngState {
|
||||
SysBusDevice parent_obj;
|
||||
|
||||
MemoryRegion mmio;
|
||||
|
||||
uint32_t ctrl;
|
||||
uint32_t status;
|
||||
uint32_t data;
|
||||
|
||||
qemu_irq irq;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -628,7 +628,7 @@ DeviceState *qdev_device_add_from_qdict(const QDict *opts,
|
|||
DeviceClass *dc;
|
||||
const char *driver, *path;
|
||||
char *id;
|
||||
DeviceState *dev = NULL;
|
||||
DeviceState *dev;
|
||||
BusState *bus = NULL;
|
||||
QDict *properties;
|
||||
|
||||
|
|
@ -717,10 +717,9 @@ DeviceState *qdev_device_add_from_qdict(const QDict *opts,
|
|||
return dev;
|
||||
|
||||
err_del_dev:
|
||||
if (dev) {
|
||||
object_unparent(OBJECT(dev));
|
||||
object_unref(OBJECT(dev));
|
||||
}
|
||||
object_unparent(OBJECT(dev));
|
||||
object_unref(OBJECT(dev));
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
|
|||
1309
target/arm/cpregs-pmu.c
Normal file
1309
target/arm/cpregs-pmu.c
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -1065,6 +1065,9 @@ void arm_cp_write_ignore(CPUARMState *env, const ARMCPRegInfo *ri,
|
|||
/* CPReadFn that can be used for read-as-zero behaviour */
|
||||
uint64_t arm_cp_read_zero(CPUARMState *env, const ARMCPRegInfo *ri);
|
||||
|
||||
/* CPReadFn that just reads the value from ri->fieldoffset */
|
||||
uint64_t raw_read(CPUARMState *env, const ARMCPRegInfo *ri);
|
||||
|
||||
/* CPWriteFn that just writes the value to ri->fieldoffset */
|
||||
void raw_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value);
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@ DEF(ID_AA64PFR1_EL1, 3, 0, 0, 4, 1)
|
|||
DEF(ID_AA64SMFR0_EL1, 3, 0, 0, 4, 5)
|
||||
DEF(ID_AA64DFR0_EL1, 3, 0, 0, 5, 0)
|
||||
DEF(ID_AA64DFR1_EL1, 3, 0, 0, 5, 1)
|
||||
DEF(ID_AA64AFR0_EL1, 3, 0, 0, 5, 4)
|
||||
DEF(ID_AA64AFR1_EL1, 3, 0, 0, 5, 5)
|
||||
DEF(ID_AA64ISAR0_EL1, 3, 0, 0, 6, 0)
|
||||
DEF(ID_AA64ISAR1_EL1, 3, 0, 0, 6, 1)
|
||||
DEF(ID_AA64ISAR2_EL1, 3, 0, 0, 6, 2)
|
||||
|
|
@ -14,6 +16,7 @@ DEF(ID_AA64MMFR3_EL1, 3, 0, 0, 7, 3)
|
|||
DEF(ID_PFR0_EL1, 3, 0, 0, 1, 0)
|
||||
DEF(ID_PFR1_EL1, 3, 0, 0, 1, 1)
|
||||
DEF(ID_DFR0_EL1, 3, 0, 0, 1, 2)
|
||||
DEF(ID_AFR0_EL1, 3, 0, 0, 1, 3)
|
||||
DEF(ID_MMFR0_EL1, 3, 0, 0, 1, 4)
|
||||
DEF(ID_MMFR1_EL1, 3, 0, 0, 1, 5)
|
||||
DEF(ID_MMFR2_EL1, 3, 0, 0, 1, 6)
|
||||
|
|
@ -32,5 +35,6 @@ DEF(MVFR2_EL1, 3, 0, 0, 3, 2)
|
|||
DEF(ID_PFR2_EL1, 3, 0, 0, 3, 4)
|
||||
DEF(ID_DFR1_EL1, 3, 0, 0, 3, 5)
|
||||
DEF(ID_MMFR5_EL1, 3, 0, 0, 3, 6)
|
||||
DEF(CLIDR_EL1, 3, 1, 0, 0, 1)
|
||||
DEF(ID_AA64ZFR0_EL1, 3, 0, 0, 4, 4)
|
||||
DEF(CTR_EL0, 3, 3, 0, 0, 1)
|
||||
|
|
|
|||
|
|
@ -1082,10 +1082,6 @@ struct ArchCPU {
|
|||
uint32_t reset_sctlr;
|
||||
uint64_t pmceid0;
|
||||
uint64_t pmceid1;
|
||||
uint32_t id_afr0;
|
||||
uint64_t id_aa64afr0;
|
||||
uint64_t id_aa64afr1;
|
||||
uint64_t clidr;
|
||||
uint64_t mp_affinity; /* MP ID without feature bits */
|
||||
/* The elements of this array are the CCSIDR values for each cache,
|
||||
* in the order L1DCache, L1ICache, L2DCache, L2ICache, etc.
|
||||
|
|
@ -2948,7 +2944,7 @@ static inline bool arm_v7m_csselr_razwi(ARMCPU *cpu)
|
|||
/* If all the CLIDR.Ctypem bits are 0 there are no caches, and
|
||||
* CSSELR is RAZ/WI.
|
||||
*/
|
||||
return (cpu->clidr & R_V7M_CLIDR_CTYPE_ALL_MASK) != 0;
|
||||
return (GET_IDREG(&cpu->isar, CLIDR) & R_V7M_CLIDR_CTYPE_ALL_MASK) != 0;
|
||||
}
|
||||
|
||||
static inline bool arm_sctlr_b(CPUARMState *env)
|
||||
|
|
|
|||
|
|
@ -663,7 +663,7 @@ static void aarch64_a57_initfn(Object *obj)
|
|||
SET_IDREG(isar, ID_PFR0, 0x00000131);
|
||||
SET_IDREG(isar, ID_PFR1, 0x00011011);
|
||||
SET_IDREG(isar, ID_DFR0, 0x03010066);
|
||||
cpu->id_afr0 = 0x00000000;
|
||||
SET_IDREG(isar, ID_AFR0, 0x00000000);
|
||||
SET_IDREG(isar, ID_MMFR0, 0x10101105);
|
||||
SET_IDREG(isar, ID_MMFR1, 0x40000000);
|
||||
SET_IDREG(isar, ID_MMFR2, 0x01260000);
|
||||
|
|
@ -683,7 +683,7 @@ static void aarch64_a57_initfn(Object *obj)
|
|||
cpu->isar.dbgdevid = 0x01110f13;
|
||||
cpu->isar.dbgdevid1 = 0x2;
|
||||
cpu->isar.reset_pmcr_el0 = 0x41013000;
|
||||
cpu->clidr = 0x0a200023;
|
||||
SET_IDREG(isar, CLIDR, 0x0a200023);
|
||||
/* 32KB L1 dcache */
|
||||
cpu->ccsidr[0] = make_ccsidr(CCSIDR_FORMAT_LEGACY, 4, 64, 32 * KiB, 7);
|
||||
/* 48KB L1 icache */
|
||||
|
|
@ -725,7 +725,7 @@ static void aarch64_a53_initfn(Object *obj)
|
|||
SET_IDREG(isar, ID_PFR0, 0x00000131);
|
||||
SET_IDREG(isar, ID_PFR1, 0x00011011);
|
||||
SET_IDREG(isar, ID_DFR0, 0x03010066);
|
||||
cpu->id_afr0 = 0x00000000;
|
||||
SET_IDREG(isar, ID_AFR0, 0x00000000);
|
||||
SET_IDREG(isar, ID_MMFR0, 0x10101105);
|
||||
SET_IDREG(isar, ID_MMFR1, 0x40000000);
|
||||
SET_IDREG(isar, ID_MMFR2, 0x01260000);
|
||||
|
|
@ -745,7 +745,7 @@ static void aarch64_a53_initfn(Object *obj)
|
|||
cpu->isar.dbgdevid = 0x00110f13;
|
||||
cpu->isar.dbgdevid1 = 0x1;
|
||||
cpu->isar.reset_pmcr_el0 = 0x41033000;
|
||||
cpu->clidr = 0x0a200023;
|
||||
SET_IDREG(isar, CLIDR, 0x0a200023);
|
||||
/* 32KB L1 dcache */
|
||||
cpu->ccsidr[0] = make_ccsidr(CCSIDR_FORMAT_LEGACY, 4, 64, 32 * KiB, 7);
|
||||
/* 32KB L1 icache */
|
||||
|
|
|
|||
1813
target/arm/helper.c
1813
target/arm/helper.c
File diff suppressed because it is too large
Load diff
|
|
@ -1871,6 +1871,10 @@ void define_debug_regs(ARMCPU *cpu);
|
|||
|
||||
/* Add the cpreg definitions for TLBI instructions */
|
||||
void define_tlb_insn_regs(ARMCPU *cpu);
|
||||
/* Add the cpreg definitions for AT instructions */
|
||||
void define_at_insn_regs(ARMCPU *cpu);
|
||||
/* Add the cpreg definitions for PM cpregs */
|
||||
void define_pm_cpregs(ARMCPU *cpu);
|
||||
|
||||
/* Effective value of MDCR_EL2 */
|
||||
static inline uint64_t arm_mdcr_el2_eff(CPUARMState *env)
|
||||
|
|
@ -1981,5 +1985,6 @@ void vfp_clear_float_status_exc_flags(CPUARMState *env);
|
|||
* specified by mask changing to the values in val.
|
||||
*/
|
||||
void vfp_set_fpcr_to_host(CPUARMState *env, uint32_t val, uint32_t mask);
|
||||
bool arm_pan_enabled(CPUARMState *env);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -47,6 +47,11 @@ bool kvm_arm_mte_supported(void)
|
|||
return false;
|
||||
}
|
||||
|
||||
bool kvm_arm_el2_supported(void)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* These functions should never actually be called without KVM support.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -230,7 +230,8 @@ static uint64_t idregs_sysreg_to_kvm_reg(ARMSysRegs sysreg)
|
|||
}
|
||||
|
||||
/* read a sysreg value and store it in the idregs */
|
||||
static int get_host_cpu_reg(int fd, ARMHostCPUFeatures *ahcf, ARMIDRegisterIdx index)
|
||||
static int get_host_cpu_reg(int fd, ARMHostCPUFeatures *ahcf,
|
||||
ARMIDRegisterIdx index)
|
||||
{
|
||||
uint64_t *reg;
|
||||
int ret;
|
||||
|
|
@ -250,6 +251,7 @@ static bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf)
|
|||
*/
|
||||
int fdarray[3];
|
||||
bool sve_supported;
|
||||
bool el2_supported;
|
||||
bool pmu_supported = false;
|
||||
uint64_t features = 0;
|
||||
int err;
|
||||
|
|
@ -269,6 +271,14 @@ static bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf)
|
|||
init.features[0] |= 1 << KVM_ARM_VCPU_SVE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Ask for EL2 if supported.
|
||||
*/
|
||||
el2_supported = kvm_arm_el2_supported();
|
||||
if (el2_supported) {
|
||||
init.features[0] |= 1 << KVM_ARM_VCPU_HAS_EL2;
|
||||
}
|
||||
|
||||
/*
|
||||
* Ask for Pointer Authentication if supported, so that we get
|
||||
* the unsanitized field values for AA64ISAR1_EL1.
|
||||
|
|
@ -422,6 +432,10 @@ static bool kvm_arm_get_host_cpu_features(ARMHostCPUFeatures *ahcf)
|
|||
features |= 1ULL << ARM_FEATURE_AARCH64;
|
||||
features |= 1ULL << ARM_FEATURE_GENERIC_TIMER;
|
||||
|
||||
if (el2_supported) {
|
||||
features |= 1ULL << ARM_FEATURE_EL2;
|
||||
}
|
||||
|
||||
ahcf->features = features;
|
||||
|
||||
return true;
|
||||
|
|
@ -1762,6 +1776,11 @@ bool kvm_arm_aarch32_supported(void)
|
|||
return kvm_check_extension(kvm_state, KVM_CAP_ARM_EL1_32BIT);
|
||||
}
|
||||
|
||||
bool kvm_arm_el2_supported(void)
|
||||
{
|
||||
return kvm_check_extension(kvm_state, KVM_CAP_ARM_EL2);
|
||||
}
|
||||
|
||||
bool kvm_arm_sve_supported(void)
|
||||
{
|
||||
return kvm_check_extension(kvm_state, KVM_CAP_ARM_SVE);
|
||||
|
|
@ -1882,6 +1901,9 @@ int kvm_arch_init_vcpu(CPUState *cs)
|
|||
cpu->kvm_init_features[0] |= (1 << KVM_ARM_VCPU_PTRAUTH_ADDRESS |
|
||||
1 << KVM_ARM_VCPU_PTRAUTH_GENERIC);
|
||||
}
|
||||
if (cpu->has_el2 && kvm_arm_el2_supported()) {
|
||||
cpu->kvm_init_features[0] |= 1 << KVM_ARM_VCPU_HAS_EL2;
|
||||
}
|
||||
|
||||
/* Do KVM_ARM_VCPU_INIT ioctl */
|
||||
ret = kvm_arm_vcpu_init(cpu);
|
||||
|
|
|
|||
|
|
@ -191,6 +191,13 @@ bool kvm_arm_sve_supported(void);
|
|||
*/
|
||||
bool kvm_arm_mte_supported(void);
|
||||
|
||||
/**
|
||||
* kvm_arm_el2_supported:
|
||||
*
|
||||
* Returns true if KVM can enable EL2 and false otherwise.
|
||||
*/
|
||||
bool kvm_arm_el2_supported(void);
|
||||
|
||||
/**
|
||||
* kvm_arm_get_max_vm_ipa_size:
|
||||
* @ms: Machine state handle
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ arm_user_ss.add(when: 'TARGET_AARCH64', if_false: files(
|
|||
'cpu32-stubs.c',
|
||||
))
|
||||
arm_user_ss.add(files(
|
||||
'cpregs-pmu.c',
|
||||
'debug_helper.c',
|
||||
'helper.c',
|
||||
'vfp_fpscr.c',
|
||||
|
|
@ -36,6 +37,7 @@ arm_common_system_ss.add(files(
|
|||
'arch_dump.c',
|
||||
'arm-powerctl.c',
|
||||
'cortex-regs.c',
|
||||
'cpregs-pmu.c',
|
||||
'debug_helper.c',
|
||||
'helper.c',
|
||||
'machine.c',
|
||||
|
|
|
|||
|
|
@ -22,11 +22,6 @@ void raise_exception_ra(CPUARMState *env, uint32_t excp, uint32_t syndrome,
|
|||
g_assert_not_reached();
|
||||
}
|
||||
|
||||
/* TLBI insns are only used by TCG, so we don't need to do anything for KVM */
|
||||
void define_tlb_insn_regs(ARMCPU *cpu)
|
||||
{
|
||||
}
|
||||
|
||||
/* With KVM, we never use float_status, so these can be no-ops */
|
||||
void arm_set_default_fp_behaviours(float_status *s)
|
||||
{
|
||||
|
|
|
|||
519
target/arm/tcg/cpregs-at.c
Normal file
519
target/arm/tcg/cpregs-at.c
Normal file
|
|
@ -0,0 +1,519 @@
|
|||
/*
|
||||
* System instructions for address translation
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "cpu.h"
|
||||
#include "cpu-features.h"
|
||||
#include "internals.h"
|
||||
#include "cpregs.h"
|
||||
|
||||
|
||||
static int par_el1_shareability(GetPhysAddrResult *res)
|
||||
{
|
||||
/*
|
||||
* The PAR_EL1.SH field must be 0b10 for Device or Normal-NC
|
||||
* memory -- see pseudocode PAREncodeShareability().
|
||||
*/
|
||||
if (((res->cacheattrs.attrs & 0xf0) == 0) ||
|
||||
res->cacheattrs.attrs == 0x44 || res->cacheattrs.attrs == 0x40) {
|
||||
return 2;
|
||||
}
|
||||
return res->cacheattrs.shareability;
|
||||
}
|
||||
|
||||
static uint64_t do_ats_write(CPUARMState *env, uint64_t value,
|
||||
MMUAccessType access_type, ARMMMUIdx mmu_idx,
|
||||
ARMSecuritySpace ss)
|
||||
{
|
||||
bool ret;
|
||||
uint64_t par64;
|
||||
bool format64 = false;
|
||||
ARMMMUFaultInfo fi = {};
|
||||
GetPhysAddrResult res = {};
|
||||
|
||||
/*
|
||||
* I_MXTJT: Granule protection checks are not performed on the final
|
||||
* address of a successful translation. This is a translation not a
|
||||
* memory reference, so "memop = none = 0".
|
||||
*/
|
||||
ret = get_phys_addr_with_space_nogpc(env, value, access_type, 0,
|
||||
mmu_idx, ss, &res, &fi);
|
||||
|
||||
/*
|
||||
* ATS operations only do S1 or S1+S2 translations, so we never
|
||||
* have to deal with the ARMCacheAttrs format for S2 only.
|
||||
*/
|
||||
assert(!res.cacheattrs.is_s2_format);
|
||||
|
||||
if (ret) {
|
||||
/*
|
||||
* Some kinds of translation fault must cause exceptions rather
|
||||
* than being reported in the PAR.
|
||||
*/
|
||||
int current_el = arm_current_el(env);
|
||||
int target_el;
|
||||
uint32_t syn, fsr, fsc;
|
||||
bool take_exc = false;
|
||||
|
||||
if (fi.s1ptw && current_el == 1
|
||||
&& arm_mmu_idx_is_stage1_of_2(mmu_idx)) {
|
||||
/*
|
||||
* Synchronous stage 2 fault on an access made as part of the
|
||||
* translation table walk for AT S1E0* or AT S1E1* insn
|
||||
* executed from NS EL1. If this is a synchronous external abort
|
||||
* and SCR_EL3.EA == 1, then we take a synchronous external abort
|
||||
* to EL3. Otherwise the fault is taken as an exception to EL2,
|
||||
* and HPFAR_EL2 holds the faulting IPA.
|
||||
*/
|
||||
if (fi.type == ARMFault_SyncExternalOnWalk &&
|
||||
(env->cp15.scr_el3 & SCR_EA)) {
|
||||
target_el = 3;
|
||||
} else {
|
||||
env->cp15.hpfar_el2 = extract64(fi.s2addr, 12, 47) << 4;
|
||||
if (arm_is_secure_below_el3(env) && fi.s1ns) {
|
||||
env->cp15.hpfar_el2 |= HPFAR_NS;
|
||||
}
|
||||
target_el = 2;
|
||||
}
|
||||
take_exc = true;
|
||||
} else if (fi.type == ARMFault_SyncExternalOnWalk) {
|
||||
/*
|
||||
* Synchronous external aborts during a translation table walk
|
||||
* are taken as Data Abort exceptions.
|
||||
*/
|
||||
if (fi.stage2) {
|
||||
if (current_el == 3) {
|
||||
target_el = 3;
|
||||
} else {
|
||||
target_el = 2;
|
||||
}
|
||||
} else {
|
||||
target_el = exception_target_el(env);
|
||||
}
|
||||
take_exc = true;
|
||||
}
|
||||
|
||||
if (take_exc) {
|
||||
/* Construct FSR and FSC using same logic as arm_deliver_fault() */
|
||||
if (target_el == 2 || arm_el_is_aa64(env, target_el) ||
|
||||
arm_s1_regime_using_lpae_format(env, mmu_idx)) {
|
||||
fsr = arm_fi_to_lfsc(&fi);
|
||||
fsc = extract32(fsr, 0, 6);
|
||||
} else {
|
||||
fsr = arm_fi_to_sfsc(&fi);
|
||||
fsc = 0x3f;
|
||||
}
|
||||
/*
|
||||
* Report exception with ESR indicating a fault due to a
|
||||
* translation table walk for a cache maintenance instruction.
|
||||
*/
|
||||
syn = syn_data_abort_no_iss(current_el == target_el, 0,
|
||||
fi.ea, 1, fi.s1ptw, 1, fsc);
|
||||
env->exception.vaddress = value;
|
||||
env->exception.fsr = fsr;
|
||||
raise_exception(env, EXCP_DATA_ABORT, syn, target_el);
|
||||
}
|
||||
}
|
||||
|
||||
if (is_a64(env)) {
|
||||
format64 = true;
|
||||
} else if (arm_feature(env, ARM_FEATURE_LPAE)) {
|
||||
/*
|
||||
* ATS1Cxx:
|
||||
* * TTBCR.EAE determines whether the result is returned using the
|
||||
* 32-bit or the 64-bit PAR format
|
||||
* * Instructions executed in Hyp mode always use the 64bit format
|
||||
*
|
||||
* ATS1S2NSOxx uses the 64bit format if any of the following is true:
|
||||
* * The Non-secure TTBCR.EAE bit is set to 1
|
||||
* * The implementation includes EL2, and the value of HCR.VM is 1
|
||||
*
|
||||
* (Note that HCR.DC makes HCR.VM behave as if it is 1.)
|
||||
*
|
||||
* ATS1Hx always uses the 64bit format.
|
||||
*/
|
||||
format64 = arm_s1_regime_using_lpae_format(env, mmu_idx);
|
||||
|
||||
if (arm_feature(env, ARM_FEATURE_EL2)) {
|
||||
if (mmu_idx == ARMMMUIdx_E10_0 ||
|
||||
mmu_idx == ARMMMUIdx_E10_1 ||
|
||||
mmu_idx == ARMMMUIdx_E10_1_PAN) {
|
||||
format64 |= env->cp15.hcr_el2 & (HCR_VM | HCR_DC);
|
||||
} else {
|
||||
format64 |= arm_current_el(env) == 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (format64) {
|
||||
/* Create a 64-bit PAR */
|
||||
par64 = (1 << 11); /* LPAE bit always set */
|
||||
if (!ret) {
|
||||
par64 |= res.f.phys_addr & ~0xfffULL;
|
||||
if (!res.f.attrs.secure) {
|
||||
par64 |= (1 << 9); /* NS */
|
||||
}
|
||||
par64 |= (uint64_t)res.cacheattrs.attrs << 56; /* ATTR */
|
||||
par64 |= par_el1_shareability(&res) << 7; /* SH */
|
||||
} else {
|
||||
uint32_t fsr = arm_fi_to_lfsc(&fi);
|
||||
|
||||
par64 |= 1; /* F */
|
||||
par64 |= (fsr & 0x3f) << 1; /* FS */
|
||||
if (fi.stage2) {
|
||||
par64 |= (1 << 9); /* S */
|
||||
}
|
||||
if (fi.s1ptw) {
|
||||
par64 |= (1 << 8); /* PTW */
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* fsr is a DFSR/IFSR value for the short descriptor
|
||||
* translation table format (with WnR always clear).
|
||||
* Convert it to a 32-bit PAR.
|
||||
*/
|
||||
if (!ret) {
|
||||
/* We do not set any attribute bits in the PAR */
|
||||
if (res.f.lg_page_size == 24
|
||||
&& arm_feature(env, ARM_FEATURE_V7)) {
|
||||
par64 = (res.f.phys_addr & 0xff000000) | (1 << 1);
|
||||
} else {
|
||||
par64 = res.f.phys_addr & 0xfffff000;
|
||||
}
|
||||
if (!res.f.attrs.secure) {
|
||||
par64 |= (1 << 9); /* NS */
|
||||
}
|
||||
} else {
|
||||
uint32_t fsr = arm_fi_to_sfsc(&fi);
|
||||
|
||||
par64 = ((fsr & (1 << 10)) >> 5) | ((fsr & (1 << 12)) >> 6) |
|
||||
((fsr & 0xf) << 1) | 1;
|
||||
}
|
||||
}
|
||||
return par64;
|
||||
}
|
||||
|
||||
static void ats_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value)
|
||||
{
|
||||
MMUAccessType access_type = ri->opc2 & 1 ? MMU_DATA_STORE : MMU_DATA_LOAD;
|
||||
uint64_t par64;
|
||||
ARMMMUIdx mmu_idx;
|
||||
int el = arm_current_el(env);
|
||||
ARMSecuritySpace ss = arm_security_space(env);
|
||||
|
||||
switch (ri->opc2 & 6) {
|
||||
case 0:
|
||||
/* stage 1 current state PL1: ATS1CPR, ATS1CPW, ATS1CPRP, ATS1CPWP */
|
||||
switch (el) {
|
||||
case 3:
|
||||
if (ri->crm == 9 && arm_pan_enabled(env)) {
|
||||
mmu_idx = ARMMMUIdx_E30_3_PAN;
|
||||
} else {
|
||||
mmu_idx = ARMMMUIdx_E3;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
g_assert(ss != ARMSS_Secure); /* ARMv8.4-SecEL2 is 64-bit only */
|
||||
/* fall through */
|
||||
case 1:
|
||||
if (ri->crm == 9 && arm_pan_enabled(env)) {
|
||||
mmu_idx = ARMMMUIdx_Stage1_E1_PAN;
|
||||
} else {
|
||||
mmu_idx = ARMMMUIdx_Stage1_E1;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
/* stage 1 current state PL0: ATS1CUR, ATS1CUW */
|
||||
switch (el) {
|
||||
case 3:
|
||||
mmu_idx = ARMMMUIdx_E30_0;
|
||||
break;
|
||||
case 2:
|
||||
g_assert(ss != ARMSS_Secure); /* ARMv8.4-SecEL2 is 64-bit only */
|
||||
mmu_idx = ARMMMUIdx_Stage1_E0;
|
||||
break;
|
||||
case 1:
|
||||
mmu_idx = ARMMMUIdx_Stage1_E0;
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
/* stage 1+2 NonSecure PL1: ATS12NSOPR, ATS12NSOPW */
|
||||
mmu_idx = ARMMMUIdx_E10_1;
|
||||
ss = ARMSS_NonSecure;
|
||||
break;
|
||||
case 6:
|
||||
/* stage 1+2 NonSecure PL0: ATS12NSOUR, ATS12NSOUW */
|
||||
mmu_idx = ARMMMUIdx_E10_0;
|
||||
ss = ARMSS_NonSecure;
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
|
||||
par64 = do_ats_write(env, value, access_type, mmu_idx, ss);
|
||||
|
||||
A32_BANKED_CURRENT_REG_SET(env, par, par64);
|
||||
}
|
||||
|
||||
static void ats1h_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||
uint64_t value)
|
||||
{
|
||||
MMUAccessType access_type = ri->opc2 & 1 ? MMU_DATA_STORE : MMU_DATA_LOAD;
|
||||
uint64_t par64;
|
||||
|
||||
/* There is no SecureEL2 for AArch32. */
|
||||
par64 = do_ats_write(env, value, access_type, ARMMMUIdx_E2,
|
||||
ARMSS_NonSecure);
|
||||
|
||||
A32_BANKED_CURRENT_REG_SET(env, par, par64);
|
||||
}
|
||||
|
||||
static CPAccessResult at_e012_access(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||
bool isread)
|
||||
{
|
||||
/*
|
||||
* R_NYXTL: instruction is UNDEFINED if it applies to an Exception level
|
||||
* lower than EL3 and the combination SCR_EL3.{NSE,NS} is reserved. This can
|
||||
* only happen when executing at EL3 because that combination also causes an
|
||||
* illegal exception return. We don't need to check FEAT_RME either, because
|
||||
* scr_write() ensures that the NSE bit is not set otherwise.
|
||||
*/
|
||||
if ((env->cp15.scr_el3 & (SCR_NSE | SCR_NS)) == SCR_NSE) {
|
||||
return CP_ACCESS_UNDEFINED;
|
||||
}
|
||||
return CP_ACCESS_OK;
|
||||
}
|
||||
|
||||
static CPAccessResult at_s1e2_access(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||
bool isread)
|
||||
{
|
||||
if (arm_current_el(env) == 3 &&
|
||||
!(env->cp15.scr_el3 & (SCR_NS | SCR_EEL2))) {
|
||||
return CP_ACCESS_UNDEFINED;
|
||||
}
|
||||
return at_e012_access(env, ri, isread);
|
||||
}
|
||||
|
||||
static CPAccessResult at_s1e01_access(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||
bool isread)
|
||||
{
|
||||
if (arm_current_el(env) == 1 && (arm_hcr_el2_eff(env) & HCR_AT)) {
|
||||
return CP_ACCESS_TRAP_EL2;
|
||||
}
|
||||
return at_e012_access(env, ri, isread);
|
||||
}
|
||||
|
||||
static void ats_write64(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||
uint64_t value)
|
||||
{
|
||||
MMUAccessType access_type = ri->opc2 & 1 ? MMU_DATA_STORE : MMU_DATA_LOAD;
|
||||
ARMMMUIdx mmu_idx;
|
||||
uint64_t hcr_el2 = arm_hcr_el2_eff(env);
|
||||
bool regime_e20 = (hcr_el2 & (HCR_E2H | HCR_TGE)) == (HCR_E2H | HCR_TGE);
|
||||
bool for_el3 = false;
|
||||
ARMSecuritySpace ss;
|
||||
|
||||
switch (ri->opc2 & 6) {
|
||||
case 0:
|
||||
switch (ri->opc1) {
|
||||
case 0: /* AT S1E1R, AT S1E1W, AT S1E1RP, AT S1E1WP */
|
||||
if (ri->crm == 9 && arm_pan_enabled(env)) {
|
||||
mmu_idx = regime_e20 ?
|
||||
ARMMMUIdx_E20_2_PAN : ARMMMUIdx_Stage1_E1_PAN;
|
||||
} else {
|
||||
mmu_idx = regime_e20 ? ARMMMUIdx_E20_2 : ARMMMUIdx_Stage1_E1;
|
||||
}
|
||||
break;
|
||||
case 4: /* AT S1E2R, AT S1E2W */
|
||||
mmu_idx = hcr_el2 & HCR_E2H ? ARMMMUIdx_E20_2 : ARMMMUIdx_E2;
|
||||
break;
|
||||
case 6: /* AT S1E3R, AT S1E3W */
|
||||
mmu_idx = ARMMMUIdx_E3;
|
||||
for_el3 = true;
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
break;
|
||||
case 2: /* AT S1E0R, AT S1E0W */
|
||||
mmu_idx = regime_e20 ? ARMMMUIdx_E20_0 : ARMMMUIdx_Stage1_E0;
|
||||
break;
|
||||
case 4: /* AT S12E1R, AT S12E1W */
|
||||
mmu_idx = regime_e20 ? ARMMMUIdx_E20_2 : ARMMMUIdx_E10_1;
|
||||
break;
|
||||
case 6: /* AT S12E0R, AT S12E0W */
|
||||
mmu_idx = regime_e20 ? ARMMMUIdx_E20_0 : ARMMMUIdx_E10_0;
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
|
||||
ss = for_el3 ? arm_security_space(env) : arm_security_space_below_el3(env);
|
||||
env->cp15.par_el[1] = do_ats_write(env, value, access_type, mmu_idx, ss);
|
||||
}
|
||||
|
||||
static CPAccessResult ats_access(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||
bool isread)
|
||||
{
|
||||
if (ri->opc2 & 4) {
|
||||
/*
|
||||
* The ATS12NSO* operations must trap to EL3 or EL2 if executed in
|
||||
* Secure EL1 (which can only happen if EL3 is AArch64).
|
||||
* They are simply UNDEF if executed from NS EL1.
|
||||
* They function normally from EL2 or EL3.
|
||||
*/
|
||||
if (arm_current_el(env) == 1) {
|
||||
if (arm_is_secure_below_el3(env)) {
|
||||
if (env->cp15.scr_el3 & SCR_EEL2) {
|
||||
return CP_ACCESS_TRAP_EL2;
|
||||
}
|
||||
return CP_ACCESS_TRAP_EL3;
|
||||
}
|
||||
return CP_ACCESS_UNDEFINED;
|
||||
}
|
||||
}
|
||||
return CP_ACCESS_OK;
|
||||
}
|
||||
|
||||
static const ARMCPRegInfo vapa_ats_reginfo[] = {
|
||||
/* This underdecoding is safe because the reginfo is NO_RAW. */
|
||||
{ .name = "ATS", .cp = 15, .crn = 7, .crm = 8, .opc1 = 0, .opc2 = CP_ANY,
|
||||
.access = PL1_W, .accessfn = ats_access,
|
||||
.writefn = ats_write, .type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC },
|
||||
};
|
||||
|
||||
static const ARMCPRegInfo v8_ats_reginfo[] = {
|
||||
/* 64 bit address translation operations */
|
||||
{ .name = "AT_S1E1R", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 1, .opc1 = 0, .crn = 7, .crm = 8, .opc2 = 0,
|
||||
.access = PL1_W, .type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC,
|
||||
.fgt = FGT_ATS1E1R,
|
||||
.accessfn = at_s1e01_access, .writefn = ats_write64 },
|
||||
{ .name = "AT_S1E1W", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 1, .opc1 = 0, .crn = 7, .crm = 8, .opc2 = 1,
|
||||
.access = PL1_W, .type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC,
|
||||
.fgt = FGT_ATS1E1W,
|
||||
.accessfn = at_s1e01_access, .writefn = ats_write64 },
|
||||
{ .name = "AT_S1E0R", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 1, .opc1 = 0, .crn = 7, .crm = 8, .opc2 = 2,
|
||||
.access = PL1_W, .type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC,
|
||||
.fgt = FGT_ATS1E0R,
|
||||
.accessfn = at_s1e01_access, .writefn = ats_write64 },
|
||||
{ .name = "AT_S1E0W", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 1, .opc1 = 0, .crn = 7, .crm = 8, .opc2 = 3,
|
||||
.access = PL1_W, .type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC,
|
||||
.fgt = FGT_ATS1E0W,
|
||||
.accessfn = at_s1e01_access, .writefn = ats_write64 },
|
||||
{ .name = "AT_S12E1R", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 1, .opc1 = 4, .crn = 7, .crm = 8, .opc2 = 4,
|
||||
.access = PL2_W, .type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC,
|
||||
.accessfn = at_e012_access, .writefn = ats_write64 },
|
||||
{ .name = "AT_S12E1W", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 1, .opc1 = 4, .crn = 7, .crm = 8, .opc2 = 5,
|
||||
.access = PL2_W, .type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC,
|
||||
.accessfn = at_e012_access, .writefn = ats_write64 },
|
||||
{ .name = "AT_S12E0R", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 1, .opc1 = 4, .crn = 7, .crm = 8, .opc2 = 6,
|
||||
.access = PL2_W, .type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC,
|
||||
.accessfn = at_e012_access, .writefn = ats_write64 },
|
||||
{ .name = "AT_S12E0W", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 1, .opc1 = 4, .crn = 7, .crm = 8, .opc2 = 7,
|
||||
.access = PL2_W, .type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC,
|
||||
.accessfn = at_e012_access, .writefn = ats_write64 },
|
||||
/* AT S1E2* are elsewhere as they UNDEF from EL3 if EL2 is not present */
|
||||
{ .name = "AT_S1E3R", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 1, .opc1 = 6, .crn = 7, .crm = 8, .opc2 = 0,
|
||||
.access = PL3_W, .type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC,
|
||||
.writefn = ats_write64 },
|
||||
{ .name = "AT_S1E3W", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 1, .opc1 = 6, .crn = 7, .crm = 8, .opc2 = 1,
|
||||
.access = PL3_W, .type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC,
|
||||
.writefn = ats_write64 },
|
||||
};
|
||||
|
||||
static const ARMCPRegInfo el2_ats_reginfo[] = {
|
||||
/*
|
||||
* Unlike the other EL2-related AT operations, these must
|
||||
* UNDEF from EL3 if EL2 is not implemented, which is why we
|
||||
* define them here rather than with the rest of the AT ops.
|
||||
*/
|
||||
{ .name = "AT_S1E2R", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 1, .opc1 = 4, .crn = 7, .crm = 8, .opc2 = 0,
|
||||
.access = PL2_W, .accessfn = at_s1e2_access,
|
||||
.type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC | ARM_CP_EL3_NO_EL2_UNDEF,
|
||||
.writefn = ats_write64 },
|
||||
{ .name = "AT_S1E2W", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 1, .opc1 = 4, .crn = 7, .crm = 8, .opc2 = 1,
|
||||
.access = PL2_W, .accessfn = at_s1e2_access,
|
||||
.type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC | ARM_CP_EL3_NO_EL2_UNDEF,
|
||||
.writefn = ats_write64 },
|
||||
/*
|
||||
* The AArch32 ATS1H* operations are CONSTRAINED UNPREDICTABLE
|
||||
* if EL2 is not implemented; we choose to UNDEF. Behaviour at EL3
|
||||
* with SCR.NS == 0 outside Monitor mode is UNPREDICTABLE; we choose
|
||||
* to behave as if SCR.NS was 1.
|
||||
*/
|
||||
{ .name = "ATS1HR", .cp = 15, .opc1 = 4, .crn = 7, .crm = 8, .opc2 = 0,
|
||||
.access = PL2_W,
|
||||
.writefn = ats1h_write, .type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC },
|
||||
{ .name = "ATS1HW", .cp = 15, .opc1 = 4, .crn = 7, .crm = 8, .opc2 = 1,
|
||||
.access = PL2_W,
|
||||
.writefn = ats1h_write, .type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC },
|
||||
};
|
||||
|
||||
static const ARMCPRegInfo ats1e1_reginfo[] = {
|
||||
{ .name = "AT_S1E1RP", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 1, .opc1 = 0, .crn = 7, .crm = 9, .opc2 = 0,
|
||||
.access = PL1_W, .type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC,
|
||||
.fgt = FGT_ATS1E1RP,
|
||||
.accessfn = at_s1e01_access, .writefn = ats_write64 },
|
||||
{ .name = "AT_S1E1WP", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 1, .opc1 = 0, .crn = 7, .crm = 9, .opc2 = 1,
|
||||
.access = PL1_W, .type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC,
|
||||
.fgt = FGT_ATS1E1WP,
|
||||
.accessfn = at_s1e01_access, .writefn = ats_write64 },
|
||||
};
|
||||
|
||||
static const ARMCPRegInfo ats1cp_reginfo[] = {
|
||||
{ .name = "ATS1CPRP",
|
||||
.cp = 15, .opc1 = 0, .crn = 7, .crm = 9, .opc2 = 0,
|
||||
.access = PL1_W, .type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC,
|
||||
.writefn = ats_write },
|
||||
{ .name = "ATS1CPWP",
|
||||
.cp = 15, .opc1 = 0, .crn = 7, .crm = 9, .opc2 = 1,
|
||||
.access = PL1_W, .type = ARM_CP_NO_RAW | ARM_CP_RAISES_EXC,
|
||||
.writefn = ats_write },
|
||||
};
|
||||
|
||||
void define_at_insn_regs(ARMCPU *cpu)
|
||||
{
|
||||
CPUARMState *env = &cpu->env;
|
||||
|
||||
if (arm_feature(env, ARM_FEATURE_VAPA)) {
|
||||
define_arm_cp_regs(cpu, vapa_ats_reginfo);
|
||||
}
|
||||
if (arm_feature(env, ARM_FEATURE_V8)) {
|
||||
define_arm_cp_regs(cpu, v8_ats_reginfo);
|
||||
}
|
||||
if (arm_feature(env, ARM_FEATURE_EL2)
|
||||
|| (arm_feature(env, ARM_FEATURE_EL3)
|
||||
&& arm_feature(env, ARM_FEATURE_V8))) {
|
||||
define_arm_cp_regs(cpu, el2_ats_reginfo);
|
||||
}
|
||||
if (cpu_isar_feature(aa64_ats1e1, cpu)) {
|
||||
define_arm_cp_regs(cpu, ats1e1_reginfo);
|
||||
}
|
||||
if (cpu_isar_feature(aa32_ats1e1, cpu)) {
|
||||
define_arm_cp_regs(cpu, ats1cp_reginfo);
|
||||
}
|
||||
}
|
||||
|
|
@ -62,7 +62,7 @@ static void cortex_m0_initfn(Object *obj)
|
|||
SET_IDREG(isar, ID_PFR0, 0x00000030);
|
||||
SET_IDREG(isar, ID_PFR1, 0x00000200);
|
||||
SET_IDREG(isar, ID_DFR0, 0x00100000);
|
||||
cpu->id_afr0 = 0x00000000;
|
||||
SET_IDREG(isar, ID_AFR0, 0x00000000);
|
||||
SET_IDREG(isar, ID_MMFR0, 0x00000030);
|
||||
SET_IDREG(isar, ID_MMFR1, 0x00000000);
|
||||
SET_IDREG(isar, ID_MMFR2, 0x00000000);
|
||||
|
|
@ -88,7 +88,7 @@ static void cortex_m3_initfn(Object *obj)
|
|||
SET_IDREG(isar, ID_PFR0, 0x00000030);
|
||||
SET_IDREG(isar, ID_PFR1, 0x00000200);
|
||||
SET_IDREG(isar, ID_DFR0, 0x00100000);
|
||||
cpu->id_afr0 = 0x00000000;
|
||||
SET_IDREG(isar, ID_AFR0, 0x00000000);
|
||||
SET_IDREG(isar, ID_MMFR0, 0x00000030);
|
||||
SET_IDREG(isar, ID_MMFR1, 0x00000000);
|
||||
SET_IDREG(isar, ID_MMFR2, 0x00000000);
|
||||
|
|
@ -119,7 +119,7 @@ static void cortex_m4_initfn(Object *obj)
|
|||
SET_IDREG(isar, ID_PFR0, 0x00000030);
|
||||
SET_IDREG(isar, ID_PFR1, 0x00000200);
|
||||
SET_IDREG(isar, ID_DFR0, 0x00100000);
|
||||
cpu->id_afr0 = 0x00000000;
|
||||
SET_IDREG(isar, ID_AFR0, 0x00000000);
|
||||
SET_IDREG(isar, ID_MMFR0, 0x00000030);
|
||||
SET_IDREG(isar, ID_MMFR1, 0x00000000);
|
||||
SET_IDREG(isar, ID_MMFR2, 0x00000000);
|
||||
|
|
@ -150,7 +150,7 @@ static void cortex_m7_initfn(Object *obj)
|
|||
SET_IDREG(isar, ID_PFR0, 0x00000030);
|
||||
SET_IDREG(isar, ID_PFR1, 0x00000200);
|
||||
SET_IDREG(isar, ID_DFR0, 0x00100000);
|
||||
cpu->id_afr0 = 0x00000000;
|
||||
SET_IDREG(isar, ID_AFR0, 0x00000000);
|
||||
SET_IDREG(isar, ID_MMFR0, 0x00100030);
|
||||
SET_IDREG(isar, ID_MMFR1, 0x00000000);
|
||||
SET_IDREG(isar, ID_MMFR2, 0x01000000);
|
||||
|
|
@ -183,7 +183,7 @@ static void cortex_m33_initfn(Object *obj)
|
|||
SET_IDREG(isar, ID_PFR0, 0x00000030);
|
||||
SET_IDREG(isar, ID_PFR1, 0x00000210);
|
||||
SET_IDREG(isar, ID_DFR0, 0x00200000);
|
||||
cpu->id_afr0 = 0x00000000;
|
||||
SET_IDREG(isar, ID_AFR0, 0x00000000);
|
||||
SET_IDREG(isar, ID_MMFR0, 0x00101F40);
|
||||
SET_IDREG(isar, ID_MMFR1, 0x00000000);
|
||||
SET_IDREG(isar, ID_MMFR2, 0x01000000);
|
||||
|
|
@ -195,7 +195,7 @@ static void cortex_m33_initfn(Object *obj)
|
|||
SET_IDREG(isar, ID_ISAR4, 0x01310132);
|
||||
SET_IDREG(isar, ID_ISAR5, 0x00000000);
|
||||
SET_IDREG(isar, ID_ISAR6, 0x00000000);
|
||||
cpu->clidr = 0x00000000;
|
||||
SET_IDREG(isar, CLIDR, 0x00000000);
|
||||
cpu->ctr = 0x8000c000;
|
||||
}
|
||||
|
||||
|
|
@ -221,7 +221,7 @@ static void cortex_m55_initfn(Object *obj)
|
|||
SET_IDREG(isar, ID_PFR0, 0x20000030);
|
||||
SET_IDREG(isar, ID_PFR1, 0x00000230);
|
||||
SET_IDREG(isar, ID_DFR0, 0x10200000);
|
||||
cpu->id_afr0 = 0x00000000;
|
||||
SET_IDREG(isar, ID_AFR0, 0x00000000);
|
||||
SET_IDREG(isar, ID_MMFR0, 0x00111040);
|
||||
SET_IDREG(isar, ID_MMFR1, 0x00000000);
|
||||
SET_IDREG(isar, ID_MMFR2, 0x01000000);
|
||||
|
|
@ -233,7 +233,7 @@ static void cortex_m55_initfn(Object *obj)
|
|||
SET_IDREG(isar, ID_ISAR4, 0x01310132);
|
||||
SET_IDREG(isar, ID_ISAR5, 0x00000000);
|
||||
SET_IDREG(isar, ID_ISAR6, 0x00000000);
|
||||
cpu->clidr = 0x00000000; /* caches not implemented */
|
||||
SET_IDREG(isar, CLIDR, 0x00000000); /* caches not implemented */
|
||||
cpu->ctr = 0x8303c003;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -225,7 +225,7 @@ static void arm1136_r2_initfn(Object *obj)
|
|||
SET_IDREG(isar, ID_PFR0, 0x111);
|
||||
SET_IDREG(isar, ID_PFR1, 0x1);
|
||||
SET_IDREG(isar, ID_DFR0, 0x2);
|
||||
cpu->id_afr0 = 0x3;
|
||||
SET_IDREG(isar, ID_AFR0, 0x3);
|
||||
SET_IDREG(isar, ID_MMFR0, 0x01130003);
|
||||
SET_IDREG(isar, ID_MMFR1, 0x10030302);
|
||||
SET_IDREG(isar, ID_MMFR2, 0x01222110);
|
||||
|
|
@ -257,7 +257,7 @@ static void arm1136_initfn(Object *obj)
|
|||
SET_IDREG(isar, ID_PFR0, 0x111);
|
||||
SET_IDREG(isar, ID_PFR1, 0x1);
|
||||
SET_IDREG(isar, ID_DFR0, 0x2);
|
||||
cpu->id_afr0 = 0x3;
|
||||
SET_IDREG(isar, ID_AFR0, 0x3);
|
||||
SET_IDREG(isar, ID_MMFR0, 0x01130003);
|
||||
SET_IDREG(isar, ID_MMFR1, 0x10030302);
|
||||
SET_IDREG(isar, ID_MMFR2, 0x01222110);
|
||||
|
|
@ -290,7 +290,7 @@ static void arm1176_initfn(Object *obj)
|
|||
SET_IDREG(isar, ID_PFR0, 0x111);
|
||||
SET_IDREG(isar, ID_PFR1, 0x11);
|
||||
SET_IDREG(isar, ID_DFR0, 0x33);
|
||||
cpu->id_afr0 = 0;
|
||||
SET_IDREG(isar, ID_AFR0, 0);
|
||||
SET_IDREG(isar, ID_MMFR0, 0x01130003);
|
||||
SET_IDREG(isar, ID_MMFR1, 0x10030302);
|
||||
SET_IDREG(isar, ID_MMFR2, 0x01222100);
|
||||
|
|
@ -320,7 +320,7 @@ static void arm11mpcore_initfn(Object *obj)
|
|||
SET_IDREG(isar, ID_PFR0, 0x111);
|
||||
SET_IDREG(isar, ID_PFR1, 0x1);
|
||||
SET_IDREG(isar, ID_DFR0, 0);
|
||||
cpu->id_afr0 = 0x2;
|
||||
SET_IDREG(isar, ID_AFR0, 0x2);
|
||||
SET_IDREG(isar, ID_MMFR0, 0x01100103);
|
||||
SET_IDREG(isar, ID_MMFR1, 0x10020302);
|
||||
SET_IDREG(isar, ID_MMFR2, 0x01222000);
|
||||
|
|
@ -360,7 +360,7 @@ static void cortex_a8_initfn(Object *obj)
|
|||
SET_IDREG(isar, ID_PFR0, 0x1031);
|
||||
SET_IDREG(isar, ID_PFR1, 0x11);
|
||||
SET_IDREG(isar, ID_DFR0, 0x400);
|
||||
cpu->id_afr0 = 0;
|
||||
SET_IDREG(isar, ID_AFR0, 0);
|
||||
SET_IDREG(isar, ID_MMFR0, 0x31100003);
|
||||
SET_IDREG(isar, ID_MMFR1, 0x20000000);
|
||||
SET_IDREG(isar, ID_MMFR2, 0x01202000);
|
||||
|
|
@ -371,7 +371,7 @@ static void cortex_a8_initfn(Object *obj)
|
|||
SET_IDREG(isar, ID_ISAR3, 0x11112131);
|
||||
SET_IDREG(isar, ID_ISAR4, 0x00111142);
|
||||
cpu->isar.dbgdidr = 0x15141000;
|
||||
cpu->clidr = (1 << 27) | (2 << 24) | 3;
|
||||
SET_IDREG(isar, CLIDR, (1 << 27) | (2 << 24) | 3);
|
||||
cpu->ccsidr[0] = 0xe007e01a; /* 16k L1 dcache. */
|
||||
cpu->ccsidr[1] = 0x2007e01a; /* 16k L1 icache. */
|
||||
cpu->ccsidr[2] = 0xf0000000; /* No L2 icache. */
|
||||
|
|
@ -436,7 +436,7 @@ static void cortex_a9_initfn(Object *obj)
|
|||
SET_IDREG(isar, ID_PFR0, 0x1031);
|
||||
SET_IDREG(isar, ID_PFR1, 0x11);
|
||||
SET_IDREG(isar, ID_DFR0, 0x000);
|
||||
cpu->id_afr0 = 0;
|
||||
SET_IDREG(isar, ID_AFR0, 0);
|
||||
SET_IDREG(isar, ID_MMFR0, 0x00100103);
|
||||
SET_IDREG(isar, ID_MMFR1, 0x20000000);
|
||||
SET_IDREG(isar, ID_MMFR2, 0x01230000);
|
||||
|
|
@ -447,7 +447,7 @@ static void cortex_a9_initfn(Object *obj)
|
|||
SET_IDREG(isar, ID_ISAR3, 0x11112131);
|
||||
SET_IDREG(isar, ID_ISAR4, 0x00111142);
|
||||
cpu->isar.dbgdidr = 0x35141000;
|
||||
cpu->clidr = (1 << 27) | (1 << 24) | 3;
|
||||
SET_IDREG(isar, CLIDR, (1 << 27) | (1 << 24) | 3);
|
||||
cpu->ccsidr[0] = 0xe00fe019; /* 16k L1 dcache. */
|
||||
cpu->ccsidr[1] = 0x200fe019; /* 16k L1 icache. */
|
||||
cpu->isar.reset_pmcr_el0 = 0x41093000;
|
||||
|
|
@ -502,7 +502,7 @@ static void cortex_a7_initfn(Object *obj)
|
|||
SET_IDREG(isar, ID_PFR0, 0x00001131);
|
||||
SET_IDREG(isar, ID_PFR1, 0x00011011);
|
||||
SET_IDREG(isar, ID_DFR0, 0x02010555);
|
||||
cpu->id_afr0 = 0x00000000;
|
||||
SET_IDREG(isar, ID_AFR0, 0x00000000);
|
||||
SET_IDREG(isar, ID_MMFR0, 0x10101105);
|
||||
SET_IDREG(isar, ID_MMFR1, 0x40000000);
|
||||
SET_IDREG(isar, ID_MMFR2, 0x01240000);
|
||||
|
|
@ -519,7 +519,7 @@ static void cortex_a7_initfn(Object *obj)
|
|||
cpu->isar.dbgdidr = 0x3515f005;
|
||||
cpu->isar.dbgdevid = 0x01110f13;
|
||||
cpu->isar.dbgdevid1 = 0x1;
|
||||
cpu->clidr = 0x0a200023;
|
||||
SET_IDREG(isar, CLIDR, 0x0a200023);
|
||||
cpu->ccsidr[0] = 0x701fe00a; /* 32K L1 dcache */
|
||||
cpu->ccsidr[1] = 0x201fe00a; /* 32K L1 icache */
|
||||
cpu->ccsidr[2] = 0x711fe07a; /* 4096K L2 unified cache */
|
||||
|
|
@ -554,7 +554,7 @@ static void cortex_a15_initfn(Object *obj)
|
|||
SET_IDREG(isar, ID_PFR0, 0x00001131);
|
||||
SET_IDREG(isar, ID_PFR1, 0x00011011);
|
||||
SET_IDREG(isar, ID_DFR0, 0x02010555);
|
||||
cpu->id_afr0 = 0x00000000;
|
||||
SET_IDREG(isar, ID_AFR0, 0x00000000);
|
||||
SET_IDREG(isar, ID_MMFR0, 0x10201105);
|
||||
SET_IDREG(isar, ID_MMFR1, 0x20000000);
|
||||
SET_IDREG(isar, ID_MMFR2, 0x01240000);
|
||||
|
|
@ -567,7 +567,7 @@ static void cortex_a15_initfn(Object *obj)
|
|||
cpu->isar.dbgdidr = 0x3515f021;
|
||||
cpu->isar.dbgdevid = 0x01110f13;
|
||||
cpu->isar.dbgdevid1 = 0x0;
|
||||
cpu->clidr = 0x0a200023;
|
||||
SET_IDREG(isar, CLIDR, 0x0a200023);
|
||||
cpu->ccsidr[0] = 0x701fe00a; /* 32K L1 dcache */
|
||||
cpu->ccsidr[1] = 0x201fe00a; /* 32K L1 icache */
|
||||
cpu->ccsidr[2] = 0x711fe07a; /* 4096K L2 unified cache */
|
||||
|
|
@ -598,7 +598,7 @@ static void cortex_r5_initfn(Object *obj)
|
|||
SET_IDREG(isar, ID_PFR0, 0x0131);
|
||||
SET_IDREG(isar, ID_PFR1, 0x001);
|
||||
SET_IDREG(isar, ID_DFR0, 0x010400);
|
||||
cpu->id_afr0 = 0x0;
|
||||
SET_IDREG(isar, ID_AFR0, 0x0);
|
||||
SET_IDREG(isar, ID_MMFR0, 0x0210030);
|
||||
SET_IDREG(isar, ID_MMFR1, 0x00000000);
|
||||
SET_IDREG(isar, ID_MMFR2, 0x01200000);
|
||||
|
|
@ -745,7 +745,7 @@ static void cortex_r52_initfn(Object *obj)
|
|||
SET_IDREG(isar, ID_PFR0, 0x00000131);
|
||||
SET_IDREG(isar, ID_PFR1, 0x10111001);
|
||||
SET_IDREG(isar, ID_DFR0, 0x03010006);
|
||||
cpu->id_afr0 = 0x00000000;
|
||||
SET_IDREG(isar, ID_AFR0, 0x00000000);
|
||||
SET_IDREG(isar, ID_MMFR0, 0x00211040);
|
||||
SET_IDREG(isar, ID_MMFR1, 0x40000000);
|
||||
SET_IDREG(isar, ID_MMFR2, 0x01200000);
|
||||
|
|
@ -758,7 +758,7 @@ static void cortex_r52_initfn(Object *obj)
|
|||
SET_IDREG(isar, ID_ISAR4, 0x00010142);
|
||||
SET_IDREG(isar, ID_ISAR5, 0x00010001);
|
||||
cpu->isar.dbgdidr = 0x77168000;
|
||||
cpu->clidr = (1 << 27) | (1 << 24) | 0x3;
|
||||
SET_IDREG(isar, CLIDR, (1 << 27) | (1 << 24) | 0x3);
|
||||
cpu->ccsidr[0] = 0x700fe01a; /* 32KB L1 dcache */
|
||||
cpu->ccsidr[1] = 0x201fe00a; /* 32KB L1 icache */
|
||||
|
||||
|
|
@ -977,7 +977,7 @@ static void arm_max_initfn(Object *obj)
|
|||
SET_IDREG(isar, ID_PFR0, 0x00000131);
|
||||
SET_IDREG(isar, ID_PFR1, 0x00011011);
|
||||
SET_IDREG(isar, ID_DFR0, 0x03010066);
|
||||
cpu->id_afr0 = 0x00000000;
|
||||
SET_IDREG(isar, ID_AFR0, 0x00000000);
|
||||
SET_IDREG(isar, ID_MMFR0, 0x10101105);
|
||||
SET_IDREG(isar, ID_MMFR1, 0x40000000);
|
||||
SET_IDREG(isar, ID_MMFR2, 0x01260000);
|
||||
|
|
@ -990,7 +990,7 @@ static void arm_max_initfn(Object *obj)
|
|||
SET_IDREG(isar, ID_ISAR5, 0x00011121);
|
||||
SET_IDREG(isar, ID_ISAR6, 0);
|
||||
cpu->isar.reset_pmcr_el0 = 0x41013000;
|
||||
cpu->clidr = 0x0a200023;
|
||||
SET_IDREG(isar, CLIDR, 0x0a200023);
|
||||
cpu->ccsidr[0] = 0x701fe00a; /* 32KB L1 dcache */
|
||||
cpu->ccsidr[1] = 0x201fe012; /* 48KB L1 icache */
|
||||
cpu->ccsidr[2] = 0x70ffe07a; /* 2048KB L2 cache */
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ static void aarch64_a35_initfn(Object *obj)
|
|||
SET_IDREG(isar, ID_PFR0, 0x00000131);
|
||||
SET_IDREG(isar, ID_PFR1, 0x00011011);
|
||||
SET_IDREG(isar, ID_DFR0, 0x03010066);
|
||||
cpu->id_afr0 = 0;
|
||||
SET_IDREG(isar, ID_AFR0, 0);
|
||||
SET_IDREG(isar, ID_MMFR0, 0x10201105);
|
||||
SET_IDREG(isar, ID_MMFR1, 0x40000000);
|
||||
SET_IDREG(isar, ID_MMFR2, 0x01260000);
|
||||
|
|
@ -71,7 +71,7 @@ static void aarch64_a35_initfn(Object *obj)
|
|||
SET_IDREG(isar, ID_AA64ISAR1, 0);
|
||||
SET_IDREG(isar, ID_AA64MMFR0, 0x00101122);
|
||||
SET_IDREG(isar, ID_AA64MMFR1, 0);
|
||||
cpu->clidr = 0x0a200023;
|
||||
SET_IDREG(isar, CLIDR, 0x0a200023);
|
||||
cpu->dcz_blocksize = 4;
|
||||
|
||||
/* From B2.4 AArch64 Virtual Memory control registers */
|
||||
|
|
@ -216,7 +216,7 @@ static void aarch64_a55_initfn(Object *obj)
|
|||
set_feature(&cpu->env, ARM_FEATURE_PMU);
|
||||
|
||||
/* Ordered by B2.4 AArch64 registers by functional group */
|
||||
cpu->clidr = 0x82000023;
|
||||
SET_IDREG(isar, CLIDR, 0x82000023);
|
||||
cpu->ctr = 0x84448004; /* L1Ip = VIPT */
|
||||
cpu->dcz_blocksize = 4; /* 64 bytes */
|
||||
SET_IDREG(isar, ID_AA64DFR0, 0x0000000010305408ull);
|
||||
|
|
@ -227,7 +227,7 @@ static void aarch64_a55_initfn(Object *obj)
|
|||
SET_IDREG(isar, ID_AA64MMFR2, 0x0000000000001011ull);
|
||||
SET_IDREG(isar, ID_AA64PFR0, 0x0000000010112222ull);
|
||||
SET_IDREG(isar, ID_AA64PFR1, 0x0000000000000010ull);
|
||||
cpu->id_afr0 = 0x00000000;
|
||||
SET_IDREG(isar, ID_AFR0, 0x00000000);
|
||||
SET_IDREG(isar, ID_DFR0, 0x04010088);
|
||||
SET_IDREG(isar, ID_ISAR0, 0x02101110);
|
||||
SET_IDREG(isar, ID_ISAR1, 0x13112111);
|
||||
|
|
@ -298,7 +298,7 @@ static void aarch64_a72_initfn(Object *obj)
|
|||
SET_IDREG(isar, ID_PFR0, 0x00000131);
|
||||
SET_IDREG(isar, ID_PFR1, 0x00011011);
|
||||
SET_IDREG(isar, ID_DFR0, 0x03010066);
|
||||
cpu->id_afr0 = 0x00000000;
|
||||
SET_IDREG(isar, ID_AFR0, 0x00000000);
|
||||
SET_IDREG(isar, ID_MMFR0, 0x10201105);
|
||||
SET_IDREG(isar, ID_MMFR1, 0x40000000);
|
||||
SET_IDREG(isar, ID_MMFR2, 0x01260000);
|
||||
|
|
@ -317,7 +317,7 @@ static void aarch64_a72_initfn(Object *obj)
|
|||
cpu->isar.dbgdevid = 0x01110f13;
|
||||
cpu->isar.dbgdevid1 = 0x2;
|
||||
cpu->isar.reset_pmcr_el0 = 0x41023000;
|
||||
cpu->clidr = 0x0a200023;
|
||||
SET_IDREG(isar, CLIDR, 0x0a200023);
|
||||
/* 32KB L1 dcache */
|
||||
cpu->ccsidr[0] = make_ccsidr(CCSIDR_FORMAT_LEGACY, 4, 64, 32 * KiB, 7);
|
||||
/* 48KB L1 dcache */
|
||||
|
|
@ -349,10 +349,10 @@ static void aarch64_a76_initfn(Object *obj)
|
|||
set_feature(&cpu->env, ARM_FEATURE_PMU);
|
||||
|
||||
/* Ordered by B2.4 AArch64 registers by functional group */
|
||||
cpu->clidr = 0x82000023;
|
||||
SET_IDREG(isar, CLIDR, 0x82000023);
|
||||
cpu->ctr = 0x8444C004;
|
||||
cpu->dcz_blocksize = 4;
|
||||
SET_IDREG(isar, ID_AA64DFR0, 0x0000000010305408ull),
|
||||
SET_IDREG(isar, ID_AA64DFR0, 0x0000000010305408ull);
|
||||
SET_IDREG(isar, ID_AA64ISAR0, 0x0000100010211120ull);
|
||||
SET_IDREG(isar, ID_AA64ISAR1, 0x0000000000100001ull);
|
||||
SET_IDREG(isar, ID_AA64MMFR0, 0x0000000000101122ull);
|
||||
|
|
@ -360,7 +360,7 @@ static void aarch64_a76_initfn(Object *obj)
|
|||
SET_IDREG(isar, ID_AA64MMFR2, 0x0000000000001011ull);
|
||||
SET_IDREG(isar, ID_AA64PFR0, 0x1100000010111112ull); /* GIC filled in later */
|
||||
SET_IDREG(isar, ID_AA64PFR1, 0x0000000000000010ull);
|
||||
cpu->id_afr0 = 0x00000000;
|
||||
SET_IDREG(isar, ID_AFR0, 0x00000000);
|
||||
SET_IDREG(isar, ID_DFR0, 0x04010088);
|
||||
SET_IDREG(isar, ID_ISAR0, 0x02101110);
|
||||
SET_IDREG(isar, ID_ISAR1, 0x13112111);
|
||||
|
|
@ -426,17 +426,17 @@ static void aarch64_a64fx_initfn(Object *obj)
|
|||
cpu->reset_sctlr = 0x30000180;
|
||||
SET_IDREG(isar, ID_AA64PFR0, 0x0000000101111111); /* No RAS Extensions */
|
||||
SET_IDREG(isar, ID_AA64PFR1, 0x0000000000000000);
|
||||
SET_IDREG(isar, ID_AA64DFR0, 0x0000000010305408),
|
||||
SET_IDREG(isar, ID_AA64DFR1, 0x0000000000000000),
|
||||
cpu->id_aa64afr0 = 0x0000000000000000;
|
||||
cpu->id_aa64afr1 = 0x0000000000000000;
|
||||
SET_IDREG(isar, ID_AA64DFR0, 0x0000000010305408);
|
||||
SET_IDREG(isar, ID_AA64DFR1, 0x0000000000000000);
|
||||
SET_IDREG(isar, ID_AA64AFR0, 0x0000000000000000);
|
||||
SET_IDREG(isar, ID_AA64AFR1, 0x0000000000000000);
|
||||
SET_IDREG(isar, ID_AA64MMFR0, 0x0000000000001122);
|
||||
SET_IDREG(isar, ID_AA64MMFR1, 0x0000000011212100);
|
||||
SET_IDREG(isar, ID_AA64MMFR2, 0x0000000000001011);
|
||||
SET_IDREG(isar, ID_AA64ISAR0, 0x0000000010211120);
|
||||
SET_IDREG(isar, ID_AA64ISAR1, 0x0000000000010001);
|
||||
SET_IDREG(isar, ID_AA64ZFR0, 0x0000000000000000);
|
||||
cpu->clidr = 0x0000000080000023;
|
||||
SET_IDREG(isar, CLIDR, 0x0000000080000023);
|
||||
/* 64KB L1 dcache */
|
||||
cpu->ccsidr[0] = make_ccsidr(CCSIDR_FORMAT_LEGACY, 4, 256, 64 * KiB, 7);
|
||||
/* 64KB L1 icache */
|
||||
|
|
@ -597,7 +597,7 @@ static void aarch64_neoverse_n1_initfn(Object *obj)
|
|||
set_feature(&cpu->env, ARM_FEATURE_PMU);
|
||||
|
||||
/* Ordered by B2.4 AArch64 registers by functional group */
|
||||
cpu->clidr = 0x82000023;
|
||||
SET_IDREG(isar, CLIDR, 0x82000023);
|
||||
cpu->ctr = 0x8444c004;
|
||||
cpu->dcz_blocksize = 4;
|
||||
SET_IDREG(isar, ID_AA64DFR0, 0x0000000110305408ull);
|
||||
|
|
@ -608,7 +608,7 @@ static void aarch64_neoverse_n1_initfn(Object *obj)
|
|||
SET_IDREG(isar, ID_AA64MMFR2, 0x0000000000001011ull);
|
||||
SET_IDREG(isar, ID_AA64PFR0, 0x1100000010111112ull); /* GIC filled in later */
|
||||
SET_IDREG(isar, ID_AA64PFR1, 0x0000000000000020ull);
|
||||
cpu->id_afr0 = 0x00000000;
|
||||
SET_IDREG(isar, ID_AFR0, 0x00000000);
|
||||
SET_IDREG(isar, ID_DFR0, 0x04010088);
|
||||
SET_IDREG(isar, ID_ISAR0, 0x02101110);
|
||||
SET_IDREG(isar, ID_ISAR1, 0x13112111);
|
||||
|
|
@ -673,21 +673,21 @@ static void aarch64_neoverse_v1_initfn(Object *obj)
|
|||
set_feature(&cpu->env, ARM_FEATURE_PMU);
|
||||
|
||||
/* Ordered by 3.2.4 AArch64 registers by functional group */
|
||||
cpu->clidr = 0x82000023;
|
||||
SET_IDREG(isar, CLIDR, 0x82000023);
|
||||
cpu->ctr = 0xb444c004; /* With DIC and IDC set */
|
||||
cpu->dcz_blocksize = 4;
|
||||
cpu->id_aa64afr0 = 0x00000000;
|
||||
cpu->id_aa64afr1 = 0x00000000;
|
||||
SET_IDREG(isar, ID_AA64DFR0, 0x000001f210305519ull),
|
||||
SET_IDREG(isar, ID_AA64DFR1, 0x00000000),
|
||||
SET_IDREG(isar, ID_AA64AFR0, 0x00000000);
|
||||
SET_IDREG(isar, ID_AA64AFR1, 0x00000000);
|
||||
SET_IDREG(isar, ID_AA64DFR0, 0x000001f210305519ull);
|
||||
SET_IDREG(isar, ID_AA64DFR1, 0x00000000);
|
||||
SET_IDREG(isar, ID_AA64ISAR0, 0x1011111110212120ull); /* with FEAT_RNG */
|
||||
SET_IDREG(isar, ID_AA64ISAR1, 0x0011000001211032ull);
|
||||
SET_IDREG(isar, ID_AA64MMFR0, 0x0000000000101125ull);
|
||||
SET_IDREG(isar, ID_AA64MMFR1, 0x0000000010212122ull),
|
||||
SET_IDREG(isar, ID_AA64MMFR2, 0x0220011102101011ull),
|
||||
SET_IDREG(isar, ID_AA64MMFR1, 0x0000000010212122ull);
|
||||
SET_IDREG(isar, ID_AA64MMFR2, 0x0220011102101011ull);
|
||||
SET_IDREG(isar, ID_AA64PFR0, 0x1101110120111112ull); /* GIC filled in later */
|
||||
SET_IDREG(isar, ID_AA64PFR1, 0x0000000000000020ull);
|
||||
cpu->id_afr0 = 0x00000000;
|
||||
SET_IDREG(isar, ID_AFR0, 0x00000000);
|
||||
SET_IDREG(isar, ID_DFR0, 0x15011099);
|
||||
SET_IDREG(isar, ID_ISAR0, 0x02101110);
|
||||
SET_IDREG(isar, ID_ISAR1, 0x13112111);
|
||||
|
|
@ -905,7 +905,7 @@ static void aarch64_a710_initfn(Object *obj)
|
|||
SET_IDREG(isar, ID_PFR0, 0x21110131);
|
||||
SET_IDREG(isar, ID_PFR1, 0x00010000); /* GIC filled in later */
|
||||
SET_IDREG(isar, ID_DFR0, 0x16011099);
|
||||
cpu->id_afr0 = 0;
|
||||
SET_IDREG(isar, ID_AFR0, 0);
|
||||
SET_IDREG(isar, ID_MMFR0, 0x10201105);
|
||||
SET_IDREG(isar, ID_MMFR1, 0x40000000);
|
||||
SET_IDREG(isar, ID_MMFR2, 0x01260000);
|
||||
|
|
@ -927,14 +927,14 @@ static void aarch64_a710_initfn(Object *obj)
|
|||
SET_IDREG(isar, ID_AA64ZFR0, 0x0000110100110021ull); /* with Crypto */
|
||||
SET_IDREG(isar, ID_AA64DFR0, 0x000011f010305619ull);
|
||||
SET_IDREG(isar, ID_AA64DFR1, 0);
|
||||
cpu->id_aa64afr0 = 0;
|
||||
cpu->id_aa64afr1 = 0;
|
||||
SET_IDREG(isar, ID_AA64AFR0, 0);
|
||||
SET_IDREG(isar, ID_AA64AFR1, 0);
|
||||
SET_IDREG(isar, ID_AA64ISAR0, 0x0221111110212120ull); /* with Crypto */
|
||||
SET_IDREG(isar, ID_AA64ISAR1, 0x0010111101211052ull);
|
||||
SET_IDREG(isar, ID_AA64MMFR0, 0x0000022200101122ull);
|
||||
SET_IDREG(isar, ID_AA64MMFR1, 0x0000000010212122ull);
|
||||
SET_IDREG(isar, ID_AA64MMFR2, 0x1221011110101011ull);
|
||||
cpu->clidr = 0x0000001482000023ull;
|
||||
SET_IDREG(isar, CLIDR, 0x0000001482000023ull);
|
||||
cpu->gm_blocksize = 4;
|
||||
cpu->ctr = 0x000000049444c004ull;
|
||||
cpu->dcz_blocksize = 4;
|
||||
|
|
@ -1007,7 +1007,7 @@ static void aarch64_neoverse_n2_initfn(Object *obj)
|
|||
SET_IDREG(isar, ID_PFR0, 0x21110131);
|
||||
SET_IDREG(isar, ID_PFR1, 0x00010000); /* GIC filled in later */
|
||||
SET_IDREG(isar, ID_DFR0, 0x16011099);
|
||||
cpu->id_afr0 = 0;
|
||||
SET_IDREG(isar, ID_AFR0, 0);
|
||||
SET_IDREG(isar, ID_MMFR0, 0x10201105);
|
||||
SET_IDREG(isar, ID_MMFR1, 0x40000000);
|
||||
SET_IDREG(isar, ID_MMFR2, 0x01260000);
|
||||
|
|
@ -1029,14 +1029,14 @@ static void aarch64_neoverse_n2_initfn(Object *obj)
|
|||
SET_IDREG(isar, ID_AA64ZFR0, 0x0000110100110021ull); /* with Crypto */
|
||||
SET_IDREG(isar, ID_AA64DFR0, 0x000011f210305619ull);
|
||||
SET_IDREG(isar, ID_AA64DFR1, 0);
|
||||
cpu->id_aa64afr0 = 0;
|
||||
cpu->id_aa64afr1 = 0;
|
||||
SET_IDREG(isar, ID_AA64AFR0, 0);
|
||||
SET_IDREG(isar, ID_AA64AFR1, 0);
|
||||
SET_IDREG(isar, ID_AA64ISAR0, 0x1221111110212120ull); /* with Crypto and FEAT_RNG */
|
||||
SET_IDREG(isar, ID_AA64ISAR1, 0x0011111101211052ull);
|
||||
SET_IDREG(isar, ID_AA64MMFR0, 0x0000022200101125ull);
|
||||
SET_IDREG(isar, ID_AA64MMFR1, 0x0000000010212122ull);
|
||||
SET_IDREG(isar, ID_AA64MMFR2, 0x1221011112101011ull);
|
||||
cpu->clidr = 0x0000001482000023ull;
|
||||
SET_IDREG(isar, CLIDR, 0x0000001482000023ull);
|
||||
cpu->gm_blocksize = 4;
|
||||
cpu->ctr = 0x00000004b444c004ull;
|
||||
cpu->dcz_blocksize = 4;
|
||||
|
|
@ -1125,10 +1125,10 @@ void aarch64_max_tcg_initfn(Object *obj)
|
|||
* We're going to set FEAT_S2FWB, which mandates that CLIDR_EL1.{LoUU,LoUIS}
|
||||
* are zero.
|
||||
*/
|
||||
u = cpu->clidr;
|
||||
u = GET_IDREG(isar, CLIDR);
|
||||
u = FIELD_DP32(u, CLIDR_EL1, LOUIS, 0);
|
||||
u = FIELD_DP32(u, CLIDR_EL1, LOUU, 0);
|
||||
cpu->clidr = u;
|
||||
SET_IDREG(isar, CLIDR, u);
|
||||
|
||||
/*
|
||||
* Set CTR_EL0.DIC and IDC to tell the guest it doesnt' need to
|
||||
|
|
|
|||
|
|
@ -658,15 +658,6 @@ void HELPER(exception_return)(CPUARMState *env, uint64_t new_pc)
|
|||
spsr &= ~PSTATE_SS;
|
||||
}
|
||||
|
||||
/*
|
||||
* FEAT_RME forbids return from EL3 with an invalid security state.
|
||||
* We don't need an explicit check for FEAT_RME here because we enforce
|
||||
* in scr_write() that you can't set the NSE bit without it.
|
||||
*/
|
||||
if (cur_el == 3 && (env->cp15.scr_el3 & (SCR_NS | SCR_NSE)) == SCR_NSE) {
|
||||
goto illegal_return;
|
||||
}
|
||||
|
||||
new_el = el_from_spsr(spsr);
|
||||
if (new_el == -1) {
|
||||
goto illegal_return;
|
||||
|
|
@ -678,6 +669,17 @@ void HELPER(exception_return)(CPUARMState *env, uint64_t new_pc)
|
|||
goto illegal_return;
|
||||
}
|
||||
|
||||
/*
|
||||
* FEAT_RME forbids return from EL3 to a lower exception level
|
||||
* with an invalid security state.
|
||||
* We don't need an explicit check for FEAT_RME here because we enforce
|
||||
* in scr_write() that you can't set the NSE bit without it.
|
||||
*/
|
||||
if (cur_el == 3 && new_el < 3 &&
|
||||
(env->cp15.scr_el3 & (SCR_NS | SCR_NSE)) == SCR_NSE) {
|
||||
goto illegal_return;
|
||||
}
|
||||
|
||||
if (new_el != 0 && arm_el_is_aa64(env, new_el) != return_to_aa64) {
|
||||
/* Return to an EL which is configured for a different register width */
|
||||
goto illegal_return;
|
||||
|
|
|
|||
|
|
@ -1209,6 +1209,5 @@ DEF_HELPER_FLAGS_4(sme2_luti4_2b, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32)
|
|||
DEF_HELPER_FLAGS_4(sme2_luti4_2h, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32)
|
||||
DEF_HELPER_FLAGS_4(sme2_luti4_2s, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32)
|
||||
|
||||
DEF_HELPER_FLAGS_4(sme2_luti4_4b, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32)
|
||||
DEF_HELPER_FLAGS_4(sme2_luti4_4h, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32)
|
||||
DEF_HELPER_FLAGS_4(sme2_luti4_4s, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32)
|
||||
|
|
|
|||
|
|
@ -64,6 +64,7 @@ arm_common_ss.add(files(
|
|||
))
|
||||
|
||||
arm_common_system_ss.add(files(
|
||||
'cpregs-at.c',
|
||||
'hflags.c',
|
||||
'iwmmxt_helper.c',
|
||||
'neon_helper.c',
|
||||
|
|
|
|||
|
|
@ -3526,7 +3526,6 @@ DO_SME2_LUT(4,1,s, 4)
|
|||
DO_SME2_LUT(4,2,b, 1)
|
||||
DO_SME2_LUT(4,2,h, 2)
|
||||
DO_SME2_LUT(4,2,s, 4)
|
||||
DO_SME2_LUT(4,4,b, 1)
|
||||
DO_SME2_LUT(4,4,h, 2)
|
||||
DO_SME2_LUT(4,4,s, 4)
|
||||
|
||||
|
|
|
|||
|
|
@ -138,6 +138,7 @@ tests_arm_system_thorough = [
|
|||
'arm_cubieboard',
|
||||
'arm_emcraft_sf2',
|
||||
'arm_integratorcp',
|
||||
'arm_max78000fthr',
|
||||
'arm_microbit',
|
||||
'arm_orangepi',
|
||||
'arm_quanta_gsj',
|
||||
|
|
|
|||
48
tests/functional/test_arm_max78000fthr.py
Executable file
48
tests/functional/test_arm_max78000fthr.py
Executable file
|
|
@ -0,0 +1,48 @@
|
|||
#!/usr/bin/env python3
|
||||
#
|
||||
# Functional test that checks the max78000fthr machine.
|
||||
# Tests ICC, GCR, TRNG, AES, and UART
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
from qemu_test import QemuSystemTest, Asset, exec_command_and_wait_for_pattern
|
||||
from qemu_test import wait_for_console_pattern
|
||||
|
||||
|
||||
class Max78000Machine(QemuSystemTest):
|
||||
|
||||
ASSET_FW = Asset(
|
||||
'https://github.com/JacksonDonaldson/max78000Test/raw/main/build/max78000.bin',
|
||||
'86940b4bf60931bc6a8aa5db4b9f7f3cf8f64dbbd7ac534647980e536cf3adf7')
|
||||
|
||||
def test_fthr(self):
|
||||
self.set_machine('max78000fthr')
|
||||
fw_path = self.ASSET_FW.fetch()
|
||||
self.vm.set_console()
|
||||
self.vm.add_args('-kernel', fw_path)
|
||||
self.vm.add_args('-device', "loader,file=" + fw_path + ",addr=0x10000000")
|
||||
self.vm.launch()
|
||||
|
||||
wait_for_console_pattern(self, 'started')
|
||||
|
||||
# i -> prints instruction cache values
|
||||
exec_command_and_wait_for_pattern(self, 'i', 'CTRL: 00010001')
|
||||
|
||||
# r -> gcr resets the machine
|
||||
exec_command_and_wait_for_pattern(self, 'r', 'started')
|
||||
|
||||
# z -> sets some memory, then has gcr zero it
|
||||
exec_command_and_wait_for_pattern(self, 'z', 'initial value: 12345678')
|
||||
wait_for_console_pattern(self, "after memz: 00000000")
|
||||
|
||||
# t -> runs trng
|
||||
exec_command_and_wait_for_pattern(self, 't', 'random data:')
|
||||
|
||||
# a -> runs aes
|
||||
exec_command_and_wait_for_pattern(self, 'a',
|
||||
'encrypted to : a47ca9dd e0df4c86 a070af6e 91710dec')
|
||||
wait_for_console_pattern(self,
|
||||
'encrypted to : cab7a28e bf456751 9049fcea 8960494b')
|
||||
|
||||
if __name__ == '__main__':
|
||||
QemuSystemTest.main()
|
||||
|
|
@ -19,6 +19,12 @@
|
|||
"-device pxb-cxl,id=cxl.1,bus=pcie.0,bus_nr=53 " \
|
||||
"-M cxl-fmw.0.targets.0=cxl.0,cxl-fmw.0.targets.1=cxl.1,cxl-fmw.0.size=4G "
|
||||
|
||||
#define QEMU_VIRT_2PXB_CMD \
|
||||
"-machine virt,cxl=on -cpu max " \
|
||||
"-device pxb-cxl,id=cxl.0,bus=pcie.0,bus_nr=52 " \
|
||||
"-device pxb-cxl,id=cxl.1,bus=pcie.0,bus_nr=53 " \
|
||||
"-M cxl-fmw.0.targets.0=cxl.0,cxl-fmw.0.targets.1=cxl.1,cxl-fmw.0.size=4G "
|
||||
|
||||
#define QEMU_RP \
|
||||
"-device cxl-rp,id=rp0,bus=cxl.0,chassis=0,slot=0 "
|
||||
|
||||
|
|
@ -197,25 +203,51 @@ static void cxl_2pxb_4rp_4t3d(void)
|
|||
qtest_end();
|
||||
rmdir(tmpfs);
|
||||
}
|
||||
|
||||
static void cxl_virt_2pxb_4rp_4t3d(void)
|
||||
{
|
||||
g_autoptr(GString) cmdline = g_string_new(NULL);
|
||||
g_autofree const char *tmpfs = NULL;
|
||||
|
||||
tmpfs = g_dir_make_tmp("cxl-test-XXXXXX", NULL);
|
||||
|
||||
g_string_printf(cmdline, QEMU_VIRT_2PXB_CMD QEMU_4RP QEMU_4T3D,
|
||||
tmpfs, tmpfs, tmpfs, tmpfs, tmpfs, tmpfs,
|
||||
tmpfs, tmpfs);
|
||||
|
||||
qtest_start(cmdline->str);
|
||||
qtest_end();
|
||||
rmdir(tmpfs);
|
||||
}
|
||||
#endif /* CONFIG_POSIX */
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
g_test_init(&argc, &argv, NULL);
|
||||
const char *arch = qtest_get_arch();
|
||||
|
||||
qtest_add_func("/pci/cxl/basic_hostbridge", cxl_basic_hb);
|
||||
qtest_add_func("/pci/cxl/basic_pxb", cxl_basic_pxb);
|
||||
qtest_add_func("/pci/cxl/pxb_with_window", cxl_pxb_with_window);
|
||||
qtest_add_func("/pci/cxl/pxb_x2_with_window", cxl_2pxb_with_window);
|
||||
qtest_add_func("/pci/cxl/rp", cxl_root_port);
|
||||
qtest_add_func("/pci/cxl/rp_x2", cxl_2root_port);
|
||||
g_test_init(&argc, &argv, NULL);
|
||||
if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) {
|
||||
qtest_add_func("/pci/cxl/basic_hostbridge", cxl_basic_hb);
|
||||
qtest_add_func("/pci/cxl/basic_pxb", cxl_basic_pxb);
|
||||
qtest_add_func("/pci/cxl/pxb_with_window", cxl_pxb_with_window);
|
||||
qtest_add_func("/pci/cxl/pxb_x2_with_window", cxl_2pxb_with_window);
|
||||
qtest_add_func("/pci/cxl/rp", cxl_root_port);
|
||||
qtest_add_func("/pci/cxl/rp_x2", cxl_2root_port);
|
||||
#ifdef CONFIG_POSIX
|
||||
qtest_add_func("/pci/cxl/type3_device", cxl_t3d_deprecated);
|
||||
qtest_add_func("/pci/cxl/type3_device_pmem", cxl_t3d_persistent);
|
||||
qtest_add_func("/pci/cxl/type3_device_vmem", cxl_t3d_volatile);
|
||||
qtest_add_func("/pci/cxl/type3_device_vmem_lsa", cxl_t3d_volatile_lsa);
|
||||
qtest_add_func("/pci/cxl/rp_x2_type3_x2", cxl_1pxb_2rp_2t3d);
|
||||
qtest_add_func("/pci/cxl/pxb_x2_root_port_x4_type3_x4", cxl_2pxb_4rp_4t3d);
|
||||
qtest_add_func("/pci/cxl/type3_device", cxl_t3d_deprecated);
|
||||
qtest_add_func("/pci/cxl/type3_device_pmem", cxl_t3d_persistent);
|
||||
qtest_add_func("/pci/cxl/type3_device_vmem", cxl_t3d_volatile);
|
||||
qtest_add_func("/pci/cxl/type3_device_vmem_lsa", cxl_t3d_volatile_lsa);
|
||||
qtest_add_func("/pci/cxl/rp_x2_type3_x2", cxl_1pxb_2rp_2t3d);
|
||||
qtest_add_func("/pci/cxl/pxb_x2_root_port_x4_type3_x4",
|
||||
cxl_2pxb_4rp_4t3d);
|
||||
#endif
|
||||
} else if (strcmp(arch, "aarch64") == 0) {
|
||||
#ifdef CONFIG_POSIX
|
||||
qtest_add_func("/pci/cxl/virt/pxb_x2_root_port_x4_type3_x4",
|
||||
cxl_virt_2pxb_4rp_4t3d);
|
||||
#endif
|
||||
}
|
||||
|
||||
return g_test_run();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -262,6 +262,7 @@ qtests_aarch64 = \
|
|||
config_all_devices.has_key('CONFIG_TPM_TIS_I2C') ? ['tpm-tis-i2c-test'] : []) + \
|
||||
(config_all_devices.has_key('CONFIG_ASPEED_SOC') ? qtests_aspeed64 : []) + \
|
||||
(config_all_devices.has_key('CONFIG_NPCM8XX') ? qtests_npcm8xx : []) + \
|
||||
qtests_cxl + \
|
||||
['arm-cpu-features',
|
||||
'numa-test',
|
||||
'boot-serial-test',
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue