From: Joel Stanley <joel@jms.id.au>
The SCU controller on the AST2600 SoC has extra registers. Increase
the number of regs of the model and introduce a new field in the class
to customize the MemoryRegion operations depending on the SoC model.
Signed-off-by: Joel Stanley <joel@jms.id.au>
[clg: - improved commit log
- changed vmstate version
- reworked model integration into new objet class ]
Signed-off-by: Cédric Le Goater <clg@kaod.org>
---
include/hw/misc/aspeed_scu.h | 7 +-
hw/misc/aspeed_scu.c | 190 +++++++++++++++++++++++++++++++++--
2 files changed, 189 insertions(+), 8 deletions(-)
diff --git a/include/hw/misc/aspeed_scu.h b/include/hw/misc/aspeed_scu.h
index 239e94fe2c47..1d7f7ffc1598 100644
--- a/include/hw/misc/aspeed_scu.h
+++ b/include/hw/misc/aspeed_scu.h
@@ -17,8 +17,10 @@
#define ASPEED_SCU(obj) OBJECT_CHECK(AspeedSCUState, (obj), TYPE_ASPEED_SCU)
#define TYPE_ASPEED_2400_SCU TYPE_ASPEED_SCU "-ast2400"
#define TYPE_ASPEED_2500_SCU TYPE_ASPEED_SCU "-ast2500"
+#define TYPE_ASPEED_2600_SCU TYPE_ASPEED_SCU "-ast2600"
#define ASPEED_SCU_NR_REGS (0x1A8 >> 2)
+#define ASPEED_AST2600_SCU_NR_REGS (0xE20 >> 2)
typedef struct AspeedSCUState {
/*< private >*/
@@ -27,7 +29,7 @@ typedef struct AspeedSCUState {
/*< public >*/
MemoryRegion iomem;
- uint32_t regs[ASPEED_SCU_NR_REGS];
+ uint32_t regs[ASPEED_AST2600_SCU_NR_REGS];
uint32_t silicon_rev;
uint32_t hw_strap1;
uint32_t hw_strap2;
@@ -38,6 +40,7 @@ typedef struct AspeedSCUState {
#define AST2400_A1_SILICON_REV 0x02010303U
#define AST2500_A0_SILICON_REV 0x04000303U
#define AST2500_A1_SILICON_REV 0x04010303U
+#define AST2600_A0_SILICON_REV 0x05000303U
#define ASPEED_IS_AST2500(si_rev) ((((si_rev) >> 24) & 0xff) == 0x04)
@@ -54,6 +57,8 @@ typedef struct AspeedSCUClass {
const uint32_t *resets;
uint32_t (*calc_hpll)(AspeedSCUState *s, uint32_t hpll_reg);
uint32_t apb_divider;
+ uint32_t nr_regs;
+ const MemoryRegionOps *ops;
} AspeedSCUClass;
#define ASPEED_SCU_PROT_KEY 0x1688A8A8
diff --git a/hw/misc/aspeed_scu.c b/hw/misc/aspeed_scu.c
index 620b25c20476..27df6d6e3001 100644
--- a/hw/misc/aspeed_scu.c
+++ b/hw/misc/aspeed_scu.c
@@ -88,6 +88,34 @@
#define BMC_REV TO_REG(0x19C)
#define BMC_DEV_ID TO_REG(0x1A4)
+#define AST2600_PROT_KEY TO_REG(0x00)
+#define AST2600_SILICON_REV TO_REG(0x04)
+#define AST2600_SILICON_REV2 TO_REG(0x14)
+#define AST2600_SYS_RST_CTRL TO_REG(0x40)
+#define AST2600_SYS_RST_CTRL_CLR TO_REG(0x44)
+#define AST2600_SYS_RST_CTRL2 TO_REG(0x50)
+#define AST2600_SYS_RST_CTRL2_CLR TO_REG(0x54)
+#define AST2600_CLK_STOP_CTRL TO_REG(0x80)
+#define AST2600_CLK_STOP_CTRL_CLR TO_REG(0x84)
+#define AST2600_CLK_STOP_CTRL2 TO_REG(0x90)
+#define AST2600_CLK_STOP_CTR2L_CLR TO_REG(0x94)
+#define AST2600_HPLL_EXT TO_REG(0x204)
+#define AST2600_MPLL_EXT TO_REG(0x224)
+#define AST2600_EPLL_EXT TO_REG(0x244)
+#define AST2600_CLK_SEL TO_REG(0x300)
+#define AST2600_CLK_SEL2 TO_REG(0x304)
+#define AST2600_CLK_SEL3 TO_REG(0x310)
+#define AST2600_HW_STRAP1 TO_REG(0x500)
+#define AST2600_HW_STRAP1_CLR TO_REG(0x504)
+#define AST2600_HW_STRAP1_PROT TO_REG(0x508)
+#define AST2600_HW_STRAP2 TO_REG(0x510)
+#define AST2600_HW_STRAP2_CLR TO_REG(0x514)
+#define AST2600_HW_STRAP2_PROT TO_REG(0x518)
+#define AST2600_RNG_CTRL TO_REG(0x524)
+#define AST2600_RNG_DATA TO_REG(0x540)
+
+#define AST2600_CLK TO_REG(0x40)
+
#define SCU_IO_REGION_SIZE 0x1000
static const uint32_t ast2400_a0_resets[ASPEED_SCU_NR_REGS] = {
@@ -178,7 +206,7 @@ static uint64_t aspeed_scu_read(void *opaque, hwaddr offset, unsigned size)
AspeedSCUState *s = ASPEED_SCU(opaque);
int reg = TO_REG(offset);
- if (reg >= ARRAY_SIZE(s->regs)) {
+ if (reg >= ASPEED_SCU_NR_REGS) {
qemu_log_mask(LOG_GUEST_ERROR,
"%s: Out-of-bounds read at offset 0x%" HWADDR_PRIx "\n",
__func__, offset);
@@ -208,7 +236,7 @@ static void aspeed_scu_write(void *opaque, hwaddr offset, uint64_t data,
AspeedSCUState *s = ASPEED_SCU(opaque);
int reg = TO_REG(offset);
- if (reg >= ARRAY_SIZE(s->regs)) {
+ if (reg >= ASPEED_SCU_NR_REGS) {
qemu_log_mask(LOG_GUEST_ERROR,
"%s: Out-of-bounds write at offset 0x%" HWADDR_PRIx "\n",
__func__, offset);
@@ -346,7 +374,7 @@ static void aspeed_scu_reset(DeviceState *dev)
AspeedSCUState *s = ASPEED_SCU(dev);
AspeedSCUClass *asc = ASPEED_SCU_GET_CLASS(dev);
- memcpy(s->regs, asc->resets, sizeof(s->regs));
+ memcpy(s->regs, asc->resets, asc->nr_regs * 4);
s->regs[SILICON_REV] = s->silicon_rev;
s->regs[HW_STRAP1] = s->hw_strap1;
s->regs[HW_STRAP2] = s->hw_strap2;
@@ -358,6 +386,7 @@ static uint32_t aspeed_silicon_revs[] = {
AST2400_A1_SILICON_REV,
AST2500_A0_SILICON_REV,
AST2500_A1_SILICON_REV,
+ AST2600_A0_SILICON_REV,
};
bool is_supported_silicon_rev(uint32_t silicon_rev)
@@ -377,6 +406,7 @@ static void aspeed_scu_realize(DeviceState *dev, Error **errp)
{
SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
AspeedSCUState *s = ASPEED_SCU(dev);
+ AspeedSCUClass *asc = ASPEED_SCU_GET_CLASS(dev);
if (!is_supported_silicon_rev(s->silicon_rev)) {
error_setg(errp, "Unknown silicon revision: 0x%" PRIx32,
@@ -384,7 +414,7 @@ static void aspeed_scu_realize(DeviceState *dev, Error **errp)
return;
}
- memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_scu_ops, s,
+ memory_region_init_io(&s->iomem, OBJECT(s), asc->ops, s,
TYPE_ASPEED_SCU, SCU_IO_REGION_SIZE);
sysbus_init_mmio(sbd, &s->iomem);
@@ -392,10 +422,10 @@ static void aspeed_scu_realize(DeviceState *dev, Error **errp)
static const VMStateDescription vmstate_aspeed_scu = {
.name = "aspeed.scu",
- .version_id = 1,
- .minimum_version_id = 1,
+ .version_id = 2,
+ .minimum_version_id = 2,
.fields = (VMStateField[]) {
- VMSTATE_UINT32_ARRAY(regs, AspeedSCUState, ASPEED_SCU_NR_REGS),
+ VMSTATE_UINT32_ARRAY(regs, AspeedSCUState, ASPEED_AST2600_SCU_NR_REGS),
VMSTATE_END_OF_LIST()
}
};
@@ -436,6 +466,8 @@ static void aspeed_2400_scu_class_init(ObjectClass *klass, void *data)
asc->resets = ast2400_a0_resets;
asc->calc_hpll = aspeed_2400_scu_calc_hpll;
asc->apb_divider = 2;
+ asc->nr_regs = ASPEED_SCU_NR_REGS;
+ asc->ops = &aspeed_scu_ops;
}
static const TypeInfo aspeed_2400_scu_info = {
@@ -454,6 +486,8 @@ static void aspeed_2500_scu_class_init(ObjectClass *klass, void *data)
asc->resets = ast2500_a1_resets;
asc->calc_hpll = aspeed_2500_scu_calc_hpll;
asc->apb_divider = 4;
+ asc->nr_regs = ASPEED_SCU_NR_REGS;
+ asc->ops = &aspeed_scu_ops;
}
static const TypeInfo aspeed_2500_scu_info = {
@@ -463,11 +497,153 @@ static const TypeInfo aspeed_2500_scu_info = {
.class_init = aspeed_2500_scu_class_init,
};
+static uint64_t aspeed_ast2600_scu_read(void *opaque, hwaddr offset,
+ unsigned size)
+{
+ AspeedSCUState *s = ASPEED_SCU(opaque);
+ int reg = TO_REG(offset);
+
+ if (reg >= ASPEED_AST2600_SCU_NR_REGS) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Out-of-bounds read at offset 0x%" HWADDR_PRIx "\n",
+ __func__, offset);
+ return 0;
+ }
+
+ switch (reg) {
+ case AST2600_HPLL_EXT:
+ case AST2600_EPLL_EXT:
+ case AST2600_MPLL_EXT:
+ /* PLLs are always "locked" */
+ return s->regs[reg] | BIT(31);
+ case AST2600_RNG_DATA:
+ /*
+ * On hardware, RNG_DATA works regardless of the state of the
+ * enable bit in RNG_CTRL
+ *
+ * TODO: Check this is true for ast2600
+ */
+ s->regs[AST2600_RNG_DATA] = aspeed_scu_get_random();
+ break;
+ }
+
+ return s->regs[reg];
+}
+
+static void aspeed_ast2600_scu_write(void *opaque, hwaddr offset, uint64_t data,
+ unsigned size)
+{
+ AspeedSCUState *s = ASPEED_SCU(opaque);
+ int reg = TO_REG(offset);
+
+ if (reg >= ASPEED_AST2600_SCU_NR_REGS) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Out-of-bounds write at offset 0x%" HWADDR_PRIx "\n",
+ __func__, offset);
+ return;
+ }
+
+ if (reg > PROT_KEY && !s->regs[PROT_KEY]) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: SCU is locked!\n", __func__);
+ }
+
+ trace_aspeed_scu_write(offset, size, data);
+
+ switch (reg) {
+ case AST2600_PROT_KEY:
+ s->regs[reg] = (data == ASPEED_SCU_PROT_KEY) ? 1 : 0;
+ return;
+ case AST2600_HW_STRAP1:
+ case AST2600_HW_STRAP2:
+ if (s->regs[reg + 2]) {
+ return;
+ }
+ /* fall through */
+ case AST2600_SYS_RST_CTRL:
+ case AST2600_SYS_RST_CTRL2:
+ /* W1S (Write 1 to set) registers */
+ s->regs[reg] |= data;
+ return;
+ case AST2600_SYS_RST_CTRL_CLR:
+ case AST2600_SYS_RST_CTRL2_CLR:
+ case AST2600_HW_STRAP1_CLR:
+ case AST2600_HW_STRAP2_CLR:
+ /* W1C (Write 1 to clear) registers */
+ s->regs[reg] &= ~data;
+ return;
+
+ case AST2600_RNG_DATA:
+ case AST2600_SILICON_REV:
+ case AST2600_SILICON_REV2:
+ /* Add read only registers here */
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Write to read-only offset 0x%" HWADDR_PRIx "\n",
+ __func__, offset);
+ return;
+ }
+
+ s->regs[reg] = data;
+}
+
+static const MemoryRegionOps aspeed_ast2600_scu_ops = {
+ .read = aspeed_ast2600_scu_read,
+ .write = aspeed_ast2600_scu_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+ .valid.min_access_size = 4,
+ .valid.max_access_size = 4,
+ .valid.unaligned = false,
+};
+
+static const uint32_t ast2600_a0_resets[ASPEED_AST2600_SCU_NR_REGS] = {
+ [AST2600_SILICON_REV] = AST2600_SILICON_REV,
+ [AST2600_SILICON_REV2] = AST2600_SILICON_REV,
+ [AST2600_SYS_RST_CTRL] = 0xF7CFFEDC | 0x100,
+ [AST2600_SYS_RST_CTRL2] = 0xFFFFFFFC,
+ [AST2600_CLK_STOP_CTRL] = 0xEFF43E8B,
+ [AST2600_CLK_STOP_CTRL2] = 0xFFF0FFF0,
+};
+
+static void aspeed_ast2600_scu_reset(DeviceState *dev)
+{
+ AspeedSCUState *s = ASPEED_SCU(dev);
+ AspeedSCUClass *asc = ASPEED_SCU_GET_CLASS(dev);
+
+ memcpy(s->regs, asc->resets, asc->nr_regs * 4);
+
+ s->regs[AST2600_SILICON_REV] = s->silicon_rev;
+ s->regs[AST2600_SILICON_REV2] = s->silicon_rev;
+ s->regs[AST2600_HW_STRAP1] = s->hw_strap1;
+ s->regs[AST2600_HW_STRAP2] = s->hw_strap2;
+ s->regs[PROT_KEY] = s->hw_prot_key;
+}
+
+static void aspeed_2600_scu_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ AspeedSCUClass *asc = ASPEED_SCU_CLASS(klass);
+
+ dc->desc = "ASPEED 2600 System Control Unit";
+ dc->reset = aspeed_ast2600_scu_reset;
+ asc->resets = ast2600_a0_resets;
+ asc->calc_hpll = aspeed_2500_scu_calc_hpll; /* No change since AST2500 */
+ asc->apb_divider = 4;
+ asc->nr_regs = ASPEED_AST2600_SCU_NR_REGS;
+ asc->ops = &aspeed_ast2600_scu_ops;
+}
+
+static const TypeInfo aspeed_2600_scu_info = {
+ .name = TYPE_ASPEED_2600_SCU,
+ .parent = TYPE_ASPEED_SCU,
+ .instance_size = sizeof(AspeedSCUState),
+ .class_init = aspeed_2600_scu_class_init,
+};
+
static void aspeed_scu_register_types(void)
{
type_register_static(&aspeed_scu_info);
type_register_static(&aspeed_2400_scu_info);
type_register_static(&aspeed_2500_scu_info);
+ type_register_static(&aspeed_2600_scu_info);
}
type_init(aspeed_scu_register_types);
--
2.21.0
On Thu, 19 Sep 2019, at 15:19, Cédric Le Goater wrote:
> From: Joel Stanley <joel@jms.id.au>
>
> The SCU controller on the AST2600 SoC has extra registers. Increase
> the number of regs of the model and introduce a new field in the class
> to customize the MemoryRegion operations depending on the SoC model.
>
> Signed-off-by: Joel Stanley <joel@jms.id.au>
> [clg: - improved commit log
> - changed vmstate version
> - reworked model integration into new objet class ]
> Signed-off-by: Cédric Le Goater <clg@kaod.org>
> ---
> include/hw/misc/aspeed_scu.h | 7 +-
> hw/misc/aspeed_scu.c | 190 +++++++++++++++++++++++++++++++++--
> 2 files changed, 189 insertions(+), 8 deletions(-)
...
> +static void aspeed_ast2600_scu_write(void *opaque, hwaddr offset,
> uint64_t data,
> + unsigned size)
> +{
> + AspeedSCUState *s = ASPEED_SCU(opaque);
> + int reg = TO_REG(offset);
> +
> + if (reg >= ASPEED_AST2600_SCU_NR_REGS) {
> + qemu_log_mask(LOG_GUEST_ERROR,
> + "%s: Out-of-bounds write at offset 0x%"
> HWADDR_PRIx "\n",
> + __func__, offset);
> + return;
> + }
> +
> + if (reg > PROT_KEY && !s->regs[PROT_KEY]) {
> + qemu_log_mask(LOG_GUEST_ERROR, "%s: SCU is locked!\n",
> __func__);
> + }
> +
> + trace_aspeed_scu_write(offset, size, data);
> +
> + switch (reg) {
> + case AST2600_PROT_KEY:
> + s->regs[reg] = (data == ASPEED_SCU_PROT_KEY) ? 1 : 0;
> + return;
> + case AST2600_HW_STRAP1:
> + case AST2600_HW_STRAP2:
> + if (s->regs[reg + 2]) {
> + return;
> + }
> + /* fall through */
> + case AST2600_SYS_RST_CTRL:
> + case AST2600_SYS_RST_CTRL2:
> + /* W1S (Write 1 to set) registers */
> + s->regs[reg] |= data;
> + return;
> + case AST2600_SYS_RST_CTRL_CLR:
> + case AST2600_SYS_RST_CTRL2_CLR:
> + case AST2600_HW_STRAP1_CLR:
> + case AST2600_HW_STRAP2_CLR:
> + /* W1C (Write 1 to clear) registers */
> + s->regs[reg] &= ~data;
This clear should respect the protection register for each strap case.
Andrew
On 20/09/2019 06:10, Andrew Jeffery wrote:
>
>
> On Thu, 19 Sep 2019, at 15:19, Cédric Le Goater wrote:
>> From: Joel Stanley <joel@jms.id.au>
>>
>> The SCU controller on the AST2600 SoC has extra registers. Increase
>> the number of regs of the model and introduce a new field in the class
>> to customize the MemoryRegion operations depending on the SoC model.
>>
>> Signed-off-by: Joel Stanley <joel@jms.id.au>
>> [clg: - improved commit log
>> - changed vmstate version
>> - reworked model integration into new objet class ]
>> Signed-off-by: Cédric Le Goater <clg@kaod.org>
>> ---
>> include/hw/misc/aspeed_scu.h | 7 +-
>> hw/misc/aspeed_scu.c | 190 +++++++++++++++++++++++++++++++++--
>> 2 files changed, 189 insertions(+), 8 deletions(-)
>
> ...
>
>> +static void aspeed_ast2600_scu_write(void *opaque, hwaddr offset,
>> uint64_t data,
>> + unsigned size)
>> +{
>> + AspeedSCUState *s = ASPEED_SCU(opaque);
>> + int reg = TO_REG(offset);
>> +
>> + if (reg >= ASPEED_AST2600_SCU_NR_REGS) {
>> + qemu_log_mask(LOG_GUEST_ERROR,
>> + "%s: Out-of-bounds write at offset 0x%"
>> HWADDR_PRIx "\n",
>> + __func__, offset);
>> + return;
>> + }
>> +
>> + if (reg > PROT_KEY && !s->regs[PROT_KEY]) {
>> + qemu_log_mask(LOG_GUEST_ERROR, "%s: SCU is locked!\n",
>> __func__);
>> + }
>> +
>> + trace_aspeed_scu_write(offset, size, data);
>> +
>> + switch (reg) {
>> + case AST2600_PROT_KEY:
>> + s->regs[reg] = (data == ASPEED_SCU_PROT_KEY) ? 1 : 0;
>> + return;
>> + case AST2600_HW_STRAP1:
>> + case AST2600_HW_STRAP2:
>> + if (s->regs[reg + 2]) {
>> + return;
>> + }
>> + /* fall through */
>> + case AST2600_SYS_RST_CTRL:
>> + case AST2600_SYS_RST_CTRL2:
>> + /* W1S (Write 1 to set) registers */
>> + s->regs[reg] |= data;
>> + return;
>> + case AST2600_SYS_RST_CTRL_CLR:
>> + case AST2600_SYS_RST_CTRL2_CLR:
>> + case AST2600_HW_STRAP1_CLR:
>> + case AST2600_HW_STRAP2_CLR:
>> + /* W1C (Write 1 to clear) registers */
>> + s->regs[reg] &= ~data;
>
> This clear should respect the protection register for each strap case.
Joel,
You are the expert ! :)
Thanks,
C.
On Fri, 20 Sep 2019 at 15:15, Cédric Le Goater <clg@kaod.org> wrote:
>
> On 20/09/2019 06:10, Andrew Jeffery wrote:
> >
> >
> > On Thu, 19 Sep 2019, at 15:19, Cédric Le Goater wrote:
> >> From: Joel Stanley <joel@jms.id.au>
> >>
> >> The SCU controller on the AST2600 SoC has extra registers. Increase
> >> the number of regs of the model and introduce a new field in the class
> >> to customize the MemoryRegion operations depending on the SoC model.
> >>
> >> + switch (reg) {
> >> + case AST2600_PROT_KEY:
> >> + s->regs[reg] = (data == ASPEED_SCU_PROT_KEY) ? 1 : 0;
> >> + return;
> >> + case AST2600_HW_STRAP1:
> >> + case AST2600_HW_STRAP2:
> >> + if (s->regs[reg + 2]) {
> >> + return;
> >> + }
> >> + /* fall through */
> >> + case AST2600_SYS_RST_CTRL:
> >> + case AST2600_SYS_RST_CTRL2:
> >> + /* W1S (Write 1 to set) registers */
> >> + s->regs[reg] |= data;
> >> + return;
> >> + case AST2600_SYS_RST_CTRL_CLR:
> >> + case AST2600_SYS_RST_CTRL2_CLR:
> >> + case AST2600_HW_STRAP1_CLR:
> >> + case AST2600_HW_STRAP2_CLR:
> >> + /* W1C (Write 1 to clear) registers */
> >> + s->regs[reg] &= ~data;
> >
> > This clear should respect the protection register for each strap case.
>
> Joel,
>
> You are the expert ! :)
Someone could implement this if they wanted to. In the future it might
be useful to create a detailed model for the OTP and secure boot
behavior, and that can affect the strapping.
However it is not critical for running guests under qemu. I think we
should defer it until there is some guest code that needs the detailed
behavior.
Cheers,
Joel
On 21/09/2019 06:37, Joel Stanley wrote:
> On Fri, 20 Sep 2019 at 15:15, Cédric Le Goater <clg@kaod.org> wrote:
>>
>> On 20/09/2019 06:10, Andrew Jeffery wrote:
>>>
>>>
>>> On Thu, 19 Sep 2019, at 15:19, Cédric Le Goater wrote:
>>>> From: Joel Stanley <joel@jms.id.au>
>>>>
>>>> The SCU controller on the AST2600 SoC has extra registers. Increase
>>>> the number of regs of the model and introduce a new field in the class
>>>> to customize the MemoryRegion operations depending on the SoC model.
>>>>
>>>> + switch (reg) {
>>>> + case AST2600_PROT_KEY:
>>>> + s->regs[reg] = (data == ASPEED_SCU_PROT_KEY) ? 1 : 0;
>>>> + return;
>>>> + case AST2600_HW_STRAP1:
>>>> + case AST2600_HW_STRAP2:
>>>> + if (s->regs[reg + 2]) {
>>>> + return;
>>>> + }
>>>> + /* fall through */
>>>> + case AST2600_SYS_RST_CTRL:
>>>> + case AST2600_SYS_RST_CTRL2:
>>>> + /* W1S (Write 1 to set) registers */
>>>> + s->regs[reg] |= data;
>>>> + return;
>>>> + case AST2600_SYS_RST_CTRL_CLR:
>>>> + case AST2600_SYS_RST_CTRL2_CLR:
>>>> + case AST2600_HW_STRAP1_CLR:
>>>> + case AST2600_HW_STRAP2_CLR:
>>>> + /* W1C (Write 1 to clear) registers */
>>>> + s->regs[reg] &= ~data;
>>>
>>> This clear should respect the protection register for each strap case.
>>
>> Joel,
>>
>> You are the expert ! :)
>
> Someone could implement this if they wanted to. In the future it might
> be useful to create a detailed model for the OTP and secure boot
> behavior, and that can affect the strapping.
>
> However it is not critical for running guests under qemu. I think we
> should defer it until there is some guest code that needs the detailed
> behavior.
ok. It think we could trap the invalid writes with a simple mask
array at the beginning of the write op .
Thanks,
C.
© 2016 - 2026 Red Hat, Inc.