Commit 12688ef9 authored by Tristan Gingold's avatar Tristan Gingold

Add wrpc-load utility to load/save a firmware image

parent a5431365
......@@ -12,6 +12,7 @@ ALL += pfilter-builder
ALL += mapper
ALL += wrpc-vuart
ALL += wrpc-gdbserver
ALL += wrpc-load
ALL += wr-streamers
ALL += wrpc-diags
ALL += gensdbfs
......@@ -84,6 +85,9 @@ wrpc-vuart: wrpc-vuart.o vuart_lib.o
wrpc-gdbserver: wrpc-gdbserver.o vuart_lib.o
$(CC) $(CFLAGS) -Werror $^ $(LDFLAGS) -o $@
wrpc-load: wrpc-load.o
$(CC) $(CFLAGS) $^ $(LDFLAGS) -o $@
pfilter-builder: pfilter-builder.c
$(CC) $(CFLAGS) -include ../include/generated/autoconf.h \
$@.c $(LDFLAGS) -o $@
......
/*
* SPDX-License-Identifier: GPL-3.0-or-later
* SPDX-FileCopyrightText: 2019 CERN (home.cern)
*
*/
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <errno.h>
#include <getopt.h>
#include <inttypes.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <poll.h>
#include <stdbool.h>
#include <time.h>
#include <limits.h>
#include "libdevmap.h"
#include "hw/wrc_cpu_csr.h"
static int verbose;
static uint32_t wrc_readl(struct mapping_desc *desc, unsigned reg)
{
uint32_t r = *(volatile uint32_t *)(desc->base + reg );
if (desc->is_be)
return ntohl(r);
else
return r;
}
static void wrc_writel(struct mapping_desc *desc, unsigned reg, uint32_t value)
{
if (desc->is_be)
value = htonl(value);
*(volatile uint32_t *)(desc->base + reg ) = value;
}
static void wrc_cpu_reset(struct mapping_desc *desc, unsigned int rst)
{
wrc_writel (desc, 0xb00 + WRC_CPU_CSR_REG_RESET, rst);
}
static void wrc_write_uaddr(struct mapping_desc *desc, unsigned int addr)
{
wrc_writel(desc, 0xb00 + WRC_CPU_CSR_REG_UADDR, addr >> 2);
}
static void wrc_write_buf(struct mapping_desc *desc,
const unsigned char *buf,
unsigned len,
unsigned addr)
{
if ((len & 0x03) != 0 || (addr & 0x03) != 0)
abort();
while (len > 0) {
uint32_t v;
wrc_write_uaddr(desc, addr);
/* Use BE. */
v = (buf[3] << 0)
| (buf[2] << 8)
| (buf[1] << 16)
| (buf[0] << 24);
wrc_writel(desc, 0xb00 + WRC_CPU_CSR_REG_UDATA, v);
if (verbose)
printf ("Write %08x at %08x\n", v, addr);
len -= 4;
addr += 4;
buf += 4;
}
}
static int wrc_load_firmware(struct mapping_desc *desc, const char *filename)
{
int fd;
unsigned char hdr[4];
unsigned char buf[1024];
ssize_t res;
unsigned addr;
fd = open(filename, O_RDONLY);
if (fd < 0) {
fprintf(stderr, "cannot open %s\n", filename);
return -1;
}
res = read(fd, hdr, sizeof(hdr));
if (res != sizeof(hdr)) {
fprintf(stderr, "cannot read %s\n", filename);
goto err_close;
}
if (hdr[0] == 0x7f
&& hdr[1] == 'E' && hdr[2] == 'L' && hdr[3] == 'F') {
fprintf(stderr, "ELF file %s not yet handled\n", filename);
goto err_close;
}
addr = 0;
wrc_write_buf(desc, hdr, sizeof(hdr), addr);
addr += sizeof (hdr);
while (1) {
res = read(fd, buf, sizeof(buf));
if (res <= 0)
break;
wrc_write_buf(desc, buf, res, addr);
addr += res;
}
printf ("%u KB written\n", addr / 1024);
close(fd);
return 0;
err_close:
close(fd);
return -1;
}
static int wrc_save_firmware(struct mapping_desc *desc, const char *filename)
{
int fd;
unsigned length = 0x20000;
unsigned char buf[1024];
ssize_t res;
unsigned addr;
fd = open(filename, O_WRONLY);
if (fd < 0) {
fprintf(stderr, "cannot open %s\n", filename);
return -1;
}
for (addr = 0; addr < length;) {
unsigned l = length - addr;
unsigned off;
if (l > sizeof (buf))
l = sizeof (buf);
for (off = 0; off < l; off += 4) {
unsigned int v;
wrc_write_uaddr(desc, addr);
v = wrc_readl(desc, 0xb00 + WRC_CPU_CSR_REG_UDATA);
/* Use BE */
buf[off + 0] = v >> 24;
buf[off + 1] = v >> 16;
buf[off + 2] = v >> 8;
buf[off + 3] = v >> 0;
addr += 4;
}
res = write(fd, buf, l);
if (res != l) {
fprintf(stderr, "write failure\n");
close(fd);
return -1;
}
}
printf ("%u KB written to %s\n", length / 1024, filename);
close(fd);
return 0;
}
static void wrc_dump(struct mapping_desc *desc, unsigned addr, unsigned len)
{
unsigned off;
off = 0;
for (off = 0; off < len; off += 4) {
uint32_t v;
if ((off & 0x0f) == 0)
printf ("%08x:", addr + off);
wrc_write_uaddr(desc, addr + off);
v = wrc_readl(desc, 0xb00 + WRC_CPU_CSR_REG_UDATA);
printf (" %08x", v);
if ((off & 0x0f) == 0xc)
printf ("\n");
}
if ((off & 0x0f) != 0xc)
printf ("\n");
}
static void wrpc_load_help(char *prog)
{
const char *mapping_help_str;
mapping_help_str = dev_mapping_help();
fprintf(stderr, "%s [-v] [-h] [-s] filename\n", prog);
fprintf(stderr, "%s\n", mapping_help_str);
fprintf(stderr, "(offset should be 0, address is the wrpc registers base)\n");
fprintf(stderr, "Only for risc-v\n");
fprintf(stderr, "Use -s to save memory to a file\n");
}
int main(int argc, char *argv[])
{
int c;
const char *filename;
struct mapping_args *map_args;
struct mapping_desc *mdesc = NULL;
enum { CMD_LOAD, CMD_DUMP, CMD_SAVE } cmd;
map_args = dev_parse_mapping_args(&argc, argv);
if (!map_args) {
wrpc_load_help(argv[0]);
return 1;
}
cmd = CMD_LOAD;
while ((c = getopt(argc, argv, "h:vds")) != -1) {
switch (c) {
case 'h':
case '?':
wrpc_load_help(argv[0]);
exit(EXIT_SUCCESS);
break;
case 'd':
cmd = CMD_DUMP;
break;
case 's':
cmd = CMD_SAVE;
break;
case 'v':
verbose++;
break;
}
}
if (((cmd == CMD_LOAD || cmd == CMD_SAVE) && (optind != argc - 1))
|| (cmd == CMD_DUMP && optind != argc)) {
wrpc_load_help(argv[0]);
return 2;
}
filename = argv[optind];
mdesc = dev_map(map_args, getpagesize());
if (!mdesc) {
fprintf(stderr, "%s: failed to map: %s\n", argv[0],
strerror(errno));
return 1;
}
/* Reset */
wrc_cpu_reset(mdesc, 1 << 0);
switch (cmd) {
case CMD_LOAD:
/* Load */
wrc_load_firmware (mdesc, filename);
break;
case CMD_SAVE:
/* Save */
wrc_save_firmware (mdesc, filename);
break;
case CMD_DUMP:
/* TODO: specify offset and length */
wrc_dump(mdesc, 0, 0x200);
break;
}
/* Start */
wrc_cpu_reset(mdesc, 0);
return 0;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment