2 * QEMU model of the Xilinx BBRAM Battery Backed RAM
4 * Copyright (c) 2014-2021 Xilinx Inc.
5 * Copyright (c) 2023 Advanced Micro Devices, Inc.
7 * Permission is hereby granted, free of charge, to any person obtaining a copy
8 * of this software and associated documentation files (the "Software"), to deal
9 * in the Software without restriction, including without limitation the rights
10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 * copies of the Software, and to permit persons to whom the Software is
12 * furnished to do so, subject to the following conditions:
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
26 #include "qemu/osdep.h"
27 #include "hw/nvram/xlnx-bbram.h"
29 #include "qemu/error-report.h"
31 #include "qapi/error.h"
32 #include "sysemu/blockdev.h"
33 #include "migration/vmstate.h"
34 #include "hw/qdev-properties.h"
35 #include "hw/qdev-properties-system.h"
36 #include "hw/nvram/xlnx-efuse.h"
38 #ifndef XLNX_BBRAM_ERR_DEBUG
39 #define XLNX_BBRAM_ERR_DEBUG 0
42 REG32(BBRAM_STATUS
, 0x0)
43 FIELD(BBRAM_STATUS
, AES_CRC_PASS
, 9, 1)
44 FIELD(BBRAM_STATUS
, AES_CRC_DONE
, 8, 1)
45 FIELD(BBRAM_STATUS
, BBRAM_ZEROIZED
, 4, 1)
46 FIELD(BBRAM_STATUS
, PGM_MODE
, 0, 1)
47 REG32(BBRAM_CTRL
, 0x4)
48 FIELD(BBRAM_CTRL
, ZEROIZE
, 0, 1)
50 REG32(BBRAM_AES_CRC
, 0xc)
60 REG32(BBRAM_SLVERR
, 0x34)
61 FIELD(BBRAM_SLVERR
, ENABLE
, 0, 1)
62 REG32(BBRAM_ISR
, 0x38)
63 FIELD(BBRAM_ISR
, APB_SLVERR
, 0, 1)
64 REG32(BBRAM_IMR
, 0x3c)
65 FIELD(BBRAM_IMR
, APB_SLVERR
, 0, 1)
66 REG32(BBRAM_IER
, 0x40)
67 FIELD(BBRAM_IER
, APB_SLVERR
, 0, 1)
68 REG32(BBRAM_IDR
, 0x44)
69 FIELD(BBRAM_IDR
, APB_SLVERR
, 0, 1)
70 REG32(BBRAM_MSW_LOCK
, 0x4c)
71 FIELD(BBRAM_MSW_LOCK
, VAL
, 0, 1)
73 #define R_MAX (R_BBRAM_MSW_LOCK + 1)
75 #define RAM_MAX (A_BBRAM_8 + 4 - A_BBRAM_0)
77 #define BBRAM_PGM_MAGIC 0x757bdf0d
79 QEMU_BUILD_BUG_ON(R_MAX
!= ARRAY_SIZE(((XlnxBBRam
*)0)->regs
));
81 static bool bbram_msw_locked(XlnxBBRam
*s
)
83 return ARRAY_FIELD_EX32(s
->regs
, BBRAM_MSW_LOCK
, VAL
) != 0;
86 static bool bbram_pgm_enabled(XlnxBBRam
*s
)
88 return ARRAY_FIELD_EX32(s
->regs
, BBRAM_STATUS
, PGM_MODE
) != 0;
91 static void bbram_bdrv_error(XlnxBBRam
*s
, int rc
, gchar
*detail
)
95 error_setg_errno(&errp
, -rc
, "%s: BBRAM backstore %s failed.",
96 blk_name(s
->blk
), detail
);
97 error_report("%s", error_get_pretty(errp
));
103 static void bbram_bdrv_read(XlnxBBRam
*s
, Error
**errp
)
105 uint32_t *ram
= &s
->regs
[R_BBRAM_0
];
112 s
->blk_ro
= !blk_supports_write_perm(s
->blk
);
116 rc
= blk_set_perm(s
->blk
,
117 (BLK_PERM_CONSISTENT_READ
| BLK_PERM_WRITE
),
124 warn_report("%s: Skip saving updates to read-only BBRAM backstore.",
128 if (blk_pread(s
->blk
, 0, nr
, ram
, 0) < 0) {
130 "%s: Failed to read %u bytes from BBRAM backstore.",
131 blk_name(s
->blk
), nr
);
135 /* Convert from little-endian backstore for each 32-bit word */
138 ram
[nr
] = le32_to_cpu(ram
[nr
]);
142 static void bbram_bdrv_sync(XlnxBBRam
*s
, uint64_t hwaddr
)
148 assert(A_BBRAM_0
<= hwaddr
&& hwaddr
<= A_BBRAM_8
);
150 /* Backstore is always in little-endian */
151 le32
= cpu_to_le32(s
->regs
[hwaddr
/ 4]);
153 /* Update zeroized flag */
154 if (le32
&& (hwaddr
!= A_BBRAM_8
|| s
->bbram8_wo
)) {
155 ARRAY_FIELD_DP32(s
->regs
, BBRAM_STATUS
, BBRAM_ZEROIZED
, 0);
158 if (!s
->blk
|| s
->blk_ro
) {
162 offset
= hwaddr
- A_BBRAM_0
;
163 rc
= blk_pwrite(s
->blk
, offset
, 4, &le32
, 0);
165 bbram_bdrv_error(s
, rc
, g_strdup_printf("write to offset %u", offset
));
169 static void bbram_bdrv_zero(XlnxBBRam
*s
)
173 ARRAY_FIELD_DP32(s
->regs
, BBRAM_STATUS
, BBRAM_ZEROIZED
, 1);
175 if (!s
->blk
|| s
->blk_ro
) {
179 rc
= blk_make_zero(s
->blk
, 0);
181 bbram_bdrv_error(s
, rc
, g_strdup("zeroizing"));
184 /* Restore bbram8 if it is non-zero */
185 if (s
->regs
[R_BBRAM_8
]) {
186 bbram_bdrv_sync(s
, A_BBRAM_8
);
190 static void bbram_zeroize(XlnxBBRam
*s
)
192 int nr
= RAM_MAX
- (s
->bbram8_wo
? 0 : 4); /* only wo bbram8 is cleared */
194 memset(&s
->regs
[R_BBRAM_0
], 0, nr
);
198 static void bbram_update_irq(XlnxBBRam
*s
)
200 bool pending
= s
->regs
[R_BBRAM_ISR
] & ~s
->regs
[R_BBRAM_IMR
];
202 qemu_set_irq(s
->irq_bbram
, pending
);
205 static void bbram_ctrl_postw(RegisterInfo
*reg
, uint64_t val64
)
207 XlnxBBRam
*s
= XLNX_BBRAM(reg
->opaque
);
208 uint32_t val
= val64
;
210 if (val
& R_BBRAM_CTRL_ZEROIZE_MASK
) {
212 /* The bit is self clearing */
213 s
->regs
[R_BBRAM_CTRL
] &= ~R_BBRAM_CTRL_ZEROIZE_MASK
;
217 static void bbram_pgm_mode_postw(RegisterInfo
*reg
, uint64_t val64
)
219 XlnxBBRam
*s
= XLNX_BBRAM(reg
->opaque
);
220 uint32_t val
= val64
;
222 if (val
== BBRAM_PGM_MAGIC
) {
225 /* The status bit is cleared only by POR */
226 ARRAY_FIELD_DP32(s
->regs
, BBRAM_STATUS
, PGM_MODE
, 1);
230 static void bbram_aes_crc_postw(RegisterInfo
*reg
, uint64_t val64
)
232 XlnxBBRam
*s
= XLNX_BBRAM(reg
->opaque
);
235 if (!bbram_pgm_enabled(s
)) {
236 /* We are not in programming mode, don't do anything */
240 /* Perform the AES integrity check */
241 s
->regs
[R_BBRAM_STATUS
] |= R_BBRAM_STATUS_AES_CRC_DONE_MASK
;
246 * ZynqMP BBRAM check has a zero-u32 prepended; see:
247 * https://github.com/Xilinx/embeddedsw/blob/release-2019.2/lib/sw_services/xilskey/src/xilskey_bbramps_zynqmp.c#L311
249 calc_crc
= xlnx_efuse_calc_crc(&s
->regs
[R_BBRAM_0
],
250 (R_BBRAM_8
- R_BBRAM_0
), s
->crc_zpads
);
252 ARRAY_FIELD_DP32(s
->regs
, BBRAM_STATUS
, AES_CRC_PASS
,
253 (s
->regs
[R_BBRAM_AES_CRC
] == calc_crc
));
256 static uint64_t bbram_key_prew(RegisterInfo
*reg
, uint64_t val64
)
258 XlnxBBRam
*s
= XLNX_BBRAM(reg
->opaque
);
259 uint32_t original_data
= *(uint32_t *) reg
->data
;
261 if (bbram_pgm_enabled(s
)) {
264 /* We are not in programming mode, don't do anything */
265 qemu_log_mask(LOG_GUEST_ERROR
,
266 "Not in programming mode, dropping the write\n");
267 return original_data
;
271 static void bbram_key_postw(RegisterInfo
*reg
, uint64_t val64
)
273 XlnxBBRam
*s
= XLNX_BBRAM(reg
->opaque
);
275 bbram_bdrv_sync(s
, reg
->access
->addr
);
278 static uint64_t bbram_wo_postr(RegisterInfo
*reg
, uint64_t val
)
283 static uint64_t bbram_r8_postr(RegisterInfo
*reg
, uint64_t val
)
285 XlnxBBRam
*s
= XLNX_BBRAM(reg
->opaque
);
287 return s
->bbram8_wo
? bbram_wo_postr(reg
, val
) : val
;
290 static bool bbram_r8_readonly(XlnxBBRam
*s
)
292 return !bbram_pgm_enabled(s
) || bbram_msw_locked(s
);
295 static uint64_t bbram_r8_prew(RegisterInfo
*reg
, uint64_t val64
)
297 XlnxBBRam
*s
= XLNX_BBRAM(reg
->opaque
);
299 if (bbram_r8_readonly(s
)) {
300 val64
= *(uint32_t *)reg
->data
;
306 static void bbram_r8_postw(RegisterInfo
*reg
, uint64_t val64
)
308 XlnxBBRam
*s
= XLNX_BBRAM(reg
->opaque
);
310 if (!bbram_r8_readonly(s
)) {
311 bbram_bdrv_sync(s
, A_BBRAM_8
);
315 static uint64_t bbram_msw_lock_prew(RegisterInfo
*reg
, uint64_t val64
)
317 XlnxBBRam
*s
= XLNX_BBRAM(reg
->opaque
);
319 /* Never lock if bbram8 is wo; and, only POR can clear the lock */
323 val64
|= s
->regs
[R_BBRAM_MSW_LOCK
];
329 static void bbram_isr_postw(RegisterInfo
*reg
, uint64_t val64
)
331 XlnxBBRam
*s
= XLNX_BBRAM(reg
->opaque
);
336 static uint64_t bbram_ier_prew(RegisterInfo
*reg
, uint64_t val64
)
338 XlnxBBRam
*s
= XLNX_BBRAM(reg
->opaque
);
339 uint32_t val
= val64
;
341 s
->regs
[R_BBRAM_IMR
] &= ~val
;
346 static uint64_t bbram_idr_prew(RegisterInfo
*reg
, uint64_t val64
)
348 XlnxBBRam
*s
= XLNX_BBRAM(reg
->opaque
);
349 uint32_t val
= val64
;
351 s
->regs
[R_BBRAM_IMR
] |= val
;
356 static RegisterAccessInfo bbram_ctrl_regs_info
[] = {
357 { .name
= "BBRAM_STATUS", .addr
= A_BBRAM_STATUS
,
360 },{ .name
= "BBRAM_CTRL", .addr
= A_BBRAM_CTRL
,
361 .post_write
= bbram_ctrl_postw
,
362 },{ .name
= "PGM_MODE", .addr
= A_PGM_MODE
,
363 .post_write
= bbram_pgm_mode_postw
,
364 },{ .name
= "BBRAM_AES_CRC", .addr
= A_BBRAM_AES_CRC
,
365 .post_write
= bbram_aes_crc_postw
,
366 .post_read
= bbram_wo_postr
,
367 },{ .name
= "BBRAM_0", .addr
= A_BBRAM_0
,
368 .pre_write
= bbram_key_prew
,
369 .post_write
= bbram_key_postw
,
370 .post_read
= bbram_wo_postr
,
371 },{ .name
= "BBRAM_1", .addr
= A_BBRAM_1
,
372 .pre_write
= bbram_key_prew
,
373 .post_write
= bbram_key_postw
,
374 .post_read
= bbram_wo_postr
,
375 },{ .name
= "BBRAM_2", .addr
= A_BBRAM_2
,
376 .pre_write
= bbram_key_prew
,
377 .post_write
= bbram_key_postw
,
378 .post_read
= bbram_wo_postr
,
379 },{ .name
= "BBRAM_3", .addr
= A_BBRAM_3
,
380 .pre_write
= bbram_key_prew
,
381 .post_write
= bbram_key_postw
,
382 .post_read
= bbram_wo_postr
,
383 },{ .name
= "BBRAM_4", .addr
= A_BBRAM_4
,
384 .pre_write
= bbram_key_prew
,
385 .post_write
= bbram_key_postw
,
386 .post_read
= bbram_wo_postr
,
387 },{ .name
= "BBRAM_5", .addr
= A_BBRAM_5
,
388 .pre_write
= bbram_key_prew
,
389 .post_write
= bbram_key_postw
,
390 .post_read
= bbram_wo_postr
,
391 },{ .name
= "BBRAM_6", .addr
= A_BBRAM_6
,
392 .pre_write
= bbram_key_prew
,
393 .post_write
= bbram_key_postw
,
394 .post_read
= bbram_wo_postr
,
395 },{ .name
= "BBRAM_7", .addr
= A_BBRAM_7
,
396 .pre_write
= bbram_key_prew
,
397 .post_write
= bbram_key_postw
,
398 .post_read
= bbram_wo_postr
,
399 },{ .name
= "BBRAM_8", .addr
= A_BBRAM_8
,
400 .pre_write
= bbram_r8_prew
,
401 .post_write
= bbram_r8_postw
,
402 .post_read
= bbram_r8_postr
,
403 },{ .name
= "BBRAM_SLVERR", .addr
= A_BBRAM_SLVERR
,
405 },{ .name
= "BBRAM_ISR", .addr
= A_BBRAM_ISR
,
407 .post_write
= bbram_isr_postw
,
408 },{ .name
= "BBRAM_IMR", .addr
= A_BBRAM_IMR
,
410 },{ .name
= "BBRAM_IER", .addr
= A_BBRAM_IER
,
411 .pre_write
= bbram_ier_prew
,
412 },{ .name
= "BBRAM_IDR", .addr
= A_BBRAM_IDR
,
413 .pre_write
= bbram_idr_prew
,
414 },{ .name
= "BBRAM_MSW_LOCK", .addr
= A_BBRAM_MSW_LOCK
,
415 .pre_write
= bbram_msw_lock_prew
,
416 .ro
= ~R_BBRAM_MSW_LOCK_VAL_MASK
,
420 static void bbram_ctrl_reset_hold(Object
*obj
)
422 XlnxBBRam
*s
= XLNX_BBRAM(obj
);
425 for (i
= 0; i
< ARRAY_SIZE(s
->regs_info
); ++i
) {
426 if (i
< R_BBRAM_0
|| i
> R_BBRAM_8
) {
427 register_reset(&s
->regs_info
[i
]);
434 static const MemoryRegionOps bbram_ctrl_ops
= {
435 .read
= register_read_memory
,
436 .write
= register_write_memory
,
437 .endianness
= DEVICE_LITTLE_ENDIAN
,
439 .min_access_size
= 4,
440 .max_access_size
= 4,
444 static void bbram_ctrl_realize(DeviceState
*dev
, Error
**errp
)
446 XlnxBBRam
*s
= XLNX_BBRAM(dev
);
452 bbram_bdrv_read(s
, errp
);
455 static void bbram_ctrl_init(Object
*obj
)
457 XlnxBBRam
*s
= XLNX_BBRAM(obj
);
458 SysBusDevice
*sbd
= SYS_BUS_DEVICE(obj
);
459 RegisterInfoArray
*reg_array
;
462 register_init_block32(DEVICE(obj
), bbram_ctrl_regs_info
,
463 ARRAY_SIZE(bbram_ctrl_regs_info
),
464 s
->regs_info
, s
->regs
,
466 XLNX_BBRAM_ERR_DEBUG
,
469 sysbus_init_mmio(sbd
, ®_array
->mem
);
470 sysbus_init_irq(sbd
, &s
->irq_bbram
);
473 static void bbram_prop_set_drive(Object
*obj
, Visitor
*v
, const char *name
,
474 void *opaque
, Error
**errp
)
476 DeviceState
*dev
= DEVICE(obj
);
478 qdev_prop_drive
.set(obj
, v
, name
, opaque
, errp
);
480 /* Fill initial data if backend is attached after realized */
482 bbram_bdrv_read(XLNX_BBRAM(obj
), errp
);
486 static void bbram_prop_get_drive(Object
*obj
, Visitor
*v
, const char *name
,
487 void *opaque
, Error
**errp
)
489 qdev_prop_drive
.get(obj
, v
, name
, opaque
, errp
);
492 static void bbram_prop_release_drive(Object
*obj
, const char *name
,
495 qdev_prop_drive
.release(obj
, name
, opaque
);
498 static const PropertyInfo bbram_prop_drive
= {
500 .description
= "Node name or ID of a block device to use as BBRAM backend",
501 .realized_set_allowed
= true,
502 .get
= bbram_prop_get_drive
,
503 .set
= bbram_prop_set_drive
,
504 .release
= bbram_prop_release_drive
,
507 static const VMStateDescription vmstate_bbram_ctrl
= {
508 .name
= TYPE_XLNX_BBRAM
,
510 .minimum_version_id
= 1,
511 .fields
= (VMStateField
[]) {
512 VMSTATE_UINT32_ARRAY(regs
, XlnxBBRam
, R_MAX
),
513 VMSTATE_END_OF_LIST(),
517 static Property bbram_ctrl_props
[] = {
518 DEFINE_PROP("drive", XlnxBBRam
, blk
, bbram_prop_drive
, BlockBackend
*),
519 DEFINE_PROP_UINT32("crc-zpads", XlnxBBRam
, crc_zpads
, 1),
520 DEFINE_PROP_END_OF_LIST(),
523 static void bbram_ctrl_class_init(ObjectClass
*klass
, void *data
)
525 DeviceClass
*dc
= DEVICE_CLASS(klass
);
526 ResettableClass
*rc
= RESETTABLE_CLASS(klass
);
528 rc
->phases
.hold
= bbram_ctrl_reset_hold
;
529 dc
->realize
= bbram_ctrl_realize
;
530 dc
->vmsd
= &vmstate_bbram_ctrl
;
531 device_class_set_props(dc
, bbram_ctrl_props
);
534 static const TypeInfo bbram_ctrl_info
= {
535 .name
= TYPE_XLNX_BBRAM
,
536 .parent
= TYPE_SYS_BUS_DEVICE
,
537 .instance_size
= sizeof(XlnxBBRam
),
538 .class_init
= bbram_ctrl_class_init
,
539 .instance_init
= bbram_ctrl_init
,
542 static void bbram_ctrl_register_types(void)
544 type_register_static(&bbram_ctrl_info
);
547 type_init(bbram_ctrl_register_types
)