fw: clang-tidy and splint: New make target: check

Add clang-tidy and splint static analytics check. For now, we use only
the cert-* warnings on clang-tidy and run splint with a lot of flags
to allow more things.

Changes to silence these analytics:

- Stop returning stuff from our debug print functions. We don't check
  them anyway and we don't have any way of detecting transmission
  failure.

- Declare more things static that isn't used outside of a file.

- Change types to be more consistent, typically to size_t or
  something or to uint32_t.
This commit is contained in:
Michael Cardell Widerkrantz 2023-03-21 14:11:08 +01:00
parent f622937918
commit c443ef8a3e
No known key found for this signature in database
GPG Key ID: D3DB3DDF57E704E5
8 changed files with 70 additions and 51 deletions

View File

@ -85,6 +85,14 @@ FIRMWARE_OBJS = \
$(P)/fw/tk1/led.o \
$(P)/fw/tk1/blake2s/blake2s.o
FIRMWARE_SOURCES = \
$(P)/fw/tk1/main.c \
$(P)/fw/tk1/proto.c \
$(P)/fw/tk1/lib.c \
$(P)/fw/tk1/assert.c \
$(P)/fw/tk1/led.c \
$(P)/fw/tk1/blake2s/blake2s.c
TESTFW_OBJS = \
$(P)/fw/testfw/main.o \
$(P)/fw/testfw/start.o \
@ -132,6 +140,11 @@ $(TESTFW_OBJS): $(FIRMWARE_DEPS)
firmware.elf: $(FIRMWARE_OBJS) $(P)/fw/tk1/firmware.lds
$(CC) $(CFLAGS) $(FIRMWARE_OBJS) $(LDFLAGS) -o $@
.PHONY: check
check:
clang-tidy -header-filter=.* -checks=cert-* $(FIRMWARE_SOURCES) -- $(CFLAGS)
splint -nolib -predboolint +boolint -nullpass -unrecog -infloops -initallelements -type -unreachable -unqualifiedtrans -fullinitblock $(FIRMWARE_SOURCES)
testfw.elf: $(TESTFW_OBJS) $(P)/fw/tk1/firmware.lds
$(CC) $(CFLAGS) $(TESTFW_OBJS) $(LDFLAGS) -o $@

View File

@ -7,8 +7,8 @@
#include "led.h"
#include "lib.h"
void assert_fail(const char *assertion, const char *file,
unsigned int line, const char *function)
void assert_fail(const char *assertion, const char *file, unsigned int line,
const char *function)
{
htif_puts("assert: ");
htif_puts(assertion);

View File

@ -7,10 +7,9 @@
#define ASSERT_H
#define assert(expr) \
((expr) ? (void)(0) \
: assert_fail(#expr, __FILE__, __LINE__, __func__))
((expr) ? (void)(0) : assert_fail(#expr, __FILE__, __LINE__, __func__))
void assert_fail(const char *assertion, const char *file,
unsigned int line, const char *function);
void assert_fail(const char *assertion, const char *file, unsigned int line,
const char *function);
#endif

View File

@ -10,10 +10,10 @@
#ifndef NOCONSOLE
struct {
uint32_t arr[2];
} volatile tohost __attribute__((section(".htif")));
} static volatile tohost __attribute__((section(".htif")));
struct {
uint32_t arr[2];
} volatile fromhost __attribute__((section(".htif")));
} /*@unused@*/ static volatile fromhost __attribute__((section(".htif")));
static void htif_send(uint8_t dev, uint8_t cmd, int64_t data)
{
@ -38,17 +38,15 @@ static void htif_set_tohost(uint8_t dev, uint8_t cmd, int64_t data)
htif_send(dev, cmd, data);
}
static int htif_putchar(int ch)
static void htif_putchar(char ch)
{
htif_set_tohost(1, 1, ch & 0xff);
return ch & 0xff;
htif_set_tohost((uint8_t)1, (uint8_t)1, (int64_t)ch & 0xff);
}
int htif_puts(const char *s)
void htif_puts(const char *s)
{
while (*s)
while (*s != '\0')
htif_putchar(*s++);
return 0;
}
void htif_hexdump(void *buf, int len)
@ -69,7 +67,7 @@ void htif_hexdump(void *buf, int len)
htif_lf();
}
void htif_putc(int ch)
void htif_putc(char ch)
{
htif_putchar(ch);
}
@ -104,7 +102,7 @@ void *memset(void *dest, int c, unsigned n)
uint8_t *s = dest;
for (; n; n--, s++)
*s = c;
*s = (uint8_t)c;
return dest;
}
@ -118,7 +116,7 @@ void memcpy_s(void *dest, size_t destsize, const void *src, size_t n)
uint8_t *src_byte = (uint8_t *)src;
uint8_t *dest_byte = (uint8_t *)dest;
for (int i = 0; i < n; i++) {
for (size_t i = 0; i < n; i++) {
dest_byte[i] = src_byte[i];
}
}
@ -132,17 +130,17 @@ void wordcpy_s(void *dest, size_t destsize, const void *src, size_t n)
uint32_t *src_word = (uint32_t *)src;
uint32_t *dest_word = (uint32_t *)dest;
for (int i = 0; i < n; i++) {
for (size_t i = 0; i < n; i++) {
dest_word[i] = src_word[i];
}
}
int memeq(void *dest, const void *src, unsigned n)
int memeq(void *dest, const void *src, size_t n)
{
uint8_t *src_byte = (uint8_t *)src;
uint8_t *dest_byte = (uint8_t *)dest;
for (int i = 0; i < n; i++) {
for (size_t i = 0; i < n; i++) {
if (dest_byte[i] != src_byte[i]) {
return 0;
}

View File

@ -13,20 +13,20 @@
#define htif_lf()
#define htif_puthex(c)
#define htif_putinthex(n)
#define htif_puts(s) ((int)0)
#define htif_puts(s)
#define htif_hexdump(buf, len)
#else
void htif_putc(int ch);
void htif_putc(char ch);
void htif_lf();
void htif_puthex(uint8_t c);
void htif_putinthex(const uint32_t n);
int htif_puts(const char *s);
void htif_puts(const char *s);
void htif_hexdump(void *buf, int len);
#endif
void *memset(void *dest, int c, unsigned n);
void memcpy_s(void *dest, size_t destsize, const void *src, size_t n);
void wordcpy_s(void *dest, size_t destsize, const void *src, size_t n);
int memeq(void *dest, const void *src, unsigned n);
int memeq(void *dest, const void *src, size_t n);
#endif

View File

@ -35,7 +35,7 @@ static volatile uint32_t *ram_scramble = (volatile uint32_t *)TK1_MMIO_TK1_RA
// Context for the loading of a TKey program
struct context {
int left; // Bytes left to receive
uint32_t left; // Bytes left to receive
uint8_t digest[32]; // Program digest
uint8_t *loadaddr; // Where we are currently loading a TKey program
uint8_t use_uss; // Use USS?
@ -45,8 +45,8 @@ struct context {
static void print_hw_version();
static void print_digest(uint8_t *md);
static uint32_t rnd_word();
static void compute_cdi(const uint8_t digest[32], const uint8_t use_uss,
const uint8_t uss[32]);
static void compute_cdi(const uint8_t *digest, const uint8_t use_uss,
const uint8_t *uss);
static void copy_name(uint8_t *buf, const size_t bufsiz, const uint32_t word);
static enum state initial_commands(const struct frame_header *hdr,
const uint8_t *cmd, enum state state,
@ -89,8 +89,8 @@ static uint32_t rnd_word()
}
// CDI = blake2s(uds, blake2s(app), uss)
static void compute_cdi(const uint8_t digest[32], const uint8_t use_uss,
const uint8_t uss[32])
static void compute_cdi(const uint8_t *digest, const uint8_t use_uss,
const uint8_t *uss)
{
uint32_t local_cdi[8];
blake2s_ctx secure_ctx = {0};
@ -102,7 +102,7 @@ static void compute_cdi(const uint8_t digest[32], const uint8_t use_uss,
rnd_sleep = rnd_word();
// Up to 65536 cycles
rnd_sleep &= 0xffff;
*timer = (rnd_sleep == 0 ? 1 : rnd_sleep);
*timer = (uint32_t)(rnd_sleep == 0 ? 1 : rnd_sleep);
*timer_ctrl = (1 << TK1_MMIO_TIMER_CTRL_START_BIT);
while (*timer_status & (1 << TK1_MMIO_TIMER_STATUS_RUNNING_BIT)) {
}
@ -123,14 +123,14 @@ static void compute_cdi(const uint8_t digest[32], const uint8_t use_uss,
}
// Write hashed result to Compound Device Identity (CDI)
blake2s_final(&secure_ctx, local_cdi);
blake2s_final(&secure_ctx, &local_cdi);
// Clear secure_ctx of any residue of UDS. Don't want to keep
// that for long even though fw_ram is cleared later.
memset(&secure_ctx, 0, sizeof(secure_ctx));
(void)memset(&secure_ctx, 0, sizeof(secure_ctx));
// CDI only word writable
wordcpy_s((void *)cdi, 8, local_cdi, 8);
wordcpy_s((void *)cdi, 8, &local_cdi, 8);
}
static void copy_name(uint8_t *buf, const size_t bufsiz, const uint32_t word)
@ -177,8 +177,8 @@ static enum state initial_commands(const struct frame_header *hdr,
}
rsp[0] = STATUS_OK;
wordcpy_s(udi_words, 2, (void *)udi, 2);
memcpy_s(&rsp[1], CMDLEN_MAXBYTES - 1, udi_words, 2 * 4);
wordcpy_s(&udi_words, 2, (void *)udi, 2);
memcpy_s(&rsp[1], CMDLEN_MAXBYTES - 1, &udi_words, 2 * 4);
fwreply(*hdr, FW_RSP_GET_UDI, rsp);
// still initial state
break;
@ -248,7 +248,7 @@ static enum state loading_commands(const struct frame_header *hdr,
struct context *ctx)
{
uint8_t rsp[CMDLEN_MAXBYTES] = {0};
int nbytes = 0;
uint32_t nbytes = 0;
switch (cmd[0]) {
case FW_CMD_LOAD_APP_DATA:
@ -269,17 +269,19 @@ static enum state loading_commands(const struct frame_header *hdr,
ctx->left -= nbytes;
if (ctx->left == 0) {
blake2s_ctx b2s_ctx = {0};
int blake2err = 0;
htif_puts("Fully loaded ");
htif_putinthex(*app_size);
htif_lf();
// Compute Blake2S digest of the app,
// storing it for FW_STATE_RUN
blake2s_ctx b2s_ctx;
blake2s(&ctx->digest, 32, NULL, 0,
(const void *)TK1_RAM_BASE, *app_size,
&b2s_ctx);
blake2err = blake2s(&ctx->digest, 32, NULL, 0,
(const void *)TK1_RAM_BASE,
*app_size, &b2s_ctx);
assert(blake2err == 0);
print_digest(ctx->digest);
// And return the digest in final
@ -323,6 +325,7 @@ static void run(const struct context *ctx)
// Clear the firmware stack
// clang-format off
#ifndef S_SPLINT_S
asm volatile(
"li a0, 0xd0000000;" // FW_RAM
"li a1, 0xd0000800;" // End of 2 KB FW_RAM (just past the end)
@ -331,6 +334,7 @@ static void run(const struct context *ctx)
"addi a0, a0, 4;"
"blt a0, a1, loop;"
::: "memory");
#endif
// clang-format on
// Flip over to application mode
@ -341,6 +345,7 @@ static void run(const struct context *ctx)
// Jump to app - doesn't return
// clang-format off
#ifndef S_SPLINT_S
asm volatile(
// Get value at TK1_MMIO_TK1_APP_ADDR
"lui a0,0xff000;"
@ -348,6 +353,7 @@ static void run(const struct context *ctx)
// Jump to it
"jalr x0,0(a0);"
::: "memory");
#endif
// clang-format on
__builtin_unreachable();

View File

@ -17,7 +17,14 @@ static volatile uint32_t *can_tx = (volatile uint32_t *)TK1_MMIO_UART_TX_STATUS;
static volatile uint32_t *tx = (volatile uint32_t *)TK1_MMIO_UART_TX_DATA;
// clang-format on
uint8_t genhdr(uint8_t id, uint8_t endpoint, uint8_t status, enum cmdlen len)
static uint8_t genhdr(uint8_t id, uint8_t endpoint, uint8_t status,
enum cmdlen len);
static int parseframe(uint8_t b, struct frame_header *hdr);
static void write(uint8_t *buf, size_t nbytes);
static int read(uint8_t *buf, size_t bufsize, size_t nbytes);
static uint8_t genhdr(uint8_t id, uint8_t endpoint, uint8_t status,
enum cmdlen len)
{
return (id << 5) | (endpoint << 3) | (status << 2) | len;
}
@ -34,7 +41,7 @@ int readcommand(struct frame_header *hdr, uint8_t *cmd, int state)
return -1;
}
memset(cmd, 0, CMDLEN_MAXBYTES);
(void)memset(cmd, 0, CMDLEN_MAXBYTES);
// Now we know the size of the cmd frame, read it all
if (read(cmd, CMDLEN_MAXBYTES, hdr->len) != 0) {
htif_puts("read: buffer overrun\n");
@ -50,7 +57,7 @@ int readcommand(struct frame_header *hdr, uint8_t *cmd, int state)
return 0;
}
int parseframe(uint8_t b, struct frame_header *hdr)
static int parseframe(uint8_t b, struct frame_header *hdr)
{
if ((b & 0x80) != 0) {
// Bad version
@ -147,7 +154,7 @@ void writebyte(uint8_t b)
}
}
void write(uint8_t *buf, size_t nbytes)
static void write(uint8_t *buf, size_t nbytes)
{
for (int i = 0; i < nbytes; i++) {
writebyte(buf[i]);
@ -163,7 +170,7 @@ uint8_t readbyte()
}
}
int read(uint8_t *buf, size_t bufsize, size_t nbytes)
static int read(uint8_t *buf, size_t bufsize, size_t nbytes)
{
if (nbytes > bufsize) {
return -1;

View File

@ -50,12 +50,8 @@ struct frame_header {
enum cmdlen len;
};
uint8_t genhdr(uint8_t id, uint8_t endpoint, uint8_t status, enum cmdlen len);
int parseframe(uint8_t b, struct frame_header *hdr);
void fwreply(struct frame_header hdr, enum fwcmd rspcode, uint8_t *buf);
void writebyte(uint8_t b);
void write(uint8_t *buf, size_t nbytes);
uint8_t readbyte();
int read(uint8_t *buf, size_t bufsize, size_t nbytes);
void fwreply(struct frame_header hdr, enum fwcmd rspcode, uint8_t *buf);
int readcommand(struct frame_header *hdr, uint8_t *cmd, int state);
#endif