From: Loïc Lefort <[email protected]>

Signed-off-by: Loïc Lefort <[email protected]>
---
 include/hw/opentitan/ot_common.h | 93 ++++++++++++++++++++++++++++++++
 1 file changed, 93 insertions(+)
 create mode 100644 include/hw/opentitan/ot_common.h

diff --git a/include/hw/opentitan/ot_common.h b/include/hw/opentitan/ot_common.h
new file mode 100644
index 0000000000..546a7d88a8
--- /dev/null
+++ b/include/hw/opentitan/ot_common.h
@@ -0,0 +1,93 @@
+/*
+ * QEMU RISC-V Helpers for OpenTitan EarlGrey
+ *
+ * Copyright (c) 2023 Rivos, Inc.
+ *
+ * Author(s):
+ *  Emmanuel Blot <[email protected]>
+ *  Loïc Lefort <[email protected]>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef HW_RISCV_OT_COMMON_H
+#define HW_RISCV_OT_COMMON_H
+
+#include "qemu/osdep.h"
+
+/* ------------------------------------------------------------------------ */
+/* Shadow Registers */
+/* ------------------------------------------------------------------------ */
+
+/*
+ * Shadow register, concept documented at:
+ * https://docs.opentitan.org/doc/rm/register_tool/#shadow-registers
+ */
+typedef struct OtShadowReg {
+    /* committed register value */
+    uint32_t committed;
+    /* staged register value */
+    uint32_t staged;
+    /* true if 'staged' holds a value */
+    bool staged_p;
+} OtShadowReg;
+
+enum {
+    OT_SHADOW_REG_ERROR = -1,
+    OT_SHADOW_REG_COMMITTED = 0,
+    OT_SHADOW_REG_STAGED = 1,
+};
+
+/**
+ * Initialize a shadow register with a committed value and no staged value
+ */
+static inline void ot_shadow_reg_init(OtShadowReg *sreg, uint32_t value)
+{
+    sreg->committed = value;
+    sreg->staged_p = false;
+}
+
+/**
+ * Write a new value to a shadow register.
+ * If no value was previously staged, the new value is only staged for next
+ * write and the function returns OT_SHADOW_REG_STAGED.
+ * If a value was previously staged and the new value is different, the 
function
+ * returns OT_SHADOW_REG_ERROR and the new value is ignored. Otherwise the 
value
+ * is committed, the staged value is discarded and the function returns
+ * OT_SHADOW_REG_COMMITTED.
+ */
+static inline int ot_shadow_reg_write(OtShadowReg *sreg, uint32_t value)
+{
+    if (sreg->staged_p) {
+        if (value != sreg->staged) {
+            /* second write is different, return error status */
+            return OT_SHADOW_REG_ERROR;
+        }
+        sreg->committed = value;
+        sreg->staged_p = false;
+        return OT_SHADOW_REG_COMMITTED;
+    } else {
+        sreg->staged = value;
+        sreg->staged_p = true;
+        return OT_SHADOW_REG_STAGED;
+    }
+}
+
+/**
+ * Return the current committed register value
+ */
+static inline uint32_t ot_shadow_reg_peek(const OtShadowReg *sreg)
+{
+    return sreg->committed;
+}
+
+/**
+ * Discard the staged value and return the current committed register value
+ */
+static inline uint32_t ot_shadow_reg_read(OtShadowReg *sreg)
+{
+    sreg->staged_p = false;
+    return sreg->committed;
+}
+
+#endif /* HW_RISCV_OT_COMMON_H */
-- 
2.49.1


Reply via email to