mirror of
https://github.com/izzy2lost/xemu.git
synced 2026-07-06 00:20:22 -07:00
Merge tag 'pull-riscv-to-apply-20250519' of https://github.com/alistair23/qemu into staging
First RISC-V PR for 10.1 * Add support for RIMT to virt machine ACPI * Don't allow PMP RLB to bypass rule privileges * Fix checks on writes to pmpcfg in Smepmp MML mode * Generate strided vector loads/stores with tcg nodes * Improve Microchip Polarfire SoC customization * Use tcg ops generation to emulate whole reg rvv loads/stores * Expand the probe_pages helper function to handle probe flags * Fix type conflict of GLib function pointers * Fix endless translation loop on big endian systems * Use tail pseudoinstruction for calling tail * Fix some RISC-V vector instruction corner cases * MAINTAINERS: Add common-user/host/riscv to RISC-V section * Fix write_misa vs aligned next_pc * KVM CSR fixes * Virt machine memmap usage cleanup # -----BEGIN PGP SIGNATURE----- # # iQIzBAABCgAdFiEEaukCtqfKh31tZZKWr3yVEwxTgBMFAmgqreUACgkQr3yVEwxT # gBMurA//WAX4X+aNi6keCr20Ffv3gUnkPPeVewLLKOrZZ7h5oyWtRcSQvwDBSr8C # vzs4Rf492iNljnbRj09KYkLB8Qq/QH2Ixl+IgG8ueJAHJ8WdG6HYrrDxcONwgL1K # lQrRaDrMCFjU35uDlejfuvWWEmb4GKDMfj/wxs5wgNvnHgNhThmVaWQysx8KHYU+ # tevPQj5s4mvVGztGRSHIZQ8bth7oVUQR5CsKngGEmVLS2L6yVYTUN5ZhB5g6Ikrq # jKn44cROLfvv+0zPB9Lgu7eKauA/h8SckjCV+dGoMDB5J5M/TvwS118VHOjNVEQZ # yLx6/BdLp3SRPwbvu9jn6vjms95iZSJXXdnY+Cg4MqAbuIRQK66n6Zoa3LjbEk2U # zsf03uYUla9CBs6VQJmF7yjks3AbWokpZ9WSsGIcHJgXe8pEUeEsWOgiBhifJ5bD # Hljlkiw1gHCjhtc2aWEH0aBwM7896lmdct70JmkjQ4uZKkFSqJ8y5l0Gm3lvgvdO # OEPyMbZ6hSO4UZovcpeFtOoXteCUVthvqz0mADoQAtG+2qoX0k+9h8v305fhlti+ # bXJfu1QPsQqCYMrv4ZSTbRg0uC8m7CHnA+coC0XnCcMwEk9ZBl373/cnQYWsmqo8 # lxZmXLvpaN9CEzjOmZhXUsOvIqAJdM1sYPWnoXJ71t7mn4QEOPA= # =dFjk # -----END PGP SIGNATURE----- # gpg: Signature made Mon 19 May 2025 00:04:53 EDT # gpg: using RSA key 6AE902B6A7CA877D6D659296AF7C95130C538013 # gpg: Good signature from "Alistair Francis <alistair@alistair23.me>" [unknown] # gpg: WARNING: This key is not certified with a trusted signature! # gpg: There is no indication that the signature belongs to the owner. # Primary key fingerprint: 6AE9 02B6 A7CA 877D 6D65 9296 AF7C 9513 0C53 8013 * tag 'pull-riscv-to-apply-20250519' of https://github.com/alistair23/qemu: (56 commits) hw/riscv/virt.c: remove 'long' casts in fmt strings hw/riscv/virt.c: use s->memmap in finalize_fdt() functions hw/riscv/virt.c: use s->memmap in create_fdt_virtio() hw/riscv/virt.c: use s->memmap in create_fdt_sockets() path hw/riscv/virt.c: use s->memmap in create_fdt() path hw/riscv/virt.c: add 'base' arg in create_fw_cfg() hw/riscv/virt.c: use s->memmap in virt_machine_done() hw/riscv/virt.c: remove trivial virt_memmap references hw/riscv/virt.c: enforce s->memmap use in machine_init() target/riscv/kvm: add scounteren CSR target/riscv/kvm: read/write KVM regs via env size target/riscv/kvm: add senvcfg CSR target/riscv/kvm: do not read unavailable CSRs target/riscv/kvm: add kvm_csr_cfgs[] target/riscv/kvm: turn kvm_riscv_reg_id_ulong() into a macro target/riscv/kvm: turn u32/u64 reg functions into macros target/riscv/kvm: fix leak in kvm_riscv_init_multiext_cfg() target/riscv/kvm: minor fixes/tweaks target/riscv: Fix write_misa vs aligned next_pc target/riscv: Move insn_len to internals.h ... Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
This commit is contained in:
@@ -328,6 +328,7 @@ F: include/hw/char/riscv_htif.h
|
||||
F: include/hw/riscv/
|
||||
F: linux-user/host/riscv32/
|
||||
F: linux-user/host/riscv64/
|
||||
F: common-user/host/riscv*
|
||||
F: tests/functional/test_riscv*
|
||||
F: tests/tcg/riscv64/
|
||||
|
||||
|
||||
@@ -69,11 +69,11 @@ safe_syscall_end:
|
||||
|
||||
/* code path setting errno */
|
||||
0: neg a0, a0
|
||||
j safe_syscall_set_errno_tail
|
||||
tail safe_syscall_set_errno_tail
|
||||
|
||||
/* code path when we didn't execute the syscall */
|
||||
2: li a0, QEMU_ERESTARTSYS
|
||||
j safe_syscall_set_errno_tail
|
||||
tail safe_syscall_set_errno_tail
|
||||
|
||||
.cfi_endproc
|
||||
.size safe_syscall_base, .-safe_syscall_base
|
||||
|
||||
@@ -5,10 +5,10 @@ Microchip PolarFire SoC Icicle Kit integrates a PolarFire SoC, with one
|
||||
SiFive's E51 plus four U54 cores and many on-chip peripherals and an FPGA.
|
||||
|
||||
For more details about Microchip PolarFire SoC, please see:
|
||||
https://www.microsemi.com/product-directory/soc-fpgas/5498-polarfire-soc-fpga
|
||||
https://www.microchip.com/en-us/products/fpgas-and-plds/system-on-chip-fpgas/polarfire-soc-fpgas
|
||||
|
||||
The Icicle Kit board information can be found here:
|
||||
https://www.microsemi.com/existing-parts/parts/152514
|
||||
https://www.microchip.com/en-us/development-tool/mpfs-icicle-kit-es
|
||||
|
||||
Supported devices
|
||||
-----------------
|
||||
@@ -26,95 +26,48 @@ The ``microchip-icicle-kit`` machine supports the following devices:
|
||||
* 2 GEM Ethernet controllers
|
||||
* 1 SDHC storage controller
|
||||
|
||||
The memory is set to 1537 MiB by default. A sanity check on RAM size is
|
||||
performed in the machine init routine to prompt user to increase the RAM size
|
||||
to > 1537 MiB when less than 1537 MiB RAM is detected.
|
||||
|
||||
Boot options
|
||||
------------
|
||||
|
||||
The ``microchip-icicle-kit`` machine can start using the standard -bios
|
||||
functionality for loading its BIOS image, aka Hart Software Services (HSS_).
|
||||
HSS loads the second stage bootloader U-Boot from an SD card. Then a kernel
|
||||
can be loaded from U-Boot. It also supports direct kernel booting via the
|
||||
-kernel option along with the device tree blob via -dtb. When direct kernel
|
||||
boot is used, the OpenSBI fw_dynamic BIOS image is used to boot a payload
|
||||
like U-Boot or OS kernel directly.
|
||||
The ``microchip-icicle-kit`` machine provides some options to run a firmware
|
||||
(BIOS) or a kernel image. QEMU follows below truth table to select the
|
||||
firmware:
|
||||
|
||||
The user provided DTB should have the following requirements:
|
||||
|
||||
* The /cpus node should contain at least one subnode for E51 and the number
|
||||
of subnodes should match QEMU's ``-smp`` option
|
||||
* The /memory reg size should match QEMU’s selected ram_size via ``-m``
|
||||
* Should contain a node for the CLINT device with a compatible string
|
||||
"riscv,clint0"
|
||||
|
||||
QEMU follows below truth table to select which payload to execute:
|
||||
|
||||
===== ========== ========== =======
|
||||
-bios -kernel -dtb payload
|
||||
===== ========== ========== =======
|
||||
N N don't care HSS
|
||||
Y don't care don't care HSS
|
||||
N Y Y kernel
|
||||
===== ========== ========== =======
|
||||
|
||||
The memory is set to 1537 MiB by default which is the minimum required high
|
||||
memory size by HSS. A sanity check on ram size is performed in the machine
|
||||
init routine to prompt user to increase the RAM size to > 1537 MiB when less
|
||||
than 1537 MiB ram is detected.
|
||||
|
||||
Running HSS
|
||||
-----------
|
||||
|
||||
HSS 2020.12 release is tested at the time of writing. To build an HSS image
|
||||
that can be booted by the ``microchip-icicle-kit`` machine, type the following
|
||||
in the HSS source tree:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ export CROSS_COMPILE=riscv64-linux-
|
||||
$ cp boards/mpfs-icicle-kit-es/def_config .config
|
||||
$ make BOARD=mpfs-icicle-kit-es
|
||||
|
||||
Download the official SD card image released by Microchip and prepare it for
|
||||
QEMU usage:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ wget ftp://ftpsoc.microsemi.com/outgoing/core-image-minimal-dev-icicle-kit-es-sd-20201009141623.rootfs.wic.gz
|
||||
$ gunzip core-image-minimal-dev-icicle-kit-es-sd-20201009141623.rootfs.wic.gz
|
||||
$ qemu-img resize core-image-minimal-dev-icicle-kit-es-sd-20201009141623.rootfs.wic 4G
|
||||
|
||||
Then we can boot the machine by:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ qemu-system-riscv64 -M microchip-icicle-kit -smp 5 \
|
||||
-bios path/to/hss.bin -sd path/to/sdcard.img \
|
||||
-nic user,model=cadence_gem \
|
||||
-nic tap,ifname=tap,model=cadence_gem,script=no \
|
||||
-display none -serial stdio \
|
||||
-chardev socket,id=serial1,path=serial1.sock,server=on,wait=on \
|
||||
-serial chardev:serial1
|
||||
|
||||
With above command line, current terminal session will be used for the first
|
||||
serial port. Open another terminal window, and use ``minicom`` to connect the
|
||||
second serial port.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ minicom -D unix\#serial1.sock
|
||||
|
||||
HSS output is on the first serial port (stdio) and U-Boot outputs on the
|
||||
second serial port. U-Boot will automatically load the Linux kernel from
|
||||
the SD card image.
|
||||
============= =========== ======================================
|
||||
-bios -kernel firmware
|
||||
============= =========== ======================================
|
||||
none N this is an error
|
||||
none Y the kernel image
|
||||
NULL, default N hss.bin
|
||||
NULL, default Y opensbi-riscv64-generic-fw_dynamic.bin
|
||||
other don't care the BIOS image
|
||||
============= =========== ======================================
|
||||
|
||||
Direct Kernel Boot
|
||||
------------------
|
||||
|
||||
Sometimes we just want to test booting a new kernel, and transforming the
|
||||
kernel image to the format required by the HSS bootflow is tedious. We can
|
||||
use '-kernel' for direct kernel booting just like other RISC-V machines do.
|
||||
Use the ``-kernel`` option to directly run a kernel image. When a direct
|
||||
kernel boot is requested, a device tree blob may be specified via the ``-dtb``
|
||||
option. Unlike other QEMU machines, this machine does not generate a device
|
||||
tree for the kernel. It shall be provided by the user. The user provided DTB
|
||||
should meet the following requirements:
|
||||
|
||||
In this mode, the OpenSBI fw_dynamic BIOS image for 'generic' platform is
|
||||
used to boot an S-mode payload like U-Boot or OS kernel directly.
|
||||
* The ``/cpus`` node should contain at least one subnode for E51 and the number
|
||||
of subnodes should match QEMU's ``-smp`` option.
|
||||
|
||||
* The ``/memory`` reg size should match QEMU’s selected RAM size via the ``-m``
|
||||
option.
|
||||
|
||||
* It should contain a node for the CLINT device with a compatible string
|
||||
"riscv,clint0".
|
||||
|
||||
When ``-bios`` is not specified or set to ``default``, the OpenSBI
|
||||
``fw_dynamic`` BIOS image for the ``generic`` platform is used to boot an
|
||||
S-mode payload like U-Boot or OS kernel directly.
|
||||
|
||||
For example, the following commands show building a U-Boot image from U-Boot
|
||||
mainline v2021.07 for the Microchip Icicle Kit board:
|
||||
@@ -146,4 +99,13 @@ CAVEATS:
|
||||
``u-boot.bin`` has to be used which does contain one. To use the ELF image,
|
||||
we need to change to CONFIG_OF_EMBED or CONFIG_OF_PRIOR_STAGE.
|
||||
|
||||
Running HSS
|
||||
-----------
|
||||
|
||||
The machine ``microchip-icicle-kit`` used to run the Hart Software Services
|
||||
(HSS_), however, the HSS development progressed and the QEMU machine
|
||||
implementation lacks behind. Currently, running the HSS no longer works.
|
||||
There is missing support in the clock and memory controller devices. In
|
||||
particular, reading from the SD card does not work.
|
||||
|
||||
.. _HSS: https://github.com/polarfire-soc/hart-software-services
|
||||
|
||||
@@ -27,7 +27,9 @@
|
||||
#include "hw/irq.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "hw/misc/mchp_pfsoc_sysreg.h"
|
||||
#include "system/runstate.h"
|
||||
|
||||
#define MSS_RESET_CR 0x18
|
||||
#define ENVM_CR 0xb8
|
||||
#define MESSAGE_INT 0x118c
|
||||
|
||||
@@ -56,6 +58,11 @@ static void mchp_pfsoc_sysreg_write(void *opaque, hwaddr offset,
|
||||
{
|
||||
MchpPfSoCSysregState *s = opaque;
|
||||
switch (offset) {
|
||||
case MSS_RESET_CR:
|
||||
if (value == 0xdead) {
|
||||
qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
|
||||
}
|
||||
break;
|
||||
case MESSAGE_INT:
|
||||
qemu_irq_lower(s->irq);
|
||||
break;
|
||||
|
||||
+113
-40
@@ -39,6 +39,7 @@
|
||||
#include "qemu/units.h"
|
||||
#include "qemu/cutils.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qapi/visitor.h"
|
||||
#include "hw/boards.h"
|
||||
#include "hw/loader.h"
|
||||
#include "hw/sysbus.h"
|
||||
@@ -61,9 +62,6 @@
|
||||
#define BIOS_FILENAME "hss.bin"
|
||||
#define RESET_VECTOR 0x20220000
|
||||
|
||||
/* CLINT timebase frequency */
|
||||
#define CLINT_TIMEBASE_FREQ 1000000
|
||||
|
||||
/* GEM version */
|
||||
#define GEM_REVISION 0x0107010c
|
||||
|
||||
@@ -193,6 +191,7 @@ static void microchip_pfsoc_soc_instance_init(Object *obj)
|
||||
static void microchip_pfsoc_soc_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
MachineState *ms = MACHINE(qdev_get_machine());
|
||||
MicrochipIcicleKitState *iks = MICROCHIP_ICICLE_KIT_MACHINE(ms);
|
||||
MicrochipPFSoCState *s = MICROCHIP_PFSOC(dev);
|
||||
const MemMapEntry *memmap = microchip_pfsoc_memmap;
|
||||
MemoryRegion *system_memory = get_system_memory();
|
||||
@@ -253,7 +252,7 @@ static void microchip_pfsoc_soc_realize(DeviceState *dev, Error **errp)
|
||||
memmap[MICROCHIP_PFSOC_CLINT].base + RISCV_ACLINT_SWI_SIZE,
|
||||
RISCV_ACLINT_DEFAULT_MTIMER_SIZE, 0, ms->smp.cpus,
|
||||
RISCV_ACLINT_DEFAULT_MTIMECMP, RISCV_ACLINT_DEFAULT_MTIME,
|
||||
CLINT_TIMEBASE_FREQ, false);
|
||||
iks->clint_timebase_freq, false);
|
||||
|
||||
/* L2 cache controller */
|
||||
create_unimplemented_device("microchip.pfsoc.l2cc",
|
||||
@@ -516,7 +515,6 @@ static void microchip_icicle_kit_machine_init(MachineState *machine)
|
||||
uint64_t mem_low_size, mem_high_size;
|
||||
hwaddr firmware_load_addr;
|
||||
const char *firmware_name;
|
||||
bool kernel_as_payload = false;
|
||||
target_ulong firmware_end_addr, kernel_start_addr;
|
||||
uint64_t kernel_entry;
|
||||
uint64_t fdt_load_addr;
|
||||
@@ -579,45 +577,50 @@ static void microchip_icicle_kit_machine_init(MachineState *machine)
|
||||
}
|
||||
|
||||
/*
|
||||
* We follow the following table to select which payload we execute.
|
||||
* We follow the following table to select which firmware we use.
|
||||
*
|
||||
* -bios | -kernel | payload
|
||||
* -------+------------+--------
|
||||
* N | N | HSS
|
||||
* Y | don't care | HSS
|
||||
* N | Y | kernel
|
||||
*
|
||||
* This ensures backwards compatibility with how we used to expose -bios
|
||||
* to users but allows them to run through direct kernel booting as well.
|
||||
*
|
||||
* When -kernel is used for direct boot, -dtb must be present to provide
|
||||
* a valid device tree for the board, as we don't generate device tree.
|
||||
* -bios | -kernel | firmware
|
||||
* --------------+------------+--------
|
||||
* none | N | error
|
||||
* none | Y | kernel
|
||||
* NULL, default | N | BIOS_FILENAME
|
||||
* NULL, default | Y | RISCV64_BIOS_BIN
|
||||
* other | don't care | other
|
||||
*/
|
||||
|
||||
if (machine->kernel_filename && machine->dtb) {
|
||||
int fdt_size;
|
||||
machine->fdt = load_device_tree(machine->dtb, &fdt_size);
|
||||
if (!machine->fdt) {
|
||||
error_report("load_device_tree() failed");
|
||||
if (machine->firmware && !strcmp(machine->firmware, "none")) {
|
||||
if (!machine->kernel_filename) {
|
||||
error_report("for -bios none, a kernel is required");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
firmware_name = RISCV64_BIOS_BIN;
|
||||
firmware_load_addr = memmap[MICROCHIP_PFSOC_DRAM_LO].base;
|
||||
kernel_as_payload = true;
|
||||
}
|
||||
|
||||
if (!kernel_as_payload) {
|
||||
firmware_name = BIOS_FILENAME;
|
||||
firmware_name = NULL;
|
||||
firmware_load_addr = RESET_VECTOR;
|
||||
} else if (!machine->firmware || !strcmp(machine->firmware, "default")) {
|
||||
if (machine->kernel_filename) {
|
||||
firmware_name = RISCV64_BIOS_BIN;
|
||||
firmware_load_addr = memmap[MICROCHIP_PFSOC_DRAM_LO].base;
|
||||
} else {
|
||||
firmware_name = BIOS_FILENAME;
|
||||
firmware_load_addr = RESET_VECTOR;
|
||||
}
|
||||
} else {
|
||||
firmware_name = machine->firmware;
|
||||
firmware_load_addr = RESET_VECTOR;
|
||||
}
|
||||
|
||||
/* Load the firmware */
|
||||
firmware_end_addr = riscv_find_and_load_firmware(machine, firmware_name,
|
||||
&firmware_load_addr, NULL);
|
||||
/* Load the firmware if necessary */
|
||||
firmware_end_addr = firmware_load_addr;
|
||||
if (firmware_name) {
|
||||
char *filename = riscv_find_firmware(firmware_name, NULL);
|
||||
if (filename) {
|
||||
firmware_end_addr = riscv_load_firmware(filename,
|
||||
&firmware_load_addr, NULL);
|
||||
g_free(filename);
|
||||
}
|
||||
}
|
||||
|
||||
riscv_boot_info_init(&boot_info, &s->soc.u_cpus);
|
||||
if (kernel_as_payload) {
|
||||
if (machine->kernel_filename) {
|
||||
kernel_start_addr = riscv_calc_kernel_start_addr(&boot_info,
|
||||
firmware_end_addr);
|
||||
|
||||
@@ -625,20 +628,82 @@ static void microchip_icicle_kit_machine_init(MachineState *machine)
|
||||
true, NULL);
|
||||
kernel_entry = boot_info.image_low_addr;
|
||||
|
||||
/* Compute the fdt load address in dram */
|
||||
fdt_load_addr = riscv_compute_fdt_addr(memmap[MICROCHIP_PFSOC_DRAM_LO].base,
|
||||
memmap[MICROCHIP_PFSOC_DRAM_LO].size,
|
||||
machine, &boot_info);
|
||||
riscv_load_fdt(fdt_load_addr, machine->fdt);
|
||||
if (machine->dtb) {
|
||||
int fdt_size;
|
||||
machine->fdt = load_device_tree(machine->dtb, &fdt_size);
|
||||
if (!machine->fdt) {
|
||||
error_report("load_device_tree() failed");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Compute the FDT load address in DRAM */
|
||||
hwaddr kernel_ram_base = memmap[MICROCHIP_PFSOC_DRAM_LO].base;
|
||||
hwaddr kernel_ram_size = memmap[MICROCHIP_PFSOC_DRAM_LO].size;
|
||||
|
||||
if (kernel_entry - kernel_ram_base >= kernel_ram_size) {
|
||||
kernel_ram_base = memmap[MICROCHIP_PFSOC_DRAM_HI].base;
|
||||
kernel_ram_size = mem_high_size;
|
||||
}
|
||||
|
||||
fdt_load_addr = riscv_compute_fdt_addr(kernel_ram_base, kernel_ram_size,
|
||||
machine, &boot_info);
|
||||
riscv_load_fdt(fdt_load_addr, machine->fdt);
|
||||
} else {
|
||||
warn_report_once("The QEMU microchip-icicle-kit machine does not "
|
||||
"generate a device tree, so no device tree is "
|
||||
"being provided to the guest.");
|
||||
fdt_load_addr = 0;
|
||||
}
|
||||
|
||||
hwaddr start_addr;
|
||||
if (firmware_name) {
|
||||
start_addr = firmware_load_addr;
|
||||
} else {
|
||||
start_addr = kernel_entry;
|
||||
}
|
||||
|
||||
/* Load the reset vector */
|
||||
riscv_setup_rom_reset_vec(machine, &s->soc.u_cpus, firmware_load_addr,
|
||||
riscv_setup_rom_reset_vec(machine, &s->soc.u_cpus, start_addr,
|
||||
memmap[MICROCHIP_PFSOC_ENVM_DATA].base,
|
||||
memmap[MICROCHIP_PFSOC_ENVM_DATA].size,
|
||||
kernel_entry, fdt_load_addr);
|
||||
}
|
||||
}
|
||||
|
||||
static void microchip_icicle_kit_set_clint_timebase_freq(Object *obj,
|
||||
Visitor *v,
|
||||
const char *name,
|
||||
void *opaque,
|
||||
Error **errp)
|
||||
{
|
||||
MicrochipIcicleKitState *s = MICROCHIP_ICICLE_KIT_MACHINE(obj);
|
||||
uint32_t value;
|
||||
|
||||
if (!visit_type_uint32(v, name, &value, errp)) {
|
||||
return;
|
||||
}
|
||||
|
||||
s->clint_timebase_freq = value;
|
||||
}
|
||||
|
||||
static void microchip_icicle_kit_get_clint_timebase_freq(Object *obj,
|
||||
Visitor *v,
|
||||
const char *name,
|
||||
void *opaque,
|
||||
Error **errp)
|
||||
{
|
||||
MicrochipIcicleKitState *s = MICROCHIP_ICICLE_KIT_MACHINE(obj);
|
||||
uint32_t value = s->clint_timebase_freq;
|
||||
|
||||
visit_type_uint32(v, name, &value, errp);
|
||||
}
|
||||
|
||||
static void microchip_icicle_kit_machine_instance_init(Object *obj)
|
||||
{
|
||||
MicrochipIcicleKitState *m = MICROCHIP_ICICLE_KIT_MACHINE(obj);
|
||||
m->clint_timebase_freq = 1000000;
|
||||
}
|
||||
|
||||
static void microchip_icicle_kit_machine_class_init(ObjectClass *oc,
|
||||
const void *data)
|
||||
{
|
||||
@@ -661,12 +726,20 @@ static void microchip_icicle_kit_machine_class_init(ObjectClass *oc,
|
||||
* See memory_tests() in mss_ddr.c in the HSS source code.
|
||||
*/
|
||||
mc->default_ram_size = 1537 * MiB;
|
||||
|
||||
object_class_property_add(oc, "clint-timebase-frequency", "uint32_t",
|
||||
microchip_icicle_kit_get_clint_timebase_freq,
|
||||
microchip_icicle_kit_set_clint_timebase_freq,
|
||||
NULL, NULL);
|
||||
object_class_property_set_description(oc, "clint-timebase-frequency",
|
||||
"Set CLINT timebase frequency in Hz.");
|
||||
}
|
||||
|
||||
static const TypeInfo microchip_icicle_kit_machine_typeinfo = {
|
||||
.name = MACHINE_TYPE_NAME("microchip-icicle-kit"),
|
||||
.parent = TYPE_MACHINE,
|
||||
.class_init = microchip_icicle_kit_machine_class_init,
|
||||
.instance_init = microchip_icicle_kit_machine_instance_init,
|
||||
.instance_size = sizeof(MicrochipIcicleKitState),
|
||||
};
|
||||
|
||||
|
||||
@@ -72,7 +72,7 @@ static void csr_call(char *cmd, uint64_t cpu_num, int csrno, uint64_t *val)
|
||||
ret = riscv_csrr(env, csrno, (target_ulong *)val);
|
||||
} else if (strcmp(cmd, "set_csr") == 0) {
|
||||
ret = riscv_csrrw(env, csrno, NULL, *(target_ulong *)val,
|
||||
MAKE_64BIT_MASK(0, TARGET_LONG_BITS));
|
||||
MAKE_64BIT_MASK(0, TARGET_LONG_BITS), 0);
|
||||
}
|
||||
|
||||
g_assert(ret == RISCV_EXCP_NONE);
|
||||
@@ -104,8 +104,11 @@ static bool csr_qtest_callback(CharBackend *chr, gchar **words)
|
||||
|
||||
static void riscv_cpu_register_csr_qtest_callback(void)
|
||||
{
|
||||
static GOnce once;
|
||||
g_once(&once, (GThreadFunc)qtest_set_command_cb, csr_qtest_callback);
|
||||
static bool first = true;
|
||||
if (first) {
|
||||
first = false;
|
||||
qtest_set_command_cb(csr_qtest_callback);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -198,6 +198,32 @@ acpi_dsdt_add_uart(Aml *scope, const MemMapEntry *uart_memmap,
|
||||
aml_append(scope, dev);
|
||||
}
|
||||
|
||||
/*
|
||||
* Add DSDT entry for the IOMMU platform device.
|
||||
* ACPI ID for IOMMU is defined in the section 6.2 of RISC-V BRS spec.
|
||||
* https://github.com/riscv-non-isa/riscv-brs/releases/download/v0.8/riscv-brs-spec.pdf
|
||||
*/
|
||||
static void acpi_dsdt_add_iommu_sys(Aml *scope, const MemMapEntry *iommu_memmap,
|
||||
uint32_t iommu_irq)
|
||||
{
|
||||
uint32_t i;
|
||||
|
||||
Aml *dev = aml_device("IMU0");
|
||||
aml_append(dev, aml_name_decl("_HID", aml_string("RSCV0004")));
|
||||
aml_append(dev, aml_name_decl("_UID", aml_int(0)));
|
||||
|
||||
Aml *crs = aml_resource_template();
|
||||
aml_append(crs, aml_memory32_fixed(iommu_memmap->base,
|
||||
iommu_memmap->size, AML_READ_WRITE));
|
||||
for (i = iommu_irq; i < iommu_irq + 4; i++) {
|
||||
aml_append(crs, aml_interrupt(AML_CONSUMER, AML_EDGE, AML_ACTIVE_LOW,
|
||||
AML_EXCLUSIVE, &i, 1));
|
||||
}
|
||||
|
||||
aml_append(dev, aml_name_decl("_CRS", crs));
|
||||
aml_append(scope, dev);
|
||||
}
|
||||
|
||||
/*
|
||||
* Serial Port Console Redirection Table (SPCR)
|
||||
* Rev: 1.10
|
||||
@@ -450,6 +476,9 @@ static void build_dsdt(GArray *table_data,
|
||||
}
|
||||
|
||||
acpi_dsdt_add_uart(scope, &memmap[VIRT_UART0], UART0_IRQ);
|
||||
if (virt_is_iommu_sys_enabled(s)) {
|
||||
acpi_dsdt_add_iommu_sys(scope, &memmap[VIRT_IOMMU_SYS], IOMMU_SYS_IRQ);
|
||||
}
|
||||
|
||||
if (socket_count == 1) {
|
||||
virtio_acpi_dsdt_add(scope, memmap[VIRT_VIRTIO].base,
|
||||
@@ -602,6 +631,187 @@ static void build_madt(GArray *table_data,
|
||||
acpi_table_end(linker, &table);
|
||||
}
|
||||
|
||||
#define ID_MAPPING_ENTRY_SIZE 20
|
||||
#define IOMMU_ENTRY_SIZE 40
|
||||
#define RISCV_INTERRUPT_WIRE_OFFSSET 40
|
||||
#define ROOT_COMPLEX_ENTRY_SIZE 20
|
||||
#define RIMT_NODE_OFFSET 48
|
||||
|
||||
/*
|
||||
* ID Mapping Structure
|
||||
*/
|
||||
static void build_rimt_id_mapping(GArray *table_data, uint32_t source_id_base,
|
||||
uint32_t num_ids, uint32_t dest_id_base)
|
||||
{
|
||||
/* Source ID Base */
|
||||
build_append_int_noprefix(table_data, source_id_base, 4);
|
||||
/* Number of IDs */
|
||||
build_append_int_noprefix(table_data, num_ids, 4);
|
||||
/* Destination Device ID Base */
|
||||
build_append_int_noprefix(table_data, source_id_base, 4);
|
||||
/* Destination IOMMU Offset */
|
||||
build_append_int_noprefix(table_data, dest_id_base, 4);
|
||||
/* Flags */
|
||||
build_append_int_noprefix(table_data, 0, 4);
|
||||
}
|
||||
|
||||
struct AcpiRimtIdMapping {
|
||||
uint32_t source_id_base;
|
||||
uint32_t num_ids;
|
||||
};
|
||||
typedef struct AcpiRimtIdMapping AcpiRimtIdMapping;
|
||||
|
||||
/* Build the rimt ID mapping to IOMMU for a given PCI host bridge */
|
||||
static int rimt_host_bridges(Object *obj, void *opaque)
|
||||
{
|
||||
GArray *idmap_blob = opaque;
|
||||
|
||||
if (object_dynamic_cast(obj, TYPE_PCI_HOST_BRIDGE)) {
|
||||
PCIBus *bus = PCI_HOST_BRIDGE(obj)->bus;
|
||||
|
||||
if (bus && !pci_bus_bypass_iommu(bus)) {
|
||||
int min_bus, max_bus;
|
||||
|
||||
pci_bus_range(bus, &min_bus, &max_bus);
|
||||
|
||||
AcpiRimtIdMapping idmap = {
|
||||
.source_id_base = min_bus << 8,
|
||||
.num_ids = (max_bus - min_bus + 1) << 8,
|
||||
};
|
||||
g_array_append_val(idmap_blob, idmap);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rimt_idmap_compare(gconstpointer a, gconstpointer b)
|
||||
{
|
||||
AcpiRimtIdMapping *idmap_a = (AcpiRimtIdMapping *)a;
|
||||
AcpiRimtIdMapping *idmap_b = (AcpiRimtIdMapping *)b;
|
||||
|
||||
return idmap_a->source_id_base - idmap_b->source_id_base;
|
||||
}
|
||||
|
||||
/*
|
||||
* RISC-V IO Mapping Table (RIMT)
|
||||
* https://github.com/riscv-non-isa/riscv-acpi-rimt/releases/download/v0.99/rimt-spec.pdf
|
||||
*/
|
||||
static void build_rimt(GArray *table_data, BIOSLinker *linker,
|
||||
RISCVVirtState *s)
|
||||
{
|
||||
int i, nb_nodes, rc_mapping_count;
|
||||
size_t node_size, iommu_offset = 0;
|
||||
uint32_t id = 0;
|
||||
g_autoptr(GArray) iommu_idmaps = g_array_new(false, true,
|
||||
sizeof(AcpiRimtIdMapping));
|
||||
|
||||
AcpiTable table = { .sig = "RIMT", .rev = 1, .oem_id = s->oem_id,
|
||||
.oem_table_id = s->oem_table_id };
|
||||
|
||||
acpi_table_begin(&table, table_data);
|
||||
|
||||
object_child_foreach_recursive(object_get_root(),
|
||||
rimt_host_bridges, iommu_idmaps);
|
||||
|
||||
/* Sort the ID mapping by Source ID Base*/
|
||||
g_array_sort(iommu_idmaps, rimt_idmap_compare);
|
||||
|
||||
nb_nodes = 2; /* RC, IOMMU */
|
||||
rc_mapping_count = iommu_idmaps->len;
|
||||
/* Number of RIMT Nodes */
|
||||
build_append_int_noprefix(table_data, nb_nodes, 4);
|
||||
|
||||
/* Offset to Array of RIMT Nodes */
|
||||
build_append_int_noprefix(table_data, RIMT_NODE_OFFSET, 4);
|
||||
build_append_int_noprefix(table_data, 0, 4); /* Reserved */
|
||||
|
||||
iommu_offset = table_data->len - table.table_offset;
|
||||
/* IOMMU Device Structure */
|
||||
build_append_int_noprefix(table_data, 0, 1); /* Type - IOMMU*/
|
||||
build_append_int_noprefix(table_data, 1, 1); /* Revision */
|
||||
node_size = IOMMU_ENTRY_SIZE;
|
||||
build_append_int_noprefix(table_data, node_size, 2); /* Length */
|
||||
build_append_int_noprefix(table_data, 0, 2); /* Reserved */
|
||||
build_append_int_noprefix(table_data, id++, 2); /* ID */
|
||||
if (virt_is_iommu_sys_enabled(s)) {
|
||||
/* Hardware ID */
|
||||
build_append_int_noprefix(table_data, 'R', 1);
|
||||
build_append_int_noprefix(table_data, 'S', 1);
|
||||
build_append_int_noprefix(table_data, 'C', 1);
|
||||
build_append_int_noprefix(table_data, 'V', 1);
|
||||
build_append_int_noprefix(table_data, '0', 1);
|
||||
build_append_int_noprefix(table_data, '0', 1);
|
||||
build_append_int_noprefix(table_data, '0', 1);
|
||||
build_append_int_noprefix(table_data, '4', 1);
|
||||
/* Base Address */
|
||||
build_append_int_noprefix(table_data,
|
||||
s->memmap[VIRT_IOMMU_SYS].base, 8);
|
||||
build_append_int_noprefix(table_data, 0, 4); /* Flags */
|
||||
} else {
|
||||
/* Hardware ID */
|
||||
build_append_int_noprefix(table_data, '0', 1);
|
||||
build_append_int_noprefix(table_data, '0', 1);
|
||||
build_append_int_noprefix(table_data, '1', 1);
|
||||
build_append_int_noprefix(table_data, '0', 1);
|
||||
build_append_int_noprefix(table_data, '0', 1);
|
||||
build_append_int_noprefix(table_data, '0', 1);
|
||||
build_append_int_noprefix(table_data, '1', 1);
|
||||
build_append_int_noprefix(table_data, '4', 1);
|
||||
|
||||
build_append_int_noprefix(table_data, 0, 8); /* Base Address */
|
||||
build_append_int_noprefix(table_data, 1, 4); /* Flags */
|
||||
}
|
||||
|
||||
build_append_int_noprefix(table_data, 0, 4); /* Proximity Domain */
|
||||
build_append_int_noprefix(table_data, 0, 2); /* PCI Segment number */
|
||||
/* PCIe B/D/F */
|
||||
if (virt_is_iommu_sys_enabled(s)) {
|
||||
build_append_int_noprefix(table_data, 0, 2);
|
||||
} else {
|
||||
build_append_int_noprefix(table_data, s->pci_iommu_bdf, 2);
|
||||
}
|
||||
/* Number of interrupt wires */
|
||||
build_append_int_noprefix(table_data, 0, 2);
|
||||
/* Interrupt wire array offset */
|
||||
build_append_int_noprefix(table_data, RISCV_INTERRUPT_WIRE_OFFSSET, 2);
|
||||
|
||||
/* PCIe Root Complex Node */
|
||||
build_append_int_noprefix(table_data, 1, 1); /* Type */
|
||||
build_append_int_noprefix(table_data, 1, 1); /* Revision */
|
||||
node_size = ROOT_COMPLEX_ENTRY_SIZE +
|
||||
ID_MAPPING_ENTRY_SIZE * rc_mapping_count;
|
||||
build_append_int_noprefix(table_data, node_size, 2); /* Length */
|
||||
build_append_int_noprefix(table_data, 0, 2); /* Reserved */
|
||||
build_append_int_noprefix(table_data, id++, 2); /* ID */
|
||||
build_append_int_noprefix(table_data, 0, 4); /* Flags */
|
||||
build_append_int_noprefix(table_data, 0, 2); /* Reserved */
|
||||
/* PCI Segment number */
|
||||
build_append_int_noprefix(table_data, 0, 2);
|
||||
/* ID mapping array offset */
|
||||
build_append_int_noprefix(table_data, ROOT_COMPLEX_ENTRY_SIZE, 2);
|
||||
/* Number of ID mappings */
|
||||
build_append_int_noprefix(table_data, rc_mapping_count, 2);
|
||||
|
||||
/* Output Reference */
|
||||
AcpiRimtIdMapping *range;
|
||||
|
||||
/* ID mapping array */
|
||||
for (i = 0; i < iommu_idmaps->len; i++) {
|
||||
range = &g_array_index(iommu_idmaps, AcpiRimtIdMapping, i);
|
||||
if (virt_is_iommu_sys_enabled(s)) {
|
||||
range->source_id_base = 0;
|
||||
} else {
|
||||
range->source_id_base = s->pci_iommu_bdf + 1;
|
||||
}
|
||||
range->num_ids = 0xffff - s->pci_iommu_bdf;
|
||||
build_rimt_id_mapping(table_data, range->source_id_base,
|
||||
range->num_ids, iommu_offset);
|
||||
}
|
||||
|
||||
acpi_table_end(linker, &table);
|
||||
}
|
||||
|
||||
/*
|
||||
* ACPI spec, Revision 6.5+
|
||||
* 5.2.16 System Resource Affinity Table (SRAT)
|
||||
@@ -679,6 +889,11 @@ static void virt_acpi_build(RISCVVirtState *s, AcpiBuildTables *tables)
|
||||
acpi_add_table(table_offsets, tables_blob);
|
||||
build_rhct(tables_blob, tables->linker, s);
|
||||
|
||||
if (virt_is_iommu_sys_enabled(s) || s->pci_iommu_bdf) {
|
||||
acpi_add_table(table_offsets, tables_blob);
|
||||
build_rimt(tables_blob, tables->linker, s);
|
||||
}
|
||||
|
||||
acpi_add_table(table_offsets, tables_blob);
|
||||
spcr_setup(tables_blob, tables->linker, s);
|
||||
|
||||
|
||||
+141
-132
File diff suppressed because it is too large
Load Diff
@@ -67,6 +67,7 @@ typedef struct MicrochipIcicleKitState {
|
||||
MachineState parent_obj;
|
||||
|
||||
/*< public >*/
|
||||
uint32_t clint_timebase_freq;
|
||||
MicrochipPFSoCState soc;
|
||||
} MicrochipIcicleKitState;
|
||||
|
||||
|
||||
@@ -63,6 +63,7 @@ struct RISCVVirtState {
|
||||
const MemMapEntry *memmap;
|
||||
struct GPEXHost *gpex_host;
|
||||
OnOffAuto iommu_sys;
|
||||
uint16_t pci_iommu_bdf;
|
||||
};
|
||||
|
||||
enum {
|
||||
|
||||
+9
-7
@@ -75,6 +75,7 @@ const char *riscv_get_misa_ext_name(uint32_t bit);
|
||||
const char *riscv_get_misa_ext_description(uint32_t bit);
|
||||
|
||||
#define CPU_CFG_OFFSET(_prop) offsetof(struct RISCVCPUConfig, _prop)
|
||||
#define ENV_CSR_OFFSET(_csr) offsetof(CPURISCVState, _csr)
|
||||
|
||||
typedef struct riscv_cpu_profile {
|
||||
struct riscv_cpu_profile *u_parent;
|
||||
@@ -813,8 +814,8 @@ RISCVException riscv_csrr(CPURISCVState *env, int csrno,
|
||||
target_ulong *ret_value);
|
||||
|
||||
RISCVException riscv_csrrw(CPURISCVState *env, int csrno,
|
||||
target_ulong *ret_value,
|
||||
target_ulong new_value, target_ulong write_mask);
|
||||
target_ulong *ret_value, target_ulong new_value,
|
||||
target_ulong write_mask, uintptr_t ra);
|
||||
RISCVException riscv_csrrw_debug(CPURISCVState *env, int csrno,
|
||||
target_ulong *ret_value,
|
||||
target_ulong new_value,
|
||||
@@ -823,13 +824,13 @@ RISCVException riscv_csrrw_debug(CPURISCVState *env, int csrno,
|
||||
static inline void riscv_csr_write(CPURISCVState *env, int csrno,
|
||||
target_ulong val)
|
||||
{
|
||||
riscv_csrrw(env, csrno, NULL, val, MAKE_64BIT_MASK(0, TARGET_LONG_BITS));
|
||||
riscv_csrrw(env, csrno, NULL, val, MAKE_64BIT_MASK(0, TARGET_LONG_BITS), 0);
|
||||
}
|
||||
|
||||
static inline target_ulong riscv_csr_read(CPURISCVState *env, int csrno)
|
||||
{
|
||||
target_ulong val = 0;
|
||||
riscv_csrrw(env, csrno, &val, 0, 0);
|
||||
riscv_csrrw(env, csrno, &val, 0, 0, 0);
|
||||
return val;
|
||||
}
|
||||
|
||||
@@ -838,7 +839,8 @@ typedef RISCVException (*riscv_csr_predicate_fn)(CPURISCVState *env,
|
||||
typedef RISCVException (*riscv_csr_read_fn)(CPURISCVState *env, int csrno,
|
||||
target_ulong *ret_value);
|
||||
typedef RISCVException (*riscv_csr_write_fn)(CPURISCVState *env, int csrno,
|
||||
target_ulong new_value);
|
||||
target_ulong new_value,
|
||||
uintptr_t ra);
|
||||
typedef RISCVException (*riscv_csr_op_fn)(CPURISCVState *env, int csrno,
|
||||
target_ulong *ret_value,
|
||||
target_ulong new_value,
|
||||
@@ -847,8 +849,8 @@ typedef RISCVException (*riscv_csr_op_fn)(CPURISCVState *env, int csrno,
|
||||
RISCVException riscv_csrr_i128(CPURISCVState *env, int csrno,
|
||||
Int128 *ret_value);
|
||||
RISCVException riscv_csrrw_i128(CPURISCVState *env, int csrno,
|
||||
Int128 *ret_value,
|
||||
Int128 new_value, Int128 write_mask);
|
||||
Int128 *ret_value, Int128 new_value,
|
||||
Int128 write_mask, uintptr_t ra);
|
||||
|
||||
typedef RISCVException (*riscv_csr_read128_fn)(CPURISCVState *env, int csrno,
|
||||
Int128 *ret_value);
|
||||
|
||||
@@ -1566,9 +1566,11 @@ static int get_physical_address(CPURISCVState *env, hwaddr *physical,
|
||||
target_ulong *pte_pa = qemu_map_ram_ptr(mr->ram_block, addr1);
|
||||
target_ulong old_pte;
|
||||
if (riscv_cpu_sxl(env) == MXL_RV32) {
|
||||
old_pte = qatomic_cmpxchg((uint32_t *)pte_pa, pte, updated_pte);
|
||||
old_pte = qatomic_cmpxchg((uint32_t *)pte_pa, cpu_to_le32(pte), cpu_to_le32(updated_pte));
|
||||
old_pte = le32_to_cpu(old_pte);
|
||||
} else {
|
||||
old_pte = qatomic_cmpxchg(pte_pa, pte, updated_pte);
|
||||
old_pte = qatomic_cmpxchg(pte_pa, cpu_to_le64(pte), cpu_to_le64(updated_pte));
|
||||
old_pte = le64_to_cpu(old_pte);
|
||||
}
|
||||
if (old_pte != pte) {
|
||||
goto restart;
|
||||
|
||||
+148
-130
File diff suppressed because it is too large
Load Diff
@@ -703,14 +703,14 @@ vfredmax_vs 000111 . ..... ..... 001 ..... 1010111 @r_vm
|
||||
# Vector widening ordered and unordered float reduction sum
|
||||
vfwredusum_vs 110001 . ..... ..... 001 ..... 1010111 @r_vm
|
||||
vfwredosum_vs 110011 . ..... ..... 001 ..... 1010111 @r_vm
|
||||
vmand_mm 011001 - ..... ..... 010 ..... 1010111 @r
|
||||
vmnand_mm 011101 - ..... ..... 010 ..... 1010111 @r
|
||||
vmandn_mm 011000 - ..... ..... 010 ..... 1010111 @r
|
||||
vmxor_mm 011011 - ..... ..... 010 ..... 1010111 @r
|
||||
vmor_mm 011010 - ..... ..... 010 ..... 1010111 @r
|
||||
vmnor_mm 011110 - ..... ..... 010 ..... 1010111 @r
|
||||
vmorn_mm 011100 - ..... ..... 010 ..... 1010111 @r
|
||||
vmxnor_mm 011111 - ..... ..... 010 ..... 1010111 @r
|
||||
vmand_mm 011001 1 ..... ..... 010 ..... 1010111 @r
|
||||
vmnand_mm 011101 1 ..... ..... 010 ..... 1010111 @r
|
||||
vmandn_mm 011000 1 ..... ..... 010 ..... 1010111 @r
|
||||
vmxor_mm 011011 1 ..... ..... 010 ..... 1010111 @r
|
||||
vmor_mm 011010 1 ..... ..... 010 ..... 1010111 @r
|
||||
vmnor_mm 011110 1 ..... ..... 010 ..... 1010111 @r
|
||||
vmorn_mm 011100 1 ..... ..... 010 ..... 1010111 @r
|
||||
vmxnor_mm 011111 1 ..... ..... 010 ..... 1010111 @r
|
||||
vcpop_m 010000 . ..... 10000 010 ..... 1010111 @r2_vm
|
||||
vfirst_m 010000 . ..... 10001 010 ..... 1010111 @r2_vm
|
||||
vmsbf_m 010100 . ..... 00001 010 ..... 1010111 @r2_vm
|
||||
@@ -732,7 +732,7 @@ vrgather_vv 001100 . ..... ..... 000 ..... 1010111 @r_vm
|
||||
vrgatherei16_vv 001110 . ..... ..... 000 ..... 1010111 @r_vm
|
||||
vrgather_vx 001100 . ..... ..... 100 ..... 1010111 @r_vm
|
||||
vrgather_vi 001100 . ..... ..... 011 ..... 1010111 @r_vm
|
||||
vcompress_vm 010111 - ..... ..... 010 ..... 1010111 @r
|
||||
vcompress_vm 010111 1 ..... ..... 010 ..... 1010111 @r
|
||||
vmv1r_v 100111 1 ..... 00000 011 ..... 1010111 @r2rd
|
||||
vmv2r_v 100111 1 ..... 00001 011 ..... 1010111 @r2rd
|
||||
vmv4r_v 100111 1 ..... 00011 011 ..... 1010111 @r2rd
|
||||
|
||||
@@ -119,8 +119,11 @@ static bool trans_vfwmaccbf16_vv(DisasContext *ctx, arg_vfwmaccbf16_vv *a)
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_ZVFBFWMA(ctx);
|
||||
|
||||
uint8_t sew = ctx->sew;
|
||||
if (require_rvv(ctx) && vext_check_isa_ill(ctx) && (ctx->sew == MO_16) &&
|
||||
vext_check_dss(ctx, a->rd, a->rs1, a->rs2, a->vm)) {
|
||||
vext_check_dss(ctx, a->rd, a->rs1, a->rs2, a->vm) &&
|
||||
vext_check_input_eew(ctx, a->rd, sew + 1, a->rs1, sew, a->vm) &&
|
||||
vext_check_input_eew(ctx, a->rd, sew + 1, a->rs2, sew, a->vm)) {
|
||||
uint32_t data = 0;
|
||||
|
||||
gen_set_rm_chkfrm(ctx, RISCV_FRM_DYN);
|
||||
@@ -146,8 +149,10 @@ static bool trans_vfwmaccbf16_vf(DisasContext *ctx, arg_vfwmaccbf16_vf *a)
|
||||
REQUIRE_FPU;
|
||||
REQUIRE_ZVFBFWMA(ctx);
|
||||
|
||||
uint8_t sew = ctx->sew;
|
||||
if (require_rvv(ctx) && (ctx->sew == MO_16) && vext_check_isa_ill(ctx) &&
|
||||
vext_check_ds(ctx, a->rd, a->rs2, a->vm)) {
|
||||
vext_check_ds(ctx, a->rd, a->rs2, a->vm) &&
|
||||
vext_check_input_eew(ctx, a->rd, sew + 1, a->rs2, sew, a->vm)) {
|
||||
uint32_t data = 0;
|
||||
|
||||
gen_set_rm(ctx, RISCV_FRM_DYN);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -201,4 +201,9 @@ static inline target_ulong adjust_addr_virt(CPURISCVState *env,
|
||||
return adjust_addr_body(env, addr, true);
|
||||
}
|
||||
|
||||
static inline int insn_len(uint16_t first_word)
|
||||
{
|
||||
return (first_word & 3) == 3 ? 4 : 2;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
+212
-123
File diff suppressed because it is too large
Load Diff
@@ -71,7 +71,7 @@ target_ulong helper_csrr(CPURISCVState *env, int csr)
|
||||
void helper_csrw(CPURISCVState *env, int csr, target_ulong src)
|
||||
{
|
||||
target_ulong mask = env->xl == MXL_RV32 ? UINT32_MAX : (target_ulong)-1;
|
||||
RISCVException ret = riscv_csrrw(env, csr, NULL, src, mask);
|
||||
RISCVException ret = riscv_csrrw(env, csr, NULL, src, mask, GETPC());
|
||||
|
||||
if (ret != RISCV_EXCP_NONE) {
|
||||
riscv_raise_exception(env, ret, GETPC());
|
||||
@@ -82,7 +82,7 @@ target_ulong helper_csrrw(CPURISCVState *env, int csr,
|
||||
target_ulong src, target_ulong write_mask)
|
||||
{
|
||||
target_ulong val = 0;
|
||||
RISCVException ret = riscv_csrrw(env, csr, &val, src, write_mask);
|
||||
RISCVException ret = riscv_csrrw(env, csr, &val, src, write_mask, GETPC());
|
||||
|
||||
if (ret != RISCV_EXCP_NONE) {
|
||||
riscv_raise_exception(env, ret, GETPC());
|
||||
@@ -108,7 +108,7 @@ void helper_csrw_i128(CPURISCVState *env, int csr,
|
||||
{
|
||||
RISCVException ret = riscv_csrrw_i128(env, csr, NULL,
|
||||
int128_make128(srcl, srch),
|
||||
UINT128_MAX);
|
||||
UINT128_MAX, GETPC());
|
||||
|
||||
if (ret != RISCV_EXCP_NONE) {
|
||||
riscv_raise_exception(env, ret, GETPC());
|
||||
@@ -116,13 +116,14 @@ void helper_csrw_i128(CPURISCVState *env, int csr,
|
||||
}
|
||||
|
||||
target_ulong helper_csrrw_i128(CPURISCVState *env, int csr,
|
||||
target_ulong srcl, target_ulong srch,
|
||||
target_ulong maskl, target_ulong maskh)
|
||||
target_ulong srcl, target_ulong srch,
|
||||
target_ulong maskl, target_ulong maskh)
|
||||
{
|
||||
Int128 rv = int128_zero();
|
||||
RISCVException ret = riscv_csrrw_i128(env, csr, &rv,
|
||||
int128_make128(srcl, srch),
|
||||
int128_make128(maskl, maskh));
|
||||
int128_make128(maskl, maskh),
|
||||
GETPC());
|
||||
|
||||
if (ret != RISCV_EXCP_NONE) {
|
||||
riscv_raise_exception(env, ret, GETPC());
|
||||
|
||||
+81
-66
@@ -32,6 +32,15 @@ static bool pmp_write_cfg(CPURISCVState *env, uint32_t addr_index,
|
||||
uint8_t val);
|
||||
static uint8_t pmp_read_cfg(CPURISCVState *env, uint32_t addr_index);
|
||||
|
||||
/*
|
||||
* Convert the PMP permissions to match the truth table in the Smepmp spec.
|
||||
*/
|
||||
static inline uint8_t pmp_get_smepmp_operation(uint8_t cfg)
|
||||
{
|
||||
return ((cfg & PMP_LOCK) >> 4) | ((cfg & PMP_READ) << 2) |
|
||||
(cfg & PMP_WRITE) | ((cfg & PMP_EXEC) >> 2);
|
||||
}
|
||||
|
||||
/*
|
||||
* Accessor method to extract address matching type 'a field' from cfg reg
|
||||
*/
|
||||
@@ -46,21 +55,58 @@ static inline uint8_t pmp_get_a_field(uint8_t cfg)
|
||||
*/
|
||||
static inline int pmp_is_locked(CPURISCVState *env, uint32_t pmp_index)
|
||||
{
|
||||
/* mseccfg.RLB is set */
|
||||
if (MSECCFG_RLB_ISSET(env)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (env->pmp_state.pmp[pmp_index].cfg_reg & PMP_LOCK) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Top PMP has no 'next' to check */
|
||||
if ((pmp_index + 1u) >= MAX_RISCV_PMPS) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check whether a PMP is locked for writing or not.
|
||||
* (i.e. has LOCK flag and mseccfg.RLB is unset)
|
||||
*/
|
||||
static int pmp_is_readonly(CPURISCVState *env, uint32_t pmp_index)
|
||||
{
|
||||
return pmp_is_locked(env, pmp_index) && !MSECCFG_RLB_ISSET(env);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check whether `val` is an invalid Smepmp config value
|
||||
*/
|
||||
static int pmp_is_invalid_smepmp_cfg(CPURISCVState *env, uint8_t val)
|
||||
{
|
||||
/* No check if mseccfg.MML is not set or if mseccfg.RLB is set */
|
||||
if (!MSECCFG_MML_ISSET(env) || MSECCFG_RLB_ISSET(env)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
/*
|
||||
* Adding a rule with executable privileges that either is M-mode-only
|
||||
* or a locked Shared-Region is not possible
|
||||
*/
|
||||
switch (pmp_get_smepmp_operation(val)) {
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
case 4:
|
||||
case 5:
|
||||
case 6:
|
||||
case 7:
|
||||
case 8:
|
||||
case 12:
|
||||
case 14:
|
||||
case 15:
|
||||
return 0;
|
||||
case 9:
|
||||
case 10:
|
||||
case 11:
|
||||
case 13:
|
||||
return 1;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -91,45 +137,18 @@ static inline uint8_t pmp_read_cfg(CPURISCVState *env, uint32_t pmp_index)
|
||||
static bool pmp_write_cfg(CPURISCVState *env, uint32_t pmp_index, uint8_t val)
|
||||
{
|
||||
if (pmp_index < MAX_RISCV_PMPS) {
|
||||
bool locked = true;
|
||||
|
||||
if (riscv_cpu_cfg(env)->ext_smepmp) {
|
||||
/* mseccfg.RLB is set */
|
||||
if (MSECCFG_RLB_ISSET(env)) {
|
||||
locked = false;
|
||||
}
|
||||
|
||||
/* mseccfg.MML is not set */
|
||||
if (!MSECCFG_MML_ISSET(env) && !pmp_is_locked(env, pmp_index)) {
|
||||
locked = false;
|
||||
}
|
||||
|
||||
/* mseccfg.MML is set */
|
||||
if (MSECCFG_MML_ISSET(env)) {
|
||||
/* not adding execute bit */
|
||||
if ((val & PMP_LOCK) != 0 && (val & PMP_EXEC) != PMP_EXEC) {
|
||||
locked = false;
|
||||
}
|
||||
/* shared region and not adding X bit */
|
||||
if ((val & PMP_LOCK) != PMP_LOCK &&
|
||||
(val & 0x7) != (PMP_WRITE | PMP_EXEC)) {
|
||||
locked = false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!pmp_is_locked(env, pmp_index)) {
|
||||
locked = false;
|
||||
}
|
||||
if (env->pmp_state.pmp[pmp_index].cfg_reg == val) {
|
||||
/* no change */
|
||||
return false;
|
||||
}
|
||||
|
||||
if (locked) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "ignoring pmpcfg write - locked\n");
|
||||
} else if (env->pmp_state.pmp[pmp_index].cfg_reg != val) {
|
||||
/* If !mseccfg.MML then ignore writes with encoding RW=01 */
|
||||
if ((val & PMP_WRITE) && !(val & PMP_READ) &&
|
||||
!MSECCFG_MML_ISSET(env)) {
|
||||
return false;
|
||||
}
|
||||
if (pmp_is_readonly(env, pmp_index)) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"ignoring pmpcfg write - read only\n");
|
||||
} else if (pmp_is_invalid_smepmp_cfg(env, val)) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"ignoring pmpcfg write - invalid\n");
|
||||
} else {
|
||||
env->pmp_state.pmp[pmp_index].cfg_reg = val;
|
||||
pmp_update_rule_addr(env, pmp_index);
|
||||
return true;
|
||||
@@ -353,16 +372,6 @@ bool pmp_hart_has_privs(CPURISCVState *env, hwaddr addr,
|
||||
const uint8_t a_field =
|
||||
pmp_get_a_field(env->pmp_state.pmp[i].cfg_reg);
|
||||
|
||||
/*
|
||||
* Convert the PMP permissions to match the truth table in the
|
||||
* Smepmp spec.
|
||||
*/
|
||||
const uint8_t smepmp_operation =
|
||||
((env->pmp_state.pmp[i].cfg_reg & PMP_LOCK) >> 4) |
|
||||
((env->pmp_state.pmp[i].cfg_reg & PMP_READ) << 2) |
|
||||
(env->pmp_state.pmp[i].cfg_reg & PMP_WRITE) |
|
||||
((env->pmp_state.pmp[i].cfg_reg & PMP_EXEC) >> 2);
|
||||
|
||||
if (((s + e) == 2) && (PMP_AMATCH_OFF != a_field)) {
|
||||
/*
|
||||
* If the PMP entry is not off and the address is in range,
|
||||
@@ -381,6 +390,9 @@ bool pmp_hart_has_privs(CPURISCVState *env, hwaddr addr,
|
||||
/*
|
||||
* If mseccfg.MML Bit set, do the enhanced pmp priv check
|
||||
*/
|
||||
const uint8_t smepmp_operation =
|
||||
pmp_get_smepmp_operation(env->pmp_state.pmp[i].cfg_reg);
|
||||
|
||||
if (mode == PRV_M) {
|
||||
switch (smepmp_operation) {
|
||||
case 0:
|
||||
@@ -517,6 +529,11 @@ void pmpaddr_csr_write(CPURISCVState *env, uint32_t addr_index,
|
||||
bool is_next_cfg_tor = false;
|
||||
|
||||
if (addr_index < MAX_RISCV_PMPS) {
|
||||
if (env->pmp_state.pmp[addr_index].addr_reg == val) {
|
||||
/* no change */
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* In TOR mode, need to check the lock bit of the next pmp
|
||||
* (if there is a next).
|
||||
@@ -525,25 +542,23 @@ void pmpaddr_csr_write(CPURISCVState *env, uint32_t addr_index,
|
||||
uint8_t pmp_cfg = env->pmp_state.pmp[addr_index + 1].cfg_reg;
|
||||
is_next_cfg_tor = PMP_AMATCH_TOR == pmp_get_a_field(pmp_cfg);
|
||||
|
||||
if (pmp_is_locked(env, addr_index + 1) && is_next_cfg_tor) {
|
||||
if (pmp_is_readonly(env, addr_index + 1) && is_next_cfg_tor) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"ignoring pmpaddr write - pmpcfg + 1 locked\n");
|
||||
"ignoring pmpaddr write - pmpcfg+1 read only\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!pmp_is_locked(env, addr_index)) {
|
||||
if (env->pmp_state.pmp[addr_index].addr_reg != val) {
|
||||
env->pmp_state.pmp[addr_index].addr_reg = val;
|
||||
pmp_update_rule_addr(env, addr_index);
|
||||
if (is_next_cfg_tor) {
|
||||
pmp_update_rule_addr(env, addr_index + 1);
|
||||
}
|
||||
tlb_flush(env_cpu(env));
|
||||
if (!pmp_is_readonly(env, addr_index)) {
|
||||
env->pmp_state.pmp[addr_index].addr_reg = val;
|
||||
pmp_update_rule_addr(env, addr_index);
|
||||
if (is_next_cfg_tor) {
|
||||
pmp_update_rule_addr(env, addr_index + 1);
|
||||
}
|
||||
tlb_flush(env_cpu(env));
|
||||
} else {
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"ignoring pmpaddr write - locked\n");
|
||||
"ignoring pmpaddr write - read only\n");
|
||||
}
|
||||
} else {
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user