@@ -24,6 +24,72 @@
#include "qemu/log.h"
#include "qemu/module.h"
#include "hw/riscv/sifive_u_otp.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <string.h>
+
+#define TRACE_PREFIX "FU540_OTP: "
+#define SIFIVE_FU540_OTP_SIZE (SIFIVE_U_OTP_NUM_FUSES * 4)
+
+static int otp_backed_fd;
+static unsigned int *otp_mmap;
+
+static void sifive_u_otp_backed_load(const char *filename);
+static uint64_t sifive_u_otp_backed_read(uint32_t fuseidx);
+static void sifive_u_otp_backed_write(uint32_t fuseidx,
+ uint32_t paio,
+ uint32_t pdin);
+static void sifive_u_otp_backed_unload(void);
+
+void sifive_u_otp_backed_load(const char *filename)
+{
+ if (otp_backed_fd < 0) {
+
+ otp_backed_fd = open(filename, O_RDWR);
+
+ if (otp_backed_fd < 0)
+ qemu_log_mask(LOG_TRACE,
+ TRACE_PREFIX "Warning: can't open otp file\n");
+ else {
+
+ otp_mmap = (unsigned int *)mmap(0,
+ SIFIVE_FU540_OTP_SIZE,
+ PROT_READ | PROT_WRITE | PROT_EXEC,
+ MAP_FILE | MAP_SHARED,
+ otp_backed_fd,
+ 0);
+
+ if (otp_mmap == MAP_FAILED)
+ qemu_log_mask(LOG_TRACE,
+ TRACE_PREFIX "Warning: can't mmap otp file\n");
+ }
+ }
+
+}
+
+uint64_t sifive_u_otp_backed_read(uint32_t fuseidx)
+{
+ return (uint64_t)(otp_mmap[fuseidx]);
+}
+
+void sifive_u_otp_backed_write(uint32_t fuseidx, uint32_t paio, uint32_t pdin)
+{
+ otp_mmap[fuseidx] &= ~(pdin << paio);
+ otp_mmap[fuseidx] |= (pdin << paio);
+}
+
+
+void sifive_u_otp_backed_unload(void)
+{
+ munmap(otp_mmap, SIFIVE_FU540_OTP_SIZE);
+ close(otp_backed_fd);
+ otp_backed_fd = -1;
+}
static uint64_t sifive_u_otp_read(void *opaque, hwaddr addr, unsigned int size)
{
@@ -46,7 +112,17 @@ static uint64_t sifive_u_otp_read(void *opaque, hwaddr addr, unsigned int size)
if ((s->pce & SIFIVE_U_OTP_PCE_EN) &&
(s->pdstb & SIFIVE_U_OTP_PDSTB_EN) &&
(s->ptrim & SIFIVE_U_OTP_PTRIM_EN)) {
- return s->fuse[s->pa & SIFIVE_U_OTP_PA_MASK];
+
+ if (otp_file) {
+ uint64_t val;
+
+ sifive_u_otp_backed_load(otp_file);
+ val = sifive_u_otp_backed_read(s->pa);
+ sifive_u_otp_backed_unload();
+
+ return val;
+ } else
+ return s->fuse[s->pa & SIFIVE_U_OTP_PA_MASK];
} else {
return 0xff;
}
@@ -123,6 +199,12 @@ static void sifive_u_otp_write(void *opaque, hwaddr addr,
s->ptrim = val32;
break;
case SIFIVE_U_OTP_PWE:
+ if (otp_file) {
+ sifive_u_otp_backed_load(otp_file);
+ sifive_u_otp_backed_write(s->pa, s->paio, s->pdin);
+ sifive_u_otp_backed_unload();
+ }
+
s->pwe = val32;
break;
default:
@@ -165,6 +247,10 @@ static void sifive_u_otp_reset(DeviceState *dev)
/* Make a valid content of serial number */
s->fuse[SIFIVE_U_OTP_SERIAL_ADDR] = s->serial;
s->fuse[SIFIVE_U_OTP_SERIAL_ADDR + 1] = ~(s->serial);
+
+ /* Initialize file mmap and descriptor. */
+ otp_mmap = NULL;
+ otp_backed_fd = -1;
}
static void sifive_u_otp_class_init(ObjectClass *klass, void *data)
@@ -52,6 +52,8 @@
#define SIFIVE_U_OTP(obj) \
OBJECT_CHECK(SiFiveUOTPState, (obj), TYPE_SIFIVE_U_OTP)
+extern const char *otp_file;
+
typedef struct SiFiveUOTPState {
/*< private >*/
SysBusDevice parent_obj;
@@ -415,10 +415,11 @@ ERST
DEF("boot", HAS_ARG, QEMU_OPTION_boot,
"-boot [order=drives][,once=drives][,menu=on|off]\n"
- " [,splash=sp_name][,splash-time=sp_time][,reboot-timeout=rb_time][,strict=on|off]\n"
+ " [,splash=sp_name][,splash-time=sp_time][,reboot-timeout=rb_time][,strict=on|off][,otp-file=otp_file]\n"
" 'drives': floppy (a), hard disk (c), CD-ROM (d), network (n)\n"
" 'sp_name': the file's name that would be passed to bios as logo picture, if menu=on\n"
" 'sp_time': the period that splash picture last if menu=on, unit is ms\n"
+ " 'otp_file': the file name backed OTP\n"
" 'rb_timeout': the timeout before guest reboot when boot failed, unit is ms\n",
QEMU_ARCH_ALL)
SRST
@@ -21,7 +21,6 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
-
#include "qemu/osdep.h"
#include "qemu-common.h"
#include "qemu/units.h"
@@ -161,6 +160,7 @@ unsigned int nb_prom_envs = 0;
const char *prom_envs[MAX_PROM_ENVS];
int boot_menu;
bool boot_strict;
+const char *otp_file;
uint8_t *boot_splash_filedata;
int only_migratable; /* turn it off unless user states otherwise */
bool wakeup_suspend_enabled;
@@ -308,6 +308,9 @@ static QemuOptsList qemu_boot_opts = {
}, {
.name = "strict",
.type = QEMU_OPT_BOOL,
+ }, {
+ .name = "otp-file",
+ .type = QEMU_OPT_STRING,
},
{ /*End of list */ }
},
@@ -4215,6 +4218,7 @@ void qemu_init(int argc, char **argv, char **envp)
boot_menu = qemu_opt_get_bool(opts, "menu", boot_menu);
boot_strict = qemu_opt_get_bool(opts, "strict", false);
+ otp_file = qemu_opt_get(opts, "otp-file");
}
if (!boot_order) {
Add a file-backed implementation for OTP of sifive_u machine. Use '-boot otp-file=xxx' to enable it. Do file open, mmap and close for every OTP read/write in case keep the update-to-date snapshot of OTP. Signed-off-by: Green Wan <green.wan@sifive.com> --- hw/riscv/sifive_u_otp.c | 88 ++++++++++++++++++++++++++++++++- include/hw/riscv/sifive_u_otp.h | 2 + qemu-options.hx | 3 +- softmmu/vl.c | 6 ++- 4 files changed, 96 insertions(+), 3 deletions(-)