2 * QEMU model of the Xilinx BBRAM Battery Backed RAM
4 * Copyright (c) 2014-2021 Xilinx Inc.
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 #include "qemu/osdep.h"
26 #include "hw/nvram/xlnx-bbram.h"
28 #include "qemu/error-report.h"
30 #include "qapi/error.h"
31 #include "sysemu/blockdev.h"
32 #include "migration/vmstate.h"
33 #include "hw/qdev-properties.h"
34 #include "hw/qdev-properties-system.h"
35 #include "hw/nvram/xlnx-efuse.h"
37 #ifndef XLNX_BBRAM_ERR_DEBUG
38 #define XLNX_BBRAM_ERR_DEBUG 0
41 REG32(BBRAM_STATUS
, 0x0)
42 FIELD(BBRAM_STATUS
, AES_CRC_PASS
, 9, 1)
43 FIELD(BBRAM_STATUS
, AES_CRC_DONE
, 8, 1)
44 FIELD(BBRAM_STATUS
, BBRAM_ZEROIZED
, 4, 1)
45 FIELD(BBRAM_STATUS
, PGM_MODE
, 0, 1)
46 REG32(BBRAM_CTRL
, 0x4)
47 FIELD(BBRAM_CTRL
, ZEROIZE
, 0, 1)
49 REG32(BBRAM_AES_CRC
, 0xc)
59 REG32(BBRAM_SLVERR
, 0x34)
60 FIELD(BBRAM_SLVERR
, ENABLE
, 0, 1)
61 REG32(BBRAM_ISR
, 0x38)
62 FIELD(BBRAM_ISR
, APB_SLVERR
, 0, 1)
63 REG32(BBRAM_IMR
, 0x3c)
64 FIELD(BBRAM_IMR
, APB_SLVERR
, 0, 1)
65 REG32(BBRAM_IER
, 0x40)
66 FIELD(BBRAM_IER
, APB_SLVERR
, 0, 1)
67 REG32(BBRAM_IDR
, 0x44)
68 FIELD(BBRAM_IDR
, APB_SLVERR
, 0, 1)
69 REG32(BBRAM_MSW_LOCK
, 0x4c)
70 FIELD(BBRAM_MSW_LOCK
, VAL
, 0, 1)
72 #define R_MAX (R_BBRAM_MSW_LOCK + 1)
74 #define RAM_MAX (A_BBRAM_8 + 4 - A_BBRAM_0)
76 #define BBRAM_PGM_MAGIC 0x757bdf0d
78 QEMU_BUILD_BUG_ON(R_MAX
!= ARRAY_SIZE(((XlnxBBRam
*)0)->regs
));
80 static bool bbram_msw_locked(XlnxBBRam
*s
)
82 return ARRAY_FIELD_EX32(s
->regs
, BBRAM_MSW_LOCK
, VAL
) != 0;
85 static bool bbram_pgm_enabled(XlnxBBRam
*s
)
87 return ARRAY_FIELD_EX32(s
->regs
, BBRAM_STATUS
, PGM_MODE
) != 0;
90 static void bbram_bdrv_error(XlnxBBRam
*s
, int rc
, gchar
*detail
)
94 error_setg_errno(&errp
, -rc
, "%s: BBRAM backstore %s failed.",
95 blk_name(s
->blk
), detail
);
96 error_report("%s", error_get_pretty(errp
));
102 static void bbram_bdrv_read(XlnxBBRam
*s
, Error
**errp
)
104 uint32_t *ram
= &s
->regs
[R_BBRAM_0
];
111 s
->blk_ro
= !blk_supports_write_perm(s
->blk
);
115 rc
= blk_set_perm(s
->blk
,
116 (BLK_PERM_CONSISTENT_READ
| BLK_PERM_WRITE
),
123 warn_report("%s: Skip saving updates to read-only BBRAM backstore.",
127 if (blk_pread(s
->blk
, 0, nr
, ram
, 0) < 0) {
129 "%s: Failed to read %u bytes from BBRAM backstore.",
130 blk_name(s
->blk
), nr
);
134 /* Convert from little-endian backstore for each 32-bit word */
137 ram
[nr
] = le32_to_cpu(ram
[nr
]);
141 static void bbram_bdrv_sync(XlnxBBRam
*s
, uint64_t hwaddr
)
147 assert(A_BBRAM_0
<= hwaddr
&& hwaddr
<= A_BBRAM_8
);
149 /* Backstore is always in little-endian */
150 le32
= cpu_to_le32(s
->regs
[hwaddr
/ 4]);
152 /* Update zeroized flag */
153 if (le32
&& (hwaddr
!= A_BBRAM_8
|| s
->bbram8_wo
)) {
154 ARRAY_FIELD_DP32(s
->regs
, BBRAM_STATUS
, BBRAM_ZEROIZED
, 0);
157 if (!s
->blk
|| s
->blk_ro
) {
161 offset
= hwaddr
- A_BBRAM_0
;
162 rc
= blk_pwrite(s
->blk
, offset
, 4, &le32
, 0);
164 bbram_bdrv_error(s
, rc
, g_strdup_printf("write to offset %u", offset
));
168 static void bbram_bdrv_zero(XlnxBBRam
*s
)
172 ARRAY_FIELD_DP32(s
->regs
, BBRAM_STATUS
, BBRAM_ZEROIZED
, 1);
174 if (!s
->blk
|| s
->blk_ro
) {
178 rc
= blk_make_zero(s
->blk
, 0);
180 bbram_bdrv_error(s
, rc
, g_strdup("zeroizing"));
183 /* Restore bbram8 if it is non-zero */
184 if (s
->regs
[R_BBRAM_8
]) {
185 bbram_bdrv_sync(s
, A_BBRAM_8
);
189 static void bbram_zeroize(XlnxBBRam
*s
)
191 int nr
= RAM_MAX
- (s
->bbram8_wo
? 0 : 4); /* only wo bbram8 is cleared */
193 memset(&s
->regs
[R_BBRAM_0
], 0, nr
);
197 static void bbram_update_irq(XlnxBBRam
*s
)
199 bool pending
= s
->regs
[R_BBRAM_ISR
] & ~s
->regs
[R_BBRAM_IMR
];
201 qemu_set_irq(s
->irq_bbram
, pending
);
204 static void bbram_ctrl_postw(RegisterInfo
*reg
, uint64_t val64
)
206 XlnxBBRam
*s
= XLNX_BBRAM(reg
->opaque
);
207 uint32_t val
= val64
;
209 if (val
& R_BBRAM_CTRL_ZEROIZE_MASK
) {
211 /* The bit is self clearing */
212 s
->regs
[R_BBRAM_CTRL
] &= ~R_BBRAM_CTRL_ZEROIZE_MASK
;
216 static void bbram_pgm_mode_postw(RegisterInfo
*reg
, uint64_t val64
)
218 XlnxBBRam
*s
= XLNX_BBRAM(reg
->opaque
);
219 uint32_t val
= val64
;
221 if (val
== BBRAM_PGM_MAGIC
) {
224 /* The status bit is cleared only by POR */
225 ARRAY_FIELD_DP32(s
->regs
, BBRAM_STATUS
, PGM_MODE
, 1);
229 static void bbram_aes_crc_postw(RegisterInfo
*reg
, uint64_t val64
)
231 XlnxBBRam
*s
= XLNX_BBRAM(reg
->opaque
);
234 if (!bbram_pgm_enabled(s
)) {
235 /* We are not in programming mode, don't do anything */
239 /* Perform the AES integrity check */
240 s
->regs
[R_BBRAM_STATUS
] |= R_BBRAM_STATUS_AES_CRC_DONE_MASK
;
245 * ZynqMP BBRAM check has a zero-u32 prepended; see:
246 * https://github.com/Xilinx/embeddedsw/blob/release-2019.2/lib/sw_services/xilskey/src/xilskey_bbramps_zynqmp.c#L311
248 calc_crc
= xlnx_efuse_calc_crc(&s
->regs
[R_BBRAM_0
],
249 (R_BBRAM_8
- R_BBRAM_0
), s
->crc_zpads
);
251 ARRAY_FIELD_DP32(s
->regs
, BBRAM_STATUS
, AES_CRC_PASS
,
252 (s
->regs
[R_BBRAM_AES_CRC
] == calc_crc
));
255 static uint64_t bbram_key_prew(RegisterInfo
*reg
, uint64_t val64
)
257 XlnxBBRam
*s
= XLNX_BBRAM(reg
->opaque
);
258 uint32_t original_data
= *(uint32_t *) reg
->data
;
260 if (bbram_pgm_enabled(s
)) {
263 /* We are not in programming mode, don't do anything */
264 qemu_log_mask(LOG_GUEST_ERROR
,
265 "Not in programming mode, dropping the write\n");
266 return original_data
;
270 static void bbram_key_postw(RegisterInfo
*reg
, uint64_t val64
)
272 XlnxBBRam
*s
= XLNX_BBRAM(reg
->opaque
);
274 bbram_bdrv_sync(s
, reg
->access
->addr
);
277 static uint64_t bbram_wo_postr(RegisterInfo
*reg
, uint64_t val
)
282 static uint64_t bbram_r8_postr(RegisterInfo
*reg
, uint64_t val
)
284 XlnxBBRam
*s
= XLNX_BBRAM(reg
->opaque
);
286 return s
->bbram8_wo
? bbram_wo_postr(reg
, val
) : val
;
289 static bool bbram_r8_readonly(XlnxBBRam
*s
)
291 return !bbram_pgm_enabled(s
) || bbram_msw_locked(s
);
294 static uint64_t bbram_r8_prew(RegisterInfo
*reg
, uint64_t val64
)
296 XlnxBBRam
*s
= XLNX_BBRAM(reg
->opaque
);
298 if (bbram_r8_readonly(s
)) {
299 val64
= *(uint32_t *)reg
->data
;
305 static void bbram_r8_postw(RegisterInfo
*reg
, uint64_t val64
)
307 XlnxBBRam
*s
= XLNX_BBRAM(reg
->opaque
);
309 if (!bbram_r8_readonly(s
)) {
310 bbram_bdrv_sync(s
, A_BBRAM_8
);
314 static uint64_t bbram_msw_lock_prew(RegisterInfo
*reg
, uint64_t val64
)
316 XlnxBBRam
*s
= XLNX_BBRAM(reg
->opaque
);
318 /* Never lock if bbram8 is wo; and, only POR can clear the lock */
322 val64
|= s
->regs
[R_BBRAM_MSW_LOCK
];
328 static void bbram_isr_postw(RegisterInfo
*reg
, uint64_t val64
)
330 XlnxBBRam
*s
= XLNX_BBRAM(reg
->opaque
);
335 static uint64_t bbram_ier_prew(RegisterInfo
*reg
, uint64_t val64
)
337 XlnxBBRam
*s
= XLNX_BBRAM(reg
->opaque
);
338 uint32_t val
= val64
;
340 s
->regs
[R_BBRAM_IMR
] &= ~val
;
345 static uint64_t bbram_idr_prew(RegisterInfo
*reg
, uint64_t val64
)
347 XlnxBBRam
*s
= XLNX_BBRAM(reg
->opaque
);
348 uint32_t val
= val64
;
350 s
->regs
[R_BBRAM_IMR
] |= val
;
355 static RegisterAccessInfo bbram_ctrl_regs_info
[] = {
356 { .name
= "BBRAM_STATUS", .addr
= A_BBRAM_STATUS
,
359 },{ .name
= "BBRAM_CTRL", .addr
= A_BBRAM_CTRL
,
360 .post_write
= bbram_ctrl_postw
,
361 },{ .name
= "PGM_MODE", .addr
= A_PGM_MODE
,
362 .post_write
= bbram_pgm_mode_postw
,
363 },{ .name
= "BBRAM_AES_CRC", .addr
= A_BBRAM_AES_CRC
,
364 .post_write
= bbram_aes_crc_postw
,
365 .post_read
= bbram_wo_postr
,
366 },{ .name
= "BBRAM_0", .addr
= A_BBRAM_0
,
367 .pre_write
= bbram_key_prew
,
368 .post_write
= bbram_key_postw
,
369 .post_read
= bbram_wo_postr
,
370 },{ .name
= "BBRAM_1", .addr
= A_BBRAM_1
,
371 .pre_write
= bbram_key_prew
,
372 .post_write
= bbram_key_postw
,
373 .post_read
= bbram_wo_postr
,
374 },{ .name
= "BBRAM_2", .addr
= A_BBRAM_2
,
375 .pre_write
= bbram_key_prew
,
376 .post_write
= bbram_key_postw
,
377 .post_read
= bbram_wo_postr
,
378 },{ .name
= "BBRAM_3", .addr
= A_BBRAM_3
,
379 .pre_write
= bbram_key_prew
,
380 .post_write
= bbram_key_postw
,
381 .post_read
= bbram_wo_postr
,
382 },{ .name
= "BBRAM_4", .addr
= A_BBRAM_4
,
383 .pre_write
= bbram_key_prew
,
384 .post_write
= bbram_key_postw
,
385 .post_read
= bbram_wo_postr
,
386 },{ .name
= "BBRAM_5", .addr
= A_BBRAM_5
,
387 .pre_write
= bbram_key_prew
,
388 .post_write
= bbram_key_postw
,
389 .post_read
= bbram_wo_postr
,
390 },{ .name
= "BBRAM_6", .addr
= A_BBRAM_6
,
391 .pre_write
= bbram_key_prew
,
392 .post_write
= bbram_key_postw
,
393 .post_read
= bbram_wo_postr
,
394 },{ .name
= "BBRAM_7", .addr
= A_BBRAM_7
,
395 .pre_write
= bbram_key_prew
,
396 .post_write
= bbram_key_postw
,
397 .post_read
= bbram_wo_postr
,
398 },{ .name
= "BBRAM_8", .addr
= A_BBRAM_8
,
399 .pre_write
= bbram_r8_prew
,
400 .post_write
= bbram_r8_postw
,
401 .post_read
= bbram_r8_postr
,
402 },{ .name
= "BBRAM_SLVERR", .addr
= A_BBRAM_SLVERR
,
404 },{ .name
= "BBRAM_ISR", .addr
= A_BBRAM_ISR
,
406 .post_write
= bbram_isr_postw
,
407 },{ .name
= "BBRAM_IMR", .addr
= A_BBRAM_IMR
,
409 },{ .name
= "BBRAM_IER", .addr
= A_BBRAM_IER
,
410 .pre_write
= bbram_ier_prew
,
411 },{ .name
= "BBRAM_IDR", .addr
= A_BBRAM_IDR
,
412 .pre_write
= bbram_idr_prew
,
413 },{ .name
= "BBRAM_MSW_LOCK", .addr
= A_BBRAM_MSW_LOCK
,
414 .pre_write
= bbram_msw_lock_prew
,
415 .ro
= ~R_BBRAM_MSW_LOCK_VAL_MASK
,
419 static void bbram_ctrl_reset(DeviceState
*dev
)
421 XlnxBBRam
*s
= XLNX_BBRAM(dev
);
424 for (i
= 0; i
< ARRAY_SIZE(s
->regs_info
); ++i
) {
425 if (i
< R_BBRAM_0
|| i
> R_BBRAM_8
) {
426 register_reset(&s
->regs_info
[i
]);
433 static const MemoryRegionOps bbram_ctrl_ops
= {
434 .read
= register_read_memory
,
435 .write
= register_write_memory
,
436 .endianness
= DEVICE_LITTLE_ENDIAN
,
438 .min_access_size
= 4,
439 .max_access_size
= 4,
443 static void bbram_ctrl_realize(DeviceState
*dev
, Error
**errp
)
445 XlnxBBRam
*s
= XLNX_BBRAM(dev
);
451 bbram_bdrv_read(s
, errp
);
454 static void bbram_ctrl_init(Object
*obj
)
456 XlnxBBRam
*s
= XLNX_BBRAM(obj
);
457 SysBusDevice
*sbd
= SYS_BUS_DEVICE(obj
);
458 RegisterInfoArray
*reg_array
;
461 register_init_block32(DEVICE(obj
), bbram_ctrl_regs_info
,
462 ARRAY_SIZE(bbram_ctrl_regs_info
),
463 s
->regs_info
, s
->regs
,
465 XLNX_BBRAM_ERR_DEBUG
,
468 sysbus_init_mmio(sbd
, ®_array
->mem
);
469 sysbus_init_irq(sbd
, &s
->irq_bbram
);
472 static void bbram_prop_set_drive(Object
*obj
, Visitor
*v
, const char *name
,
473 void *opaque
, Error
**errp
)
475 DeviceState
*dev
= DEVICE(obj
);
477 qdev_prop_drive
.set(obj
, v
, name
, opaque
, errp
);
479 /* Fill initial data if backend is attached after realized */
481 bbram_bdrv_read(XLNX_BBRAM(obj
), errp
);
485 static void bbram_prop_get_drive(Object
*obj
, Visitor
*v
, const char *name
,
486 void *opaque
, Error
**errp
)
488 qdev_prop_drive
.get(obj
, v
, name
, opaque
, errp
);
491 static void bbram_prop_release_drive(Object
*obj
, const char *name
,
494 qdev_prop_drive
.release(obj
, name
, opaque
);
497 static const PropertyInfo bbram_prop_drive
= {
499 .description
= "Node name or ID of a block device to use as BBRAM backend",
500 .realized_set_allowed
= true,
501 .get
= bbram_prop_get_drive
,
502 .set
= bbram_prop_set_drive
,
503 .release
= bbram_prop_release_drive
,
506 static const VMStateDescription vmstate_bbram_ctrl
= {
507 .name
= TYPE_XLNX_BBRAM
,
509 .minimum_version_id
= 1,
510 .fields
= (VMStateField
[]) {
511 VMSTATE_UINT32_ARRAY(regs
, XlnxBBRam
, R_MAX
),
512 VMSTATE_END_OF_LIST(),
516 static Property bbram_ctrl_props
[] = {
517 DEFINE_PROP("drive", XlnxBBRam
, blk
, bbram_prop_drive
, BlockBackend
*),
518 DEFINE_PROP_UINT32("crc-zpads", XlnxBBRam
, crc_zpads
, 1),
519 DEFINE_PROP_END_OF_LIST(),
522 static void bbram_ctrl_class_init(ObjectClass
*klass
, void *data
)
524 DeviceClass
*dc
= DEVICE_CLASS(klass
);
526 dc
->reset
= bbram_ctrl_reset
;
527 dc
->realize
= bbram_ctrl_realize
;
528 dc
->vmsd
= &vmstate_bbram_ctrl
;
529 device_class_set_props(dc
, bbram_ctrl_props
);
532 static const TypeInfo bbram_ctrl_info
= {
533 .name
= TYPE_XLNX_BBRAM
,
534 .parent
= TYPE_SYS_BUS_DEVICE
,
535 .instance_size
= sizeof(XlnxBBRam
),
536 .class_init
= bbram_ctrl_class_init
,
537 .instance_init
= bbram_ctrl_init
,
540 static void bbram_ctrl_register_types(void)
542 type_register_static(&bbram_ctrl_info
);
545 type_init(bbram_ctrl_register_types
)