Skip to content

Commit 196d3ab

Browse files
loiclefortlexbaileylowrisc
authored andcommitted
[ot] hw/opentitan: add OpenTitan shadow register helpers
Signed-off-by: Loïc Lefort <loic@rivosinc.com>
1 parent e9aa2bd commit 196d3ab

1 file changed

Lines changed: 93 additions & 0 deletions

File tree

include/hw/opentitan/ot_common.h

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
/*
2+
* QEMU RISC-V Helpers for OpenTitan EarlGrey
3+
*
4+
* Copyright (c) 2023 Rivos, Inc.
5+
*
6+
* Author(s):
7+
* Emmanuel Blot <eblot@rivosinc.com>
8+
* Loïc Lefort <loic@rivosinc.com>
9+
*
10+
* SPDX-License-Identifier: GPL-2.0-or-later
11+
*/
12+
13+
#ifndef HW_RISCV_OT_COMMON_H
14+
#define HW_RISCV_OT_COMMON_H
15+
16+
#include "qemu/osdep.h"
17+
18+
/* ------------------------------------------------------------------------ */
19+
/* Shadow Registers */
20+
/* ------------------------------------------------------------------------ */
21+
22+
/*
23+
* Shadow register, concept documented at:
24+
* https://docs.opentitan.org/doc/rm/register_tool/#shadow-registers
25+
*/
26+
typedef struct OtShadowReg {
27+
/* committed register value */
28+
uint32_t committed;
29+
/* staged register value */
30+
uint32_t staged;
31+
/* true if 'staged' holds a value */
32+
bool staged_p;
33+
} OtShadowReg;
34+
35+
enum {
36+
OT_SHADOW_REG_ERROR = -1,
37+
OT_SHADOW_REG_COMMITTED = 0,
38+
OT_SHADOW_REG_STAGED = 1,
39+
};
40+
41+
/**
42+
* Initialize a shadow register with a committed value and no staged value
43+
*/
44+
static inline void ot_shadow_reg_init(OtShadowReg *sreg, uint32_t value)
45+
{
46+
sreg->committed = value;
47+
sreg->staged_p = false;
48+
}
49+
50+
/**
51+
* Write a new value to a shadow register.
52+
* If no value was previously staged, the new value is only staged for next
53+
* write and the function returns OT_SHADOW_REG_STAGED.
54+
* If a value was previously staged and the new value is different, the function
55+
* returns OT_SHADOW_REG_ERROR and the new value is ignored. Otherwise the value
56+
* is committed, the staged value is discarded and the function returns
57+
* OT_SHADOW_REG_COMMITTED.
58+
*/
59+
static inline int ot_shadow_reg_write(OtShadowReg *sreg, uint32_t value)
60+
{
61+
if (sreg->staged_p) {
62+
if (value != sreg->staged) {
63+
/* second write is different, return error status */
64+
return OT_SHADOW_REG_ERROR;
65+
}
66+
sreg->committed = value;
67+
sreg->staged_p = false;
68+
return OT_SHADOW_REG_COMMITTED;
69+
} else {
70+
sreg->staged = value;
71+
sreg->staged_p = true;
72+
return OT_SHADOW_REG_STAGED;
73+
}
74+
}
75+
76+
/**
77+
* Return the current committed register value
78+
*/
79+
static inline uint32_t ot_shadow_reg_peek(const OtShadowReg *sreg)
80+
{
81+
return sreg->committed;
82+
}
83+
84+
/**
85+
* Discard the staged value and return the current committed register value
86+
*/
87+
static inline uint32_t ot_shadow_reg_read(OtShadowReg *sreg)
88+
{
89+
sreg->staged_p = false;
90+
return sreg->committed;
91+
}
92+
93+
#endif /* HW_RISCV_OT_COMMON_H */

0 commit comments

Comments
 (0)