mirror of
https://gitlab.com/qemu-project/qemu.git
synced 2026-10-28 11:54:41 +08:00
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:
commit
d29412cca5
31 files changed
+1425
-236
No files matched your search
@@ -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(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(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_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)
|
||||
@@ -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(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(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_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)
|
||||
|
||||
@@ -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_jr[] = { rvc_rd_eq_x0, rvc_imm_eq_zero,
|
||||
rvc_end };
|
||||
static const rvc_constraint rvcc_vabs_v[] = { rvc_rs1_eq_x0, rvc_end };
|
||||
static const rvc_constraint rvcc_true[] = { rvc_end };
|
||||
|
||||
/* 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. */
|
||||
#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 49: return &op_vwredsum_vs;
|
||||
case 53: return &op_vwsll_vv;
|
||||
case 61: return &op_vwabda_vv;
|
||||
case 62: return &op_vwabdau_vv;
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
@@ -2167,6 +2175,8 @@ static const rv_opcode_data *decode_inst_opcode(rv_decode *dec, rv_isa isa)
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 21: return &op_vabd_vv;
|
||||
case 22: return &op_vabdu_vv;
|
||||
case 23:
|
||||
if ((inst >> 25) & 1) {
|
||||
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 47: return &op_vnclip_wx;
|
||||
case 53: return &op_vwsll_vx;
|
||||
case 61: return &op_vwabda_vx;
|
||||
case 62: return &op_vwabdau_vx;
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
@@ -2428,6 +2440,8 @@ static const rv_opcode_data *decode_inst_opcode(rv_decode *dec, rv_isa isa)
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 21: return &op_vabd_vx;
|
||||
case 22: return &op_vabdu_vx;
|
||||
case 32: return &op_vdivu_vx;
|
||||
case 33: return &op_vdiv_vx;
|
||||
case 34: return &op_vremu_vx;
|
||||
|
||||
@@ -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
|
||||
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
|
||||
''''''''''''''''''''
|
||||
|
||||
|
||||
@@ -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
|
||||
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)
|
||||
''''''''''''''''''''''''''''''''''''''''''''
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ tt-atlantis QEMU model features
|
||||
|
||||
* 8-core Ascalon-X CPU Cluster
|
||||
* RISC-V compliant Advanced Interrupt Architecture
|
||||
* 16550A compatible UART
|
||||
* DW8250 compatible UART x5
|
||||
* 4 PRCMs (Clock and Reset Controllers)
|
||||
|
||||
Known limitations
|
||||
@@ -25,9 +25,8 @@ real platform. Notably:
|
||||
* There is no PCI host bridge, so virtio-pci devices cannot be
|
||||
attached. Boots that need block storage must use ``-initrd`` with
|
||||
an initramfs.
|
||||
* The DesignWare UART is modelled with QEMU's ns16550-compatible
|
||||
``serial_mm`` device; DesignWare-specific registers beyond that
|
||||
set return 0.
|
||||
* The Atlantis platform has 5 UARTs but only ``UART1`` is currently exposed
|
||||
on the command line serial interface. ``UART1`` is the Ascalon console.
|
||||
|
||||
Supported software
|
||||
------------------
|
||||
|
||||
+44
-44
@@ -304,54 +304,54 @@ static uint64_t k230_gsdma_read(void *opaque, hwaddr addr, unsigned int size)
|
||||
hwaddr ch_off;
|
||||
uint64_t ret = 0;
|
||||
|
||||
switch (addr) {
|
||||
case K230_GSDMA_DMA_CH_EN:
|
||||
ret = s->dma_ch_en;
|
||||
break;
|
||||
case K230_GSDMA_DMA_INT_MASK:
|
||||
ret = s->dma_int_mask;
|
||||
break;
|
||||
case K230_GSDMA_DMA_INT_STAT:
|
||||
ret = s->dma_int_stat;
|
||||
break;
|
||||
case K230_GSDMA_DMA_CFG:
|
||||
ret = s->dma_cfg;
|
||||
break;
|
||||
case K230_GSDMA_DMA_WEIGHT:
|
||||
ret = s->dma_weight;
|
||||
break;
|
||||
default:
|
||||
if (addr < K230_GSDMA_CH_BASE) {
|
||||
if (addr < K230_GSDMA_CH_BASE) {
|
||||
switch (addr) {
|
||||
case K230_GSDMA_DMA_CH_EN:
|
||||
ret = s->dma_ch_en;
|
||||
break;
|
||||
case K230_GSDMA_DMA_INT_MASK:
|
||||
ret = s->dma_int_mask;
|
||||
break;
|
||||
case K230_GSDMA_DMA_INT_STAT:
|
||||
ret = s->dma_int_stat;
|
||||
break;
|
||||
case K230_GSDMA_DMA_CFG:
|
||||
ret = s->dma_cfg;
|
||||
break;
|
||||
case K230_GSDMA_DMA_WEIGHT:
|
||||
ret = s->dma_weight;
|
||||
break;
|
||||
default:
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"%s: not implement gdma at offset 0x%" HWADDR_PRIx
|
||||
"\n", __func__, addr);
|
||||
return ret;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
ch = (addr - K230_GSDMA_CH_BASE) / K230_GSDMA_CH_STRIDE;
|
||||
ch_off = (addr - K230_GSDMA_CH_BASE) % K230_GSDMA_CH_STRIDE;
|
||||
if (ch < K230_GSDMA_NUM_SDMA_CHANNELS) {
|
||||
switch (ch_off) {
|
||||
case K230_GSDMA_CH_CTL:
|
||||
break;
|
||||
case K230_GSDMA_CH_STATUS:
|
||||
ret = s->channels[ch].status;
|
||||
break;
|
||||
case K230_GSDMA_CH_CFG:
|
||||
ret = s->channels[ch].cfg;
|
||||
break;
|
||||
case K230_GSDMA_CH_USR_DATA:
|
||||
ret = s->channels[ch].usr_data;
|
||||
break;
|
||||
case K230_GSDMA_CH_LLT_SADDR:
|
||||
ret = s->channels[ch].llt_saddr;
|
||||
break;
|
||||
case K230_GSDMA_CH_CURRENT_LLT:
|
||||
ret = s->channels[ch].current_llt;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
} else {
|
||||
ch = (addr - K230_GSDMA_CH_BASE) / K230_GSDMA_CH_STRIDE;
|
||||
ch_off = (addr - K230_GSDMA_CH_BASE) % K230_GSDMA_CH_STRIDE;
|
||||
if (ch < K230_GSDMA_NUM_SDMA_CHANNELS) {
|
||||
switch (ch_off) {
|
||||
case K230_GSDMA_CH_CTL:
|
||||
break;
|
||||
case K230_GSDMA_CH_STATUS:
|
||||
ret = s->channels[ch].status;
|
||||
break;
|
||||
case K230_GSDMA_CH_CFG:
|
||||
ret = s->channels[ch].cfg;
|
||||
break;
|
||||
case K230_GSDMA_CH_USR_DATA:
|
||||
ret = s->channels[ch].usr_data;
|
||||
break;
|
||||
case K230_GSDMA_CH_LLT_SADDR:
|
||||
ret = s->channels[ch].llt_saddr;
|
||||
break;
|
||||
case K230_GSDMA_CH_CURRENT_LLT:
|
||||
ret = s->channels[ch].current_llt;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -53,13 +53,13 @@ static bool k230_decomp_gzip_write_mem(K230DecompGzipState *s, hwaddr addr,
|
||||
static hwaddr k230_decomp_gzip_output_addr(K230DecompGzipState *s)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -102,7 +102,7 @@ static void k230_decomp_gzip_finish(K230DecompGzipState *s, bool crc_ok)
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
|
||||
+1
-1
@@ -144,7 +144,7 @@ config TENSTORRENT
|
||||
select RISCV_ACLINT
|
||||
select RISCV_APLIC
|
||||
select RISCV_IMSIC
|
||||
select SERIAL_MM
|
||||
select DW8250
|
||||
select DEVICE_TREE
|
||||
select DESIGNWARE_I2C
|
||||
select DS1338
|
||||
|
||||
+101
-89
@@ -1582,107 +1582,96 @@ static guint riscv_iommu_iot_hash(gconstpointer v)
|
||||
/* GV: 0 AV: 0 PSCV: 0 GVMA: 0 */
|
||||
/* GV: 0 AV: 0 GVMA: 1 */
|
||||
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 *arg = (RISCVIOMMUEntry *) data;
|
||||
if (iot->tag == arg->tag) {
|
||||
iot->perm = IOMMU_NONE;
|
||||
}
|
||||
return iot->tag == arg->tag;
|
||||
}
|
||||
|
||||
/* GV: 0 AV: 0 PSCV: 1 GVMA: 0 */
|
||||
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 *arg = (RISCVIOMMUEntry *) data;
|
||||
if (iot->tag == arg->tag &&
|
||||
iot->pscid == arg->pscid) {
|
||||
iot->perm = IOMMU_NONE;
|
||||
}
|
||||
return iot->tag == arg->tag &&
|
||||
iot->pscid == arg->pscid;
|
||||
}
|
||||
|
||||
/* GV: 0 AV: 1 PSCV: 0 GVMA: 0 */
|
||||
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 *arg = (RISCVIOMMUEntry *) data;
|
||||
if (iot->tag == arg->tag &&
|
||||
iot->iova == arg->iova) {
|
||||
iot->perm = IOMMU_NONE;
|
||||
}
|
||||
return iot->tag == arg->tag &&
|
||||
iot->iova == arg->iova;
|
||||
}
|
||||
|
||||
/* GV: 0 AV: 1 PSCV: 1 GVMA: 0 */
|
||||
static void riscv_iommu_iot_inval_pscid_iova(gpointer key, gpointer value,
|
||||
gpointer data)
|
||||
static gboolean riscv_iommu_iot_inval_pscid_iova(gpointer key,
|
||||
gpointer value,
|
||||
gpointer data)
|
||||
{
|
||||
RISCVIOMMUEntry *iot = (RISCVIOMMUEntry *) value;
|
||||
RISCVIOMMUEntry *arg = (RISCVIOMMUEntry *) data;
|
||||
if (iot->tag == arg->tag &&
|
||||
iot->pscid == arg->pscid &&
|
||||
iot->iova == arg->iova) {
|
||||
iot->perm = IOMMU_NONE;
|
||||
}
|
||||
return iot->tag == arg->tag &&
|
||||
iot->pscid == arg->pscid &&
|
||||
iot->iova == arg->iova;
|
||||
}
|
||||
|
||||
/* GV: 1 AV: 0 PSCV: 0 GVMA: 0 */
|
||||
/* GV: 1 AV: 0 GVMA: 1 */
|
||||
static
|
||||
void riscv_iommu_iot_inval_gscid(gpointer key, gpointer value, gpointer data)
|
||||
static gboolean riscv_iommu_iot_inval_gscid(gpointer key, gpointer value,
|
||||
gpointer data)
|
||||
{
|
||||
RISCVIOMMUEntry *iot = (RISCVIOMMUEntry *) value;
|
||||
RISCVIOMMUEntry *arg = (RISCVIOMMUEntry *) data;
|
||||
if (iot->tag == arg->tag &&
|
||||
iot->gscid == arg->gscid) {
|
||||
iot->perm = IOMMU_NONE;
|
||||
}
|
||||
return iot->tag == arg->tag &&
|
||||
iot->gscid == arg->gscid;
|
||||
}
|
||||
|
||||
/* GV: 1 AV: 0 PSCV: 1 GVMA: 0 */
|
||||
static void riscv_iommu_iot_inval_gscid_pscid(gpointer key, gpointer value,
|
||||
gpointer data)
|
||||
static gboolean riscv_iommu_iot_inval_gscid_pscid(gpointer key,
|
||||
gpointer value,
|
||||
gpointer data)
|
||||
{
|
||||
RISCVIOMMUEntry *iot = (RISCVIOMMUEntry *) value;
|
||||
RISCVIOMMUEntry *arg = (RISCVIOMMUEntry *) data;
|
||||
if (iot->tag == arg->tag &&
|
||||
iot->gscid == arg->gscid &&
|
||||
iot->pscid == arg->pscid) {
|
||||
iot->perm = IOMMU_NONE;
|
||||
}
|
||||
return iot->tag == arg->tag &&
|
||||
iot->gscid == arg->gscid &&
|
||||
iot->pscid == arg->pscid;
|
||||
}
|
||||
|
||||
/* GV: 1 AV: 1 PSCV: 0 GVMA: 0 */
|
||||
/* GV: 1 AV: 1 GVMA: 1 */
|
||||
static void riscv_iommu_iot_inval_gscid_iova(gpointer key, gpointer value,
|
||||
gpointer data)
|
||||
static gboolean riscv_iommu_iot_inval_gscid_iova(gpointer key,
|
||||
gpointer value,
|
||||
gpointer data)
|
||||
{
|
||||
RISCVIOMMUEntry *iot = (RISCVIOMMUEntry *) value;
|
||||
RISCVIOMMUEntry *arg = (RISCVIOMMUEntry *) data;
|
||||
if (iot->tag == arg->tag &&
|
||||
iot->gscid == arg->gscid &&
|
||||
iot->iova == arg->iova) {
|
||||
iot->perm = IOMMU_NONE;
|
||||
}
|
||||
return iot->tag == arg->tag &&
|
||||
iot->gscid == arg->gscid &&
|
||||
iot->iova == arg->iova;
|
||||
}
|
||||
|
||||
/* GV: 1 AV: 1 PSCV: 1 GVMA: 0 */
|
||||
static void riscv_iommu_iot_inval_gscid_pscid_iova(gpointer key, gpointer value,
|
||||
gpointer data)
|
||||
static gboolean riscv_iommu_iot_inval_gscid_pscid_iova(gpointer key,
|
||||
gpointer value,
|
||||
gpointer data)
|
||||
{
|
||||
RISCVIOMMUEntry *iot = (RISCVIOMMUEntry *) value;
|
||||
RISCVIOMMUEntry *arg = (RISCVIOMMUEntry *) data;
|
||||
if (iot->tag == arg->tag &&
|
||||
iot->gscid == arg->gscid &&
|
||||
iot->pscid == arg->pscid &&
|
||||
iot->iova == arg->iova) {
|
||||
iot->perm = IOMMU_NONE;
|
||||
}
|
||||
return iot->tag == arg->tag &&
|
||||
iot->gscid == arg->gscid &&
|
||||
iot->pscid == arg->pscid &&
|
||||
iot->iova == arg->iova;
|
||||
}
|
||||
|
||||
/* caller should keep ref-count for iot_cache object */
|
||||
/* caller must hold iot_lock */
|
||||
static RISCVIOMMUEntry *riscv_iommu_iot_lookup(RISCVIOMMUContext *ctx,
|
||||
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);
|
||||
}
|
||||
|
||||
/* caller should keep ref-count for iot_cache object */
|
||||
static void riscv_iommu_iot_update(RISCVIOMMUState *s,
|
||||
GHashTable *iot_cache, RISCVIOMMUEntry *iot)
|
||||
/* caller must hold iot_lock */
|
||||
static void riscv_iommu_iot_update(RISCVIOMMUState *s, RISCVIOMMUEntry *iot)
|
||||
{
|
||||
if (!s->iot_limit) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (g_hash_table_size(s->iot_cache) >= s->iot_limit) {
|
||||
iot_cache = g_hash_table_new_full(riscv_iommu_iot_hash,
|
||||
riscv_iommu_iot_equal,
|
||||
g_free, NULL);
|
||||
g_hash_table_unref(qatomic_xchg(&s->iot_cache, iot_cache));
|
||||
GHashTable *old_cache = s->iot_cache;
|
||||
s->iot_cache = g_hash_table_new_full(riscv_iommu_iot_hash,
|
||||
riscv_iommu_iot_equal,
|
||||
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)
|
||||
{
|
||||
GHashTable *iot_cache;
|
||||
RISCVIOMMUEntry key = {
|
||||
.tag = transtag,
|
||||
.gscid = gscid,
|
||||
@@ -1723,9 +1711,9 @@ static void riscv_iommu_iot_inval(RISCVIOMMUState *s, GHFunc func,
|
||||
.iova = PPN_DOWN(iova),
|
||||
};
|
||||
|
||||
iot_cache = g_hash_table_ref(s->iot_cache);
|
||||
g_hash_table_foreach(iot_cache, func, &key);
|
||||
g_hash_table_unref(iot_cache);
|
||||
qemu_mutex_lock(&s->iot_lock);
|
||||
g_hash_table_foreach_remove(s->iot_cache, func, &key);
|
||||
qemu_mutex_unlock(&s->iot_lock);
|
||||
}
|
||||
|
||||
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);
|
||||
RISCVIOMMUEntry *iot;
|
||||
IOMMUAccessFlags perm;
|
||||
IOMMUAccessFlags perm = IOMMU_NONE;
|
||||
bool enable_pid;
|
||||
bool enable_pri;
|
||||
GHashTable *iot_cache;
|
||||
hwaddr phys = 0;
|
||||
int fault;
|
||||
|
||||
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) &&
|
||||
(ctx->tc & RISCV_IOMMU_DC_TC_EN_PRI);
|
||||
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);
|
||||
perm = iot ? iot->perm : IOMMU_NONE;
|
||||
qemu_mutex_lock(&s->iot_lock);
|
||||
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) {
|
||||
iotlb->translated_addr = PPN_PHYS(iot->phys);
|
||||
iotlb->translated_addr = PPN_PHYS(phys);
|
||||
iotlb->addr_mask = ~TARGET_PAGE_MASK;
|
||||
iotlb->perm = perm;
|
||||
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->perm = iotlb->perm;
|
||||
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:
|
||||
g_hash_table_unref(iot_cache);
|
||||
|
||||
if (enable_pri && fault) {
|
||||
struct riscv_iommu_pq_record pr = {0};
|
||||
if (enable_pid) {
|
||||
@@ -1969,7 +1961,8 @@ static void riscv_iommu_process_cq_tail(RISCVIOMMUState *s)
|
||||
dma_addr_t addr;
|
||||
uint32_t tail, head, ctrl;
|
||||
uint64_t cmd_opcode;
|
||||
GHFunc func;
|
||||
GHRFunc iot_func;
|
||||
GHFunc ctx_func;
|
||||
|
||||
ctrl = riscv_iommu_reg_get32(s, RISCV_IOMMU_REG_CQCSR);
|
||||
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;
|
||||
}
|
||||
|
||||
func = riscv_iommu_iot_inval_all;
|
||||
iot_func = riscv_iommu_iot_inval_all;
|
||||
|
||||
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(
|
||||
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(
|
||||
s, func, gscid, pscid, iova, RISCV_IOMMU_TRANS_TAG_VN);
|
||||
s, iot_func, gscid, pscid, iova, RISCV_IOMMU_TRANS_TAG_VN);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -2063,24 +2056,24 @@ static void riscv_iommu_process_cq_tail(RISCVIOMMUState *s)
|
||||
if (gv) {
|
||||
transtag = RISCV_IOMMU_TRANS_TAG_VN;
|
||||
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;
|
||||
} else {
|
||||
func = (av) ? riscv_iommu_iot_inval_gscid_iova :
|
||||
iot_func = (av) ? riscv_iommu_iot_inval_gscid_iova :
|
||||
riscv_iommu_iot_inval_gscid;
|
||||
}
|
||||
} else {
|
||||
transtag = RISCV_IOMMU_TRANS_TAG_SS;
|
||||
if (pscv) {
|
||||
func = (av) ? riscv_iommu_iot_inval_pscid_iova :
|
||||
iot_func = (av) ? riscv_iommu_iot_inval_pscid_iova :
|
||||
riscv_iommu_iot_inval_pscid;
|
||||
} 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(s, func, gscid, pscid, iova, transtag);
|
||||
riscv_iommu_iot_inval(s, iot_func, gscid, pscid, iova, transtag);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -2088,12 +2081,12 @@ static void riscv_iommu_process_cq_tail(RISCVIOMMUState *s)
|
||||
RISCV_IOMMU_CMD_IODIR_OPCODE):
|
||||
if (!(cmd.dword0 & RISCV_IOMMU_CMD_IODIR_DV)) {
|
||||
/* invalidate all device context cache mappings */
|
||||
func = riscv_iommu_ctx_inval_all;
|
||||
ctx_func = riscv_iommu_ctx_inval_all;
|
||||
} else {
|
||||
/* 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);
|
||||
break;
|
||||
|
||||
@@ -2103,9 +2096,9 @@ static void riscv_iommu_process_cq_tail(RISCVIOMMUState *s)
|
||||
/* illegal command arguments IODIR_PDT & DV == 0 */
|
||||
goto cmd_ill;
|
||||
} 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_PID));
|
||||
break;
|
||||
@@ -2281,8 +2274,20 @@ static void riscv_iommu_process_dbg(RISCVIOMMUState *s)
|
||||
if (fault) {
|
||||
iova = RISCV_IOMMU_TR_RESPONSE_FAULT | (((uint64_t) fault) << 10);
|
||||
} else {
|
||||
uint64_t ppn;
|
||||
|
||||
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);
|
||||
}
|
||||
@@ -2674,6 +2679,7 @@ static void riscv_iommu_instance_init(Object *obj)
|
||||
s->iot_cache = g_hash_table_new_full(riscv_iommu_iot_hash,
|
||||
riscv_iommu_iot_equal,
|
||||
g_free, NULL);
|
||||
qemu_mutex_init(&s->iot_lock);
|
||||
|
||||
s->iommus.le_next = 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->iot_cache);
|
||||
|
||||
qemu_mutex_destroy(&s->iot_lock);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
g_hash_table_remove_all(s->ctx_cache);
|
||||
|
||||
qemu_mutex_lock(&s->iot_lock);
|
||||
g_hash_table_remove_all(s->iot_cache);
|
||||
qemu_mutex_unlock(&s->iot_lock);
|
||||
}
|
||||
|
||||
static const Property riscv_iommu_properties[] = {
|
||||
@@ -2919,7 +2930,8 @@ static IOMMUTLBEntry riscv_iommu_memory_region_translate(
|
||||
/* Translation disabled or invalid. */
|
||||
iotlb.addr_mask = 0;
|
||||
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. */
|
||||
iotlb.addr_mask = 0;
|
||||
iotlb.perm = IOMMU_NONE;
|
||||
|
||||
@@ -73,6 +73,7 @@ struct RISCVIOMMUState {
|
||||
|
||||
GHashTable *iot_cache; /* IO Translated Address Cache */
|
||||
unsigned iot_limit; /* IO Translation Cache size limit */
|
||||
QemuMutex iot_lock;
|
||||
|
||||
/* MMIO Hardware Interface */
|
||||
MemoryRegion regs_mr;
|
||||
|
||||
+35
-33
@@ -24,9 +24,8 @@
|
||||
#include "hw/riscv/fdt-common.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/misc/unimp.h"
|
||||
#include "hw/misc/tt_atlantis_prcm.h"
|
||||
|
||||
#include "system/system.h"
|
||||
@@ -65,7 +64,11 @@ static const MemMapEntry tt_atlantis_memmap[] = {
|
||||
[TT_ATL_I2C2] = { 0xd4060000, 0x10000 },
|
||||
[TT_ATL_I2C3] = { 0xd4070000, 0x10000 },
|
||||
[TT_ATL_I2C4] = { 0xd4080000, 0x10000 },
|
||||
[TT_ATL_UART0] = { 0xd4100000, 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_MM] = { 0xdc000000, 0x1000 },
|
||||
[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,
|
||||
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,
|
||||
mem->base);
|
||||
|
||||
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_cell(fdt, name, "reg-shift", 2);
|
||||
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);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
static inline int tt_atlantis_uart_index(int uart_dev)
|
||||
{
|
||||
return uart_dev - TT_ATL_UART0;
|
||||
}
|
||||
|
||||
static void tt_atlantis_soc_init(Object *obj)
|
||||
{
|
||||
TTAtlantisSoCState *s = TT_ATLANTIS_SOC(obj);
|
||||
|
||||
object_initialize_child(obj, "cpus", &s->cpus, TYPE_RISCV_HART_ARRAY);
|
||||
|
||||
object_initialize_child(obj, "uart1", &s->uart1,
|
||||
TYPE_UNIMPLEMENTED_DEVICE);
|
||||
for (int i = 0; i < TT_ATL_NUM_UARTS; i++) {
|
||||
object_initialize_child(obj, "uart[*]", &s->uart[i],
|
||||
TYPE_DW8250);
|
||||
}
|
||||
|
||||
object_initialize_child(obj, "prcm-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,
|
||||
&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 */
|
||||
if (!sysbus_realize(SYS_BUS_DEVICE(&s->prcm[TT_ATLANTIS_PRCM_DOMAIN_RCPU]),
|
||||
errp)) {
|
||||
@@ -695,18 +693,22 @@ static void tt_atlantis_soc_realize(DeviceState *dev, Error **errp)
|
||||
sysbus_mmio_get_region(
|
||||
SYS_BUS_DEVICE(&s->prcm[TT_ATLANTIS_PRCM_DOMAIN_MM]), 0));
|
||||
|
||||
/*
|
||||
* Atlantis contains a DesignWare uart while the QEMU machine
|
||||
* uses the serial_mm model with the base ns16550 register set.
|
||||
* Linux's dw driver writes outside of serial_mm's 0x20 sized
|
||||
* mapping and faults.
|
||||
*
|
||||
* Create an unimplemented device region so writes don't fault
|
||||
* and reads return zero, which keeps Linux happy.
|
||||
*/
|
||||
mmio_map_unimplemented(s->memory, SYS_BUS_DEVICE(&s->uart1),
|
||||
"tt-atlantis.uart1", s->memmap[TT_ATL_UART1].base,
|
||||
s->memmap[TT_ATL_UART1].size);
|
||||
/* UART1, the soc console (UART0 is for the boot microcontroller) */
|
||||
qdev_prop_set_chr(DEVICE(&s->uart[tt_atlantis_uart_index(TT_ATL_UART1)]),
|
||||
"chardev", serial_hd(0));
|
||||
|
||||
for (int i = 0; i < TT_ATL_NUM_UARTS; i++) {
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(&s->uart[i]);
|
||||
if (!sysbus_realize(sbd, errp)) {
|
||||
return;
|
||||
}
|
||||
|
||||
memory_region_add_subregion(s->memory,
|
||||
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 */
|
||||
for (int i = 0; i < TT_ATL_NUM_I2C; i++) {
|
||||
|
||||
@@ -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_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_HART_NUM_GUESTS(__guest_bits) \
|
||||
|
||||
@@ -13,8 +13,8 @@
|
||||
#include "hw/core/sysbus.h"
|
||||
#include "hw/i2c/designware_i2c.h"
|
||||
#include "hw/intc/riscv_imsic.h"
|
||||
#include "hw/misc/unimp.h"
|
||||
#include "hw/misc/tt_atlantis_prcm.h"
|
||||
#include "hw/char/dw8250.h"
|
||||
#include "hw/riscv/riscv_hart.h"
|
||||
|
||||
#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_PRCM 4
|
||||
#define TT_ATL_NUM_UARTS 5
|
||||
|
||||
struct TTAtlantisSoCState {
|
||||
/*< private >*/
|
||||
@@ -41,7 +42,7 @@ struct TTAtlantisSoCState {
|
||||
RISCVHartArrayState cpus;
|
||||
DeviceState *irqchip;
|
||||
DesignWareI2CState i2c[TT_ATL_NUM_I2C];
|
||||
UnimplementedDeviceState uart1;
|
||||
DW8250State uart[TT_ATL_NUM_UARTS];
|
||||
MemoryRegion bootrom;
|
||||
TTAtlantisPRCMState prcm[TT_ATL_NUM_PRCM];
|
||||
|
||||
@@ -66,7 +67,11 @@ enum {
|
||||
TT_ATL_I2C2_IRQ = 35,
|
||||
TT_ATL_I2C3_IRQ = 36,
|
||||
TT_ATL_I2C4_IRQ = 37,
|
||||
TT_ATL_UART0_IRQ = 38,
|
||||
TT_ATL_UART1_IRQ = 39,
|
||||
TT_ATL_UART2_IRQ = 40,
|
||||
TT_ATL_UART3_IRQ = 41,
|
||||
TT_ATL_UART4_IRQ = 42,
|
||||
};
|
||||
|
||||
enum {
|
||||
@@ -83,7 +88,11 @@ enum {
|
||||
TT_ATL_MIMSIC,
|
||||
TT_ATL_SAPLIC,
|
||||
TT_ATL_SIMSIC,
|
||||
TT_ATL_UART0,
|
||||
TT_ATL_UART1,
|
||||
TT_ATL_UART2,
|
||||
TT_ATL_UART3,
|
||||
TT_ATL_UART4,
|
||||
TT_ATL_PRCM_RCPU,
|
||||
TT_ATL_PRCM_HSIO,
|
||||
TT_ATL_PRCM_PCIE,
|
||||
|
||||
+21
-1
@@ -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(zkt, PRIV_VERSION_1_12_0, ext_zkt),
|
||||
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(zvbc, PRIV_VERSION_1_12_0, ext_zvbc),
|
||||
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->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) {
|
||||
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();
|
||||
}
|
||||
|
||||
invalid_val = 1LL << (mxlen - 1);
|
||||
invalid_val = 1ULL << (mxlen - 1);
|
||||
|
||||
if (value == invalid_val) {
|
||||
error_setg(errp, "Unable to set marchid with MSB (%u) bit set "
|
||||
|
||||
@@ -83,6 +83,7 @@ BOOL_FIELD(ext_zve32x)
|
||||
BOOL_FIELD(ext_zve64f)
|
||||
BOOL_FIELD(ext_zve64d)
|
||||
BOOL_FIELD(ext_zve64x)
|
||||
BOOL_FIELD(ext_zvabd)
|
||||
BOOL_FIELD(ext_zvbb)
|
||||
BOOL_FIELD(ext_zvbc)
|
||||
BOOL_FIELD(ext_zvkb)
|
||||
|
||||
@@ -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_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 */
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
DEF_HELPER_1(ssamoswap_disabled, void, env)
|
||||
|
||||
@@ -1087,3 +1087,13 @@ sb_aqrl 00111 . . ..... ..... 000 ..... 0101111 @atom_st
|
||||
sh_aqrl 00111 . . ..... ..... 001 ..... 0101111 @atom_st
|
||||
sw_aqrl 00111 . . ..... ..... 010 ..... 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
|
||||
@@ -58,6 +58,7 @@ void riscv_kvm_aplic_request(void *opaque, int irq, int level)
|
||||
}
|
||||
|
||||
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 | \
|
||||
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);
|
||||
}
|
||||
|
||||
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 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);
|
||||
if (ret) {
|
||||
return ret;
|
||||
@@ -1624,6 +1646,11 @@ int kvm_arch_get_default_type(MachineState *ms)
|
||||
int kvm_arch_init(MachineState *ms, KVMState *s)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
+43
-7
@@ -2108,6 +2108,9 @@ static RISCVException write_mstatus(CPURISCVState *env, int csrno,
|
||||
}
|
||||
|
||||
if (xl != MXL_RV32 || env->debugger) {
|
||||
if (riscv_has_ext(env, RVH)) {
|
||||
mask |= MSTATUS_MPV | MSTATUS_GVA;
|
||||
}
|
||||
if ((val & MSTATUS64_SXL) != 0) {
|
||||
mask |= 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)
|
||||
{
|
||||
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) {
|
||||
mask |= MSTATUS_MDT;
|
||||
@@ -3388,10 +3391,19 @@ static RISCVException write_menvcfg(CPURISCVState *env, int csrno,
|
||||
target_ulong val, uintptr_t ra)
|
||||
{
|
||||
const RISCVCPUConfig *cfg = riscv_cpu_cfg(env);
|
||||
uint64_t mask = MENVCFG_FIOM | MENVCFG_CBIE | MENVCFG_CBCFE |
|
||||
MENVCFG_CBZE;
|
||||
uint64_t mask = MENVCFG_FIOM;
|
||||
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
|
||||
* 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,
|
||||
target_ulong val, uintptr_t ra)
|
||||
{
|
||||
uint64_t mask = SENVCFG_FIOM | SENVCFG_CBIE | SENVCFG_CBCFE | SENVCFG_CBZE;
|
||||
uint64_t mask = SENVCFG_FIOM;
|
||||
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 */
|
||||
if (env_archcpu(env)->cfg.ext_ssnpm &&
|
||||
riscv_cpu_mxl(env) == MXL_RV64 &&
|
||||
@@ -3550,10 +3572,20 @@ static RISCVException write_henvcfg(CPURISCVState *env, int csrno,
|
||||
target_ulong val, uintptr_t ra)
|
||||
{
|
||||
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;
|
||||
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);
|
||||
if (ret != RISCV_EXCP_NONE) {
|
||||
return ret;
|
||||
@@ -5484,14 +5516,14 @@ static RISCVException write_vsscratch(CPURISCVState *env, int csrno,
|
||||
static RISCVException read_vsepc(CPURISCVState *env, int csrno,
|
||||
target_ulong *val)
|
||||
{
|
||||
*val = env->vsepc;
|
||||
*val = env->vsepc & get_xepc_mask(env);
|
||||
return RISCV_EXCP_NONE;
|
||||
}
|
||||
|
||||
static RISCVException write_vsepc(CPURISCVState *env, int csrno,
|
||||
target_ulong val, uintptr_t ra)
|
||||
{
|
||||
env->vsepc = val;
|
||||
env->vsepc = val & get_xepc_mask(env);
|
||||
return RISCV_EXCP_NONE;
|
||||
}
|
||||
|
||||
@@ -5766,6 +5798,10 @@ static RISCVException write_mnstatus(CPURISCVState *env, int csrno,
|
||||
mask |= MNSTATUS_MNPV;
|
||||
}
|
||||
|
||||
if (env_archcpu(env)->cfg.ext_zicfilp) {
|
||||
mask |= MNSTATUS_MNPELP;
|
||||
}
|
||||
|
||||
/* mnstatus.mnie can only be cleared by hardware. */
|
||||
env->mnstatus = (env->mnstatus & MNSTATUS_NMIE) | (val & mask);
|
||||
return RISCV_EXCP_NONE;
|
||||
|
||||
@@ -424,7 +424,7 @@ static bool gen_load(DisasContext *ctx, arg_lb *a, MemOp memop)
|
||||
}
|
||||
|
||||
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;
|
||||
@@ -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);
|
||||
|
||||
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);
|
||||
|
||||
@@ -731,7 +731,7 @@ static bool ldst_us_trans(uint32_t vd, uint32_t rs1, uint32_t data,
|
||||
* around the loop.
|
||||
*/
|
||||
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);
|
||||
@@ -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);
|
||||
|
||||
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);
|
||||
@@ -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_vf4, 2, 4)
|
||||
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)
|
||||
@@ -201,12 +201,20 @@ static bool pmp_write_cfg(CPURISCVState *env, uint32_t pmp_index, uint8_t val)
|
||||
|
||||
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;
|
||||
|
||||
for (i = 0; i < pmp_num; i++) {
|
||||
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)
|
||||
|
||||
+13
-5
@@ -355,7 +355,8 @@ static void pmu_timer_trigger_irq(RISCVCPU *cpu,
|
||||
CPURISCVState *env = &cpu->env;
|
||||
PMUCTRState *counter;
|
||||
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;
|
||||
|
||||
if (evt_idx != RISCV_PMU_EVENT_HW_CPU_CYCLES &&
|
||||
@@ -383,12 +384,19 @@ static void pmu_timer_trigger_irq(RISCVCPU *cpu,
|
||||
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) {
|
||||
riscv_pmu_read_ctr(env, (target_ulong *)&curr_ctrh_val, true, ctr_idx);
|
||||
curr_ctr_val = curr_ctr_val | (curr_ctrh_val << 32);
|
||||
riscv_pmu_read_ctr(env, &ctr_hi, true, ctr_idx);
|
||||
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
|
||||
|
||||
@@ -760,6 +760,12 @@ void riscv_cpu_validate_set_extensions(RISCVCPU *cpu, Error **errp)
|
||||
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_is_user_set(cpu, CPU_CFG_OFFSET(ext_zicntr))) {
|
||||
error_setg(errp, "zicntr requires zicsr");
|
||||
|
||||
@@ -693,7 +693,7 @@ static TCGv get_address_indexed(DisasContext *ctx, int rs1, TCGv offs)
|
||||
*/
|
||||
static void mark_fs_dirty(DisasContext *ctx)
|
||||
{
|
||||
TCGv tmp;
|
||||
TCGv_i64 tmp;
|
||||
|
||||
if (!has_ext(ctx, RVF)) {
|
||||
return;
|
||||
@@ -703,15 +703,15 @@ static void mark_fs_dirty(DisasContext *ctx)
|
||||
/* Remember the state change for the rest of the TB. */
|
||||
ctx->mstatus_fs = EXT_STATUS_DIRTY;
|
||||
|
||||
tmp = tcg_temp_new();
|
||||
tcg_gen_ld_tl(tmp, tcg_env, offsetof(CPURISCVState, mstatus));
|
||||
tcg_gen_ori_tl(tmp, tmp, MSTATUS_FS);
|
||||
tcg_gen_st_tl(tmp, tcg_env, offsetof(CPURISCVState, mstatus));
|
||||
tmp = tcg_temp_new_i64();
|
||||
tcg_gen_ld_i64(tmp, tcg_env, offsetof(CPURISCVState, mstatus));
|
||||
tcg_gen_ori_i64(tmp, tmp, MSTATUS_FS);
|
||||
tcg_gen_st_i64(tmp, tcg_env, offsetof(CPURISCVState, mstatus));
|
||||
|
||||
if (ctx->virt_enabled) {
|
||||
tcg_gen_ld_tl(tmp, tcg_env, offsetof(CPURISCVState, mstatus_hs));
|
||||
tcg_gen_ori_tl(tmp, tmp, MSTATUS_FS);
|
||||
tcg_gen_st_tl(tmp, tcg_env, offsetof(CPURISCVState, mstatus_hs));
|
||||
tcg_gen_ld_i64(tmp, tcg_env, offsetof(CPURISCVState, mstatus_hs));
|
||||
tcg_gen_ori_i64(tmp, tmp, MSTATUS_FS);
|
||||
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)
|
||||
{
|
||||
TCGv tmp;
|
||||
TCGv_i64 tmp;
|
||||
|
||||
if (ctx->mstatus_vs != EXT_STATUS_DIRTY) {
|
||||
/* Remember the state change for the rest of the TB. */
|
||||
ctx->mstatus_vs = EXT_STATUS_DIRTY;
|
||||
|
||||
tmp = tcg_temp_new();
|
||||
tcg_gen_ld_tl(tmp, tcg_env, offsetof(CPURISCVState, mstatus));
|
||||
tcg_gen_ori_tl(tmp, tmp, MSTATUS_VS);
|
||||
tcg_gen_st_tl(tmp, tcg_env, offsetof(CPURISCVState, mstatus));
|
||||
tmp = tcg_temp_new_i64();
|
||||
tcg_gen_ld_i64(tmp, tcg_env, offsetof(CPURISCVState, mstatus));
|
||||
tcg_gen_ori_i64(tmp, tmp, MSTATUS_VS);
|
||||
tcg_gen_st_i64(tmp, tcg_env, offsetof(CPURISCVState, mstatus));
|
||||
|
||||
if (ctx->virt_enabled) {
|
||||
tcg_gen_ld_tl(tmp, tcg_env, offsetof(CPURISCVState, mstatus_hs));
|
||||
tcg_gen_ori_tl(tmp, tmp, MSTATUS_VS);
|
||||
tcg_gen_st_tl(tmp, tcg_env, offsetof(CPURISCVState, mstatus_hs));
|
||||
tcg_gen_ld_i64(tmp, tcg_env, offsetof(CPURISCVState, mstatus_hs));
|
||||
tcg_gen_ori_i64(tmp, tmp, MSTATUS_VS);
|
||||
tcg_gen_st_i64(tmp, tcg_env, offsetof(CPURISCVState, mstatus_hs));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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_d, int64_t, int16_t, H8, H2)
|
||||
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)
|
||||
@@ -19,6 +19,12 @@
|
||||
|
||||
#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 */
|
||||
#define RISCV_GPEX_PIO_BASE 0x3000000
|
||||
#define RISCV_BUS_PIO_LIMIT 0x10000
|
||||
@@ -35,6 +41,64 @@ typedef struct RiscvIommuTestState {
|
||||
uint64_t iommu_base;
|
||||
} 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)
|
||||
{
|
||||
qpci->gpex_pio_base = RISCV_GPEX_PIO_BASE;
|
||||
@@ -264,6 +328,129 @@ static void test_riscv_iommu_nested(void)
|
||||
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)
|
||||
{
|
||||
g_test_init(&argc, &argv, NULL);
|
||||
@@ -275,5 +462,11 @@ int main(int argc, char **argv)
|
||||
test_riscv_iommu_g_stage_only);
|
||||
qtest_add_func("/iommu-testdev/translation/ns-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();
|
||||
}
|
||||
@@ -46,7 +46,7 @@ static inline hwaddr k230_sram_addr(hwaddr off)
|
||||
static inline hwaddr k230_sram_input_addr(unsigned int slot)
|
||||
{
|
||||
return k230_sram_addr(K230_DECOMP_GZIP_SRAM_IN_BASE +
|
||||
slot * K230_DECOMP_GZIP_BLOCK_SIZE);
|
||||
(hwaddr) slot * K230_DECOMP_GZIP_BLOCK_SIZE);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -25,6 +25,18 @@ tests += {
|
||||
'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-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 += {
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
Reference in new issue
Block a user