Source code for the Trusted Boot Module.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
tbm-mcu/shell.c

269 lines
4.3 KiB

#define _GNU_SOURCE
#include <libopencm3/stm32/rcc.h>
#include <libopencm3/stm32/gpio.h>
#include <libopencm3/stm32/spi.h>
#include <libopencm3/stm32/usart.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <stddef.h>
#include <limits.h>
#include <sys/types.h>
#include "shell.h"
#include "spi_flash.h"
#include "usart.h"
static void do_probe(FILE *fp, const char *s);
static void do_read(FILE *fp, const char *s);
static void do_write(FILE *fp, const char *s);
static void do_erase(FILE *fp, const char *s);
struct cmd cmds[] = {
{ "probe", do_probe },
{ "read", do_read },
{ "write", do_write },
{ "erase", do_erase },
{ NULL, NULL },
};
/* TODO: implement a parser for hex arrays that is more user-friendly.
* Also implement dry runs for programmers. */
static void parse_hex(FILE *fp, char *buf, size_t len)
{
size_t i;
char s[3];
for (i = 0; i < len; ++i) {
memset(s, '\0', 3);
while ((s[0] = fgetc(fp)) && !isxdigit(s[0]))
fputc(s[0], fp);
fputc(s[0], fp);
while ((s[1] = fgetc(fp)) && !isxdigit(s[1]))
fputc(s[1], fp);
fputc(s[1], fp);
*buf++ = strtoul(s, NULL, 16);
}
}
static void print_hex_ascii(FILE *fp, const char *buf, size_t len)
{
size_t i, j;
char c;
for (j = 0; j < len; j += 16, buf += 16) {
for (i = 0; i < 16; ++i) {
fprintf(fp, "%02x", buf[i]);
}
fprintf(fp, " ");
for (i = 0; i < 16; ++i) {
c = buf[i];
fprintf(fp, "%c", isalnum(c) ? c : '.');
}
fprintf(fp, "\r\n");
}
}
static char *prompt(FILE *fp, const char *prefix)
{
char *alloc, *line, *s;
size_t nbytes = 0, nalloc_bytes = 16;
char c;
fprintf(fp, prefix);
if (!(line = malloc(nalloc_bytes)))
return NULL;
s = line;
while ((c = fgetc(fp)) && c != '\r') {
fputc(c, fp);
if (nbytes + 1 >= nalloc_bytes) {
nalloc_bytes *= 2;
if (!(alloc = realloc(line, nalloc_bytes)))
goto err_free_line;
line = alloc;
}
*s++ = c;
nbytes++;
}
fprintf(fp, "\r\n");
*s = '\0';
return line;
err_free_line:
free(line);
return NULL;
}
static void do_probe(FILE *fp, const char *s)
{
char cmd[1] = { CMD_READ_ID };
char buf[6];
(void)s;
spi_send_cmd(SPI1, cmd, 1, buf, 6);
fprintf(fp, "JEDEC ID: %02x%02x%02x\r\n", buf[0], buf[1], buf[2]);
}
static void do_read(FILE *fp, const char *s)
{
char buf[256], *end = NULL;
size_t addr, len, nbytes;
if (strncmp(s, "0x", 2) == 0)
s += 2;
addr = strtoull(s, &end, 16);
s = end;
if (errno == EINVAL || errno == ERANGE)
return;
s += strspn(s, " \r\n");
if (strncmp(s, "0x", 2) == 0)
s += 2;
len = strtoull(s, &end, 16);
s = end;
if (errno == EINVAL || errno == ERANGE)
return;
if (!len)
return;
while (len) {
nbytes = (len > 256) ? 256 : len;
spi_flash_read(SPI1, addr, buf, nbytes);
print_hex_ascii(fp, buf, nbytes);
addr += nbytes;
len -= nbytes;
}
}
static void do_write(FILE *fp, const char *s)
{
char buf[256], *end = NULL;
size_t addr, len, nbytes;
if (strncmp(s, "0x", 2) == 0)
s += 2;
addr = strtoull(s, &end, 16);
s = end;
if (errno == EINVAL || errno == ERANGE)
return;
s += strspn(s, " \r\n");
if (strncmp(s, "0x", 2) == 0)
s += 2;
len = strtoull(s, &end, 16);
s = end;
if (errno == EINVAL || errno == ERANGE)
return;
if (!len)
return;
while (len) {
nbytes = (len > 256) ? 256 : len;
parse_hex(fp, buf, nbytes);
fprintf(fp, "\r\n");
print_hex_ascii(fp, buf, nbytes);
spi_flash_write(SPI1, addr, buf, nbytes);
addr += nbytes;
len -= nbytes;
}
}
static void do_erase(FILE *fp, const char *s)
{
char *end = NULL;
size_t addr, len;
(void)fp;
if (strncmp(s, "0x", 2) == 0)
s += 2;
addr = strtoull(s, &end, 16);
s = end;
if (errno == EINVAL || errno == ERANGE)
return;
s += strspn(s, " \r\n");
if (strncmp(s, "0x", 2) == 0)
s += 2;
len = strtoull(s, &end, 16);
s = end;
if (errno == EINVAL || errno == ERANGE)
return;
if (!len)
return;
spi_flash_erase(fp, SPI1, addr, len);
}
static void parse_cmd(FILE *fp, const char *s)
{
struct cmd *cmd;
const char *args;
char *key;
size_t n;
n = strcspn(s, " \r\n");
key = strndup(s, n);
args = s + n;
args += strspn(args, " \r\n");
for (cmd = cmds; cmd->key; cmd++) {
if (strcmp(cmd->key, key) == 0)
cmd->exec(fp, args);
}
}
void cmd_loop(FILE *fp, const char *show)
{
char *line;
while (1) {
line = prompt(fp, show);
parse_cmd(fp, line);
free(line);
}
}