Merge tag 'pull-riscv-to-apply-20261027' of https://github.com/alistair23/qemu into staging

RISC-V PR for 11.2

* Add experimental Zvabd extension support
* Mask vsepc according to IALIGN
* Reset vCPU on VM reset via MP_STATE_INIT_RECEIVED
* Improve modeling of the Atlantis UART
* Fix IOMMU entry leak with ioatc-limit=0
* Fix integer handling issues in k230_gsdma and k230_decomp_gzip
* Reclaim invalidated IOATC entries for IOMMU
* Duct tape fix for QMP and RV profiles introspection
* Move RISC-V 'Z' CPU properties section to removed features
* Use TSO barriers instead of full barriers for Ztso
* Make mnstatus.MNPELP writable with Zicfilp
* Gate envcfg CBO fields on extensions
* Fix stale PMP state across reset
* Use 1ULL for a value we're going to shift by 63
* Remove unused IMISC macro
* Encode debug translation ranges in IOMMU
* Allow regular mstatus MPV/GVA writes again
* Fix uninitialised upper half in pmu_timer_trigger_irq
* Fix CPU state access on big-endian hosts

# -----BEGIN PGP SIGNATURE-----
#
# iQIzBAABCgAdFiEEaukCtqfKh31tZZKWr3yVEwxTgBMFAmrgREAACgkQr3yVEwxT
# gBPBHxAAmIzV1LXJAxQTvU46+1j+4+mSvGr37byb1iU8yg+dJCNtYpFLHKdNjF0Q
# Fn+5uBL+QJC3rEA0Xbq6iF4EP2GO8t/Qm4rElLmWCw1xzraj7RAZrNJHWCebLp1j
# PLS53gINaQNIuE6DC91mwcuWanKo7q+tvOiwcShaVyUH771J1+1xVOkpcbkQaVrZ
# a54IfHIcs4TIsKrpmxCJPkEuBcL4VtaK5JwcqbeCQQ68v7L7qQpec75t9idr3o25
# Pn/BOsHwkXoJ1qxFuY61JGhUpFKUzZIqd6HKqwv4SENZY+O87J79R9X/HU9H17xh
# B75+h91ZFSZ2luNd2vZCCMx4vOXuCa+YE/m0ZmyyjJnGLA4LHRoeFRmUUu5Dxzkn
# kP+psnaeUfcI6W71d8Dcqov1g1O7MBdVrQD1hzK8IeAuYL438cLZpo9WT6TVX5cn
# /DRCyDR4f6uzf8Lnh0wItJGzSUlW2xadFLu357KsJ0+lpytpmYolOBxUGJXtJu2g
# BSfgQX9y9xhszCbFopngunu3guOlDoHZEJ9l29+tXicezvJxXw+FRyc4EU3onRtz
# zXGWa7sN4XGifzoDorbVcWGpOT2w2LI1himS4N9qXWNCZ4s115xENMVCMDRt6a9Z
# aZRyBib2nbrrgnO4JJbxBUe/MViBfQlc+AuqMmEwrwdP3LRBbZA=
# =qxZ6
# -----END PGP SIGNATURE-----
# gpg: Signature made Tue 27 Oct 2026 01:27:12 AM CDT
# 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-20261027' of https://github.com/alistair23/qemu: (29 commits)
  target/riscv: Fix CPU state access on big-endian hosts
  target/riscv: fix uninitialised upper half in pmu_timer_trigger_irq()
  target/riscv/csr.c: allow regular mstatus MPV/GVA writes again
  hw/riscv/riscv-iommu: encode debug translation ranges
  include/hw/intc/riscv_imsic.h: remove unused macro
  target/riscv: Use 1ULL for a value we're going to shift by 63
  target/riscv: pmp: reset the derived PMP bounds and rule count
  target/riscv: pmp: clear A and L on every implemented PMP entry at reset
  target/riscv: gate envcfg CBO fields on extensions
  target/riscv: make mnstatus.MNPELP writable with Zicfilp
  target/riscv: Use TSO barriers instead of full barriers for Ztso
  docs: Move RISC-V 'Z' CPU properties section to removed features
  target/riscv/cpu.c: duct tape fix for QMP + RV profiles introspection
  hw/riscv/riscv-iommu: reclaim invalidated IOATC entries
  hw/riscv/riscv-iommu: serialize IOATC accesses
  hw/dma: fix k230_gsdma integer handling issues
  qtest: fix k230_decomp_gzip test integer handling issues
  hw/misc: use hwaddr for the k230_decomp_gzip input address
  hw/misc: fix calculating input address overflow in k230_decomp_gzip
  hw/misc: fix calculating output address overflow in k230_decomp_gzip
  ...

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
Richard Henderson committed 2026-10-27 14:27:13 -05:00
commit d29412cca5
31 files changed
+1425 -236

No files matched your search

+9
View File
@@ -490,6 +490,11 @@ OP(vaadd_vv, "vaadd.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm)
OP(vaadd_vx, "vaadd.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) OP(vaadd_vx, "vaadd.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm)
OP(vaaddu_vv, "vaaddu.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) OP(vaaddu_vv, "vaaddu.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm)
OP(vaaddu_vx, "vaaddu.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) OP(vaaddu_vx, "vaaddu.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm)
OP(vabd_vv, "vabd.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm)
OP(vabd_vx, "vabd.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm, rvcp_vabd_vx)
OP(vabdu_vv, "vabdu.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm)
OP(vabdu_vx, "vabdu.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm)
OP(vabs_v, "vabs.v", rv_codec_illegal, rv_fmt_vd_vs2_vm)
OP(vadc_vim, "vadc.vim", rv_codec_v_i, rv_fmt_vd_vs2_imm_vl) OP(vadc_vim, "vadc.vim", rv_codec_v_i, rv_fmt_vd_vs2_imm_vl)
OP(vadc_vvm, "vadc.vvm", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vl) OP(vadc_vvm, "vadc.vvm", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vl)
OP(vadc_vxm, "vadc.vxm", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vl) OP(vadc_vxm, "vadc.vxm", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vl)
@@ -861,6 +866,10 @@ OP(vsuxei16_v, "vsuxei16.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_vs2_vm)
OP(vsuxei32_v, "vsuxei32.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_vs2_vm) OP(vsuxei32_v, "vsuxei32.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_vs2_vm)
OP(vsuxei64_v, "vsuxei64.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_vs2_vm) OP(vsuxei64_v, "vsuxei64.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_vs2_vm)
OP(vsuxei8_v, "vsuxei8.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_vs2_vm) OP(vsuxei8_v, "vsuxei8.v", rv_codec_v_r, rv_fmt_ldst_vd_rs1_vs2_vm)
OP(vwabda_vv, "vwabda.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm)
OP(vwabda_vx, "vwabda.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm)
OP(vwabdau_vv, "vwabdau.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm)
OP(vwabdau_vx, "vwabdau.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm)
OP(vwadd_vv, "vwadd.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) OP(vwadd_vv, "vwadd.vv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm)
OP(vwadd_vx, "vwadd.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm) OP(vwadd_vx, "vwadd.vx", rv_codec_v_r, rv_fmt_vd_vs2_rs1_vm)
OP(vwadd_wv, "vwadd.wv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm) OP(vwadd_wv, "vwadd.wv", rv_codec_v_r, rv_fmt_vd_vs2_vs1_vm)
+14
View File
@@ -104,6 +104,7 @@ static const rvc_constraint rvcc_j[] = { rvc_rd_eq_x0, rvc_end };
static const rvc_constraint rvcc_ret[] = { rvc_rs1_eq_ra, rvc_end }; static const rvc_constraint rvcc_ret[] = { rvc_rs1_eq_ra, rvc_end };
static const rvc_constraint rvcc_jr[] = { rvc_rd_eq_x0, rvc_imm_eq_zero, static const rvc_constraint rvcc_jr[] = { rvc_rd_eq_x0, rvc_imm_eq_zero,
rvc_end }; rvc_end };
static const rvc_constraint rvcc_vabs_v[] = { rvc_rs1_eq_x0, rvc_end };
static const rvc_constraint rvcc_true[] = { rvc_end }; static const rvc_constraint rvcc_true[] = { rvc_end };
/* pseudo-instruction metadata */ /* pseudo-instruction metadata */
@@ -243,6 +244,11 @@ static const rv_comp_data rvcp_fsgnjx_q[] = {
{ }, { },
}; };
static const rv_comp_data rvcp_vabd_vx[] = {
{ &op_vabs_v, rvcc_vabs_v },
{ },
};
/* Convert compressed insns into normal insns via pseudo expansion. */ /* Convert compressed insns into normal insns via pseudo expansion. */
#define DECOMP(X) &(const rv_comp_data){ &X, rvcc_true } #define DECOMP(X) &(const rv_comp_data){ &X, rvcc_true }
@@ -2025,6 +2031,8 @@ static const rv_opcode_data *decode_inst_opcode(rv_decode *dec, rv_isa isa)
case 48: return &op_vwredsumu_vs; case 48: return &op_vwredsumu_vs;
case 49: return &op_vwredsum_vs; case 49: return &op_vwredsum_vs;
case 53: return &op_vwsll_vv; case 53: return &op_vwsll_vv;
case 61: return &op_vwabda_vv;
case 62: return &op_vwabdau_vv;
} }
break; break;
case 1: case 1:
@@ -2167,6 +2175,8 @@ static const rv_opcode_data *decode_inst_opcode(rv_decode *dec, rv_isa isa)
break; break;
} }
break; break;
case 21: return &op_vabd_vv;
case 22: return &op_vabdu_vv;
case 23: case 23:
if ((inst >> 25) & 1) { if ((inst >> 25) & 1) {
return &op_vcompress_vm; return &op_vcompress_vm;
@@ -2352,6 +2362,8 @@ static const rv_opcode_data *decode_inst_opcode(rv_decode *dec, rv_isa isa)
case 46: return &op_vnclipu_wx; case 46: return &op_vnclipu_wx;
case 47: return &op_vnclip_wx; case 47: return &op_vnclip_wx;
case 53: return &op_vwsll_vx; case 53: return &op_vwsll_vx;
case 61: return &op_vwabda_vx;
case 62: return &op_vwabdau_vx;
} }
break; break;
case 5: case 5:
@@ -2428,6 +2440,8 @@ static const rv_opcode_data *decode_inst_opcode(rv_decode *dec, rv_isa isa)
} }
} }
break; break;
case 21: return &op_vabd_vx;
case 22: return &op_vabdu_vx;
case 32: return &op_vdivu_vx; case 32: return &op_vdivu_vx;
case 33: return &op_vdiv_vx; case 33: return &op_vdiv_vx;
case 34: return &op_vremu_vx; case 34: return &op_vremu_vx;
-24
View File
@@ -362,30 +362,6 @@ the addition of volatile memory support, it is now necessary to distinguish
between persistent and volatile memory backends. As such, memdev is deprecated between persistent and volatile memory backends. As such, memdev is deprecated
in favor of persistent-memdev. in favor of persistent-memdev.
RISC-V CPU properties which start with capital 'Z' (since 8.2)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
All RISC-V CPU properties which start with capital 'Z' are being deprecated
starting in 8.2. The reason is that they were wrongly added with capital 'Z'
in the past. CPU properties were later added with lower-case names, which
is the format we want to use from now on.
Users which try to use these deprecated properties will receive a warning
recommending to switch to their stable counterparts:
- "Zifencei" should be replaced with "zifencei"
- "Zicsr" should be replaced with "zicsr"
- "Zihintntl" should be replaced with "zihintntl"
- "Zihintpause" should be replaced with "zihintpause"
- "Zawrs" should be replaced with "zawrs"
- "Zfa" should be replaced with "zfa"
- "Zfh" should be replaced with "zfh"
- "Zfhmin" should be replaced with "zfhmin"
- "Zve32f" should be replaced with "zve32f"
- "Zve64f" should be replaced with "zve64f"
- "Zve64d" should be replaced with "zve64d"
Block device options Block device options
'''''''''''''''''''' ''''''''''''''''''''
+7
View File
@@ -1038,6 +1038,13 @@ initial RISC-V QEMU port. Its usage was always been unclear: users don't know
what to expect from a CPU called 'any', and in fact the CPU does not do anything what to expect from a CPU called 'any', and in fact the CPU does not do anything
special that isn't already done by the default CPUs rv32/rv64. special that isn't already done by the default CPUs rv32/rv64.
RISC-V CPU properties which start with capital 'Z' (removed in 10.1)
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
All RISC-V CPU properties which start with capital 'Z' have been removed.
They were wrongly added with capital 'Z' in the past. CPU properties
with lower-case names are used instead.
Power8E and Power8NVL CPUs (removed in 11.1) Power8E and Power8NVL CPUs (removed in 11.1)
'''''''''''''''''''''''''''''''''''''''''''' ''''''''''''''''''''''''''''''''''''''''''''
+3 -4
View File
@@ -13,7 +13,7 @@ tt-atlantis QEMU model features
* 8-core Ascalon-X CPU Cluster * 8-core Ascalon-X CPU Cluster
* RISC-V compliant Advanced Interrupt Architecture * RISC-V compliant Advanced Interrupt Architecture
* 16550A compatible UART * DW8250 compatible UART x5
* 4 PRCMs (Clock and Reset Controllers) * 4 PRCMs (Clock and Reset Controllers)
Known limitations Known limitations
@@ -25,9 +25,8 @@ real platform. Notably:
* There is no PCI host bridge, so virtio-pci devices cannot be * There is no PCI host bridge, so virtio-pci devices cannot be
attached. Boots that need block storage must use ``-initrd`` with attached. Boots that need block storage must use ``-initrd`` with
an initramfs. an initramfs.
* The DesignWare UART is modelled with QEMU's ns16550-compatible * The Atlantis platform has 5 UARTs but only ``UART1`` is currently exposed
``serial_mm`` device; DesignWare-specific registers beyond that on the command line serial interface. ``UART1`` is the Ascalon console.
set return 0.
Supported software Supported software
------------------ ------------------
+44 -44
View File
@@ -304,54 +304,54 @@ static uint64_t k230_gsdma_read(void *opaque, hwaddr addr, unsigned int size)
hwaddr ch_off; hwaddr ch_off;
uint64_t ret = 0; uint64_t ret = 0;
switch (addr) { if (addr < K230_GSDMA_CH_BASE) {
case K230_GSDMA_DMA_CH_EN: switch (addr) {
ret = s->dma_ch_en; case K230_GSDMA_DMA_CH_EN:
break; ret = s->dma_ch_en;
case K230_GSDMA_DMA_INT_MASK: break;
ret = s->dma_int_mask; case K230_GSDMA_DMA_INT_MASK:
break; ret = s->dma_int_mask;
case K230_GSDMA_DMA_INT_STAT: break;
ret = s->dma_int_stat; case K230_GSDMA_DMA_INT_STAT:
break; ret = s->dma_int_stat;
case K230_GSDMA_DMA_CFG: break;
ret = s->dma_cfg; case K230_GSDMA_DMA_CFG:
break; ret = s->dma_cfg;
case K230_GSDMA_DMA_WEIGHT: break;
ret = s->dma_weight; case K230_GSDMA_DMA_WEIGHT:
break; ret = s->dma_weight;
default: break;
if (addr < K230_GSDMA_CH_BASE) { default:
qemu_log_mask(LOG_GUEST_ERROR, qemu_log_mask(LOG_GUEST_ERROR,
"%s: not implement gdma at offset 0x%" HWADDR_PRIx "%s: not implement gdma at offset 0x%" HWADDR_PRIx
"\n", __func__, addr); "\n", __func__, addr);
return ret;
} }
break; } else {
} ch = (addr - K230_GSDMA_CH_BASE) / K230_GSDMA_CH_STRIDE;
ch_off = (addr - K230_GSDMA_CH_BASE) % K230_GSDMA_CH_STRIDE;
ch = (addr - K230_GSDMA_CH_BASE) / K230_GSDMA_CH_STRIDE; if (ch < K230_GSDMA_NUM_SDMA_CHANNELS) {
ch_off = (addr - K230_GSDMA_CH_BASE) % K230_GSDMA_CH_STRIDE; switch (ch_off) {
if (ch < K230_GSDMA_NUM_SDMA_CHANNELS) { case K230_GSDMA_CH_CTL:
switch (ch_off) { break;
case K230_GSDMA_CH_CTL: case K230_GSDMA_CH_STATUS:
break; ret = s->channels[ch].status;
case K230_GSDMA_CH_STATUS: break;
ret = s->channels[ch].status; case K230_GSDMA_CH_CFG:
break; ret = s->channels[ch].cfg;
case K230_GSDMA_CH_CFG: break;
ret = s->channels[ch].cfg; case K230_GSDMA_CH_USR_DATA:
break; ret = s->channels[ch].usr_data;
case K230_GSDMA_CH_USR_DATA: break;
ret = s->channels[ch].usr_data; case K230_GSDMA_CH_LLT_SADDR:
break; ret = s->channels[ch].llt_saddr;
case K230_GSDMA_CH_LLT_SADDR: break;
ret = s->channels[ch].llt_saddr; case K230_GSDMA_CH_CURRENT_LLT:
break; ret = s->channels[ch].current_llt;
case K230_GSDMA_CH_CURRENT_LLT: break;
ret = s->channels[ch].current_llt; default:
break; break;
default: }
break;
} }
} }
+3 -3
View File
@@ -53,13 +53,13 @@ static bool k230_decomp_gzip_write_mem(K230DecompGzipState *s, hwaddr addr,
static hwaddr k230_decomp_gzip_output_addr(K230DecompGzipState *s) static hwaddr k230_decomp_gzip_output_addr(K230DecompGzipState *s)
{ {
return K230_DECOMP_GZIP_SRAM_OUT_BASE + return K230_DECOMP_GZIP_SRAM_OUT_BASE +
s->output.slot * K230_DECOMP_GZIP_BLOCK_SIZE + (hwaddr) s->output.slot * K230_DECOMP_GZIP_BLOCK_SIZE +
s->output.current_offset; s->output.current_offset;
} }
static hwaddr k230_decomp_gzip_input_addr(K230DecompGzipState *s) static hwaddr k230_decomp_gzip_input_addr(K230DecompGzipState *s)
{ {
return s->input.slot * K230_DECOMP_GZIP_BLOCK_SIZE + return (hwaddr) s->input.slot * K230_DECOMP_GZIP_BLOCK_SIZE +
K230_DECOMP_GZIP_SRAM_IN_BASE; K230_DECOMP_GZIP_SRAM_IN_BASE;
} }
@@ -102,7 +102,7 @@ static void k230_decomp_gzip_finish(K230DecompGzipState *s, bool crc_ok)
} }
static bool k230_decomp_gzip_load_input(K230DecompGzipState *s, static bool k230_decomp_gzip_load_input(K230DecompGzipState *s,
uint32_t addr, uint32_t size) hwaddr addr, uint32_t size)
{ {
s->input.current_offset = 0; s->input.current_offset = 0;
+1 -1
View File
@@ -144,7 +144,7 @@ config TENSTORRENT
select RISCV_ACLINT select RISCV_ACLINT
select RISCV_APLIC select RISCV_APLIC
select RISCV_IMSIC select RISCV_IMSIC
select SERIAL_MM select DW8250
select DEVICE_TREE select DEVICE_TREE
select DESIGNWARE_I2C select DESIGNWARE_I2C
select DS1338 select DS1338
+101 -89
View File
@@ -1582,107 +1582,96 @@ static guint riscv_iommu_iot_hash(gconstpointer v)
/* GV: 0 AV: 0 PSCV: 0 GVMA: 0 */ /* GV: 0 AV: 0 PSCV: 0 GVMA: 0 */
/* GV: 0 AV: 0 GVMA: 1 */ /* GV: 0 AV: 0 GVMA: 1 */
static static
void riscv_iommu_iot_inval_all(gpointer key, gpointer value, gpointer data) gboolean riscv_iommu_iot_inval_all(gpointer key, gpointer value, gpointer data)
{ {
RISCVIOMMUEntry *iot = (RISCVIOMMUEntry *) value; RISCVIOMMUEntry *iot = (RISCVIOMMUEntry *) value;
RISCVIOMMUEntry *arg = (RISCVIOMMUEntry *) data; RISCVIOMMUEntry *arg = (RISCVIOMMUEntry *) data;
if (iot->tag == arg->tag) { return iot->tag == arg->tag;
iot->perm = IOMMU_NONE;
}
} }
/* GV: 0 AV: 0 PSCV: 1 GVMA: 0 */ /* GV: 0 AV: 0 PSCV: 1 GVMA: 0 */
static static
void riscv_iommu_iot_inval_pscid(gpointer key, gpointer value, gpointer data) gboolean riscv_iommu_iot_inval_pscid(gpointer key, gpointer value,
gpointer data)
{ {
RISCVIOMMUEntry *iot = (RISCVIOMMUEntry *) value; RISCVIOMMUEntry *iot = (RISCVIOMMUEntry *) value;
RISCVIOMMUEntry *arg = (RISCVIOMMUEntry *) data; RISCVIOMMUEntry *arg = (RISCVIOMMUEntry *) data;
if (iot->tag == arg->tag && return iot->tag == arg->tag &&
iot->pscid == arg->pscid) { iot->pscid == arg->pscid;
iot->perm = IOMMU_NONE;
}
} }
/* GV: 0 AV: 1 PSCV: 0 GVMA: 0 */ /* GV: 0 AV: 1 PSCV: 0 GVMA: 0 */
static static
void riscv_iommu_iot_inval_iova(gpointer key, gpointer value, gpointer data) gboolean riscv_iommu_iot_inval_iova(gpointer key, gpointer value, gpointer data)
{ {
RISCVIOMMUEntry *iot = (RISCVIOMMUEntry *) value; RISCVIOMMUEntry *iot = (RISCVIOMMUEntry *) value;
RISCVIOMMUEntry *arg = (RISCVIOMMUEntry *) data; RISCVIOMMUEntry *arg = (RISCVIOMMUEntry *) data;
if (iot->tag == arg->tag && return iot->tag == arg->tag &&
iot->iova == arg->iova) { iot->iova == arg->iova;
iot->perm = IOMMU_NONE;
}
} }
/* GV: 0 AV: 1 PSCV: 1 GVMA: 0 */ /* GV: 0 AV: 1 PSCV: 1 GVMA: 0 */
static void riscv_iommu_iot_inval_pscid_iova(gpointer key, gpointer value, static gboolean riscv_iommu_iot_inval_pscid_iova(gpointer key,
gpointer data) gpointer value,
gpointer data)
{ {
RISCVIOMMUEntry *iot = (RISCVIOMMUEntry *) value; RISCVIOMMUEntry *iot = (RISCVIOMMUEntry *) value;
RISCVIOMMUEntry *arg = (RISCVIOMMUEntry *) data; RISCVIOMMUEntry *arg = (RISCVIOMMUEntry *) data;
if (iot->tag == arg->tag && return iot->tag == arg->tag &&
iot->pscid == arg->pscid && iot->pscid == arg->pscid &&
iot->iova == arg->iova) { iot->iova == arg->iova;
iot->perm = IOMMU_NONE;
}
} }
/* GV: 1 AV: 0 PSCV: 0 GVMA: 0 */ /* GV: 1 AV: 0 PSCV: 0 GVMA: 0 */
/* GV: 1 AV: 0 GVMA: 1 */ /* GV: 1 AV: 0 GVMA: 1 */
static static gboolean riscv_iommu_iot_inval_gscid(gpointer key, gpointer value,
void riscv_iommu_iot_inval_gscid(gpointer key, gpointer value, gpointer data) gpointer data)
{ {
RISCVIOMMUEntry *iot = (RISCVIOMMUEntry *) value; RISCVIOMMUEntry *iot = (RISCVIOMMUEntry *) value;
RISCVIOMMUEntry *arg = (RISCVIOMMUEntry *) data; RISCVIOMMUEntry *arg = (RISCVIOMMUEntry *) data;
if (iot->tag == arg->tag && return iot->tag == arg->tag &&
iot->gscid == arg->gscid) { iot->gscid == arg->gscid;
iot->perm = IOMMU_NONE;
}
} }
/* GV: 1 AV: 0 PSCV: 1 GVMA: 0 */ /* GV: 1 AV: 0 PSCV: 1 GVMA: 0 */
static void riscv_iommu_iot_inval_gscid_pscid(gpointer key, gpointer value, static gboolean riscv_iommu_iot_inval_gscid_pscid(gpointer key,
gpointer data) gpointer value,
gpointer data)
{ {
RISCVIOMMUEntry *iot = (RISCVIOMMUEntry *) value; RISCVIOMMUEntry *iot = (RISCVIOMMUEntry *) value;
RISCVIOMMUEntry *arg = (RISCVIOMMUEntry *) data; RISCVIOMMUEntry *arg = (RISCVIOMMUEntry *) data;
if (iot->tag == arg->tag && return iot->tag == arg->tag &&
iot->gscid == arg->gscid && iot->gscid == arg->gscid &&
iot->pscid == arg->pscid) { iot->pscid == arg->pscid;
iot->perm = IOMMU_NONE;
}
} }
/* GV: 1 AV: 1 PSCV: 0 GVMA: 0 */ /* GV: 1 AV: 1 PSCV: 0 GVMA: 0 */
/* GV: 1 AV: 1 GVMA: 1 */ /* GV: 1 AV: 1 GVMA: 1 */
static void riscv_iommu_iot_inval_gscid_iova(gpointer key, gpointer value, static gboolean riscv_iommu_iot_inval_gscid_iova(gpointer key,
gpointer data) gpointer value,
gpointer data)
{ {
RISCVIOMMUEntry *iot = (RISCVIOMMUEntry *) value; RISCVIOMMUEntry *iot = (RISCVIOMMUEntry *) value;
RISCVIOMMUEntry *arg = (RISCVIOMMUEntry *) data; RISCVIOMMUEntry *arg = (RISCVIOMMUEntry *) data;
if (iot->tag == arg->tag && return iot->tag == arg->tag &&
iot->gscid == arg->gscid && iot->gscid == arg->gscid &&
iot->iova == arg->iova) { iot->iova == arg->iova;
iot->perm = IOMMU_NONE;
}
} }
/* GV: 1 AV: 1 PSCV: 1 GVMA: 0 */ /* GV: 1 AV: 1 PSCV: 1 GVMA: 0 */
static void riscv_iommu_iot_inval_gscid_pscid_iova(gpointer key, gpointer value, static gboolean riscv_iommu_iot_inval_gscid_pscid_iova(gpointer key,
gpointer data) gpointer value,
gpointer data)
{ {
RISCVIOMMUEntry *iot = (RISCVIOMMUEntry *) value; RISCVIOMMUEntry *iot = (RISCVIOMMUEntry *) value;
RISCVIOMMUEntry *arg = (RISCVIOMMUEntry *) data; RISCVIOMMUEntry *arg = (RISCVIOMMUEntry *) data;
if (iot->tag == arg->tag && return iot->tag == arg->tag &&
iot->gscid == arg->gscid && iot->gscid == arg->gscid &&
iot->pscid == arg->pscid && iot->pscid == arg->pscid &&
iot->iova == arg->iova) { iot->iova == arg->iova;
iot->perm = IOMMU_NONE;
}
} }
/* caller should keep ref-count for iot_cache object */ /* caller must hold iot_lock */
static RISCVIOMMUEntry *riscv_iommu_iot_lookup(RISCVIOMMUContext *ctx, static RISCVIOMMUEntry *riscv_iommu_iot_lookup(RISCVIOMMUContext *ctx,
GHashTable *iot_cache, hwaddr iova, RISCVIOMMUTransTag transtag) GHashTable *iot_cache, hwaddr iova, RISCVIOMMUTransTag transtag)
{ {
@@ -1695,27 +1684,26 @@ static RISCVIOMMUEntry *riscv_iommu_iot_lookup(RISCVIOMMUContext *ctx,
return g_hash_table_lookup(iot_cache, &key); return g_hash_table_lookup(iot_cache, &key);
} }
/* caller should keep ref-count for iot_cache object */ /* caller must hold iot_lock */
static void riscv_iommu_iot_update(RISCVIOMMUState *s, static void riscv_iommu_iot_update(RISCVIOMMUState *s, RISCVIOMMUEntry *iot)
GHashTable *iot_cache, RISCVIOMMUEntry *iot)
{ {
if (!s->iot_limit) { if (!s->iot_limit) {
return; return;
} }
if (g_hash_table_size(s->iot_cache) >= s->iot_limit) { if (g_hash_table_size(s->iot_cache) >= s->iot_limit) {
iot_cache = g_hash_table_new_full(riscv_iommu_iot_hash, GHashTable *old_cache = s->iot_cache;
riscv_iommu_iot_equal, s->iot_cache = g_hash_table_new_full(riscv_iommu_iot_hash,
g_free, NULL); riscv_iommu_iot_equal,
g_hash_table_unref(qatomic_xchg(&s->iot_cache, iot_cache)); g_free, NULL);
g_hash_table_unref(old_cache);
} }
g_hash_table_add(iot_cache, iot); g_hash_table_add(s->iot_cache, iot);
} }
static void riscv_iommu_iot_inval(RISCVIOMMUState *s, GHFunc func, static void riscv_iommu_iot_inval(RISCVIOMMUState *s, GHRFunc func,
uint32_t gscid, uint32_t pscid, hwaddr iova, RISCVIOMMUTransTag transtag) uint32_t gscid, uint32_t pscid, hwaddr iova, RISCVIOMMUTransTag transtag)
{ {
GHashTable *iot_cache;
RISCVIOMMUEntry key = { RISCVIOMMUEntry key = {
.tag = transtag, .tag = transtag,
.gscid = gscid, .gscid = gscid,
@@ -1723,9 +1711,9 @@ static void riscv_iommu_iot_inval(RISCVIOMMUState *s, GHFunc func,
.iova = PPN_DOWN(iova), .iova = PPN_DOWN(iova),
}; };
iot_cache = g_hash_table_ref(s->iot_cache); qemu_mutex_lock(&s->iot_lock);
g_hash_table_foreach(iot_cache, func, &key); g_hash_table_foreach_remove(s->iot_cache, func, &key);
g_hash_table_unref(iot_cache); qemu_mutex_unlock(&s->iot_lock);
} }
static RISCVIOMMUTransTag riscv_iommu_get_transtag(RISCVIOMMUContext *ctx) static RISCVIOMMUTransTag riscv_iommu_get_transtag(RISCVIOMMUContext *ctx)
@@ -1747,15 +1735,14 @@ static int riscv_iommu_translate(RISCVIOMMUState *s, RISCVIOMMUContext *ctx,
{ {
RISCVIOMMUTransTag transtag = riscv_iommu_get_transtag(ctx); RISCVIOMMUTransTag transtag = riscv_iommu_get_transtag(ctx);
RISCVIOMMUEntry *iot; RISCVIOMMUEntry *iot;
IOMMUAccessFlags perm; IOMMUAccessFlags perm = IOMMU_NONE;
bool enable_pid; bool enable_pid;
bool enable_pri; bool enable_pri;
GHashTable *iot_cache; hwaddr phys = 0;
int fault; int fault;
riscv_iommu_hpm_incr_ctr(s, ctx, RISCV_IOMMU_HPMEVENT_URQ); riscv_iommu_hpm_incr_ctr(s, ctx, RISCV_IOMMU_HPMEVENT_URQ);
iot_cache = g_hash_table_ref(s->iot_cache);
enable_pri = (iotlb->perm == IOMMU_NONE) && enable_pri = (iotlb->perm == IOMMU_NONE) &&
(ctx->tc & RISCV_IOMMU_DC_TC_EN_PRI); (ctx->tc & RISCV_IOMMU_DC_TC_EN_PRI);
enable_pid = (ctx->tc & RISCV_IOMMU_DC_TC_PDTV); enable_pid = (ctx->tc & RISCV_IOMMU_DC_TC_PDTV);
@@ -1771,10 +1758,15 @@ static int riscv_iommu_translate(RISCVIOMMUState *s, RISCVIOMMUContext *ctx,
} }
} }
iot = riscv_iommu_iot_lookup(ctx, iot_cache, iotlb->iova, transtag); qemu_mutex_lock(&s->iot_lock);
perm = iot ? iot->perm : IOMMU_NONE; iot = riscv_iommu_iot_lookup(ctx, s->iot_cache, iotlb->iova, transtag);
if (iot) {
perm = iot->perm;
phys = iot->phys;
}
qemu_mutex_unlock(&s->iot_lock);
if (perm != IOMMU_NONE) { if (perm != IOMMU_NONE) {
iotlb->translated_addr = PPN_PHYS(iot->phys); iotlb->translated_addr = PPN_PHYS(phys);
iotlb->addr_mask = ~TARGET_PAGE_MASK; iotlb->addr_mask = ~TARGET_PAGE_MASK;
iotlb->perm = perm; iotlb->perm = perm;
fault = 0; fault = 0;
@@ -1805,12 +1797,12 @@ static int riscv_iommu_translate(RISCVIOMMUState *s, RISCVIOMMUContext *ctx,
iot->pscid = get_field(ctx->ta, RISCV_IOMMU_DC_TA_PSCID); iot->pscid = get_field(ctx->ta, RISCV_IOMMU_DC_TA_PSCID);
iot->perm = iotlb->perm; iot->perm = iotlb->perm;
iot->tag = transtag; iot->tag = transtag;
riscv_iommu_iot_update(s, iot_cache, iot); qemu_mutex_lock(&s->iot_lock);
riscv_iommu_iot_update(s, iot);
qemu_mutex_unlock(&s->iot_lock);
} }
done: done:
g_hash_table_unref(iot_cache);
if (enable_pri && fault) { if (enable_pri && fault) {
struct riscv_iommu_pq_record pr = {0}; struct riscv_iommu_pq_record pr = {0};
if (enable_pid) { if (enable_pid) {
@@ -1969,7 +1961,8 @@ static void riscv_iommu_process_cq_tail(RISCVIOMMUState *s)
dma_addr_t addr; dma_addr_t addr;
uint32_t tail, head, ctrl; uint32_t tail, head, ctrl;
uint64_t cmd_opcode; uint64_t cmd_opcode;
GHFunc func; GHRFunc iot_func;
GHFunc ctx_func;
ctrl = riscv_iommu_reg_get32(s, RISCV_IOMMU_REG_CQCSR); ctrl = riscv_iommu_reg_get32(s, RISCV_IOMMU_REG_CQCSR);
tail = riscv_iommu_reg_get32(s, RISCV_IOMMU_REG_CQT) & s->cq_mask; tail = riscv_iommu_reg_get32(s, RISCV_IOMMU_REG_CQT) & s->cq_mask;
@@ -2032,18 +2025,18 @@ static void riscv_iommu_process_cq_tail(RISCVIOMMUState *s)
goto cmd_ill; goto cmd_ill;
} }
func = riscv_iommu_iot_inval_all; iot_func = riscv_iommu_iot_inval_all;
if (gv) { if (gv) {
func = (av) ? riscv_iommu_iot_inval_gscid_iova : iot_func = (av) ? riscv_iommu_iot_inval_gscid_iova :
riscv_iommu_iot_inval_gscid; riscv_iommu_iot_inval_gscid;
} }
riscv_iommu_iot_inval( riscv_iommu_iot_inval(
s, func, gscid, pscid, iova, RISCV_IOMMU_TRANS_TAG_VG); s, iot_func, gscid, pscid, iova, RISCV_IOMMU_TRANS_TAG_VG);
riscv_iommu_iot_inval( riscv_iommu_iot_inval(
s, func, gscid, pscid, iova, RISCV_IOMMU_TRANS_TAG_VN); s, iot_func, gscid, pscid, iova, RISCV_IOMMU_TRANS_TAG_VN);
break; break;
} }
@@ -2063,24 +2056,24 @@ static void riscv_iommu_process_cq_tail(RISCVIOMMUState *s)
if (gv) { if (gv) {
transtag = RISCV_IOMMU_TRANS_TAG_VN; transtag = RISCV_IOMMU_TRANS_TAG_VN;
if (pscv) { if (pscv) {
func = (av) ? riscv_iommu_iot_inval_gscid_pscid_iova : iot_func = (av) ? riscv_iommu_iot_inval_gscid_pscid_iova :
riscv_iommu_iot_inval_gscid_pscid; riscv_iommu_iot_inval_gscid_pscid;
} else { } else {
func = (av) ? riscv_iommu_iot_inval_gscid_iova : iot_func = (av) ? riscv_iommu_iot_inval_gscid_iova :
riscv_iommu_iot_inval_gscid; riscv_iommu_iot_inval_gscid;
} }
} else { } else {
transtag = RISCV_IOMMU_TRANS_TAG_SS; transtag = RISCV_IOMMU_TRANS_TAG_SS;
if (pscv) { if (pscv) {
func = (av) ? riscv_iommu_iot_inval_pscid_iova : iot_func = (av) ? riscv_iommu_iot_inval_pscid_iova :
riscv_iommu_iot_inval_pscid; riscv_iommu_iot_inval_pscid;
} else { } else {
func = (av) ? riscv_iommu_iot_inval_iova : iot_func = (av) ? riscv_iommu_iot_inval_iova :
riscv_iommu_iot_inval_all; riscv_iommu_iot_inval_all;
} }
} }
riscv_iommu_iot_inval(s, func, gscid, pscid, iova, transtag); riscv_iommu_iot_inval(s, iot_func, gscid, pscid, iova, transtag);
break; break;
} }
@@ -2088,12 +2081,12 @@ static void riscv_iommu_process_cq_tail(RISCVIOMMUState *s)
RISCV_IOMMU_CMD_IODIR_OPCODE): RISCV_IOMMU_CMD_IODIR_OPCODE):
if (!(cmd.dword0 & RISCV_IOMMU_CMD_IODIR_DV)) { if (!(cmd.dword0 & RISCV_IOMMU_CMD_IODIR_DV)) {
/* invalidate all device context cache mappings */ /* invalidate all device context cache mappings */
func = riscv_iommu_ctx_inval_all; ctx_func = riscv_iommu_ctx_inval_all;
} else { } else {
/* invalidate all device context matching DID */ /* invalidate all device context matching DID */
func = riscv_iommu_ctx_inval_devid; ctx_func = riscv_iommu_ctx_inval_devid;
} }
riscv_iommu_ctx_inval(s, func, riscv_iommu_ctx_inval(s, ctx_func,
get_field(cmd.dword0, RISCV_IOMMU_CMD_IODIR_DID), 0); get_field(cmd.dword0, RISCV_IOMMU_CMD_IODIR_DID), 0);
break; break;
@@ -2103,9 +2096,9 @@ static void riscv_iommu_process_cq_tail(RISCVIOMMUState *s)
/* illegal command arguments IODIR_PDT & DV == 0 */ /* illegal command arguments IODIR_PDT & DV == 0 */
goto cmd_ill; goto cmd_ill;
} else { } else {
func = riscv_iommu_ctx_inval_devid_procid; ctx_func = riscv_iommu_ctx_inval_devid_procid;
} }
riscv_iommu_ctx_inval(s, func, riscv_iommu_ctx_inval(s, ctx_func,
get_field(cmd.dword0, RISCV_IOMMU_CMD_IODIR_DID), get_field(cmd.dword0, RISCV_IOMMU_CMD_IODIR_DID),
get_field(cmd.dword0, RISCV_IOMMU_CMD_IODIR_PID)); get_field(cmd.dword0, RISCV_IOMMU_CMD_IODIR_PID));
break; break;
@@ -2281,8 +2274,20 @@ static void riscv_iommu_process_dbg(RISCVIOMMUState *s)
if (fault) { if (fault) {
iova = RISCV_IOMMU_TR_RESPONSE_FAULT | (((uint64_t) fault) << 10); iova = RISCV_IOMMU_TR_RESPONSE_FAULT | (((uint64_t) fault) << 10);
} else { } else {
uint64_t ppn;
iova = iotlb.translated_addr & ~iotlb.addr_mask; iova = iotlb.translated_addr & ~iotlb.addr_mask;
iova = set_field(0, RISCV_IOMMU_TR_RESPONSE_PPN, PPN_DOWN(iova)); ppn = PPN_DOWN(iova);
if (iotlb.addr_mask > TARGET_PAGE_SIZE - 1) {
/* Encode the translation range as trailing ones in the PPN. */
ppn |= PPN_DOWN(iotlb.addr_mask) >> 1;
iova = RISCV_IOMMU_TR_RESPONSE_S;
} else {
iova = 0;
}
iova = set_field(iova, RISCV_IOMMU_TR_RESPONSE_PPN, ppn);
} }
riscv_iommu_reg_set64(s, RISCV_IOMMU_REG_TR_RESPONSE, iova); riscv_iommu_reg_set64(s, RISCV_IOMMU_REG_TR_RESPONSE, iova);
} }
@@ -2674,6 +2679,7 @@ static void riscv_iommu_instance_init(Object *obj)
s->iot_cache = g_hash_table_new_full(riscv_iommu_iot_hash, s->iot_cache = g_hash_table_new_full(riscv_iommu_iot_hash,
riscv_iommu_iot_equal, riscv_iommu_iot_equal,
g_free, NULL); g_free, NULL);
qemu_mutex_init(&s->iot_lock);
s->iommus.le_next = NULL; s->iommus.le_next = NULL;
s->iommus.le_prev = NULL; s->iommus.le_prev = NULL;
@@ -2690,6 +2696,8 @@ static void riscv_iommu_instance_finalize(Object *obj)
g_hash_table_unref(s->ctx_cache); g_hash_table_unref(s->ctx_cache);
g_hash_table_unref(s->iot_cache); g_hash_table_unref(s->iot_cache);
qemu_mutex_destroy(&s->iot_lock);
} }
static void riscv_iommu_realize(DeviceState *dev, Error **errp) static void riscv_iommu_realize(DeviceState *dev, Error **errp)
@@ -2850,7 +2858,10 @@ void riscv_iommu_reset(RISCVIOMMUState *s)
riscv_iommu_reg_set32(s, RISCV_IOMMU_REG_IPSR, 0); riscv_iommu_reg_set32(s, RISCV_IOMMU_REG_IPSR, 0);
g_hash_table_remove_all(s->ctx_cache); g_hash_table_remove_all(s->ctx_cache);
qemu_mutex_lock(&s->iot_lock);
g_hash_table_remove_all(s->iot_cache); g_hash_table_remove_all(s->iot_cache);
qemu_mutex_unlock(&s->iot_lock);
} }
static const Property riscv_iommu_properties[] = { static const Property riscv_iommu_properties[] = {
@@ -2919,7 +2930,8 @@ static IOMMUTLBEntry riscv_iommu_memory_region_translate(
/* Translation disabled or invalid. */ /* Translation disabled or invalid. */
iotlb.addr_mask = 0; iotlb.addr_mask = 0;
iotlb.perm = IOMMU_NONE; iotlb.perm = IOMMU_NONE;
} else if (riscv_iommu_translate(as->iommu, ctx, &iotlb, true)) { } else if (riscv_iommu_translate(as->iommu, ctx, &iotlb,
as->iommu->iot_limit > 0)) {
/* Translation disabled or fault reported. */ /* Translation disabled or fault reported. */
iotlb.addr_mask = 0; iotlb.addr_mask = 0;
iotlb.perm = IOMMU_NONE; iotlb.perm = IOMMU_NONE;
+1
View File
@@ -73,6 +73,7 @@ struct RISCVIOMMUState {
GHashTable *iot_cache; /* IO Translated Address Cache */ GHashTable *iot_cache; /* IO Translated Address Cache */
unsigned iot_limit; /* IO Translation Cache size limit */ unsigned iot_limit; /* IO Translation Cache size limit */
QemuMutex iot_lock;
/* MMIO Hardware Interface */ /* MMIO Hardware Interface */
MemoryRegion regs_mr; MemoryRegion regs_mr;
+35 -33
View File
@@ -24,9 +24,8 @@
#include "hw/riscv/fdt-common.h" #include "hw/riscv/fdt-common.h"
#include "hw/riscv/riscv_hart.h" #include "hw/riscv/riscv_hart.h"
#include "hw/char/serial-mm.h" #include "hw/char/dw8250.h"
#include "hw/intc/riscv_aclint.h" #include "hw/intc/riscv_aclint.h"
#include "hw/misc/unimp.h"
#include "hw/misc/tt_atlantis_prcm.h" #include "hw/misc/tt_atlantis_prcm.h"
#include "system/system.h" #include "system/system.h"
@@ -65,7 +64,11 @@ static const MemMapEntry tt_atlantis_memmap[] = {
[TT_ATL_I2C2] = { 0xd4060000, 0x10000 }, [TT_ATL_I2C2] = { 0xd4060000, 0x10000 },
[TT_ATL_I2C3] = { 0xd4070000, 0x10000 }, [TT_ATL_I2C3] = { 0xd4070000, 0x10000 },
[TT_ATL_I2C4] = { 0xd4080000, 0x10000 }, [TT_ATL_I2C4] = { 0xd4080000, 0x10000 },
[TT_ATL_UART0] = { 0xd4100000, 0x10000 },
[TT_ATL_UART1] = { 0xd4110000, 0x10000 }, [TT_ATL_UART1] = { 0xd4110000, 0x10000 },
[TT_ATL_UART2] = { 0xd4120000, 0x10000 },
[TT_ATL_UART3] = { 0xd4130000, 0x10000 },
[TT_ATL_UART4] = { 0xd4140000, 0x10000 },
[TT_ATL_PRCM_PCIE] = { 0xd8000000, 0x100 }, [TT_ATL_PRCM_PCIE] = { 0xd8000000, 0x100 },
[TT_ATL_PRCM_MM] = { 0xdc000000, 0x1000 }, [TT_ATL_PRCM_MM] = { 0xdc000000, 0x1000 },
[TT_ATL_PRCM_HSIO] = { 0xe00c0000, 0x510 }, [TT_ATL_PRCM_HSIO] = { 0xe00c0000, 0x510 },
@@ -268,11 +271,15 @@ static void create_fdt_uart(void *fdt, const MemMapEntry *mem, int irq,
int irqchip_phandle, uint32_t clk_parent_phandle, int irqchip_phandle, uint32_t clk_parent_phandle,
uint32_t clk_phandle) uint32_t clk_phandle)
{ {
static const char * const compat[2] = {
"snps,dw-apb-uart", "ns16550a"
};
g_autofree char *name = g_strdup_printf("/soc/serial@%"HWADDR_PRIX, g_autofree char *name = g_strdup_printf("/soc/serial@%"HWADDR_PRIX,
mem->base); mem->base);
qemu_fdt_add_subnode(fdt, name); qemu_fdt_add_subnode(fdt, name);
qemu_fdt_setprop_string(fdt, name, "compatible", "ns16550a"); qemu_fdt_setprop_string_array(fdt, name, "compatible",
(char **)&compat, ARRAY_SIZE(compat));
qemu_fdt_setprop_sized_cells(fdt, name, "reg", 2, mem->base, 2, mem->size); qemu_fdt_setprop_sized_cells(fdt, name, "reg", 2, mem->base, 2, mem->size);
qemu_fdt_setprop_cell(fdt, name, "reg-shift", 2); qemu_fdt_setprop_cell(fdt, name, "reg-shift", 2);
qemu_fdt_setprop_cell(fdt, name, "reg-io-width", 4); qemu_fdt_setprop_cell(fdt, name, "reg-io-width", 4);
@@ -466,17 +473,6 @@ static void load_fdt(TTAtlantisState *ams)
create_fdt_memory(ms->fdt, &ams->soc); create_fdt_memory(ms->fdt, &ams->soc);
} }
static void mmio_map_unimplemented(MemoryRegion *memory, SysBusDevice *dev,
const char *name, hwaddr addr, uint64_t size)
{
qdev_prop_set_string(DEVICE(dev), "name", name);
qdev_prop_set_uint64(DEVICE(dev), "size", size);
sysbus_realize(dev, &error_abort);
memory_region_add_subregion_overlap(memory, addr,
sysbus_mmio_get_region(dev, 0), -1000);
}
static void tt_atlantis_machine_done(Notifier *n, void *data) static void tt_atlantis_machine_done(Notifier *n, void *data)
{ {
TTAtlantisState *ams = container_of(n, TTAtlantisState, machine_done); TTAtlantisState *ams = container_of(n, TTAtlantisState, machine_done);
@@ -539,14 +535,21 @@ static void tt_atlantis_machine_done(Notifier *n, void *data)
fdt_load_addr); fdt_load_addr);
} }
static inline int tt_atlantis_uart_index(int uart_dev)
{
return uart_dev - TT_ATL_UART0;
}
static void tt_atlantis_soc_init(Object *obj) static void tt_atlantis_soc_init(Object *obj)
{ {
TTAtlantisSoCState *s = TT_ATLANTIS_SOC(obj); TTAtlantisSoCState *s = TT_ATLANTIS_SOC(obj);
object_initialize_child(obj, "cpus", &s->cpus, TYPE_RISCV_HART_ARRAY); object_initialize_child(obj, "cpus", &s->cpus, TYPE_RISCV_HART_ARRAY);
object_initialize_child(obj, "uart1", &s->uart1, for (int i = 0; i < TT_ATL_NUM_UARTS; i++) {
TYPE_UNIMPLEMENTED_DEVICE); object_initialize_child(obj, "uart[*]", &s->uart[i],
TYPE_DW8250);
}
object_initialize_child(obj, "prcm-rcpu", object_initialize_child(obj, "prcm-rcpu",
&s->prcm[TT_ATLANTIS_PRCM_DOMAIN_RCPU], &s->prcm[TT_ATLANTIS_PRCM_DOMAIN_RCPU],
@@ -653,11 +656,6 @@ static void tt_atlantis_soc_realize(DeviceState *dev, Error **errp)
memory_region_add_subregion(s->memory, s->memmap[TT_ATL_BOOTROM].base, memory_region_add_subregion(s->memory, s->memmap[TT_ATL_BOOTROM].base,
&s->bootrom); &s->bootrom);
/* UART1, the soc console (UART0 is for the boot microcontroller) */
serial_mm_init(s->memory, s->memmap[TT_ATL_UART1].base, 2,
qdev_get_gpio_in(s->irqchip, TT_ATL_UART1_IRQ),
115200, serial_hd(0), DEVICE_LITTLE_ENDIAN);
/* 4 PRCM blocks */ /* 4 PRCM blocks */
if (!sysbus_realize(SYS_BUS_DEVICE(&s->prcm[TT_ATLANTIS_PRCM_DOMAIN_RCPU]), if (!sysbus_realize(SYS_BUS_DEVICE(&s->prcm[TT_ATLANTIS_PRCM_DOMAIN_RCPU]),
errp)) { errp)) {
@@ -695,18 +693,22 @@ static void tt_atlantis_soc_realize(DeviceState *dev, Error **errp)
sysbus_mmio_get_region( sysbus_mmio_get_region(
SYS_BUS_DEVICE(&s->prcm[TT_ATLANTIS_PRCM_DOMAIN_MM]), 0)); SYS_BUS_DEVICE(&s->prcm[TT_ATLANTIS_PRCM_DOMAIN_MM]), 0));
/* /* UART1, the soc console (UART0 is for the boot microcontroller) */
* Atlantis contains a DesignWare uart while the QEMU machine qdev_prop_set_chr(DEVICE(&s->uart[tt_atlantis_uart_index(TT_ATL_UART1)]),
* uses the serial_mm model with the base ns16550 register set. "chardev", serial_hd(0));
* Linux's dw driver writes outside of serial_mm's 0x20 sized
* mapping and faults. for (int i = 0; i < TT_ATL_NUM_UARTS; i++) {
* SysBusDevice *sbd = SYS_BUS_DEVICE(&s->uart[i]);
* Create an unimplemented device region so writes don't fault if (!sysbus_realize(sbd, errp)) {
* and reads return zero, which keeps Linux happy. return;
*/ }
mmio_map_unimplemented(s->memory, SYS_BUS_DEVICE(&s->uart1),
"tt-atlantis.uart1", s->memmap[TT_ATL_UART1].base, memory_region_add_subregion(s->memory,
s->memmap[TT_ATL_UART1].size); s->memmap[TT_ATL_UART0 + i].base,
sysbus_mmio_get_region(sbd, 0));
sysbus_connect_irq(sbd, 0,
qdev_get_gpio_in(s->irqchip, TT_ATL_UART0_IRQ + i));
}
/* I2C */ /* I2C */
for (int i = 0; i < TT_ATL_NUM_I2C; i++) { for (int i = 0; i < TT_ATL_NUM_I2C; i++) {
-1
View File
@@ -31,7 +31,6 @@ DECLARE_INSTANCE_CHECKER(RISCVIMSICState, RISCV_IMSIC, TYPE_RISCV_IMSIC)
#define IMSIC_MMIO_PAGE_SZ (1UL << IMSIC_MMIO_PAGE_SHIFT) #define IMSIC_MMIO_PAGE_SZ (1UL << IMSIC_MMIO_PAGE_SHIFT)
#define IMSIC_MMIO_SIZE(__num_pages) ((__num_pages) * IMSIC_MMIO_PAGE_SZ) #define IMSIC_MMIO_SIZE(__num_pages) ((__num_pages) * IMSIC_MMIO_PAGE_SZ)
#define IMSIC_MMIO_HART_GUEST_MAX_BTIS 6
#define IMSIC_MMIO_GROUP_MIN_SHIFT 24 #define IMSIC_MMIO_GROUP_MIN_SHIFT 24
#define IMSIC_HART_NUM_GUESTS(__guest_bits) \ #define IMSIC_HART_NUM_GUESTS(__guest_bits) \
+11 -2
View File
@@ -13,8 +13,8 @@
#include "hw/core/sysbus.h" #include "hw/core/sysbus.h"
#include "hw/i2c/designware_i2c.h" #include "hw/i2c/designware_i2c.h"
#include "hw/intc/riscv_imsic.h" #include "hw/intc/riscv_imsic.h"
#include "hw/misc/unimp.h"
#include "hw/misc/tt_atlantis_prcm.h" #include "hw/misc/tt_atlantis_prcm.h"
#include "hw/char/dw8250.h"
#include "hw/riscv/riscv_hart.h" #include "hw/riscv/riscv_hart.h"
#define TYPE_TT_ATLANTIS_MACHINE MACHINE_TYPE_NAME("tt-atlantis") #define TYPE_TT_ATLANTIS_MACHINE MACHINE_TYPE_NAME("tt-atlantis")
@@ -25,6 +25,7 @@ OBJECT_DECLARE_SIMPLE_TYPE(TTAtlantisSoCState, TT_ATLANTIS_SOC)
#define TT_ATL_NUM_I2C 5 #define TT_ATL_NUM_I2C 5
#define TT_ATL_NUM_PRCM 4 #define TT_ATL_NUM_PRCM 4
#define TT_ATL_NUM_UARTS 5
struct TTAtlantisSoCState { struct TTAtlantisSoCState {
/*< private >*/ /*< private >*/
@@ -41,7 +42,7 @@ struct TTAtlantisSoCState {
RISCVHartArrayState cpus; RISCVHartArrayState cpus;
DeviceState *irqchip; DeviceState *irqchip;
DesignWareI2CState i2c[TT_ATL_NUM_I2C]; DesignWareI2CState i2c[TT_ATL_NUM_I2C];
UnimplementedDeviceState uart1; DW8250State uart[TT_ATL_NUM_UARTS];
MemoryRegion bootrom; MemoryRegion bootrom;
TTAtlantisPRCMState prcm[TT_ATL_NUM_PRCM]; TTAtlantisPRCMState prcm[TT_ATL_NUM_PRCM];
@@ -66,7 +67,11 @@ enum {
TT_ATL_I2C2_IRQ = 35, TT_ATL_I2C2_IRQ = 35,
TT_ATL_I2C3_IRQ = 36, TT_ATL_I2C3_IRQ = 36,
TT_ATL_I2C4_IRQ = 37, TT_ATL_I2C4_IRQ = 37,
TT_ATL_UART0_IRQ = 38,
TT_ATL_UART1_IRQ = 39, TT_ATL_UART1_IRQ = 39,
TT_ATL_UART2_IRQ = 40,
TT_ATL_UART3_IRQ = 41,
TT_ATL_UART4_IRQ = 42,
}; };
enum { enum {
@@ -83,7 +88,11 @@ enum {
TT_ATL_MIMSIC, TT_ATL_MIMSIC,
TT_ATL_SAPLIC, TT_ATL_SAPLIC,
TT_ATL_SIMSIC, TT_ATL_SIMSIC,
TT_ATL_UART0,
TT_ATL_UART1, TT_ATL_UART1,
TT_ATL_UART2,
TT_ATL_UART3,
TT_ATL_UART4,
TT_ATL_PRCM_RCPU, TT_ATL_PRCM_RCPU,
TT_ATL_PRCM_HSIO, TT_ATL_PRCM_HSIO,
TT_ATL_PRCM_PCIE, TT_ATL_PRCM_PCIE,
+21 -1
View File
@@ -222,6 +222,7 @@ const RISCVIsaExtData isa_edata_arr[] = {
ISA_EXT_DATA_ENTRY(zksh, PRIV_VERSION_1_12_0, ext_zksh), ISA_EXT_DATA_ENTRY(zksh, PRIV_VERSION_1_12_0, ext_zksh),
ISA_EXT_DATA_ENTRY(zkt, PRIV_VERSION_1_12_0, ext_zkt), ISA_EXT_DATA_ENTRY(zkt, PRIV_VERSION_1_12_0, ext_zkt),
ISA_EXT_DATA_ENTRY(ztso, PRIV_VERSION_1_12_0, ext_ztso), ISA_EXT_DATA_ENTRY(ztso, PRIV_VERSION_1_12_0, ext_ztso),
ISA_EXPERIMENTAL_EXT_DATA_ENTRY(zvabd, PRIV_VERSION_1_13_0, ext_zvabd),
ISA_EXT_DATA_ENTRY(zvbb, PRIV_VERSION_1_12_0, ext_zvbb), ISA_EXT_DATA_ENTRY(zvbb, PRIV_VERSION_1_12_0, ext_zvbb),
ISA_EXT_DATA_ENTRY(zvbc, PRIV_VERSION_1_12_0, ext_zvbc), ISA_EXT_DATA_ENTRY(zvbc, PRIV_VERSION_1_12_0, ext_zvbc),
ISA_EXT_DATA_ENTRY(zve32f, PRIV_VERSION_1_10_0, ext_zve32f), ISA_EXT_DATA_ENTRY(zve32f, PRIV_VERSION_1_10_0, ext_zve32f),
@@ -1549,6 +1550,25 @@ static void riscv_cpu_init(Object *obj)
cpu->env.vext_ver = VEXT_VERSION_1_00_0; cpu->env.vext_ver = VEXT_VERSION_1_00_0;
cpu->cfg.max_satp_mode = -1; cpu->cfg.max_satp_mode = -1;
/*
* The way we're handling profiles does not cope well with QMP
* instropection. We have a static array that stores RISCVCPUProfiles
* objs that hold runtime state for the lifetime of the QEMU process.
* Thus setting profile->enabled once, e.g. when instropecting a
* profile CPU, will leave the flag set for subsequent intropections.
*
* For now, clear all 'enabled' flags to avoid misleading QMP w.r.t
* profiles being set.
*
* FIXME: a better long term solution is to remove profile->enabled
* and just use regular cpu->cfg flags, avoiding static variables
* storing dynamic state. This will help us not only with QMP but
* also single-binary support.
*/
for (int i = 0; riscv_profiles[i] != NULL; i++) {
riscv_profiles[i]->enabled = false;
}
if (mcc->def->profile) { if (mcc->def->profile) {
mcc->def->profile->enabled = true; mcc->def->profile->enabled = true;
} }
@@ -2297,7 +2317,7 @@ static void prop_marchid_set(Object *obj, Visitor *v, const char *name,
g_assert_not_reached(); g_assert_not_reached();
} }
invalid_val = 1LL << (mxlen - 1); invalid_val = 1ULL << (mxlen - 1);
if (value == invalid_val) { if (value == invalid_val) {
error_setg(errp, "Unable to set marchid with MSB (%u) bit set " error_setg(errp, "Unable to set marchid with MSB (%u) bit set "
+1
View File
@@ -83,6 +83,7 @@ BOOL_FIELD(ext_zve32x)
BOOL_FIELD(ext_zve64f) BOOL_FIELD(ext_zve64f)
BOOL_FIELD(ext_zve64d) BOOL_FIELD(ext_zve64d)
BOOL_FIELD(ext_zve64x) BOOL_FIELD(ext_zve64x)
BOOL_FIELD(ext_zvabd)
BOOL_FIELD(ext_zvbb) BOOL_FIELD(ext_zvbb)
BOOL_FIELD(ext_zvbc) BOOL_FIELD(ext_zvbc)
BOOL_FIELD(ext_zvkb) BOOL_FIELD(ext_zvkb)
+26
View File
@@ -1353,6 +1353,32 @@ DEF_HELPER_5(vsm4k_vi, void, ptr, ptr, i32, env, i32)
DEF_HELPER_4(vsm4r_vv, void, ptr, ptr, env, i32) DEF_HELPER_4(vsm4r_vv, void, ptr, ptr, env, i32)
DEF_HELPER_4(vsm4r_vs, void, ptr, ptr, env, i32) DEF_HELPER_4(vsm4r_vs, void, ptr, ptr, env, i32)
/* Zvabd Extension */
DEF_HELPER_6(vabd_vv_b, void, ptr, ptr, ptr, ptr, env, i32)
DEF_HELPER_6(vabd_vv_h, void, ptr, ptr, ptr, ptr, env, i32)
DEF_HELPER_6(vabd_vv_w, void, ptr, ptr, ptr, ptr, env, i32)
DEF_HELPER_6(vabd_vv_d, void, ptr, ptr, ptr, ptr, env, i32)
DEF_HELPER_6(vabd_vx_b, void, ptr, ptr, tl, ptr, env, i32)
DEF_HELPER_6(vabd_vx_h, void, ptr, ptr, tl, ptr, env, i32)
DEF_HELPER_6(vabd_vx_w, void, ptr, ptr, tl, ptr, env, i32)
DEF_HELPER_6(vabd_vx_d, void, ptr, ptr, tl, ptr, env, i32)
DEF_HELPER_6(vabdu_vv_b, void, ptr, ptr, ptr, ptr, env, i32)
DEF_HELPER_6(vabdu_vv_h, void, ptr, ptr, ptr, ptr, env, i32)
DEF_HELPER_6(vabdu_vv_w, void, ptr, ptr, ptr, ptr, env, i32)
DEF_HELPER_6(vabdu_vv_d, void, ptr, ptr, ptr, ptr, env, i32)
DEF_HELPER_6(vabdu_vx_b, void, ptr, ptr, tl, ptr, env, i32)
DEF_HELPER_6(vabdu_vx_h, void, ptr, ptr, tl, ptr, env, i32)
DEF_HELPER_6(vabdu_vx_w, void, ptr, ptr, tl, ptr, env, i32)
DEF_HELPER_6(vabdu_vx_d, void, ptr, ptr, tl, ptr, env, i32)
DEF_HELPER_6(vwabda_vv_b, void, ptr, ptr, ptr, ptr, env, i32)
DEF_HELPER_6(vwabda_vv_h, void, ptr, ptr, ptr, ptr, env, i32)
DEF_HELPER_6(vwabda_vx_b, void, ptr, ptr, tl, ptr, env, i32)
DEF_HELPER_6(vwabda_vx_h, void, ptr, ptr, tl, ptr, env, i32)
DEF_HELPER_6(vwabdau_vv_b, void, ptr, ptr, ptr, ptr, env, i32)
DEF_HELPER_6(vwabdau_vv_h, void, ptr, ptr, ptr, ptr, env, i32)
DEF_HELPER_6(vwabdau_vx_b, void, ptr, ptr, tl, ptr, env, i32)
DEF_HELPER_6(vwabdau_vx_h, void, ptr, ptr, tl, ptr, env, i32)
/* CFI (zicfiss) helpers */ /* CFI (zicfiss) helpers */
#ifndef CONFIG_USER_ONLY #ifndef CONFIG_USER_ONLY
DEF_HELPER_1(ssamoswap_disabled, void, env) DEF_HELPER_1(ssamoswap_disabled, void, env)
+10
View File
@@ -1087,3 +1087,13 @@ sb_aqrl 00111 . . ..... ..... 000 ..... 0101111 @atom_st
sh_aqrl 00111 . . ..... ..... 001 ..... 0101111 @atom_st sh_aqrl 00111 . . ..... ..... 001 ..... 0101111 @atom_st
sw_aqrl 00111 . . ..... ..... 010 ..... 0101111 @atom_st sw_aqrl 00111 . . ..... ..... 010 ..... 0101111 @atom_st
sd_aqrl 00111 . . ..... ..... 011 ..... 0101111 @atom_st sd_aqrl 00111 . . ..... ..... 011 ..... 0101111 @atom_st
# *** Zvabd Extension ***
vabd_vv 010101 . ..... ..... 010 ..... 1010111 @r_vm
vabd_vx 010101 . ..... ..... 110 ..... 1010111 @r_vm
vabdu_vv 010110 . ..... ..... 010 ..... 1010111 @r_vm
vabdu_vx 010110 . ..... ..... 110 ..... 1010111 @r_vm
vwabda_vv 111101 . ..... ..... 000 ..... 1010111 @r_vm
vwabda_vx 111101 . ..... ..... 100 ..... 1010111 @r_vm
vwabdau_vv 111110 . ..... ..... 000 ..... 1010111 @r_vm
vwabdau_vx 111110 . ..... ..... 100 ..... 1010111 @r_vm
+27
View File
@@ -58,6 +58,7 @@ void riscv_kvm_aplic_request(void *opaque, int irq, int level)
} }
static bool cap_has_mp_state; static bool cap_has_mp_state;
static bool mp_state_reset;
#define KVM_RISCV_REG_ID_U32(type, idx) (KVM_REG_RISCV | KVM_REG_SIZE_U32 | \ #define KVM_RISCV_REG_ID_U32(type, idx) (KVM_REG_RISCV | KVM_REG_SIZE_U32 | \
type | idx) type | idx)
@@ -1444,10 +1445,31 @@ static int kvm_riscv_put_mp_state(CPUState *cs)
return kvm_vcpu_ioctl(cs, KVM_SET_MP_STATE, &mp_state); return kvm_vcpu_ioctl(cs, KVM_SET_MP_STATE, &mp_state);
} }
static int kvm_riscv_mp_state_init_received(CPUState *cs)
{
struct kvm_mp_state mp_state = {
.mp_state = KVM_MP_STATE_INIT_RECEIVED,
};
if (!cap_has_mp_state || !mp_state_reset) {
return 0;
}
/* Let KVM resets the VCPU, The original MP_STATE is preserved*/
return kvm_vcpu_ioctl(cs, KVM_SET_MP_STATE, &mp_state);
}
int kvm_arch_put_registers(CPUState *cs, KvmPutState level, Error **errp) int kvm_arch_put_registers(CPUState *cs, KvmPutState level, Error **errp)
{ {
int ret = 0; int ret = 0;
if (KVM_PUT_RESET_STATE == level) {
ret = kvm_riscv_mp_state_init_received(cs);
if (ret) {
return ret;
}
}
ret = kvm_riscv_put_regs_core(cs); ret = kvm_riscv_put_regs_core(cs);
if (ret) { if (ret) {
return ret; return ret;
@@ -1624,6 +1646,11 @@ int kvm_arch_get_default_type(MachineState *ms)
int kvm_arch_init(MachineState *ms, KVMState *s) int kvm_arch_init(MachineState *ms, KVMState *s)
{ {
cap_has_mp_state = kvm_check_extension(s, KVM_CAP_MP_STATE); cap_has_mp_state = kvm_check_extension(s, KVM_CAP_MP_STATE);
if (cap_has_mp_state) {
mp_state_reset = !kvm_vm_enable_cap(s, KVM_CAP_RISCV_MP_STATE_RESET, 0);
}
return 0; return 0;
} }
+43 -7
View File
@@ -2108,6 +2108,9 @@ static RISCVException write_mstatus(CPURISCVState *env, int csrno,
} }
if (xl != MXL_RV32 || env->debugger) { if (xl != MXL_RV32 || env->debugger) {
if (riscv_has_ext(env, RVH)) {
mask |= MSTATUS_MPV | MSTATUS_GVA;
}
if ((val & MSTATUS64_SXL) != 0) { if ((val & MSTATUS64_SXL) != 0) {
mask |= MSTATUS64_SXL; mask |= MSTATUS64_SXL;
val = riscv_write_uxl(env, val, MSTATUS64_SXL); val = riscv_write_uxl(env, val, MSTATUS64_SXL);
@@ -2150,7 +2153,7 @@ static RISCVException write_mstatush(CPURISCVState *env, int csrno,
target_ulong val, uintptr_t ra) target_ulong val, uintptr_t ra)
{ {
uint64_t valh = (uint64_t)val << 32; uint64_t valh = (uint64_t)val << 32;
uint64_t mask = 0; uint64_t mask = riscv_has_ext(env, RVH) ? MSTATUS_MPV | MSTATUS_GVA : 0;
if (riscv_cpu_cfg(env)->ext_smdbltrp) { if (riscv_cpu_cfg(env)->ext_smdbltrp) {
mask |= MSTATUS_MDT; mask |= MSTATUS_MDT;
@@ -3388,10 +3391,19 @@ static RISCVException write_menvcfg(CPURISCVState *env, int csrno,
target_ulong val, uintptr_t ra) target_ulong val, uintptr_t ra)
{ {
const RISCVCPUConfig *cfg = riscv_cpu_cfg(env); const RISCVCPUConfig *cfg = riscv_cpu_cfg(env);
uint64_t mask = MENVCFG_FIOM | MENVCFG_CBIE | MENVCFG_CBCFE | uint64_t mask = MENVCFG_FIOM;
MENVCFG_CBZE;
bool stce_changed = false; bool stce_changed = false;
/* CBIE/CBCFE are read-only zero when Zicbom is not implemented. */
if (cfg->ext_zicbom) {
mask |= MENVCFG_CBIE | MENVCFG_CBCFE;
}
/* CBZE is read-only zero when Zicboz is not implemented. */
if (cfg->ext_zicboz) {
mask |= MENVCFG_CBZE;
}
/* /*
* menvcfg.LPE (Zicfilp) and menvcfg.SSE (Zicfiss) reside in the low * menvcfg.LPE (Zicfilp) and menvcfg.SSE (Zicfiss) reside in the low
* 32 bits and are defined for both RV32 and RV64, so they must be * 32 bits and are defined for both RV32 and RV64, so they must be
@@ -3492,8 +3504,18 @@ static RISCVException read_senvcfg(CPURISCVState *env, int csrno,
static RISCVException write_senvcfg(CPURISCVState *env, int csrno, static RISCVException write_senvcfg(CPURISCVState *env, int csrno,
target_ulong val, uintptr_t ra) target_ulong val, uintptr_t ra)
{ {
uint64_t mask = SENVCFG_FIOM | SENVCFG_CBIE | SENVCFG_CBCFE | SENVCFG_CBZE; uint64_t mask = SENVCFG_FIOM;
RISCVException ret; RISCVException ret;
/* CBIE/CBCFE are read-only zero when Zicbom is not implemented. */
if (env_archcpu(env)->cfg.ext_zicbom) {
mask |= SENVCFG_CBIE | SENVCFG_CBCFE;
}
/* CBZE is read-only zero when Zicboz is not implemented. */
if (env_archcpu(env)->cfg.ext_zicboz) {
mask |= SENVCFG_CBZE;
}
/* Update PMM field only if the value is valid according to Zjpm v1.0 */ /* Update PMM field only if the value is valid according to Zjpm v1.0 */
if (env_archcpu(env)->cfg.ext_ssnpm && if (env_archcpu(env)->cfg.ext_ssnpm &&
riscv_cpu_mxl(env) == MXL_RV64 && riscv_cpu_mxl(env) == MXL_RV64 &&
@@ -3550,10 +3572,20 @@ static RISCVException write_henvcfg(CPURISCVState *env, int csrno,
target_ulong val, uintptr_t ra) target_ulong val, uintptr_t ra)
{ {
const RISCVCPUConfig *cfg = riscv_cpu_cfg(env); const RISCVCPUConfig *cfg = riscv_cpu_cfg(env);
uint64_t mask = HENVCFG_FIOM | HENVCFG_CBIE | HENVCFG_CBCFE | HENVCFG_CBZE; uint64_t mask = HENVCFG_FIOM;
RISCVException ret; RISCVException ret;
bool stce_changed = false; bool stce_changed = false;
/* CBIE/CBCFE are read-only zero when Zicbom is not implemented. */
if (cfg->ext_zicbom) {
mask |= HENVCFG_CBIE | HENVCFG_CBCFE;
}
/* CBZE is read-only zero when Zicboz is not implemented. */
if (cfg->ext_zicboz) {
mask |= HENVCFG_CBZE;
}
ret = smstateen_acc_ok(env, 0, SMSTATEEN0_HSENVCFG); ret = smstateen_acc_ok(env, 0, SMSTATEEN0_HSENVCFG);
if (ret != RISCV_EXCP_NONE) { if (ret != RISCV_EXCP_NONE) {
return ret; return ret;
@@ -5484,14 +5516,14 @@ static RISCVException write_vsscratch(CPURISCVState *env, int csrno,
static RISCVException read_vsepc(CPURISCVState *env, int csrno, static RISCVException read_vsepc(CPURISCVState *env, int csrno,
target_ulong *val) target_ulong *val)
{ {
*val = env->vsepc; *val = env->vsepc & get_xepc_mask(env);
return RISCV_EXCP_NONE; return RISCV_EXCP_NONE;
} }
static RISCVException write_vsepc(CPURISCVState *env, int csrno, static RISCVException write_vsepc(CPURISCVState *env, int csrno,
target_ulong val, uintptr_t ra) target_ulong val, uintptr_t ra)
{ {
env->vsepc = val; env->vsepc = val & get_xepc_mask(env);
return RISCV_EXCP_NONE; return RISCV_EXCP_NONE;
} }
@@ -5766,6 +5798,10 @@ static RISCVException write_mnstatus(CPURISCVState *env, int csrno,
mask |= MNSTATUS_MNPV; mask |= MNSTATUS_MNPV;
} }
if (env_archcpu(env)->cfg.ext_zicfilp) {
mask |= MNSTATUS_MNPELP;
}
/* mnstatus.mnie can only be cleared by hardware. */ /* mnstatus.mnie can only be cleared by hardware. */
env->mnstatus = (env->mnstatus & MNSTATUS_NMIE) | (val & mask); env->mnstatus = (env->mnstatus & MNSTATUS_NMIE) | (val & mask);
return RISCV_EXCP_NONE; return RISCV_EXCP_NONE;
+2 -2
View File
@@ -424,7 +424,7 @@ static bool gen_load(DisasContext *ctx, arg_lb *a, MemOp memop)
} }
if (ctx->ztso) { if (ctx->ztso) {
tcg_gen_mb(TCG_MO_ALL | TCG_BAR_LDAQ); tcg_gen_mb(TCG_MO_LD_LD | TCG_MO_LD_ST | TCG_BAR_LDAQ);
} }
return out; return out;
@@ -485,7 +485,7 @@ static bool gen_store_tl(DisasContext *ctx, arg_sb *a, MemOp memop)
TCGv data = get_gpr(ctx, a->rs2, EXT_NONE); TCGv data = get_gpr(ctx, a->rs2, EXT_NONE);
if (ctx->ztso) { if (ctx->ztso) {
tcg_gen_mb(TCG_MO_ALL | TCG_BAR_STRL); tcg_gen_mb(TCG_MO_LD_ST | TCG_MO_ST_ST | TCG_BAR_STRL);
} }
tcg_gen_qemu_st_tl(data, addr, ctx->mem_idx, memop); tcg_gen_qemu_st_tl(data, addr, ctx->mem_idx, memop);
+47 -2
View File
@@ -731,7 +731,7 @@ static bool ldst_us_trans(uint32_t vd, uint32_t rs1, uint32_t data,
* around the loop. * around the loop.
*/ */
if (is_store && s->ztso) { if (is_store && s->ztso) {
tcg_gen_mb(TCG_MO_ALL | TCG_BAR_STRL); tcg_gen_mb(TCG_MO_LD_ST | TCG_MO_ST_ST | TCG_BAR_STRL);
} }
mark_vs_dirty(s); mark_vs_dirty(s);
@@ -739,7 +739,7 @@ static bool ldst_us_trans(uint32_t vd, uint32_t rs1, uint32_t data,
fn(dest, mask, base, tcg_env, desc); fn(dest, mask, base, tcg_env, desc);
if (!is_store && s->ztso) { if (!is_store && s->ztso) {
tcg_gen_mb(TCG_MO_ALL | TCG_BAR_LDAQ); tcg_gen_mb(TCG_MO_LD_LD | TCG_MO_LD_ST | TCG_BAR_LDAQ);
} }
finalize_rvv_inst(s); finalize_rvv_inst(s);
@@ -4091,3 +4091,48 @@ GEN_INT_EXT_TRANS(vzext_vf8, 3, 2)
GEN_INT_EXT_TRANS(vsext_vf2, 1, 3) GEN_INT_EXT_TRANS(vsext_vf2, 1, 3)
GEN_INT_EXT_TRANS(vsext_vf4, 2, 4) GEN_INT_EXT_TRANS(vsext_vf4, 2, 4)
GEN_INT_EXT_TRANS(vsext_vf8, 3, 5) GEN_INT_EXT_TRANS(vsext_vf8, 3, 5)
/* Zvabd Extension */
#define GEN_ABD_CHECK(NAME, CHECK_FN, MAX_SEW) \
static bool NAME(DisasContext *s, arg_rmrr *a) \
{ \
return CHECK_FN(s, a) && s->cfg_ptr->ext_zvabd && \
s->sew <= MAX_SEW && \
(s->sew != MO_64 || s->cfg_ptr->ext_zve64x); \
}
GEN_ABD_CHECK(vabd_vv_check, opivv_check, MO_64)
GEN_ABD_CHECK(vabd_vx_check, opivx_check, MO_64)
GEN_ABD_CHECK(vwabd_vv_check, opivv_overwrite_widen_check, MO_16)
GEN_ABD_CHECK(vwabd_vx_check, opivx_overwrite_widen_check, MO_16)
GEN_OPIVV_TRANS(vabd_vv, vabd_vv_check)
GEN_OPIVX_TRANS(vabd_vx, vabd_vx_check)
GEN_OPIVV_TRANS(vabdu_vv, vabd_vv_check)
GEN_OPIVX_TRANS(vabdu_vx, vabd_vx_check)
#define GEN_ABD_OPIVV_WIDEN_TRANS(NAME, CHECK) \
static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
{ \
static gen_helper_gvec_4_ptr * const fns[2] = { \
gen_helper_##NAME##_b, gen_helper_##NAME##_h, \
}; \
return s->sew <= MO_16 && do_opivv_widen(s, a, fns[s->sew], CHECK); \
}
#define GEN_ABD_OPIVX_WIDEN_TRANS(NAME, CHECK) \
static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \
{ \
if (CHECK(s, a)) { \
static gen_helper_opivx * const fns[2] = { \
gen_helper_##NAME##_b, gen_helper_##NAME##_h, \
}; \
return opivx_trans(a->rd, a->rs1, a->rs2, a->vm, \
fns[s->sew], s); \
} \
return false; \
}
GEN_ABD_OPIVV_WIDEN_TRANS(vwabda_vv, vwabd_vv_check)
GEN_ABD_OPIVX_WIDEN_TRANS(vwabda_vx, vwabd_vx_check)
GEN_ABD_OPIVV_WIDEN_TRANS(vwabdau_vv, vwabd_vv_check)
GEN_ABD_OPIVX_WIDEN_TRANS(vwabdau_vx, vwabd_vx_check)
+9 -1
View File
@@ -201,12 +201,20 @@ static bool pmp_write_cfg(CPURISCVState *env, uint32_t pmp_index, uint8_t val)
void pmp_unlock_entries(CPURISCVState *env) void pmp_unlock_entries(CPURISCVState *env)
{ {
uint32_t pmp_num = pmp_get_num_rules(env); uint32_t pmp_num = riscv_cpu_cfg(env)->pmp_regions;
int i; int i;
for (i = 0; i < pmp_num; i++) { for (i = 0; i < pmp_num; i++) {
env->pmp_state.pmp[i].cfg_reg &= ~(PMP_LOCK | PMP_AMATCH); env->pmp_state.pmp[i].cfg_reg &= ~(PMP_LOCK | PMP_AMATCH);
} }
/*
* addr[] and num_rules are derived from the pmpaddr and pmpcfg write
* paths and are not recomputed at reset. Clear them here so they
* cannot disagree with the architectural fields cleared above.
*/
memset(env->pmp_state.addr, 0, sizeof(env->pmp_state.addr));
env->pmp_state.num_rules = 0;
} }
static void pmp_decode_napot(hwaddr a, hwaddr *sa, hwaddr *ea) static void pmp_decode_napot(hwaddr a, hwaddr *sa, hwaddr *ea)
+13 -5
View File
@@ -355,7 +355,8 @@ static void pmu_timer_trigger_irq(RISCVCPU *cpu,
CPURISCVState *env = &cpu->env; CPURISCVState *env = &cpu->env;
PMUCTRState *counter; PMUCTRState *counter;
int64_t irq_trigger_at; int64_t irq_trigger_at;
uint64_t curr_ctr_val, curr_ctrh_val; target_ulong ctr_lo = 0, ctr_hi = 0;
uint64_t curr_ctr_val;
uint64_t ctr_val; uint64_t ctr_val;
if (evt_idx != RISCV_PMU_EVENT_HW_CPU_CYCLES && if (evt_idx != RISCV_PMU_EVENT_HW_CPU_CYCLES &&
@@ -383,12 +384,19 @@ static void pmu_timer_trigger_irq(RISCVCPU *cpu,
return; return;
} }
riscv_pmu_read_ctr(env, (target_ulong *)&curr_ctr_val, false, ctr_idx); /*
ctr_val = counter->mhpmcounter_val; * riscv_pmu_read_ctr() stores a target_ulong, so on RV32 each call fills
* only 32 bits. Read each half into its own target_ulong and build the
* 64 bit value explicitly instead of passing a cast uint64_t pointer,
* which would leave the upper half uninitialised.
*/
riscv_pmu_read_ctr(env, &ctr_lo, false, ctr_idx);
curr_ctr_val = ctr_lo;
if (riscv_cpu_mxl(env) == MXL_RV32) { if (riscv_cpu_mxl(env) == MXL_RV32) {
riscv_pmu_read_ctr(env, (target_ulong *)&curr_ctrh_val, true, ctr_idx); riscv_pmu_read_ctr(env, &ctr_hi, true, ctr_idx);
curr_ctr_val = curr_ctr_val | (curr_ctrh_val << 32); curr_ctr_val |= (uint64_t)ctr_hi << 32;
} }
ctr_val = counter->mhpmcounter_val;
/* /*
* We can not accommodate for inhibited modes when setting up timer. Check * We can not accommodate for inhibited modes when setting up timer. Check
+6
View File
@@ -760,6 +760,12 @@ void riscv_cpu_validate_set_extensions(RISCVCPU *cpu, Error **errp)
return; return;
} }
if ((cpu->cfg.ext_zvabd) && !cpu->cfg.ext_zve32x) {
error_setg(errp,
"Zvabd extensions require V or Zve* extensions");
return;
}
if (cpu->cfg.ext_zicntr && !cpu->cfg.ext_zicsr) { if (cpu->cfg.ext_zicntr && !cpu->cfg.ext_zicsr) {
if (cpu_cfg_ext_is_user_set(cpu, CPU_CFG_OFFSET(ext_zicntr))) { if (cpu_cfg_ext_is_user_set(cpu, CPU_CFG_OFFSET(ext_zicntr))) {
error_setg(errp, "zicntr requires zicsr"); error_setg(errp, "zicntr requires zicsr");
+16 -16
View File
@@ -693,7 +693,7 @@ static TCGv get_address_indexed(DisasContext *ctx, int rs1, TCGv offs)
*/ */
static void mark_fs_dirty(DisasContext *ctx) static void mark_fs_dirty(DisasContext *ctx)
{ {
TCGv tmp; TCGv_i64 tmp;
if (!has_ext(ctx, RVF)) { if (!has_ext(ctx, RVF)) {
return; return;
@@ -703,15 +703,15 @@ static void mark_fs_dirty(DisasContext *ctx)
/* Remember the state change for the rest of the TB. */ /* Remember the state change for the rest of the TB. */
ctx->mstatus_fs = EXT_STATUS_DIRTY; ctx->mstatus_fs = EXT_STATUS_DIRTY;
tmp = tcg_temp_new(); tmp = tcg_temp_new_i64();
tcg_gen_ld_tl(tmp, tcg_env, offsetof(CPURISCVState, mstatus)); tcg_gen_ld_i64(tmp, tcg_env, offsetof(CPURISCVState, mstatus));
tcg_gen_ori_tl(tmp, tmp, MSTATUS_FS); tcg_gen_ori_i64(tmp, tmp, MSTATUS_FS);
tcg_gen_st_tl(tmp, tcg_env, offsetof(CPURISCVState, mstatus)); tcg_gen_st_i64(tmp, tcg_env, offsetof(CPURISCVState, mstatus));
if (ctx->virt_enabled) { if (ctx->virt_enabled) {
tcg_gen_ld_tl(tmp, tcg_env, offsetof(CPURISCVState, mstatus_hs)); tcg_gen_ld_i64(tmp, tcg_env, offsetof(CPURISCVState, mstatus_hs));
tcg_gen_ori_tl(tmp, tmp, MSTATUS_FS); tcg_gen_ori_i64(tmp, tmp, MSTATUS_FS);
tcg_gen_st_tl(tmp, tcg_env, offsetof(CPURISCVState, mstatus_hs)); tcg_gen_st_i64(tmp, tcg_env, offsetof(CPURISCVState, mstatus_hs));
} }
} }
} }
@@ -726,21 +726,21 @@ static inline void mark_fs_dirty(DisasContext *ctx) { }
*/ */
static void mark_vs_dirty(DisasContext *ctx) static void mark_vs_dirty(DisasContext *ctx)
{ {
TCGv tmp; TCGv_i64 tmp;
if (ctx->mstatus_vs != EXT_STATUS_DIRTY) { if (ctx->mstatus_vs != EXT_STATUS_DIRTY) {
/* Remember the state change for the rest of the TB. */ /* Remember the state change for the rest of the TB. */
ctx->mstatus_vs = EXT_STATUS_DIRTY; ctx->mstatus_vs = EXT_STATUS_DIRTY;
tmp = tcg_temp_new(); tmp = tcg_temp_new_i64();
tcg_gen_ld_tl(tmp, tcg_env, offsetof(CPURISCVState, mstatus)); tcg_gen_ld_i64(tmp, tcg_env, offsetof(CPURISCVState, mstatus));
tcg_gen_ori_tl(tmp, tmp, MSTATUS_VS); tcg_gen_ori_i64(tmp, tmp, MSTATUS_VS);
tcg_gen_st_tl(tmp, tcg_env, offsetof(CPURISCVState, mstatus)); tcg_gen_st_i64(tmp, tcg_env, offsetof(CPURISCVState, mstatus));
if (ctx->virt_enabled) { if (ctx->virt_enabled) {
tcg_gen_ld_tl(tmp, tcg_env, offsetof(CPURISCVState, mstatus_hs)); tcg_gen_ld_i64(tmp, tcg_env, offsetof(CPURISCVState, mstatus_hs));
tcg_gen_ori_tl(tmp, tmp, MSTATUS_VS); tcg_gen_ori_i64(tmp, tmp, MSTATUS_VS);
tcg_gen_st_tl(tmp, tcg_env, offsetof(CPURISCVState, mstatus_hs)); tcg_gen_st_i64(tmp, tcg_env, offsetof(CPURISCVState, mstatus_hs));
} }
} }
} }
+56
View File
@@ -5911,3 +5911,59 @@ GEN_VEXT_INT_EXT(vsext_vf2_d, int64_t, int32_t, H8, H4)
GEN_VEXT_INT_EXT(vsext_vf4_w, int32_t, int8_t, H4, H1) GEN_VEXT_INT_EXT(vsext_vf4_w, int32_t, int8_t, H4, H1)
GEN_VEXT_INT_EXT(vsext_vf4_d, int64_t, int16_t, H8, H2) GEN_VEXT_INT_EXT(vsext_vf4_d, int64_t, int16_t, H8, H2)
GEN_VEXT_INT_EXT(vsext_vf8_d, int64_t, int8_t, H8, H1) GEN_VEXT_INT_EXT(vsext_vf8_d, int64_t, int8_t, H8, H1)
/* Zvabd Extension */
#define DO_ABD(N, M) (N > M ? N - M : M - N)
#define DO_ABDACC(N, M, D) (DO_ABD(N, M) + D)
RVVCALL(OPIVV2, vabd_vv_b, OP_SSS_B, H1, H1, H1, DO_ABD)
RVVCALL(OPIVV2, vabd_vv_h, OP_SSS_H, H2, H2, H2, DO_ABD)
RVVCALL(OPIVV2, vabd_vv_w, OP_SSS_W, H4, H4, H4, DO_ABD)
RVVCALL(OPIVV2, vabd_vv_d, OP_SSS_D, H8, H8, H8, DO_ABD)
RVVCALL(OPIVX2, vabd_vx_b, OP_SSS_B, H1, H1, DO_ABD)
RVVCALL(OPIVX2, vabd_vx_h, OP_SSS_H, H2, H2, DO_ABD)
RVVCALL(OPIVX2, vabd_vx_w, OP_SSS_W, H4, H4, DO_ABD)
RVVCALL(OPIVX2, vabd_vx_d, OP_SSS_D, H8, H8, DO_ABD)
RVVCALL(OPIVV2, vabdu_vv_b, OP_UUU_B, H1, H1, H1, DO_ABD)
RVVCALL(OPIVV2, vabdu_vv_h, OP_UUU_H, H2, H2, H2, DO_ABD)
RVVCALL(OPIVV2, vabdu_vv_w, OP_UUU_W, H4, H4, H4, DO_ABD)
RVVCALL(OPIVV2, vabdu_vv_d, OP_UUU_D, H8, H8, H8, DO_ABD)
RVVCALL(OPIVX2, vabdu_vx_b, OP_UUU_B, H1, H1, DO_ABD)
RVVCALL(OPIVX2, vabdu_vx_h, OP_UUU_H, H2, H2, DO_ABD)
RVVCALL(OPIVX2, vabdu_vx_w, OP_UUU_W, H4, H4, DO_ABD)
RVVCALL(OPIVX2, vabdu_vx_d, OP_UUU_D, H8, H8, DO_ABD)
RVVCALL(OPIVV3, vwabda_vv_b, WOP_SSS_B, H2, H1, H1, DO_ABDACC)
RVVCALL(OPIVV3, vwabda_vv_h, WOP_SSS_H, H4, H2, H2, DO_ABDACC)
RVVCALL(OPIVX3, vwabda_vx_b, WOP_SSS_B, H2, H1, DO_ABDACC)
RVVCALL(OPIVX3, vwabda_vx_h, WOP_SSS_H, H4, H2, DO_ABDACC)
RVVCALL(OPIVV3, vwabdau_vv_b, WOP_UUU_B, H2, H1, H1, DO_ABDACC)
RVVCALL(OPIVV3, vwabdau_vv_h, WOP_UUU_H, H4, H2, H2, DO_ABDACC)
RVVCALL(OPIVX3, vwabdau_vx_b, WOP_UUU_B, H2, H1, DO_ABDACC)
RVVCALL(OPIVX3, vwabdau_vx_h, WOP_UUU_H, H4, H2, DO_ABDACC)
GEN_VEXT_VV(vabd_vv_b, 1)
GEN_VEXT_VV(vabd_vv_h, 2)
GEN_VEXT_VV(vabd_vv_w, 4)
GEN_VEXT_VV(vabd_vv_d, 8)
GEN_VEXT_VX(vabd_vx_b, 1)
GEN_VEXT_VX(vabd_vx_h, 2)
GEN_VEXT_VX(vabd_vx_w, 4)
GEN_VEXT_VX(vabd_vx_d, 8)
GEN_VEXT_VV(vabdu_vv_b, 1)
GEN_VEXT_VV(vabdu_vv_h, 2)
GEN_VEXT_VV(vabdu_vv_w, 4)
GEN_VEXT_VV(vabdu_vv_d, 8)
GEN_VEXT_VX(vabdu_vx_b, 1)
GEN_VEXT_VX(vabdu_vx_h, 2)
GEN_VEXT_VX(vabdu_vx_w, 4)
GEN_VEXT_VX(vabdu_vx_d, 8)
GEN_VEXT_VV(vwabda_vv_b, 2)
GEN_VEXT_VV(vwabda_vv_h, 4)
GEN_VEXT_VX(vwabda_vx_b, 2)
GEN_VEXT_VX(vwabda_vx_h, 4)
GEN_VEXT_VV(vwabdau_vv_b, 2)
GEN_VEXT_VV(vwabdau_vv_h, 4)
GEN_VEXT_VX(vwabdau_vx_b, 2)
GEN_VEXT_VX(vwabdau_vx_h, 4)
+193
View File
@@ -19,6 +19,12 @@
#define DMA_LEN 4 #define DMA_LEN 4
#define DBG_PAGE_SIZE 0x1000ull
#define DBG_NAPOT_SIZE 0x10000ull
#define DBG_SUPERPAGE_SIZE 0x200000ull
#define DBG_TRANSLATED_PA 0x90000000ull
#define DBG_NESTED_GPA 0x200000ull
/* RISC-V virt machine PCI configuration */ /* RISC-V virt machine PCI configuration */
#define RISCV_GPEX_PIO_BASE 0x3000000 #define RISCV_GPEX_PIO_BASE 0x3000000
#define RISCV_BUS_PIO_LIMIT 0x10000 #define RISCV_BUS_PIO_LIMIT 0x10000
@@ -35,6 +41,64 @@ typedef struct RiscvIommuTestState {
uint64_t iommu_base; uint64_t iommu_base;
} RiscvIommuTestState; } RiscvIommuTestState;
typedef struct RiscvIommuDbgTest {
const char *name;
QRIOMMUTransMode mode;
uint64_t s_page_size;
uint64_t g_page_size;
uint64_t pa;
uint64_t expected_response;
} RiscvIommuDbgTest;
static const RiscvIommuDbgTest debug_tests[] = {
{
.name = "page-4k",
.mode = QRIOMMU_TM_S_STAGE_ONLY,
.s_page_size = DBG_PAGE_SIZE,
.pa = DBG_TRANSLATED_PA + DBG_PAGE_SIZE,
.expected_response = 0x24000400ull,
}, {
.name = "napot-64k",
.mode = QRIOMMU_TM_S_STAGE_ONLY,
.s_page_size = DBG_NAPOT_SIZE,
.pa = DBG_TRANSLATED_PA,
.expected_response = 0x24001e00ull,
}, {
.name = "superpage",
.mode = QRIOMMU_TM_S_STAGE_ONLY,
.s_page_size = DBG_SUPERPAGE_SIZE,
.pa = DBG_TRANSLATED_PA,
.expected_response = 0x2403fe00ull,
}, {
.name = "g-stage-superpage",
.mode = QRIOMMU_TM_G_STAGE_ONLY,
.g_page_size = DBG_SUPERPAGE_SIZE,
.pa = DBG_TRANSLATED_PA,
.expected_response = 0x2403fe00ull,
}, {
.name = "nested-s4k-g2m",
.mode = QRIOMMU_TM_NESTED,
.s_page_size = DBG_PAGE_SIZE,
.g_page_size = DBG_SUPERPAGE_SIZE,
.pa = DBG_TRANSLATED_PA,
.expected_response = 0x24001000ull,
}, {
.name = "nested-s2m-g4k",
.mode = QRIOMMU_TM_NESTED,
.s_page_size = DBG_SUPERPAGE_SIZE,
.g_page_size = DBG_PAGE_SIZE,
.pa = DBG_TRANSLATED_PA,
.expected_response = 0x24001000ull,
}, {
.name = "nested-s2m-g2m",
.mode = QRIOMMU_TM_NESTED,
.s_page_size = DBG_SUPERPAGE_SIZE,
.g_page_size = DBG_SUPERPAGE_SIZE,
.pa = DBG_TRANSLATED_PA,
.expected_response = 0x2403fe00ull,
},
};
static void riscv_config_qpci_bus(QGenericPCIBus *qpci) static void riscv_config_qpci_bus(QGenericPCIBus *qpci)
{ {
qpci->gpex_pio_base = RISCV_GPEX_PIO_BASE; qpci->gpex_pio_base = RISCV_GPEX_PIO_BASE;
@@ -264,6 +328,129 @@ static void test_riscv_iommu_nested(void)
run_riscv_iommu_translation(&cfg); run_riscv_iommu_translation(&cfg);
} }
static void riscv_iommu_dbg_map_leaf(QTestState *qts, uint64_t l1_pa,
uint64_t l2_pa, uint64_t va, uint64_t pa,
uint64_t page_size)
{
uint64_t pte = ((pa >> 12) << 10) | QRIOMMU_LEAF_PTE_RW_MASK;
uint64_t pte_addr;
g_assert_cmphex(pa & (page_size - 1), ==, 0);
if (page_size == DBG_SUPERPAGE_SIZE) {
pte_addr = l1_pa + (((va >> 21) & 0x1ff) * sizeof(uint64_t));
qtest_writeq(qts, pte_addr, pte);
} else if (page_size == DBG_NAPOT_SIZE) {
/* A 64 KiB NAPOT PTE has N=1 and PPN[3:0]=1000. */
pte |= BIT_ULL(63) | (8ull << 10);
va &= ~(DBG_NAPOT_SIZE - 1);
for (unsigned i = 0; i < DBG_NAPOT_SIZE / DBG_PAGE_SIZE; i++) {
pte_addr = l2_pa + ((((va >> 12) + i) & 0x1ff) *
sizeof(uint64_t));
qtest_writeq(qts, pte_addr, pte);
}
} else {
g_assert_cmphex(page_size, ==, DBG_PAGE_SIZE);
pte_addr = l2_pa + (((va >> 12) & 0x1ff) * sizeof(uint64_t));
qtest_writeq(qts, pte_addr, pte);
}
}
static uint64_t riscv_iommu_dbg_translate(RiscvIommuTestState *state,
uint64_t iova)
{
uint64_t request;
qtest_writeq(state->qts,
state->iommu_base + RISCV_IOMMU_REG_TR_REQ_IOVA, iova);
request = ((uint64_t)state->testdev->devfn << 40) |
RISCV_IOMMU_TR_REQ_CTL_GO_BUSY;
qtest_writeq(state->qts,
state->iommu_base + RISCV_IOMMU_REG_TR_REQ_CTL, request);
request = qtest_readq(state->qts,
state->iommu_base + RISCV_IOMMU_REG_TR_REQ_CTL);
g_assert_cmpuint(request & RISCV_IOMMU_TR_REQ_CTL_GO_BUSY, ==, 0);
return qtest_readq(state->qts,
state->iommu_base + RISCV_IOMMU_REG_TR_RESPONSE);
}
static void test_riscv_iommu_dbg(gconstpointer data)
{
const RiscvIommuDbgTest *cfg = data;
RiscvIommuTestState state = { 0 };
uint64_t iova = QRIOMMU_IOVA & ~(DBG_PAGE_SIZE - 1);
uint64_t s_pa = cfg->pa;
uint64_t page_size = cfg->mode == QRIOMMU_TM_G_STAGE_ONLY ?
cfg->g_page_size : cfg->s_page_size;
uint64_t response;
if (!riscv_iommu_test_setup(&state)) {
return;
}
riscv_iommu_check(state.qts, state.iommu_base, cfg->mode);
qriommu_build_translation(state.qts, cfg->mode, state.testdev->devfn);
if (cfg->mode == QRIOMMU_TM_NESTED) {
uint64_t g_l1_pa = QRIOMMU_SPACE_OFFS + QRIOMMU_G_L0_PTE_VAL;
uint64_t g_l2_pa = QRIOMMU_SPACE_OFFS + QRIOMMU_G_L1_PTE_VAL;
uint64_t offset = iova & (DBG_SUPERPAGE_SIZE - 1);
uint64_t gpa = DBG_NESTED_GPA + offset;
uint64_t pte_addr;
uint64_t pte;
/* Map all S-stage page tables through one 2 MiB G-stage leaf. */
riscv_iommu_dbg_map_leaf(state.qts, g_l1_pa, g_l2_pa, 0,
QRIOMMU_SPACE_OFFS, DBG_SUPERPAGE_SIZE);
if (cfg->g_page_size == DBG_PAGE_SIZE) {
pte_addr = g_l1_pa + (((gpa >> 21) & 0x1ff) * sizeof(uint64_t));
pte = ((g_l2_pa >> 12) << 10) | QRIOMMU_NON_LEAF_PTE_MASK;
qtest_writeq(state.qts, pte_addr, pte);
}
riscv_iommu_dbg_map_leaf(state.qts, g_l1_pa, g_l2_pa, gpa,
cfg->pa + (offset & ~(cfg->g_page_size - 1)),
cfg->g_page_size);
s_pa = gpa & ~(cfg->s_page_size - 1);
page_size = MIN(page_size, cfg->g_page_size);
}
if (cfg->mode == QRIOMMU_TM_G_STAGE_ONLY) {
riscv_iommu_dbg_map_leaf(state.qts,
QRIOMMU_SPACE_OFFS + QRIOMMU_G_L0_PTE_VAL,
QRIOMMU_SPACE_OFFS + QRIOMMU_G_L1_PTE_VAL,
iova, cfg->pa, cfg->g_page_size);
} else {
riscv_iommu_dbg_map_leaf(state.qts,
QRIOMMU_SPACE_OFFS + QRIOMMU_L0_PTE_VAL,
QRIOMMU_SPACE_OFFS + QRIOMMU_L1_PTE_VAL,
iova, s_pa, cfg->s_page_size);
}
qriommu_program_regs(state.qts, state.iommu_base);
/*
* The spec permits reporting a smaller range. These tests check QEMU's
* choice to report the effective range returned by an uncached walk.
* No DMA precedes these requests, and debug requests do not fill the IOTLB.
*/
response = riscv_iommu_dbg_translate(&state, iova);
g_assert_cmphex(response, ==, cfg->expected_response);
if (page_size > DBG_PAGE_SIZE) {
/* Check both ends as well as the interior of the reported range. */
iova &= ~(page_size - 1);
response = riscv_iommu_dbg_translate(&state, iova);
g_assert_cmphex(response, ==, cfg->expected_response);
response = riscv_iommu_dbg_translate(&state,
iova + page_size - DBG_PAGE_SIZE);
g_assert_cmphex(response, ==, cfg->expected_response);
}
riscv_iommu_test_teardown(&state);
}
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
g_test_init(&argc, &argv, NULL); g_test_init(&argc, &argv, NULL);
@@ -275,5 +462,11 @@ int main(int argc, char **argv)
test_riscv_iommu_g_stage_only); test_riscv_iommu_g_stage_only);
qtest_add_func("/iommu-testdev/translation/ns-nested", qtest_add_func("/iommu-testdev/translation/ns-nested",
test_riscv_iommu_nested); test_riscv_iommu_nested);
for (unsigned i = 0; i < G_N_ELEMENTS(debug_tests); i++) {
g_autofree char *path = g_strdup_printf("/iommu-testdev/debug/%s",
debug_tests[i].name);
qtest_add_data_func(path, &debug_tests[i], test_riscv_iommu_dbg);
}
return g_test_run(); return g_test_run();
} }
+1 -1
View File
@@ -46,7 +46,7 @@ static inline hwaddr k230_sram_addr(hwaddr off)
static inline hwaddr k230_sram_input_addr(unsigned int slot) static inline hwaddr k230_sram_input_addr(unsigned int slot)
{ {
return k230_sram_addr(K230_DECOMP_GZIP_SRAM_IN_BASE + return k230_sram_addr(K230_DECOMP_GZIP_SRAM_IN_BASE +
slot * K230_DECOMP_GZIP_BLOCK_SIZE); (hwaddr) slot * K230_DECOMP_GZIP_BLOCK_SIZE);
} }
/* /*
+12
View File
@@ -25,6 +25,18 @@ tests += {
'test-minstret-ecall.S': setup + {'qemu_args': ['-icount', 'shift=1', qemu_args]}, 'test-minstret-ecall.S': setup + {'qemu_args': ['-icount', 'shift=1', qemu_args]},
'test-minstret-wfi.S': setup + {'qemu_args': ['-icount', 'shift=1', qemu_args]}, 'test-minstret-wfi.S': setup + {'qemu_args': ['-icount', 'shift=1', qemu_args]},
'test-misa-w.S': setup + {'qemu_args': ['-cpu', 'rv64,x-misa-w=true,c=true,v=true', qemu_args]}, 'test-misa-w.S': setup + {'qemu_args': ['-cpu', 'rv64,x-misa-w=true,c=true,v=true', qemu_args]},
'test-zvabd.S': setup + {'qemu_args': ['-cpu', 'rv64,v=true,vlen=256,x-zvabd=true', qemu_args]},
'test-vsepc-masking.S': setup + {
'test_name': 'test-vsepc-masking-c',
'qemu_args': ['-cpu', 'rv64,h=true,c=true', qemu_args],
},
}
tests += {
'test-vsepc-masking.S': {
'test_name': 'test-vsepc-masking-no-c',
'qemu_args': ['-cpu', 'rv64,h=true,c=false,zca=false', qemu_args],
},
} }
tests += { tests += {
+54
View File
@@ -0,0 +1,54 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
#define MISA_C (1 << 2)
.option norvc
.text
.global _start
_start:
csrr s0, misa
andi s0, s0, MISA_C
lla s1, test_addr
ori t0, s1, 3
csrw vsepc, t0
csrr t1, vsepc
beqz s0, ialign32
addi t2, s1, 2 /* IALIGN=16: bit 0 reads as zero. */
j check
ialign32:
/* IALIGN=32: bits [1:0] read as zero. */
mv t2, s1
check:
li a0, 2
bne t1, t2, _exit
li a0, 0
j _exit
.balign 4
test_addr:
nop
/* Exit code in a0. */
_exit:
lla a1, semiargs
li t0, 0x20026 /* ADP_Stopped_ApplicationExit */
sd t0, 0(a1)
sd a0, 8(a1)
li a0, 0x20 /* TARGET_SYS_EXIT_EXTENDED */
/* Semihosting call sequence. */
.balign 16
slli zero, zero, 0x1f
ebreak
srai zero, zero, 0x7
j .
.data
.balign 16
semiargs:
.space 16
+659
View File
@@ -0,0 +1,659 @@
/*
* Test the Zvabd vector absolute-difference instructions and the vabs.v
* pseudoinstruction.
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
.option arch, +v
.option norvc
.text
.global _start
_start:
/* Enable the vector unit (mstatus.VS = Initial). */
li t0, 1 << 9
csrs mstatus, t0
/* Route synchronous traps to trap_handler (mtvec direct mode). */
la t0, trap_handler
csrw mtvec, t0
/* Run each test function. */
call test_vabs_v
bnez a0, _exit
call test_vabs_v_mask
bnez a0, _exit
call test_vabd_vv
bnez a0, _exit
call test_vabd_vv_mask
bnez a0, _exit
call test_vabd_vx
bnez a0, _exit
call test_vabd_vx_mask
bnez a0, _exit
call test_vabdu_vv
bnez a0, _exit
call test_vabdu_vv_mask
bnez a0, _exit
call test_vabdu_vx
bnez a0, _exit
call test_vabdu_vx_mask
bnez a0, _exit
call test_vwabda_vv
bnez a0, _exit
call test_vwabda_vv_mask
bnez a0, _exit
call test_vwabda_vx
bnez a0, _exit
call test_vwabda_vx_mask
bnez a0, _exit
call test_vwabdau_vv
bnez a0, _exit
call test_vwabdau_vv_mask
bnez a0, _exit
call test_vwabdau_vx
bnez a0, _exit
call test_vwabdau_vx_mask
bnez a0, _exit
j _exit
test_vabs_v:
vsetivli zero, 2, e8, m1, ta, ma
/* Load .arr_neg array in v1 */
la t0,.arr_neg
vle8.v v1,0(t0)
/* vabs.v v2, v1 (vabd.vx v2, v1, x0) raw opcode */
.insn r 0x57, 0x6, 0x2b, x2, x0, x1
/* Load .arr_pos in v3 */
la t1,.arr_pos
vle8.v v3,0(t1)
/* Compare v2 and v3 into v0 */
vmsne.vv v0,v2,v3
vcpop.m a0,v0
snez a0,a0
ret
test_vabs_v_mask:
vsetivli zero, 2, e8, m1, ta, mu
/* Load .arr_neg array in v1 */
la t0, .arr_neg
vle8.v v1, 0(t0)
/* Zero v2 using .arr_zero */
la t0,.arr_zero
vle8.v v2,0(t0)
/* Load .v0_mask array in v0 */
la t1,.v0_mask
vle8.v v0,0(t1)
/* vabs.v v2, v1, v0.t raw opcode */
.insn r 0x57, 0x6, 0x2a, x2, x0, x1
/* Load .arr_masked in v3 */
la t0,.arr_masked
vle8.v v3,0(t0)
/* Compare v2 and v3 into v0 */
vmsne.vv v0,v2,v3
vcpop.m a0,v0
snez a0,a0
ret
test_vabd_vv:
/*
* Test signed vector-vector absolute difference:
* abs({-5, -7} - {5, 7}) = {10, 14}.
*/
vsetivli zero, 2, e8, m1, ta, mu
/* Load the two signed source vectors into v1 and v3. */
la t0, .arr_neg
vle8.v v1, 0(t0)
la t0, .arr_pos
vle8.v v3, 0(t0)
/* Execute vabd.vv v2, v1, v3. */
.insn r 0x57, 0x2, 0x2b, x2, x3, x1
/* Load the expected result into v3. */
la t0, .expect_vabd_vv
vle8.v v3, 0(t0)
/* Compare v2 and v3 into v0 */
vmsne.vv v0, v2, v3
vcpop.m a0, v0
snez a0, a0
ret
test_vabd_vv_mask:
/*
* Test masked vabd.vv. Element 0 remains 9 and element 1 becomes
* abs(-7 - 7) = 14.
*/
vsetivli zero, 2, e8, m1, ta, mu
/* Load the two signed source vectors into v1 and v3. */
la t0, .arr_neg
vle8.v v1, 0(t0)
la t0, .arr_pos
vle8.v v3, 0(t0)
/* Load original value into v2 */
la t0, .arr_init
vle8.v v2, 0(t0)
/* Load mask value into v0 */
la t0, .v0_mask
vle8.v v0, 0(t0)
.insn r 0x57, 0x2, 0x2a, x2, x3, x1
/* Load the expected result into v3. */
la t0, .expect_vabd_vv_masked
vle8.v v3, 0(t0)
vmsne.vv v0, v2, v3
vcpop.m a0, v0
snez a0, a0
ret
test_vabd_vx:
/*
* Test signed vector-scalar absolute difference:
* abs({-5, -7} - 3) = {8, 10}.
*/
vsetivli zero, 2, e8, m1, ta, mu
la t0, .arr_neg
vle8.v v1, 0(t0)
li a2, 3
/* Execute vabd.vx v2, v1, a2. */
.insn r 0x57, 0x6, 0x2b, x2, x12, x1
/* Load the expected result into v3. */
la t0, .expect_vabd_vx
vle8.v v3, 0(t0)
vmsne.vv v0, v2, v3
vcpop.m a0, v0
snez a0, a0
ret
test_vabd_vx_mask:
/*
* Test masked vabd.vx. Element 0 remains 9 and element 1 becomes
* abs(-7 - 3) = 10.
*/
vsetivli zero, 2, e8, m1, ta, mu
la t0, .arr_neg
vle8.v v1, 0(t0)
li a2, 3
la t0, .arr_init
vle8.v v2, 0(t0)
la t0, .v0_mask
vle8.v v0, 0(t0)
.insn r 0x57, 0x6, 0x2a, x2, x12, x1
la t0, .expect_vabd_vx_masked
vle8.v v3, 0(t0)
vmsne.vv v0, v2, v3
vcpop.m a0, v0
snez a0, a0
ret
test_vabdu_vv:
/*
* Test unsigned vector-vector absolute difference:
* abs({0, 255} - {255, 0}) = {255, 255}.
*/
vsetivli zero, 2, e8, m1, ta, mu
/* Load the two unsigned source vectors into v1 and v3. */
la t0, .arr_unsigned_lhs
vle8.v v1, 0(t0)
la t0, .arr_unsigned_rhs
vle8.v v3, 0(t0)
/* Execute vabdu.vv v2, v1, v3. */
.insn r 0x57, 0x2, 0x2d, x2, x3, x1
/* Load the expected result into v3. */
la t0, .expect_vabdu_vv
vle8.v v3, 0(t0)
vmsne.vv v0, v2, v3
vcpop.m a0, v0
snez a0, a0
ret
test_vabdu_vv_mask:
/*
* Test masked vabdu.vv. Element 0 remains 9 and element 1 becomes
* abs(255 - 0) = 255.
*/
vsetivli zero, 2, e8, m1, ta, mu
la t0, .arr_unsigned_lhs
vle8.v v1, 0(t0)
la t0, .arr_unsigned_rhs
vle8.v v3, 0(t0)
la t0, .arr_init
vle8.v v2, 0(t0)
la t0, .v0_mask
vle8.v v0, 0(t0)
.insn r 0x57, 0x2, 0x2c, x2, x3, x1
la t0, .expect_vabdu_vv_masked
vle8.v v3, 0(t0)
vmsne.vv v0, v2, v3
vcpop.m a0, v0
snez a0, a0
ret
test_vabdu_vx:
/*
* Test unsigned vector-scalar absolute difference:
* abs({0, 255} - 128) = {128, 127}.
*/
vsetivli zero, 2, e8, m1, ta, mu
la t0, .arr_unsigned_lhs
vle8.v v1, 0(t0)
li a2, 128
/* Execute vabdu.vx v2, v1, a2. */
.insn r 0x57, 0x6, 0x2d, x2, x12, x1
la t0, .expect_vabdu_vx
vle8.v v3, 0(t0)
vmsne.vv v0, v2, v3
vcpop.m a0, v0
snez a0, a0
ret
test_vabdu_vx_mask:
/*
* Test masked vabdu.vx. Element 0 remains 9 and element 1 becomes
* abs(255 - 128) = 127.
*/
vsetivli zero, 2, e8, m1, ta, mu
la t0, .arr_unsigned_lhs
vle8.v v1, 0(t0)
li a2, 128
la t0, .arr_init
vle8.v v2, 0(t0)
la t0, .v0_mask
vle8.v v0, 0(t0)
.insn r 0x57, 0x6, 0x2c, x2, x12, x1
la t0, .expect_vabdu_vx_masked
vle8.v v3, 0(t0)
vmsne.vv v0, v2, v3
vcpop.m a0, v0
snez a0, a0
ret
test_vwabda_vv:
/*
* Test signed widening vector-vector absolute difference and
* accumulation. Start with v4 = {1000, -1000}, and the expected
* widened result is {1000, -1000} + abs({-5, -7} - {5, 7}) =
* {1010, -986}.
*/
/* Load the 16-bit accumulator before selecting 8-bit operands. */
vsetivli zero, 2, e16, m2, ta, mu
la t0, .arr_signed_acc
vle16.v v4, 0(t0)
vsetivli zero, 2, e8, m1, ta, mu
la t0, .arr_neg
vle8.v v1, 0(t0)
la t0, .arr_pos
vle8.v v2, 0(t0)
/* Execute vwabda.vv v4, v1, v2. */
.insn r 0x57, 0x0, 0x7b, x4, x2, x1
/* Select the widened EEW and compare v4 with the expected result. */
vsetivli zero, 2, e16, m2, ta, mu
la t0, .expect_vwabda_vv
vle16.v v6, 0(t0)
vmsne.vv v0, v4, v6
vcpop.m a0, v0
snez a0, a0
ret
test_vwabda_vv_mask:
/*
* Test masked vwabda.vv.
* Start with v4 = {1000, -1000}, v0 = {0, 1}, and the expected widened
* result is {1000, -1000} + abs({-5, -7} - {5, 7}) = {1000, -986}.
*/
vsetivli zero, 2, e16, m2, ta, mu
la t0, .arr_signed_acc
vle16.v v4, 0(t0)
vsetivli zero, 2, e8, m1, ta, mu
la t0, .arr_neg
vle8.v v1, 0(t0)
la t0, .arr_pos
vle8.v v2, 0(t0)
la t0, .v0_mask
vle8.v v0, 0(t0)
.insn r 0x57, 0x0, 0x7a, x4, x2, x1
vsetivli zero, 2, e16, m2, ta, mu
la t0, .expect_vwabda_vv_masked
vle16.v v6, 0(t0)
vmsne.vv v0, v4, v6
vcpop.m a0, v0
snez a0, a0
ret
test_vwabda_vx:
/*
* Test signed widening vector-scalar absolute difference and
* accumulation. With scalar 3, v4 becomes {1000 + 8, -1000 + 10}.
*/
/* Load the 16-bit accumulator before selecting 8-bit operands. */
vsetivli zero, 2, e16, m2, ta, mu
la t0, .arr_signed_acc
vle16.v v4, 0(t0)
vsetivli zero, 2, e8, m1, ta, mu
la t0, .arr_neg
vle8.v v1, 0(t0)
li a2, 3
/* Execute vwabda.vx v4, v1, a2. */
.insn r 0x57, 0x4, 0x7b, x4, x12, x1
/* Select the widened EEW and compare v4 with the expected result. */
vsetivli zero, 2, e16, m2, ta, mu
la t0, .expect_vwabda_vx
vle16.v v6, 0(t0)
vmsne.vv v0, v4, v6
vcpop.m a0, v0
snez a0, a0
ret
test_vwabda_vx_mask:
/*
* Test masked vwabda.vx. Element 0 remains 1000 while element 1
* accumulates 10 and becomes -990.
*/
vsetivli zero, 2, e16, m2, ta, mu
la t0, .arr_signed_acc
vle16.v v4, 0(t0)
vsetivli zero, 2, e8, m1, ta, mu
la t0, .arr_neg
vle8.v v1, 0(t0)
li a2, 3
la t0, .v0_mask
vle8.v v0, 0(t0)
.insn r 0x57, 0x4, 0x7a, x4, x12, x1
vsetivli zero, 2, e16, m2, ta, mu
la t0, .expect_vwabda_vx_masked
vle16.v v6, 0(t0)
vmsne.vv v0, v4, v6
vcpop.m a0, v0
snez a0, a0
ret
test_vwabdau_vv:
/*
* Test unsigned widening vector-vector absolute difference and
* accumulation. Start with v4 = {1000, 2000}, adding {255, 255}
* produces {1255, 2255}.
*/
/* Load the unsigned 16-bit accumulator and 8-bit source vectors. */
vsetivli zero, 2, e16, m2, ta, mu
la t0, .arr_unsigned_acc
vle16.v v4, 0(t0)
vsetivli zero, 2, e8, m1, ta, mu
la t0, .arr_unsigned_lhs
vle8.v v1, 0(t0)
la t0, .arr_unsigned_rhs
vle8.v v2, 0(t0)
/* Execute vwabdau.vv v4, v1, v2. */
.insn r 0x57, 0x0, 0x7d, x4, x2, x1
/* Select the widened EEW and compare v4 with the expected result. */
vsetivli zero, 2, e16, m2, ta, mu
la t0, .expect_vwabdau_vv
vle16.v v6, 0(t0)
vmsne.vv v0, v4, v6
vcpop.m a0, v0
snez a0, a0
ret
test_vwabdau_vv_mask:
/*
* Test masked vwabdau.vv. Element 0 remains 1000 while element 1
* accumulates 255 and becomes 2255.
*/
vsetivli zero, 2, e16, m2, ta, mu
la t0, .arr_unsigned_acc
vle16.v v4, 0(t0)
vsetivli zero, 2, e8, m1, ta, mu
la t0, .arr_unsigned_lhs
vle8.v v1, 0(t0)
la t0, .arr_unsigned_rhs
vle8.v v2, 0(t0)
la t0, .v0_mask
vle8.v v0, 0(t0)
.insn r 0x57, 0x0, 0x7c, x4, x2, x1
vsetivli zero, 2, e16, m2, ta, mu
la t0, .expect_vwabdau_vv_masked
vle16.v v6, 0(t0)
vmsne.vv v0, v4, v6
vcpop.m a0, v0
snez a0, a0
ret
test_vwabdau_vx:
/*
* Test unsigned widening vector-scalar absolute difference and
* accumulation. With scalar 128, v4 becomes {1000 + 128, 2000 + 127}.
*/
/* Load the unsigned 16-bit accumulator and 8-bit source vector. */
vsetivli zero, 2, e16, m2, ta, mu
la t0, .arr_unsigned_acc
vle16.v v4, 0(t0)
vsetivli zero, 2, e8, m1, ta, mu
la t0, .arr_unsigned_lhs
vle8.v v1, 0(t0)
li a2, 128
/* Execute vwabdau.vx v4, v1, a2. */
.insn r 0x57, 0x4, 0x7d, x4, x12, x1
/* Select the widened EEW and compare v4 with the expected result. */
vsetivli zero, 2, e16, m2, ta, mu
la t0, .expect_vwabdau_vx
vle16.v v6, 0(t0)
vmsne.vv v0, v4, v6
vcpop.m a0, v0
snez a0, a0
ret
test_vwabdau_vx_mask:
/*
* Test masked vwabdau.vx. Element 0 remains 1000 while element 1
* accumulates 127 and becomes 2127.
*/
vsetivli zero, 2, e16, m2, ta, mu
la t0, .arr_unsigned_acc
vle16.v v4, 0(t0)
vsetivli zero, 2, e8, m1, ta, mu
la t0, .arr_unsigned_lhs
vle8.v v1, 0(t0)
li a2, 128
la t0, .v0_mask
vle8.v v0, 0(t0)
.insn r 0x57, 0x4, 0x7c, x4, x12, x1
vsetivli zero, 2, e16, m2, ta, mu
la t0, .expect_vwabdau_vx_masked
vle16.v v6, 0(t0)
vmsne.vv v0, v4, v6
vcpop.m a0, v0
snez a0, a0
ret
/* Exit through the semihosting SYS_EXIT_EXTENDED call with a0 as the code. */
_exit:
la a1, semiargs
li t0, 0x20026 /* ADP_Stopped_ApplicationExit */
sd t0, 0(a1)
sd a0, 8(a1)
li a0, 0x20 /* TARGET_SYS_EXIT_EXTENDED */
.balign 16
slli zero, zero, 0x1f
ebreak
srai zero, zero, 0x7
j .
.balign 4
trap_handler:
csrr t4, mcause
la t5, trap_mcause
sd t4, 0(t5)
csrr t4, mtval
la t5, trap_mtval
sd t4, 0(t5)
li a0, 1
j _exit
.data
.balign 8
semiargs:
.space 16
trap_mcause:
.space 8
trap_mtval:
.space 8
.arr_neg:
.byte -5, -7
.arr_pos:
.byte 5, 7
.arr_zero:
.byte 0, 0
.arr_init:
.byte 9, 9
.v0_mask:
.byte 0b10
.arr_masked:
.byte 0, 7
/* Unsigned input vectors used by vabdu and vwabdau. */
.arr_unsigned_lhs:
.byte 0, 255
.arr_unsigned_rhs:
.byte 255, 0
.balign 2
/* Nonzero accumulators verify the add part of widening operations. */
.arr_signed_acc:
.half 1000, -1000
.arr_unsigned_acc:
.half 1000, 2000
/* Expected results for the unmasked and masked forms. */
.expect_vabd_vv:
.byte 10, 14
.expect_vabd_vv_masked:
.byte 9, 14
.expect_vabd_vx:
.byte 8, 10
.expect_vabd_vx_masked:
.byte 9, 10
.expect_vabdu_vv:
.byte 255, 255
.expect_vabdu_vv_masked:
.byte 9, 255
.expect_vabdu_vx:
.byte 128, 127
.expect_vabdu_vx_masked:
.byte 9, 127
.expect_vwabda_vv:
.half 1010, -986
.expect_vwabda_vv_masked:
.half 1000, -986
.expect_vwabda_vx:
.half 1008, -990
.expect_vwabda_vx_masked:
.half 1000, -990
.expect_vwabdau_vv:
.half 1255, 2255
.expect_vwabdau_vv_masked:
.half 1000, 2255
.expect_vwabdau_vx:
.half 1128, 2127
.expect_vwabdau_vx_masked:
.half 1000, 2127