#include "qemu/main-loop.h"
#include "exec/exec-all.h"
#include "sysemu/cpu-timers.h"
+#include "qemu/guest-random.h"
+#include "qapi/error.h"
/* CSR function table public API */
void riscv_get_csr_ops(int csrno, riscv_csr_operations *ops)
}
#endif
+static RISCVException seed(CPURISCVState *env, int csrno)
+{
+ RISCVCPU *cpu = env_archcpu(env);
+
+ if (!cpu->cfg.ext_zkr) {
+ return RISCV_EXCP_ILLEGAL_INST;
+ }
+
+#if !defined(CONFIG_USER_ONLY)
+ /*
+ * With a CSR read-write instruction:
+ * 1) The seed CSR is always available in machine mode as normal.
+ * 2) Attempted access to seed from virtual modes VS and VU always raises
+ * an exception(virtual instruction exception only if mseccfg.sseed=1).
+ * 3) Without the corresponding access control bit set to 1, any attempted
+ * access to seed from U, S or HS modes will raise an illegal instruction
+ * exception.
+ */
+ if (env->priv == PRV_M) {
+ return RISCV_EXCP_NONE;
+ } else if (riscv_cpu_virt_enabled(env)) {
+ if (env->mseccfg & MSECCFG_SSEED) {
+ return RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
+ } else {
+ return RISCV_EXCP_ILLEGAL_INST;
+ }
+ } else {
+ if (env->priv == PRV_S && (env->mseccfg & MSECCFG_SSEED)) {
+ return RISCV_EXCP_NONE;
+ } else if (env->priv == PRV_U && (env->mseccfg & MSECCFG_USEED)) {
+ return RISCV_EXCP_NONE;
+ } else {
+ return RISCV_EXCP_ILLEGAL_INST;
+ }
+ }
+#else
+ return RISCV_EXCP_NONE;
+#endif
+}
+
/* User Floating-Point CSRs */
static RISCVException read_fflags(CPURISCVState *env, int csrno,
target_ulong *val)
#endif
+/* Crypto Extension */
+static RISCVException rmw_seed(CPURISCVState *env, int csrno,
+ target_ulong *ret_value,
+ target_ulong new_value,
+ target_ulong write_mask)
+{
+ uint16_t random_v;
+ Error *random_e = NULL;
+ int random_r;
+ target_ulong rval;
+
+ random_r = qemu_guest_getrandom(&random_v, 2, &random_e);
+ if (unlikely(random_r < 0)) {
+ /*
+ * Failed, for unknown reasons in the crypto subsystem.
+ * The best we can do is log the reason and return a
+ * failure indication to the guest. There is no reason
+ * we know to expect the failure to be transitory, so
+ * indicate DEAD to avoid having the guest spin on WAIT.
+ */
+ qemu_log_mask(LOG_UNIMP, "%s: Crypto failure: %s",
+ __func__, error_get_pretty(random_e));
+ error_free(random_e);
+ rval = SEED_OPST_DEAD;
+ } else {
+ rval = random_v | SEED_OPST_ES16;
+ }
+
+ if (ret_value) {
+ *ret_value = rval;
+ }
+
+ return RISCV_EXCP_NONE;
+}
+
/*
* riscv_csrrw - read and/or update control and status register
*
[CSR_TIME] = { "time", ctr, read_time },
[CSR_TIMEH] = { "timeh", ctr32, read_timeh },
+ /* Crypto Extension */
+ [CSR_SEED] = { "seed", seed, NULL, NULL, rmw_seed },
+
#if !defined(CONFIG_USER_ONLY)
/* Machine Timers and Counters */
[CSR_MCYCLE] = { "mcycle", any, read_instret },