mirror of
https://github.com/tillitis/tillitis-key1.git
synced 2025-08-10 07:29:59 -04:00
Make initial public release
This commit is contained in:
commit
715de60f4a
251 changed files with 881225 additions and 0 deletions
15
hw/application_fpga/fw/.clang-format
Normal file
15
hw/application_fpga/fw/.clang-format
Normal file
|
@ -0,0 +1,15 @@
|
|||
BasedOnStyle: LLVM
|
||||
UseTab: Always
|
||||
IndentWidth: 8
|
||||
TabWidth: 8
|
||||
|
||||
IncludeBlocks: Preserve
|
||||
|
||||
BreakBeforeBraces: Custom
|
||||
BraceWrapping:
|
||||
AfterFunction: true
|
||||
|
||||
AllowShortFunctionsOnASingleLine: false
|
||||
AllowShortIfStatementsOnASingleLine: Never
|
||||
AllowShortEnumsOnASingleLine: false
|
||||
|
4
hw/application_fpga/fw/mta1_mkdf/Makefile
Normal file
4
hw/application_fpga/fw/mta1_mkdf/Makefile
Normal file
|
@ -0,0 +1,4 @@
|
|||
.PHONY: fmt
|
||||
fmt:
|
||||
# Uses ../.clang-format
|
||||
clang-format --verbose -i main.c lib.h lib.c proto.h proto.c types.h
|
53
hw/application_fpga/fw/mta1_mkdf/README.md
Normal file
53
hw/application_fpga/fw/mta1_mkdf/README.md
Normal file
|
@ -0,0 +1,53 @@
|
|||
# Tillitis Key firmware
|
||||
|
||||
## Build the firmware
|
||||
|
||||
You need Clang with 32 bit RISC-V support. You can check this with:
|
||||
|
||||
```
|
||||
$ llc --version|grep riscv32
|
||||
riscv32 - 32-bit RISC-V
|
||||
```
|
||||
|
||||
or just try building.
|
||||
|
||||
Build the FPGA bitstream with the firmware using `make` in the
|
||||
`hw/application_fpga` directory.
|
||||
|
||||
If your available `objcopy` and `size` commands is anything other than
|
||||
the default `llvm-objcopy-14` and `llvm-size-14` define `OBJCOPY` and
|
||||
`SIZE` to whatever they're called on your system.
|
||||
|
||||
## Using QEMU
|
||||
|
||||
Checkout the `mta1` branch of [our version of the
|
||||
qemu](https://github.com/tillitis/qemu) and build:
|
||||
|
||||
```
|
||||
$ git clone -b mta1 https://github.com/tillitis/qemu
|
||||
$ mkdir qemu/build
|
||||
$ cd qemu/build
|
||||
$ ../configure --target-list=riscv32-softmmu
|
||||
$ make -j $(nproc)
|
||||
```
|
||||
|
||||
Run it like this:
|
||||
|
||||
```
|
||||
$ /path/to/qemu/build/qemu-system-riscv32 -nographic -M mta1_mkdf,fifo=chrid -bios firmware \
|
||||
-chardev pty,id=chrid
|
||||
```
|
||||
|
||||
This attaches the FIFO to a tty, something like `/dev/pts/16` which
|
||||
you can use with host software to talk to the firmware.
|
||||
|
||||
To quit QEMU you can use: `Ctrl-a x` (see `Ctrl-a ?` for other commands).
|
||||
|
||||
Debugging? Use the HTIF console by removing `-DNOCONSOLE` from the
|
||||
`CFLAGS` and using the helper functions in `lib.c` for printf-like
|
||||
debugging.
|
||||
|
||||
You can also use the qemu monitor for debugging, e.g. `info
|
||||
registers`, or run qemu with `-d in_asm` or `-d trace:riscv_trap`.
|
||||
|
||||
Happy hacking!
|
116
hw/application_fpga/fw/mta1_mkdf/blake2s/LICENSE
Normal file
116
hw/application_fpga/fw/mta1_mkdf/blake2s/LICENSE
Normal file
|
@ -0,0 +1,116 @@
|
|||
CC0 1.0 Universal
|
||||
|
||||
Statement of Purpose
|
||||
|
||||
The laws of most jurisdictions throughout the world automatically confer
|
||||
exclusive Copyright and Related Rights (defined below) upon the creator and
|
||||
subsequent owner(s) (each and all, an "owner") of an original work of
|
||||
authorship and/or a database (each, a "Work").
|
||||
|
||||
Certain owners wish to permanently relinquish those rights to a Work for the
|
||||
purpose of contributing to a commons of creative, cultural and scientific
|
||||
works ("Commons") that the public can reliably and without fear of later
|
||||
claims of infringement build upon, modify, incorporate in other works, reuse
|
||||
and redistribute as freely as possible in any form whatsoever and for any
|
||||
purposes, including without limitation commercial purposes. These owners may
|
||||
contribute to the Commons to promote the ideal of a free culture and the
|
||||
further production of creative, cultural and scientific works, or to gain
|
||||
reputation or greater distribution for their Work in part through the use and
|
||||
efforts of others.
|
||||
|
||||
For these and/or other purposes and motivations, and without any expectation
|
||||
of additional consideration or compensation, the person associating CC0 with a
|
||||
Work (the "Affirmer"), to the extent that he or she is an owner of Copyright
|
||||
and Related Rights in the Work, voluntarily elects to apply CC0 to the Work
|
||||
and publicly distribute the Work under its terms, with knowledge of his or her
|
||||
Copyright and Related Rights in the Work and the meaning and intended legal
|
||||
effect of CC0 on those rights.
|
||||
|
||||
1. Copyright and Related Rights. A Work made available under CC0 may be
|
||||
protected by copyright and related or neighboring rights ("Copyright and
|
||||
Related Rights"). Copyright and Related Rights include, but are not limited
|
||||
to, the following:
|
||||
|
||||
i. the right to reproduce, adapt, distribute, perform, display, communicate,
|
||||
and translate a Work;
|
||||
|
||||
ii. moral rights retained by the original author(s) and/or performer(s);
|
||||
|
||||
iii. publicity and privacy rights pertaining to a person's image or likeness
|
||||
depicted in a Work;
|
||||
|
||||
iv. rights protecting against unfair competition in regards to a Work,
|
||||
subject to the limitations in paragraph 4(a), below;
|
||||
|
||||
v. rights protecting the extraction, dissemination, use and reuse of data in
|
||||
a Work;
|
||||
|
||||
vi. database rights (such as those arising under Directive 96/9/EC of the
|
||||
European Parliament and of the Council of 11 March 1996 on the legal
|
||||
protection of databases, and under any national implementation thereof,
|
||||
including any amended or successor version of such directive); and
|
||||
|
||||
vii. other similar, equivalent or corresponding rights throughout the world
|
||||
based on applicable law or treaty, and any national implementations thereof.
|
||||
|
||||
2. Waiver. To the greatest extent permitted by, but not in contravention of,
|
||||
applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and
|
||||
unconditionally waives, abandons, and surrenders all of Affirmer's Copyright
|
||||
and Related Rights and associated claims and causes of action, whether now
|
||||
known or unknown (including existing as well as future claims and causes of
|
||||
action), in the Work (i) in all territories worldwide, (ii) for the maximum
|
||||
duration provided by applicable law or treaty (including future time
|
||||
extensions), (iii) in any current or future medium and for any number of
|
||||
copies, and (iv) for any purpose whatsoever, including without limitation
|
||||
commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes
|
||||
the Waiver for the benefit of each member of the public at large and to the
|
||||
detriment of Affirmer's heirs and successors, fully intending that such Waiver
|
||||
shall not be subject to revocation, rescission, cancellation, termination, or
|
||||
any other legal or equitable action to disrupt the quiet enjoyment of the Work
|
||||
by the public as contemplated by Affirmer's express Statement of Purpose.
|
||||
|
||||
3. Public License Fallback. Should any part of the Waiver for any reason be
|
||||
judged legally invalid or ineffective under applicable law, then the Waiver
|
||||
shall be preserved to the maximum extent permitted taking into account
|
||||
Affirmer's express Statement of Purpose. In addition, to the extent the Waiver
|
||||
is so judged Affirmer hereby grants to each affected person a royalty-free,
|
||||
non transferable, non sublicensable, non exclusive, irrevocable and
|
||||
unconditional license to exercise Affirmer's Copyright and Related Rights in
|
||||
the Work (i) in all territories worldwide, (ii) for the maximum duration
|
||||
provided by applicable law or treaty (including future time extensions), (iii)
|
||||
in any current or future medium and for any number of copies, and (iv) for any
|
||||
purpose whatsoever, including without limitation commercial, advertising or
|
||||
promotional purposes (the "License"). The License shall be deemed effective as
|
||||
of the date CC0 was applied by Affirmer to the Work. Should any part of the
|
||||
License for any reason be judged legally invalid or ineffective under
|
||||
applicable law, such partial invalidity or ineffectiveness shall not
|
||||
invalidate the remainder of the License, and in such case Affirmer hereby
|
||||
affirms that he or she will not (i) exercise any of his or her remaining
|
||||
Copyright and Related Rights in the Work or (ii) assert any associated claims
|
||||
and causes of action with respect to the Work, in either case contrary to
|
||||
Affirmer's express Statement of Purpose.
|
||||
|
||||
4. Limitations and Disclaimers.
|
||||
|
||||
a. No trademark or patent rights held by Affirmer are waived, abandoned,
|
||||
surrendered, licensed or otherwise affected by this document.
|
||||
|
||||
b. Affirmer offers the Work as-is and makes no representations or warranties
|
||||
of any kind concerning the Work, express, implied, statutory or otherwise,
|
||||
including without limitation warranties of title, merchantability, fitness
|
||||
for a particular purpose, non infringement, or the absence of latent or
|
||||
other defects, accuracy, or the present or absence of errors, whether or not
|
||||
discoverable, all to the greatest extent permissible under applicable law.
|
||||
|
||||
c. Affirmer disclaims responsibility for clearing rights of other persons
|
||||
that may apply to the Work or any use thereof, including without limitation
|
||||
any person's Copyright and Related Rights in the Work. Further, Affirmer
|
||||
disclaims responsibility for obtaining any necessary consents, permissions
|
||||
or other rights required for any use of the Work.
|
||||
|
||||
d. Affirmer understands and acknowledges that Creative Commons is not a
|
||||
party to this document and has no duty or obligation with respect to this
|
||||
CC0 or use of the Work.
|
||||
|
||||
For more information, please see
|
||||
<http://creativecommons.org/publicdomain/zero/1.0/>
|
11
hw/application_fpga/fw/mta1_mkdf/blake2s/README.md
Normal file
11
hw/application_fpga/fw/mta1_mkdf/blake2s/README.md
Normal file
|
@ -0,0 +1,11 @@
|
|||
# blake2s
|
||||
|
||||
A Blake2s implementation taken from Joachim Strömbergson's
|
||||
|
||||
https://github.com/secworks/blake2s
|
||||
|
||||
Specifically from
|
||||
|
||||
https://github.com/secworks/blake2s/tree/master/src/model
|
||||
|
||||
Minor local changes for build purposes.
|
352
hw/application_fpga/fw/mta1_mkdf/blake2s/blake2s.c
Normal file
352
hw/application_fpga/fw/mta1_mkdf/blake2s/blake2s.c
Normal file
|
@ -0,0 +1,352 @@
|
|||
//======================================================================
|
||||
//
|
||||
// blake2s.c
|
||||
// ---------
|
||||
//
|
||||
// A simple blake2s Reference Implementation.
|
||||
//======================================================================
|
||||
|
||||
#include "../types.h"
|
||||
#include "../lib.h"
|
||||
#include "blake2s.h"
|
||||
|
||||
// Dummy printf() for verbose mode
|
||||
static void printf(const char *format, ...)
|
||||
{
|
||||
}
|
||||
|
||||
#define VERBOSE 0
|
||||
#define SHOW_V 0
|
||||
#define SHOW_M_WORDS 0
|
||||
|
||||
|
||||
// Cyclic right rotation.
|
||||
#ifndef ROTR32
|
||||
#define ROTR32(x, y) (((x) >> (y)) ^ ((x) << (32 - (y))))
|
||||
#endif
|
||||
|
||||
|
||||
// Little-endian byte access.
|
||||
#define B2S_GET32(p) \
|
||||
(((uint32_t) ((uint8_t *) (p))[0]) ^ \
|
||||
(((uint32_t) ((uint8_t *) (p))[1]) << 8) ^ \
|
||||
(((uint32_t) ((uint8_t *) (p))[2]) << 16) ^ \
|
||||
(((uint32_t) ((uint8_t *) (p))[3]) << 24))
|
||||
|
||||
|
||||
// Initialization Vector.
|
||||
static const uint32_t blake2s_iv[8] = {
|
||||
0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
|
||||
0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19
|
||||
};
|
||||
|
||||
|
||||
//------------------------------------------------------------------
|
||||
//------------------------------------------------------------------
|
||||
void print_v(uint32_t *v) {
|
||||
printf("0x%08x, 0x%08x, 0x%08x, 0x%08x\n", v[0], v[1], v[2], v[3]);
|
||||
printf("0x%08x, 0x%08x, 0x%08x, 0x%08x\n", v[4], v[5], v[6], v[7]);
|
||||
printf("0x%08x, 0x%08x, 0x%08x, 0x%08x\n", v[8], v[9], v[10], v[11]);
|
||||
printf("0x%08x, 0x%08x, 0x%08x, 0x%08x\n", v[12], v[13], v[14], v[15]);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// print_ctx()
|
||||
// Print the contents of the context data structure.
|
||||
//------------------------------------------------------------------
|
||||
void print_ctx(blake2s_ctx *ctx) {
|
||||
printf("Chained state (h):\n");
|
||||
printf("0x%08x, 0x%08x, 0x%08x, 0x%08x, ",
|
||||
ctx->h[0], ctx->h[1], ctx->h[2], ctx->h[3]);
|
||||
printf("0x%08x, 0x%08x, 0x%08x, 0x%08x",
|
||||
ctx->h[4], ctx->h[5], ctx->h[6], ctx->h[7]);
|
||||
printf("\n");
|
||||
|
||||
printf("Byte counter (t):\n");
|
||||
printf("0x%08x, 0x%08x", ctx->t[0], ctx->t[1]);
|
||||
printf("\n");
|
||||
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// B2S_G macro redefined as a G function.
|
||||
// Allows us to output intermediate values for debugging.
|
||||
//------------------------------------------------------------------
|
||||
void G(uint32_t *v, uint32_t a, uint32_t b, uint32_t c, uint32_t d, uint32_t x, uint32_t y) {
|
||||
if (VERBOSE) {
|
||||
printf("G started.\n");
|
||||
}
|
||||
|
||||
if (SHOW_V) {
|
||||
printf("v before processing:\n");
|
||||
print_v(&v[0]);
|
||||
}
|
||||
|
||||
if (SHOW_M_WORDS) {
|
||||
printf("x: 0x%08x, y: 0x%08x\n", x, y);
|
||||
}
|
||||
|
||||
v[a] = v[a] + v[b] + x;
|
||||
v[d] = ROTR32(v[d] ^ v[a], 16);
|
||||
v[c] = v[c] + v[d];
|
||||
v[b] = ROTR32(v[b] ^ v[c], 12);
|
||||
v[a] = v[a] + v[b] + y;
|
||||
v[d] = ROTR32(v[d] ^ v[a], 8);
|
||||
v[c] = v[c] + v[d];
|
||||
v[b] = ROTR32(v[b] ^ v[c], 7);
|
||||
|
||||
if (SHOW_V) {
|
||||
printf("v after processing:\n");
|
||||
print_v(&v[0]);
|
||||
}
|
||||
|
||||
if (VERBOSE) {
|
||||
printf("G completed.\n\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// Compression function. "last" flag indicates last block.
|
||||
//------------------------------------------------------------------
|
||||
static void blake2s_compress(blake2s_ctx *ctx, int last)
|
||||
{
|
||||
const uint8_t sigma[10][16] = {
|
||||
{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15},
|
||||
{14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3},
|
||||
{11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4},
|
||||
{7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8},
|
||||
{9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13},
|
||||
{2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9},
|
||||
{12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11},
|
||||
{13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10},
|
||||
{6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5},
|
||||
{10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0}
|
||||
};
|
||||
|
||||
int i;
|
||||
uint32_t v[16], m[16];
|
||||
|
||||
if (VERBOSE) {
|
||||
printf("blake2s_compress started.\n");
|
||||
}
|
||||
|
||||
// init work variables
|
||||
for (i = 0; i < 8; i++) {
|
||||
v[i] = ctx->h[i];
|
||||
v[i + 8] = blake2s_iv[i];
|
||||
}
|
||||
|
||||
// low 32 bits of offset
|
||||
// high 32 bits
|
||||
if (VERBOSE) {
|
||||
printf("t[0]: 0x%08x, t[1]: 0x%08x\n", ctx->t[0], ctx->t[1]);
|
||||
}
|
||||
v[12] ^= ctx->t[0];
|
||||
v[13] ^= ctx->t[1];
|
||||
|
||||
// last block flag set ?
|
||||
if (last) {
|
||||
v[14] = ~v[14];
|
||||
}
|
||||
|
||||
// get little-endian words
|
||||
for (i = 0; i < 16; i++) {
|
||||
m[i] = B2S_GET32(&ctx->b[4 * i]);
|
||||
}
|
||||
|
||||
if (VERBOSE) {
|
||||
printf("v before G processing:\n");
|
||||
print_v(&v[0]);
|
||||
}
|
||||
|
||||
// Ten rounds of the G function applied on rows, diagonal.
|
||||
for (i = 0; i < 10; i++) {
|
||||
if (VERBOSE) {
|
||||
printf("Round %02d:\n", (i + 1));
|
||||
printf("Row processing started.\n");
|
||||
}
|
||||
|
||||
G(&v[0], 0, 4, 8, 12, m[sigma[i][ 0]], m[sigma[i][ 1]]);
|
||||
G(&v[0], 1, 5, 9, 13, m[sigma[i][ 2]], m[sigma[i][ 3]]);
|
||||
G(&v[0], 2, 6, 10, 14, m[sigma[i][ 4]], m[sigma[i][ 5]]);
|
||||
G(&v[0], 3, 7, 11, 15, m[sigma[i][ 6]], m[sigma[i][ 7]]);
|
||||
|
||||
if (VERBOSE) {
|
||||
printf("Row processing completed.\n");
|
||||
printf("Diagonal processing started.\n");
|
||||
}
|
||||
|
||||
G(&v[0], 0, 5, 10, 15, m[sigma[i][ 8]], m[sigma[i][ 9]]);
|
||||
G(&v[0], 1, 6, 11, 12, m[sigma[i][10]], m[sigma[i][11]]);
|
||||
G(&v[0], 2, 7, 8, 13, m[sigma[i][12]], m[sigma[i][13]]);
|
||||
G(&v[0], 3, 4, 9, 14, m[sigma[i][14]], m[sigma[i][15]]);
|
||||
|
||||
if (VERBOSE) {
|
||||
printf("Diagonal processing completed.\n");
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (VERBOSE) {
|
||||
printf("v after G processing:\n");
|
||||
print_v(&v[0]);
|
||||
}
|
||||
|
||||
// Update the hash state.
|
||||
for (i = 0; i < 8; ++i) {
|
||||
ctx->h[i] ^= v[i] ^ v[i + 8];
|
||||
}
|
||||
|
||||
if (VERBOSE) {
|
||||
printf("blake2s_compress completed.\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// Initialize the hashing context "ctx" with optional key "key".
|
||||
// 1 <= outlen <= 32 gives the digest size in bytes.
|
||||
// Secret key (also <= 32 bytes) is optional (keylen = 0).
|
||||
//------------------------------------------------------------------
|
||||
int blake2s_init(blake2s_ctx *ctx, size_t outlen,
|
||||
const void *key, size_t keylen) // (keylen=0: no key)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
if (VERBOSE) {
|
||||
printf("blake2s_init started.\n");
|
||||
printf("Context before blake2s_init processing:\n");
|
||||
print_ctx(ctx);
|
||||
}
|
||||
|
||||
if (outlen == 0 || outlen > 32 || keylen > 32)
|
||||
return -1; // illegal parameters
|
||||
|
||||
for (i = 0; i < 8; i++) // state, "param block"
|
||||
ctx->h[i] = blake2s_iv[i];
|
||||
ctx->h[0] ^= 0x01010000 ^ (keylen << 8) ^ outlen;
|
||||
|
||||
ctx->t[0] = 0; // input count low word
|
||||
ctx->t[1] = 0; // input count high word
|
||||
ctx->c = 0; // pointer within buffer
|
||||
ctx->outlen = outlen;
|
||||
|
||||
for (i = keylen; i < 64; i++) // zero input block
|
||||
ctx->b[i] = 0;
|
||||
if (keylen > 0) {
|
||||
blake2s_update(ctx, key, keylen);
|
||||
ctx->c = 64; // at the end
|
||||
}
|
||||
|
||||
if (VERBOSE) {
|
||||
printf("Context after blake2s_init processing:\n");
|
||||
print_ctx(ctx);
|
||||
printf("blake2s_init completed.\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// Add "inlen" bytes from "in" into the hash.
|
||||
//------------------------------------------------------------------
|
||||
void blake2s_update(blake2s_ctx *ctx,
|
||||
const void *in, size_t inlen) // data bytes
|
||||
{
|
||||
size_t i;
|
||||
|
||||
if (VERBOSE) {
|
||||
printf("blake2s_update started.\n");
|
||||
printf("Context before blake2s_update processing:\n");
|
||||
print_ctx(ctx);
|
||||
}
|
||||
|
||||
for (i = 0; i < inlen; i++) {
|
||||
if (ctx->c == 64) { // buffer full ?
|
||||
ctx->t[0] += ctx->c; // add counters
|
||||
if (ctx->t[0] < ctx->c) // carry overflow ?
|
||||
ctx->t[1]++; // high word
|
||||
blake2s_compress(ctx, 0); // compress (not last)
|
||||
ctx->c = 0; // counter to zero
|
||||
}
|
||||
ctx->b[ctx->c++] = ((const uint8_t *) in)[i];
|
||||
}
|
||||
|
||||
if (VERBOSE) {
|
||||
printf("Context after blake2s_update processing:\n");
|
||||
print_ctx(ctx);
|
||||
printf("blake2s_update completed.\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// Generate the message digest (size given in init).
|
||||
// Result placed in "out".
|
||||
//------------------------------------------------------------------
|
||||
void blake2s_final(blake2s_ctx *ctx, void *out)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
if (VERBOSE) {
|
||||
printf("blake2s_final started.\n");
|
||||
printf("Context before blake2s_final processing:\n");
|
||||
print_ctx(ctx);
|
||||
}
|
||||
|
||||
ctx->t[0] += ctx->c; // mark last block offset
|
||||
|
||||
// carry overflow
|
||||
// high word
|
||||
if (ctx->t[0] < ctx->c) {
|
||||
ctx->t[1]++;
|
||||
}
|
||||
|
||||
// fill up with zeros
|
||||
// final block flag = 1
|
||||
while (ctx->c < 64) {
|
||||
ctx->b[ctx->c++] = 0;
|
||||
}
|
||||
blake2s_compress(ctx, 1);
|
||||
|
||||
// little endian convert and store
|
||||
for (i = 0; i < ctx->outlen; i++) {
|
||||
((uint8_t *) out)[i] =
|
||||
(ctx->h[i >> 2] >> (8 * (i & 3))) & 0xFF;
|
||||
}
|
||||
|
||||
if (VERBOSE) {
|
||||
printf("Context after blake2s_final processing:\n");
|
||||
print_ctx(ctx);
|
||||
printf("blake2s_final completed.\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// Convenience function for all-in-one computation.
|
||||
//------------------------------------------------------------------
|
||||
int blake2s(void *out, size_t outlen,
|
||||
const void *key, size_t keylen,
|
||||
const void *in, size_t inlen)
|
||||
{
|
||||
blake2s_ctx ctx;
|
||||
|
||||
if (blake2s_init(&ctx, outlen, key, keylen))
|
||||
return -1;
|
||||
|
||||
blake2s_update(&ctx, in, inlen);
|
||||
|
||||
blake2s_final(&ctx, out);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//======================================================================
|
||||
//======================================================================
|
38
hw/application_fpga/fw/mta1_mkdf/blake2s/blake2s.h
Normal file
38
hw/application_fpga/fw/mta1_mkdf/blake2s/blake2s.h
Normal file
|
@ -0,0 +1,38 @@
|
|||
// blake2s.h
|
||||
// BLAKE2s Hashing Context and API Prototypes
|
||||
|
||||
#ifndef BLAKE2S_H
|
||||
#define BLAKE2S_H
|
||||
|
||||
#include "../types.h"
|
||||
|
||||
// state context
|
||||
typedef struct {
|
||||
uint8_t b[64]; // input buffer
|
||||
uint32_t h[8]; // chained state
|
||||
uint32_t t[2]; // total number of bytes
|
||||
size_t c; // pointer for b[]
|
||||
size_t outlen; // digest size
|
||||
} blake2s_ctx;
|
||||
|
||||
// Initialize the hashing context "ctx" with optional key "key".
|
||||
// 1 <= outlen <= 32 gives the digest size in bytes.
|
||||
// Secret key (also <= 32 bytes) is optional (keylen = 0).
|
||||
int blake2s_init(blake2s_ctx *ctx, size_t outlen,
|
||||
const void *key, size_t keylen); // secret key
|
||||
|
||||
// Add "inlen" bytes from "in" into the hash.
|
||||
void blake2s_update(blake2s_ctx *ctx, // context
|
||||
const void *in, size_t inlen); // data to be hashed
|
||||
|
||||
// Generate the message digest (size given in init).
|
||||
// Result placed in "out".
|
||||
void blake2s_final(blake2s_ctx *ctx, void *out);
|
||||
|
||||
// All-in-one convenience function.
|
||||
int blake2s(void *out, size_t outlen, // return buffer for digest
|
||||
const void *key, size_t keylen, // optional secret key
|
||||
const void *in, size_t inlen); // data to be hashed
|
||||
|
||||
#endif
|
||||
|
71
hw/application_fpga/fw/mta1_mkdf/firmware.lds
Normal file
71
hw/application_fpga/fw/mta1_mkdf/firmware.lds
Normal file
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
* Copyright (C) 2022 - Tillitis AB
|
||||
* SPDX-License-Identifier: GPL-2.0-only
|
||||
*/
|
||||
|
||||
OUTPUT_ARCH( "riscv" )
|
||||
ENTRY(_start)
|
||||
|
||||
MEMORY
|
||||
{
|
||||
/* TODO ROM size should be adjusted, RAM should be ok. */
|
||||
ROM (rx) : ORIGIN = 0x00000000, LENGTH = 0x20000 /* 128 KB */
|
||||
RAM (rwx) : ORIGIN = 0x40000000, LENGTH = 0x20000 /* 128 KB */
|
||||
}
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
.text.init :
|
||||
{
|
||||
*(.text.init)
|
||||
} >ROM
|
||||
|
||||
.htif :
|
||||
{
|
||||
. = ALIGN(0x00000000);
|
||||
*(.htif)
|
||||
} >ROM
|
||||
|
||||
.text :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
*(.text) /* .text sections (code) */
|
||||
*(.text*) /* .text* sections (code) */
|
||||
*(.rodata) /* .rodata sections (constants, strings, etc.) */
|
||||
*(.rodata*) /* .rodata* sections (constants, strings, etc.) */
|
||||
*(.srodata) /* .rodata sections (constants, strings, etc.) */
|
||||
*(.srodata*) /* .rodata* sections (constants, strings, etc.) */
|
||||
. = ALIGN(4);
|
||||
_etext = .;
|
||||
_sidata = _etext;
|
||||
} >ROM
|
||||
|
||||
.data : AT (_etext)
|
||||
{
|
||||
. = ALIGN(4);
|
||||
_sdata = .;
|
||||
. = ALIGN(4);
|
||||
*(.data) /* .data sections */
|
||||
*(.data*) /* .data* sections */
|
||||
*(.sdata) /* .sdata sections */
|
||||
*(.sdata*) /* .sdata* sections */
|
||||
. = ALIGN(4);
|
||||
_edata = .;
|
||||
} >RAM
|
||||
|
||||
/* Uninitialized data section */
|
||||
.bss :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
_sbss = .;
|
||||
*(.bss)
|
||||
*(.bss*)
|
||||
*(.sbss)
|
||||
*(.sbss*)
|
||||
*(COMMON)
|
||||
|
||||
. = ALIGN(4);
|
||||
_ebss = .;
|
||||
} >RAM
|
||||
/* Init stack to _ebss + size */
|
||||
}
|
171
hw/application_fpga/fw/mta1_mkdf/lib.c
Normal file
171
hw/application_fpga/fw/mta1_mkdf/lib.c
Normal file
|
@ -0,0 +1,171 @@
|
|||
/*
|
||||
* Copyright (C) 2022 - Tillitis AB
|
||||
* SPDX-License-Identifier: GPL-2.0-only
|
||||
*/
|
||||
|
||||
#include "lib.h"
|
||||
#include "types.h"
|
||||
|
||||
#if NOCONSOLE
|
||||
void putc(int ch)
|
||||
{
|
||||
}
|
||||
|
||||
void lf()
|
||||
{
|
||||
}
|
||||
|
||||
void puthex(uint8_t c)
|
||||
{
|
||||
}
|
||||
|
||||
void putinthex(const uint32_t n)
|
||||
{
|
||||
}
|
||||
|
||||
int puts(const char *s)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void hexdump(uint8_t *buf, int len)
|
||||
{
|
||||
}
|
||||
|
||||
#else
|
||||
struct {
|
||||
uint32_t arr[2];
|
||||
} volatile tohost __attribute__((section(".htif")));
|
||||
struct {
|
||||
uint32_t arr[2];
|
||||
} volatile fromhost __attribute__((section(".htif")));
|
||||
|
||||
static void htif_send(uint8_t dev, uint8_t cmd, int64_t data)
|
||||
{
|
||||
/* endian neutral encoding with ordered 32-bit writes */
|
||||
union {
|
||||
uint32_t arr[2];
|
||||
uint64_t val;
|
||||
} encode = {.val = (uint64_t)dev << 56 | (uint64_t)cmd << 48 | data};
|
||||
tohost.arr[0] = encode.arr[0];
|
||||
tohost.arr[1] = encode.arr[1];
|
||||
}
|
||||
|
||||
static void htif_set_tohost(uint8_t dev, uint8_t cmd, int64_t data)
|
||||
{
|
||||
/* send data with specified device and command */
|
||||
while (tohost.arr[0]) {
|
||||
asm volatile("" : : "r"(fromhost.arr[0]));
|
||||
asm volatile("" : : "r"(fromhost.arr[1]));
|
||||
}
|
||||
htif_send(dev, cmd, data);
|
||||
}
|
||||
|
||||
static int htif_putchar(int ch)
|
||||
{
|
||||
htif_set_tohost(1, 1, ch & 0xff);
|
||||
return ch & 0xff;
|
||||
}
|
||||
|
||||
int puts(const char *s)
|
||||
{
|
||||
while (*s)
|
||||
htif_putchar(*s++);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void hexdump(uint8_t *buf, int len)
|
||||
{
|
||||
uint8_t *row;
|
||||
uint8_t *byte;
|
||||
uint8_t *max;
|
||||
|
||||
row = buf;
|
||||
max = &buf[len];
|
||||
for (byte = 0; byte != max; row = byte) {
|
||||
for (byte = row; byte != max && byte != (row + 16); byte++) {
|
||||
puthex(*byte);
|
||||
}
|
||||
|
||||
lf();
|
||||
}
|
||||
}
|
||||
|
||||
void putc(int ch)
|
||||
{
|
||||
htif_putchar(ch);
|
||||
}
|
||||
|
||||
void lf()
|
||||
{
|
||||
htif_putchar('\n');
|
||||
}
|
||||
|
||||
void puthex(uint8_t c)
|
||||
{
|
||||
unsigned int upper = (c >> 4) & 0xf;
|
||||
unsigned int lower = c & 0xf;
|
||||
|
||||
htif_putchar(upper < 10 ? '0' + upper : 'a' - 10 + upper);
|
||||
htif_putchar(lower < 10 ? '0' + lower : 'a' - 10 + lower);
|
||||
}
|
||||
|
||||
void putinthex(const uint32_t n)
|
||||
{
|
||||
uint8_t buf[4];
|
||||
|
||||
memcpy(buf, &n, 4);
|
||||
puts("0x");
|
||||
for (int i = 3; i > -1; i--) {
|
||||
puthex(buf[i]);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void *memset(void *dest, int c, unsigned n)
|
||||
{
|
||||
uint8_t *s = dest;
|
||||
|
||||
for (; n; n--, s++)
|
||||
*s = c;
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
__attribute__((used)) void *memcpy(void *dest, const void *src, unsigned n)
|
||||
{
|
||||
uint8_t *src_byte = (uint8_t *)src;
|
||||
uint8_t *dest_byte = (uint8_t *)dest;
|
||||
|
||||
for (int i = 0; i < n; i++) {
|
||||
dest_byte[i] = src_byte[i];
|
||||
}
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
__attribute__((used)) void *wordcpy(void *dest, const void *src, unsigned n)
|
||||
{
|
||||
uint32_t *src_word = (uint32_t *)src;
|
||||
uint32_t *dest_word = (uint32_t *)dest;
|
||||
|
||||
for (int i = 0; i < n; i++) {
|
||||
dest_word[i] = src_word[i];
|
||||
}
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
int memeq(void *dest, const void *src, unsigned n)
|
||||
{
|
||||
uint8_t *src_byte = (uint8_t *)src;
|
||||
uint8_t *dest_byte = (uint8_t *)dest;
|
||||
|
||||
for (int i = 0; i < n; i++) {
|
||||
if (dest_byte[i] != src_byte[i]) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
22
hw/application_fpga/fw/mta1_mkdf/lib.h
Normal file
22
hw/application_fpga/fw/mta1_mkdf/lib.h
Normal file
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* Copyright (C) 2022 - Tillitis AB
|
||||
* SPDX-License-Identifier: GPL-2.0-only
|
||||
*/
|
||||
|
||||
#ifndef LIB_H
|
||||
#define LIB_H
|
||||
|
||||
#include "types.h"
|
||||
|
||||
void putc(int ch);
|
||||
void lf();
|
||||
void puthex(uint8_t c);
|
||||
void putinthex(const uint32_t n);
|
||||
int puts(const char *s);
|
||||
void hexdump(uint8_t *buf, int len);
|
||||
void *memset(void *dest, int c, unsigned n);
|
||||
void *memcpy(void *dest, const void *src, unsigned n);
|
||||
void *wordcpy(void *dest, const void *src, unsigned n);
|
||||
int memeq(void *dest, const void *src, unsigned n);
|
||||
|
||||
#endif
|
262
hw/application_fpga/fw/mta1_mkdf/main.c
Normal file
262
hw/application_fpga/fw/mta1_mkdf/main.c
Normal file
|
@ -0,0 +1,262 @@
|
|||
/*
|
||||
* Copyright (C) 2022 - Tillitis AB
|
||||
* SPDX-License-Identifier: GPL-2.0-only
|
||||
*/
|
||||
|
||||
#include "../mta1_mkdf_mem.h"
|
||||
#include "blake2s/blake2s.h"
|
||||
#include "lib.h"
|
||||
#include "proto.h"
|
||||
#include "types.h"
|
||||
|
||||
// In RAM + above the stack (0x40010000)
|
||||
#define APP_RAM_ADDR (MTA1_MKDF_RAM_BASE + 0x10000)
|
||||
#define APP_MAX_SIZE 65536
|
||||
|
||||
// clang-format off
|
||||
static volatile uint32_t *uds = (volatile uint32_t *)MTA1_MKDF_MMIO_UDS_FIRST;
|
||||
static volatile uint32_t *switch_app = (volatile uint32_t *)MTA1_MKDF_MMIO_MTA1_SWITCH_APP;
|
||||
static volatile uint32_t *name0 = (volatile uint32_t *)MTA1_MKDF_MMIO_MTA1_NAME0;
|
||||
static volatile uint32_t *name1 = (volatile uint32_t *)MTA1_MKDF_MMIO_MTA1_NAME1;
|
||||
static volatile uint32_t *ver = (volatile uint32_t *)MTA1_MKDF_MMIO_MTA1_VERSION;
|
||||
static volatile uint32_t *cdi = (volatile uint32_t *)MTA1_MKDF_MMIO_MTA1_CDI_FIRST;
|
||||
static volatile uint32_t *app_addr = (volatile uint32_t *)MTA1_MKDF_MMIO_MTA1_APP_ADDR;
|
||||
static volatile uint32_t *app_size = (volatile uint32_t *)MTA1_MKDF_MMIO_MTA1_APP_SIZE;
|
||||
|
||||
#define LED_RED (1 << MTA1_MKDF_MMIO_MTA1_LED_R_BIT)
|
||||
#define LED_GREEN (1 << MTA1_MKDF_MMIO_MTA1_LED_G_BIT)
|
||||
#define LED_BLUE (1 << MTA1_MKDF_MMIO_MTA1_LED_B_BIT)
|
||||
|
||||
static void print_hw_version(uint32_t name0, uint32_t name1, uint32_t ver)
|
||||
{
|
||||
puts("Hello, I'm ");
|
||||
putc(name0 >> 24);
|
||||
putc(name0 >> 16);
|
||||
putc(name0 >> 8);
|
||||
putc(name0);
|
||||
|
||||
putc('-');
|
||||
|
||||
putc(name1 >> 24);
|
||||
putc(name1 >> 16);
|
||||
putc(name1 >> 8);
|
||||
putc(name1);
|
||||
|
||||
putc(' ');
|
||||
putinthex(ver);
|
||||
lf();
|
||||
}
|
||||
// clang-format on
|
||||
|
||||
static void print_digest(uint8_t *md)
|
||||
{
|
||||
puts("The app digest:\n");
|
||||
for (int j = 0; j < 4; j++) {
|
||||
for (int i = 0; i < 8; i++) {
|
||||
puthex(md[i + 8 * j]);
|
||||
}
|
||||
lf();
|
||||
}
|
||||
lf();
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
uint32_t local_name0 = *name0;
|
||||
uint32_t local_name1 = *name1;
|
||||
uint32_t local_ver = *ver;
|
||||
struct frame_header hdr; // Used in both directions
|
||||
uint8_t cmd[CMDLEN_MAXBYTES];
|
||||
uint8_t rsp[CMDLEN_MAXBYTES];
|
||||
uint8_t *loadaddr = (uint8_t *)APP_RAM_ADDR;
|
||||
int left = 0; // Bytes left to read
|
||||
int nbytes = 0; // Bytes to write to memory
|
||||
uint32_t local_app_size = 0;
|
||||
uint8_t in;
|
||||
uint8_t digest[32];
|
||||
|
||||
print_hw_version(local_name0, local_name1, local_ver);
|
||||
|
||||
for (;;) {
|
||||
// blocking; fw flashing white while waiting for cmd
|
||||
in = readbyte_ledflash(LED_RED | LED_BLUE | LED_GREEN, 500000);
|
||||
|
||||
if (parseframe(in, &hdr) == -1) {
|
||||
puts("Couldn't parse header\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
memset(cmd, 0, CMDLEN_MAXBYTES);
|
||||
// Read firmware command: Blocks!
|
||||
read(cmd, hdr.len);
|
||||
|
||||
// Is it for us?
|
||||
if (hdr.endpoint != DST_FW) {
|
||||
puts("Message not meant for us\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
// Reset response buffer
|
||||
memset(rsp, 0, CMDLEN_MAXBYTES);
|
||||
|
||||
// Min length is 1 byte so this should always be here
|
||||
switch (cmd[0]) {
|
||||
case FW_CMD_NAME_VERSION:
|
||||
puts("request: name-version\n");
|
||||
|
||||
if (hdr.len != 1) {
|
||||
// Bad length - give them an empty response
|
||||
fwreply(hdr, FW_RSP_NAME_VERSION, rsp);
|
||||
break;
|
||||
}
|
||||
|
||||
memcpy(rsp, (uint8_t *)&local_name0, 4);
|
||||
memcpy(rsp + 4, (uint8_t *)&local_name1, 4);
|
||||
memcpy(rsp + 8, (uint8_t *)&local_ver, 4);
|
||||
|
||||
fwreply(hdr, FW_RSP_NAME_VERSION, rsp);
|
||||
break;
|
||||
|
||||
case FW_CMD_LOAD_APP_SIZE:
|
||||
puts("request: load-app-size\n");
|
||||
|
||||
if (hdr.len != 32) {
|
||||
// Bad length
|
||||
rsp[0] = STATUS_BAD;
|
||||
fwreply(hdr, FW_RSP_LOAD_APP_SIZE, rsp);
|
||||
break;
|
||||
}
|
||||
|
||||
// cmd[1..4] contains the size.
|
||||
local_app_size = cmd[1] + (cmd[2] << 8) +
|
||||
(cmd[3] << 16) + (cmd[4] << 24);
|
||||
|
||||
puts("app size: ");
|
||||
putinthex(local_app_size);
|
||||
lf();
|
||||
|
||||
if (local_app_size > APP_MAX_SIZE) {
|
||||
rsp[0] = STATUS_BAD;
|
||||
fwreply(hdr, FW_RSP_LOAD_APP_SIZE, rsp);
|
||||
break;
|
||||
}
|
||||
|
||||
*app_size = local_app_size;
|
||||
*app_addr = 0;
|
||||
|
||||
// Reset where to start loading the program
|
||||
loadaddr = (uint8_t *)APP_RAM_ADDR;
|
||||
left = *app_size;
|
||||
|
||||
rsp[0] = STATUS_OK;
|
||||
fwreply(hdr, FW_RSP_LOAD_APP_SIZE, rsp);
|
||||
break;
|
||||
|
||||
case FW_CMD_LOAD_APP_DATA:
|
||||
puts("request: load-app-data\n");
|
||||
|
||||
if (hdr.len != 128 || *app_size == 0) {
|
||||
// Bad length of this command or bad app size -
|
||||
// they need to call FW_CMD_LOAD_APP_SIZE first
|
||||
rsp[0] = STATUS_BAD;
|
||||
fwreply(hdr, FW_RSP_LOAD_APP_DATA, rsp);
|
||||
break;
|
||||
}
|
||||
|
||||
if (left > 127) {
|
||||
nbytes = 127;
|
||||
} else {
|
||||
nbytes = left;
|
||||
}
|
||||
memcpy(loadaddr, cmd + 1, nbytes);
|
||||
loadaddr += nbytes;
|
||||
left -= nbytes;
|
||||
|
||||
if (left == 0) {
|
||||
uint8_t scratch[64];
|
||||
|
||||
puts("Fully loaded ");
|
||||
putinthex(*app_size);
|
||||
lf();
|
||||
|
||||
*app_addr = APP_RAM_ADDR;
|
||||
// Get the Blake2S digest of the app - store it
|
||||
// for later queries
|
||||
blake2s(digest, 32, NULL, 0,
|
||||
(const void *)*app_addr, *app_size);
|
||||
print_digest(digest);
|
||||
|
||||
// CDI = hash(uds, hash(app))
|
||||
uint32_t local_cdi[8];
|
||||
|
||||
// Only word aligned access to UDS
|
||||
wordcpy(scratch, (void *)uds, 8);
|
||||
memcpy(scratch + 32, digest, 32);
|
||||
blake2s((void *)local_cdi, 32, NULL, 0,
|
||||
(const void *)scratch, 64);
|
||||
// Only word aligned access to CDI
|
||||
wordcpy((void *)cdi, (void *)local_cdi, 8);
|
||||
}
|
||||
|
||||
rsp[0] = STATUS_OK;
|
||||
fwreply(hdr, FW_RSP_LOAD_APP_DATA, rsp);
|
||||
break;
|
||||
|
||||
case FW_CMD_RUN_APP:
|
||||
puts("request: run-app\n");
|
||||
|
||||
if (hdr.len != 1) {
|
||||
// Bad length
|
||||
rsp[0] = STATUS_BAD;
|
||||
fwreply(hdr, FW_RSP_RUN_APP, rsp);
|
||||
break;
|
||||
}
|
||||
|
||||
if (*app_size > 0 && *app_addr != 0) {
|
||||
rsp[0] = STATUS_OK;
|
||||
fwreply(hdr, FW_RSP_RUN_APP, rsp);
|
||||
|
||||
// Flip over to application mode
|
||||
*switch_app = 1;
|
||||
|
||||
// Jump to app - doesn't return
|
||||
// First clears memory of firmware remains
|
||||
puts("Jumping to ");
|
||||
putinthex(*app_addr);
|
||||
lf();
|
||||
// clang-format off
|
||||
asm volatile(
|
||||
"li a0, 0x40000000;" // MTA1_MKDF_RAM_BASE
|
||||
"li a1, 0x40010000;"
|
||||
"loop:;"
|
||||
"sw zero, 0(a0);"
|
||||
"addi a0, a0, 4;"
|
||||
"blt a0, a1, loop;"
|
||||
// Get value at MTA1_MKDF_MMIO_MTA1_APP_ADDR
|
||||
"lui a0,0xff000;"
|
||||
"lw a0,0x030(a0);"
|
||||
"jalr x0,0(a0);"
|
||||
::: "memory");
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
rsp[0] = STATUS_BAD;
|
||||
fwreply(hdr, FW_RSP_RUN_APP, rsp);
|
||||
break;
|
||||
|
||||
case FW_CMD_GET_APP_DIGEST:
|
||||
puts("request: get-app-digest\n");
|
||||
|
||||
memcpy(rsp, &digest, 32);
|
||||
fwreply(hdr, FW_RSP_GET_APP_DIGEST, rsp);
|
||||
break;
|
||||
|
||||
default:
|
||||
puts("Received unknown firmware command: 0x");
|
||||
puthex(cmd[0]);
|
||||
lf();
|
||||
}
|
||||
}
|
||||
|
||||
return (int)0xcafebabe;
|
||||
}
|
156
hw/application_fpga/fw/mta1_mkdf/proto.c
Normal file
156
hw/application_fpga/fw/mta1_mkdf/proto.c
Normal file
|
@ -0,0 +1,156 @@
|
|||
/*
|
||||
* Copyright (C) 2022 - Tillitis AB
|
||||
* SPDX-License-Identifier: GPL-2.0-only
|
||||
*/
|
||||
|
||||
#include "proto.h"
|
||||
#include "../mta1_mkdf_mem.h"
|
||||
#include "lib.h"
|
||||
#include "types.h"
|
||||
|
||||
// clang-format off
|
||||
static volatile uint32_t *can_rx = (volatile uint32_t *)MTA1_MKDF_MMIO_UART_RX_STATUS;
|
||||
static volatile uint32_t *rx = (volatile uint32_t *)MTA1_MKDF_MMIO_UART_RX_DATA;
|
||||
static volatile uint32_t *can_tx = (volatile uint32_t *)MTA1_MKDF_MMIO_UART_TX_STATUS;
|
||||
static volatile uint32_t *tx = (volatile uint32_t *)MTA1_MKDF_MMIO_UART_TX_DATA;
|
||||
static volatile uint32_t *led = (volatile uint32_t *)MTA1_MKDF_MMIO_MTA1_LED;
|
||||
// clang-format on
|
||||
|
||||
uint8_t genhdr(uint8_t id, uint8_t endpoint, uint8_t status, enum cmdlen len)
|
||||
{
|
||||
return (id << 5) | (endpoint << 3) | (status << 2) | len;
|
||||
}
|
||||
|
||||
int parseframe(uint8_t b, struct frame_header *hdr)
|
||||
{
|
||||
if ((b & 0x80) != 0) {
|
||||
// Bad version
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((b & 0x4) != 0) {
|
||||
// Must be 0
|
||||
return -1;
|
||||
}
|
||||
|
||||
hdr->id = (b & 0x60) >> 5;
|
||||
hdr->endpoint = (b & 0x18) >> 3;
|
||||
|
||||
// Length
|
||||
switch (b & 0x3) {
|
||||
case LEN_1:
|
||||
hdr->len = 1;
|
||||
break;
|
||||
case LEN_4:
|
||||
hdr->len = 4;
|
||||
break;
|
||||
case LEN_32:
|
||||
hdr->len = 32;
|
||||
break;
|
||||
case LEN_128:
|
||||
hdr->len = 128;
|
||||
break;
|
||||
default:
|
||||
// Unknown length
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Send a firmware reply with a frame header, response code rspcode and
|
||||
// following data in buf
|
||||
void fwreply(struct frame_header hdr, enum fwcmd rspcode, uint8_t *buf)
|
||||
{
|
||||
size_t nbytes;
|
||||
enum cmdlen len; // length covering (rspcode + length of buf)
|
||||
|
||||
switch (rspcode) {
|
||||
case FW_RSP_NAME_VERSION:
|
||||
len = LEN_32;
|
||||
nbytes = 32;
|
||||
break;
|
||||
|
||||
case FW_RSP_LOAD_APP_SIZE:
|
||||
len = LEN_4;
|
||||
nbytes = 4;
|
||||
break;
|
||||
|
||||
case FW_RSP_LOAD_APP_DATA:
|
||||
len = LEN_4;
|
||||
nbytes = 4;
|
||||
break;
|
||||
|
||||
case FW_RSP_RUN_APP:
|
||||
len = LEN_4;
|
||||
nbytes = 4;
|
||||
break;
|
||||
|
||||
case FW_RSP_GET_APP_DIGEST:
|
||||
len = LEN_128;
|
||||
nbytes = 128;
|
||||
break;
|
||||
|
||||
default:
|
||||
puts("fwreply(): Unknown response code: 0x");
|
||||
puthex(rspcode);
|
||||
lf();
|
||||
return;
|
||||
}
|
||||
|
||||
// Frame Protocol Header
|
||||
writebyte(genhdr(hdr.id, hdr.endpoint, 0x0, len));
|
||||
|
||||
// FW protocol header
|
||||
writebyte(rspcode);
|
||||
nbytes--;
|
||||
|
||||
write(buf, nbytes);
|
||||
}
|
||||
|
||||
void writebyte(uint8_t b)
|
||||
{
|
||||
for (;;) {
|
||||
if (*can_tx) {
|
||||
*tx = b;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void write(uint8_t *buf, size_t nbytes)
|
||||
{
|
||||
for (int i = 0; i < nbytes; i++) {
|
||||
writebyte(buf[i]);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t readbyte()
|
||||
{
|
||||
for (;;) {
|
||||
if (*can_rx) {
|
||||
return *rx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t readbyte_ledflash(int ledvalue, int loopcount)
|
||||
{
|
||||
int led_on = 0;
|
||||
for (;;) {
|
||||
*led = led_on ? ledvalue : 0;
|
||||
for (int i = 0; i < loopcount; i++) {
|
||||
if (*can_rx) {
|
||||
return *rx;
|
||||
}
|
||||
}
|
||||
led_on = !led_on;
|
||||
}
|
||||
}
|
||||
|
||||
void read(uint8_t *buf, size_t nbytes)
|
||||
{
|
||||
for (int n = 0; n < nbytes; n++) {
|
||||
buf[n] = readbyte();
|
||||
}
|
||||
}
|
62
hw/application_fpga/fw/mta1_mkdf/proto.h
Normal file
62
hw/application_fpga/fw/mta1_mkdf/proto.h
Normal file
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* Copyright (C) 2022 - Tillitis AB
|
||||
* SPDX-License-Identifier: GPL-2.0-only
|
||||
*/
|
||||
|
||||
#include "types.h"
|
||||
|
||||
#ifndef PROTO_H
|
||||
#define PROTO_H
|
||||
|
||||
enum endpoints {
|
||||
DST_HW_IFPGA,
|
||||
DST_HW_AFPGA,
|
||||
DST_FW,
|
||||
DST_SW
|
||||
};
|
||||
|
||||
enum cmdlen {
|
||||
LEN_1,
|
||||
LEN_4,
|
||||
LEN_32,
|
||||
LEN_128
|
||||
};
|
||||
|
||||
#define CMDLEN_MAXBYTES 128
|
||||
|
||||
// clang-format off
|
||||
enum fwcmd {
|
||||
FW_CMD_NAME_VERSION = 0x01,
|
||||
FW_RSP_NAME_VERSION = 0x02,
|
||||
FW_CMD_LOAD_APP_SIZE = 0x03,
|
||||
FW_RSP_LOAD_APP_SIZE = 0x04,
|
||||
FW_CMD_LOAD_APP_DATA = 0x05,
|
||||
FW_RSP_LOAD_APP_DATA = 0x06,
|
||||
FW_CMD_RUN_APP = 0x07,
|
||||
FW_RSP_RUN_APP = 0x08,
|
||||
FW_CMD_GET_APP_DIGEST = 0x09,
|
||||
FW_RSP_GET_APP_DIGEST = 0x10
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
enum status {
|
||||
STATUS_OK,
|
||||
STATUS_BAD
|
||||
};
|
||||
|
||||
struct frame_header {
|
||||
uint8_t id;
|
||||
enum endpoints endpoint;
|
||||
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();
|
||||
uint8_t readbyte_ledflash(int ledvalue, int loopcount);
|
||||
void read(uint8_t *buf, size_t nbytes);
|
||||
|
||||
#endif
|
72
hw/application_fpga/fw/mta1_mkdf/start.S
Normal file
72
hw/application_fpga/fw/mta1_mkdf/start.S
Normal file
|
@ -0,0 +1,72 @@
|
|||
/*
|
||||
* Copyright (C) 2022 - Tillitis AB
|
||||
* SPDX-License-Identifier: GPL-2.0-only
|
||||
*/
|
||||
|
||||
.section ".text.init"
|
||||
.globl _start
|
||||
_start:
|
||||
li x1, 0
|
||||
li x2, 0
|
||||
li x3, 0
|
||||
li x4, 0
|
||||
li x5, 0
|
||||
li x6, 0
|
||||
li x7, 0
|
||||
li x8, 0
|
||||
li x9, 0
|
||||
li x10,0
|
||||
li x11,0
|
||||
li x12,0
|
||||
li x13,0
|
||||
li x14,0
|
||||
li x15,0
|
||||
li x16,0
|
||||
li x17,0
|
||||
li x18,0
|
||||
li x19,0
|
||||
li x20,0
|
||||
li x21,0
|
||||
li x22,0
|
||||
li x23,0
|
||||
li x24,0
|
||||
li x25,0
|
||||
li x26,0
|
||||
li x27,0
|
||||
li x28,0
|
||||
li x29,0
|
||||
li x30,0
|
||||
li x31,0
|
||||
|
||||
/* init stack to right under where we load app at 0x40010000 */
|
||||
li sp, 0x4000fff0
|
||||
|
||||
/* copy data section */
|
||||
la a0, _sidata
|
||||
la a1, _sdata
|
||||
la a2, _edata
|
||||
bge a1, a2, end_init_data
|
||||
|
||||
loop_init_data:
|
||||
lw a3, 0(a0)
|
||||
sw a3, 0(a1)
|
||||
addi a0, a0, 4
|
||||
addi a1, a1, 4
|
||||
blt a1, a2, loop_init_data
|
||||
|
||||
end_init_data:
|
||||
/* zero-init bss section */
|
||||
la a0, _sbss
|
||||
la a1, _ebss
|
||||
bge a0, a1, end_init_bss
|
||||
|
||||
loop_init_bss:
|
||||
sw zero, 0(a0)
|
||||
addi a0, a0, 4
|
||||
blt a0, a1, loop_init_bss
|
||||
|
||||
end_init_bss:
|
||||
call main
|
||||
|
||||
loop:
|
||||
j loop
|
19
hw/application_fpga/fw/mta1_mkdf/types.h
Normal file
19
hw/application_fpga/fw/mta1_mkdf/types.h
Normal file
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
* Copyright (C) 2022 - Tillitis AB
|
||||
* SPDX-License-Identifier: GPL-2.0-only
|
||||
*/
|
||||
|
||||
#ifndef TYPES_H
|
||||
#define TYPES_H
|
||||
|
||||
typedef unsigned int uintptr_t;
|
||||
typedef unsigned long long uint64_t;
|
||||
typedef unsigned int uint32_t;
|
||||
typedef int int32_t;
|
||||
typedef long long int64_t;
|
||||
typedef unsigned char uint8_t;
|
||||
typedef unsigned long size_t;
|
||||
|
||||
#define NULL ((char *)0)
|
||||
|
||||
#endif
|
109
hw/application_fpga/fw/mta1_mkdf_mem.h
Normal file
109
hw/application_fpga/fw/mta1_mkdf_mem.h
Normal file
|
@ -0,0 +1,109 @@
|
|||
/*
|
||||
* QEMU RISC-V Board Compatible with Mullvad MTA1-MKDF platform
|
||||
*
|
||||
* Copyright (c) 2022 Tillitis AB
|
||||
* SPDX-License-Identifier: GPL-2.0-only
|
||||
*/
|
||||
|
||||
// clang-format off
|
||||
|
||||
#ifndef HW_MTA1_MKDF_MEM_H
|
||||
#define HW_MTA1_MKDF_MEM_H
|
||||
|
||||
// The canonical location of this file is:
|
||||
// repo: https://github.com/tillitis/tillitis-key1
|
||||
// path: /hw/application_fpga/fw/mta1_mkdf_mem.h
|
||||
|
||||
// The contents are derived from the Verilog code. For use by QEMU model,
|
||||
// firmware, and apps.
|
||||
|
||||
enum {
|
||||
MTA1_MKDF_ROM_BASE = 0x00000000, // 0b00000000...
|
||||
MTA1_MKDF_RAM_BASE = 0x40000000, // 0b01000000...
|
||||
MTA1_MKDF_RESERVED_BASE = 0x80000000, // 0b10000000...
|
||||
MTA1_MKDF_MMIO_BASE = 0xc0000000, // 0b11000000...
|
||||
MTA1_MKDF_MMIO_SIZE = 0xffffffff - MTA1_MKDF_MMIO_BASE,
|
||||
|
||||
MTA1_MKDF_MMIO_TRNG_BASE = MTA1_MKDF_MMIO_BASE | 0x00000000,
|
||||
MTA1_MKDF_MMIO_TIMER_BASE = MTA1_MKDF_MMIO_BASE | 0x01000000,
|
||||
MTA1_MKDF_MMIO_UDS_BASE = MTA1_MKDF_MMIO_BASE | 0x02000000,
|
||||
MTA1_MKDF_MMIO_UART_BASE = MTA1_MKDF_MMIO_BASE | 0x03000000,
|
||||
MTA1_MKDF_MMIO_TOUCH_BASE = MTA1_MKDF_MMIO_BASE | 0x04000000,
|
||||
// This "core" only exists in QEMU
|
||||
MTA1_MKDF_MMIO_QEMU_BASE = MTA1_MKDF_MMIO_BASE | 0x3e000000,
|
||||
MTA1_MKDF_MMIO_MTA1_BASE = MTA1_MKDF_MMIO_BASE | 0x3f000000, // 0xff000000
|
||||
|
||||
MTA1_MKDF_NAME0_SUFFIX = 0x00,
|
||||
MTA1_MKDF_NAME1_SUFFIX = 0x04,
|
||||
MTA1_MKDF_VERSION_SUFFIX = 0x08,
|
||||
|
||||
MTA1_MKDF_MMIO_TRNG_NAME0 = MTA1_MKDF_MMIO_TRNG_BASE | MTA1_MKDF_NAME0_SUFFIX,
|
||||
MTA1_MKDF_MMIO_TRNG_NAME1 = MTA1_MKDF_MMIO_TRNG_BASE | MTA1_MKDF_NAME1_SUFFIX,
|
||||
MTA1_MKDF_MMIO_TRNG_VERSION = MTA1_MKDF_MMIO_TRNG_BASE | MTA1_MKDF_VERSION_SUFFIX,
|
||||
MTA1_MKDF_MMIO_TRNG_STATUS = MTA1_MKDF_MMIO_TRNG_BASE | 0x24,
|
||||
MTA1_MKDF_MMIO_TRNG_STATUS_READY_BIT = 0,
|
||||
MTA1_MKDF_MMIO_TRNG_SAMPLE_RATE = MTA1_MKDF_MMIO_TRNG_BASE | 0x40,
|
||||
MTA1_MKDF_MMIO_TRNG_ENTROPY = MTA1_MKDF_MMIO_TRNG_BASE | 0x80,
|
||||
|
||||
MTA1_MKDF_MMIO_TIMER_NAME0 = MTA1_MKDF_MMIO_TIMER_BASE | MTA1_MKDF_NAME0_SUFFIX,
|
||||
MTA1_MKDF_MMIO_TIMER_NAME1 = MTA1_MKDF_MMIO_TIMER_BASE | MTA1_MKDF_NAME1_SUFFIX,
|
||||
MTA1_MKDF_MMIO_TIMER_VERSION = MTA1_MKDF_MMIO_TIMER_BASE | MTA1_MKDF_VERSION_SUFFIX,
|
||||
MTA1_MKDF_MMIO_TIMER_CTRL = MTA1_MKDF_MMIO_TIMER_BASE | 0x20,
|
||||
MTA1_MKDF_MMIO_TIMER_CTRL_START_BIT = 0,
|
||||
MTA1_MKDF_MMIO_TIMER_CTRL_STOP_BIT = 1,
|
||||
MTA1_MKDF_MMIO_TIMER_STATUS = MTA1_MKDF_MMIO_TIMER_BASE | 0x24,
|
||||
MTA1_MKDF_MMIO_TIMER_STATUS_READY_BIT = 0,
|
||||
MTA1_MKDF_MMIO_TIMER_PRESCALER = MTA1_MKDF_MMIO_TIMER_BASE | 0x28,
|
||||
MTA1_MKDF_MMIO_TIMER_TIMER = MTA1_MKDF_MMIO_TIMER_BASE | 0x2c,
|
||||
|
||||
MTA1_MKDF_MMIO_UDS_NAME0 = MTA1_MKDF_MMIO_UDS_BASE | MTA1_MKDF_NAME0_SUFFIX,
|
||||
MTA1_MKDF_MMIO_UDS_NAME1 = MTA1_MKDF_MMIO_UDS_BASE | MTA1_MKDF_NAME1_SUFFIX,
|
||||
MTA1_MKDF_MMIO_UDS_VERSION = MTA1_MKDF_MMIO_UDS_BASE | MTA1_MKDF_VERSION_SUFFIX,
|
||||
MTA1_MKDF_MMIO_UDS_FIRST = MTA1_MKDF_MMIO_UDS_BASE | 0x40,
|
||||
MTA1_MKDF_MMIO_UDS_LAST = MTA1_MKDF_MMIO_UDS_BASE | 0x5c, // Address of last 32-bit word of UDS
|
||||
|
||||
MTA1_MKDF_MMIO_UART_NAME0 = MTA1_MKDF_MMIO_UART_BASE | MTA1_MKDF_NAME0_SUFFIX,
|
||||
MTA1_MKDF_MMIO_UART_NAME1 = MTA1_MKDF_MMIO_UART_BASE | MTA1_MKDF_NAME1_SUFFIX,
|
||||
MTA1_MKDF_MMIO_UART_VERSION = MTA1_MKDF_MMIO_UART_BASE | MTA1_MKDF_VERSION_SUFFIX,
|
||||
MTA1_MKDF_MMIO_UART_BIT_RATE = MTA1_MKDF_MMIO_UART_BASE | 0x40,
|
||||
MTA1_MKDF_MMIO_UART_DATA_BITS = MTA1_MKDF_MMIO_UART_BASE | 0x44,
|
||||
MTA1_MKDF_MMIO_UART_STOP_BITS = MTA1_MKDF_MMIO_UART_BASE | 0x48,
|
||||
MTA1_MKDF_MMIO_UART_RX_STATUS = MTA1_MKDF_MMIO_UART_BASE | 0x80,
|
||||
MTA1_MKDF_MMIO_UART_RX_DATA = MTA1_MKDF_MMIO_UART_BASE | 0x84,
|
||||
MTA1_MKDF_MMIO_UART_TX_STATUS = MTA1_MKDF_MMIO_UART_BASE | 0x100,
|
||||
MTA1_MKDF_MMIO_UART_TX_DATA = MTA1_MKDF_MMIO_UART_BASE | 0x104,
|
||||
|
||||
MTA1_MKDF_MMIO_TOUCH_NAME0 = MTA1_MKDF_MMIO_TOUCH_BASE | MTA1_MKDF_NAME0_SUFFIX,
|
||||
MTA1_MKDF_MMIO_TOUCH_NAME1 = MTA1_MKDF_MMIO_TOUCH_BASE | MTA1_MKDF_NAME1_SUFFIX,
|
||||
MTA1_MKDF_MMIO_TOUCH_VERSION = MTA1_MKDF_MMIO_TOUCH_BASE | MTA1_MKDF_VERSION_SUFFIX,
|
||||
MTA1_MKDF_MMIO_TOUCH_STATUS = MTA1_MKDF_MMIO_TOUCH_BASE | 0x24,
|
||||
MTA1_MKDF_MMIO_TOUCH_STATUS_EVENT_BIT = 0,
|
||||
|
||||
// TODO HW core/addr is not yet defined for this:
|
||||
MTA1_MKDF_MMIO_QEMU_UDA = MTA1_MKDF_MMIO_QEMU_BASE | 0x20,
|
||||
// This will only ever exist in QEMU:
|
||||
MTA1_MKDF_MMIO_QEMU_DEBUG = MTA1_MKDF_MMIO_QEMU_BASE | 0x1000,
|
||||
|
||||
MTA1_MKDF_MMIO_MTA1_NAME0 = MTA1_MKDF_MMIO_MTA1_BASE | MTA1_MKDF_NAME0_SUFFIX,
|
||||
MTA1_MKDF_MMIO_MTA1_NAME1 = MTA1_MKDF_MMIO_MTA1_BASE | MTA1_MKDF_NAME1_SUFFIX,
|
||||
MTA1_MKDF_MMIO_MTA1_VERSION = MTA1_MKDF_MMIO_MTA1_BASE | MTA1_MKDF_VERSION_SUFFIX,
|
||||
MTA1_MKDF_MMIO_MTA1_SWITCH_APP = MTA1_MKDF_MMIO_MTA1_BASE | 0x20,
|
||||
MTA1_MKDF_MMIO_MTA1_LED = MTA1_MKDF_MMIO_MTA1_BASE | 0x24,
|
||||
MTA1_MKDF_MMIO_MTA1_LED_R_BIT = 2,
|
||||
MTA1_MKDF_MMIO_MTA1_LED_G_BIT = 1,
|
||||
MTA1_MKDF_MMIO_MTA1_LED_B_BIT = 0,
|
||||
MTA1_MKDF_MMIO_MTA1_GPIO = MTA1_MKDF_MMIO_MTA1_BASE | 0x28,
|
||||
MTA1_MKDF_MMIO_MTA1_GPIO1_BIT = 0,
|
||||
MTA1_MKDF_MMIO_MTA1_GPIO2_BIT = 1,
|
||||
MTA1_MKDF_MMIO_MTA1_GPIO3_BIT = 2,
|
||||
MTA1_MKDF_MMIO_MTA1_GPIO4_BIT = 3,
|
||||
MTA1_MKDF_MMIO_MTA1_APP_ADDR = MTA1_MKDF_MMIO_MTA1_BASE | 0x30, // 0x4000_0000
|
||||
MTA1_MKDF_MMIO_MTA1_APP_SIZE = MTA1_MKDF_MMIO_MTA1_BASE | 0x34,
|
||||
MTA1_MKDF_MMIO_MTA1_DEBUG = MTA1_MKDF_MMIO_MTA1_BASE | 0x40,
|
||||
MTA1_MKDF_MMIO_MTA1_CDI_FIRST = MTA1_MKDF_MMIO_MTA1_BASE | 0x80,
|
||||
MTA1_MKDF_MMIO_MTA1_CDI_LAST = MTA1_MKDF_MMIO_MTA1_BASE | 0x9c, // Address of last 32-bit word of CDI.
|
||||
MTA1_MKDF_MMIO_MTA1_UDI_FIRST = MTA1_MKDF_MMIO_MTA1_BASE | 0xc0,
|
||||
MTA1_MKDF_MMIO_MTA1_UDI_LAST = MTA1_MKDF_MMIO_MTA1_BASE | 0xc4, // Address of last 32-bit word of UDI.
|
||||
};
|
||||
|
||||
#endif
|
4
hw/application_fpga/fw/testfw/Makefile
Normal file
4
hw/application_fpga/fw/testfw/Makefile
Normal file
|
@ -0,0 +1,4 @@
|
|||
.PHONY: fmt
|
||||
fmt:
|
||||
# Uses ../.clang-format
|
||||
clang-format --verbose -i main.c
|
171
hw/application_fpga/fw/testfw/main.c
Normal file
171
hw/application_fpga/fw/testfw/main.c
Normal file
|
@ -0,0 +1,171 @@
|
|||
/*
|
||||
* Copyright (C) 2022 - Tillitis AB
|
||||
* SPDX-License-Identifier: GPL-2.0-only
|
||||
*/
|
||||
|
||||
#include "../mta1_mkdf/lib.h"
|
||||
#include "../mta1_mkdf/proto.h"
|
||||
#include "../mta1_mkdf/types.h"
|
||||
#include "../mta1_mkdf_mem.h"
|
||||
|
||||
// clang-format off
|
||||
volatile uint32_t *mta1name0 = (volatile uint32_t *)MTA1_MKDF_MMIO_MTA1_NAME0;
|
||||
volatile uint32_t *mta1name1 = (volatile uint32_t *)MTA1_MKDF_MMIO_MTA1_NAME1;
|
||||
volatile uint32_t *uds = (volatile uint32_t *)MTA1_MKDF_MMIO_UDS_FIRST;
|
||||
volatile uint32_t *uda = (volatile uint32_t *)MTA1_MKDF_MMIO_QEMU_UDA; // Only in QEMU right now
|
||||
volatile uint32_t *cdi = (volatile uint32_t *)MTA1_MKDF_MMIO_MTA1_CDI_FIRST;
|
||||
volatile uint32_t *udi = (volatile uint32_t *)MTA1_MKDF_MMIO_MTA1_UDI_FIRST;
|
||||
volatile uint32_t *switch_app = (volatile uint32_t *)MTA1_MKDF_MMIO_MTA1_SWITCH_APP;
|
||||
// clang-format on
|
||||
|
||||
// TODO Real UDA is 4 words (16 bytes)
|
||||
#define UDA_WORDS 1
|
||||
|
||||
void test_puts(char *reason)
|
||||
{
|
||||
for (char *c = reason; *c != '\0'; c++) {
|
||||
writebyte(*c);
|
||||
}
|
||||
}
|
||||
|
||||
void test_putsn(char *p, int n)
|
||||
{
|
||||
for (int i = 0; i < n; i++) {
|
||||
writebyte(p[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void test_puthex(uint8_t c)
|
||||
{
|
||||
unsigned int upper = (c >> 4) & 0xf;
|
||||
unsigned int lower = c & 0xf;
|
||||
writebyte(upper < 10 ? '0' + upper : 'a' - 10 + upper);
|
||||
writebyte(lower < 10 ? '0' + lower : 'a' - 10 + lower);
|
||||
}
|
||||
|
||||
void test_puthexn(uint8_t *p, int n)
|
||||
{
|
||||
for (int i = 0; i < n; i++) {
|
||||
test_puthex(p[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void test_reverseword(uint32_t *wordp)
|
||||
{
|
||||
*wordp = ((*wordp & 0xff000000) >> 24) | ((*wordp & 0x00ff0000) >> 8) |
|
||||
((*wordp & 0x0000ff00) << 8) | ((*wordp & 0x000000ff) << 24);
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
uint8_t in;
|
||||
|
||||
// Wait for terminal program and a character to be typed
|
||||
in = readbyte();
|
||||
|
||||
test_puts("Hello, I'm testfw on:");
|
||||
// Output the MTA1 core's NAME0 and NAME1
|
||||
uint32_t name;
|
||||
wordcpy(&name, (void *)mta1name0, 1);
|
||||
test_reverseword(&name);
|
||||
test_putsn((char *)&name, 4);
|
||||
test_puts(" ");
|
||||
wordcpy(&name, (void *)mta1name1, 1);
|
||||
test_reverseword(&name);
|
||||
test_putsn((char *)&name, 4);
|
||||
test_puts("\r\n");
|
||||
|
||||
int anyfailed = 0;
|
||||
|
||||
uint32_t uds_local[8];
|
||||
uint32_t uds_zeros[8];
|
||||
memset(uds_zeros, 0, 8 * 4);
|
||||
// Should get non-empty UDS
|
||||
wordcpy(uds_local, (void *)uds, 8);
|
||||
if (memeq(uds_local, uds_zeros, 8 * 4)) {
|
||||
test_puts("FAIL: UDS empty!\r\n");
|
||||
anyfailed = 1;
|
||||
}
|
||||
// Should NOT be able to read from UDS again
|
||||
wordcpy(uds_local, (void *)uds, 8);
|
||||
if (!memeq(uds_local, uds_zeros, 8 * 4)) {
|
||||
test_puts("FAIL: Could read UDS a second time!\r\n");
|
||||
anyfailed = 1;
|
||||
}
|
||||
|
||||
// TODO test UDA once we have it in real hw
|
||||
// uint32_t uda_local[UDA_WORDS];
|
||||
// uint32_t uda_zeros[UDA_WORDS];
|
||||
// memset(uda_zeros, 0, UDA_WORDS*4);
|
||||
// // Should get non-empty UDA
|
||||
// wordcpy(uda_local, (void *)uda, UDA_WORDS);
|
||||
// if (memeq(uda_local, uda_zeros, UDA_WORDS*4)) {
|
||||
// test_puts("FAIL: UDA empty!\r\n");
|
||||
// anyfailed = 1;
|
||||
// }
|
||||
|
||||
uint32_t udi_local[2];
|
||||
uint32_t udi_zeros[2];
|
||||
memset(udi_zeros, 0, 2 * 4);
|
||||
// Should get non-empty UDI
|
||||
wordcpy(udi_local, (void *)udi, 2);
|
||||
if (memeq(udi_local, udi_zeros, 2 * 4)) {
|
||||
test_puts("FAIL: UDI empty!\r\n");
|
||||
anyfailed = 1;
|
||||
}
|
||||
|
||||
// Should be able to write to CDI in non-app mode.
|
||||
uint32_t cdi_writetest[8] = {0xdeafbeef, 0xdeafbeef, 0xdeafbeef,
|
||||
0xdeafbeef, 0xdeafbeef, 0xdeafbeef,
|
||||
0xdeafbeef, 0xdeafbeef};
|
||||
uint32_t cdi_readback[8];
|
||||
wordcpy((void *)cdi, cdi_writetest, 8);
|
||||
wordcpy(cdi_readback, (void *)cdi, 8);
|
||||
if (!memeq(cdi_writetest, cdi_readback, 8 * 4)) {
|
||||
test_puts("FAIL: Could not write to CDI in non-app mode!\r\n");
|
||||
anyfailed = 1;
|
||||
}
|
||||
|
||||
// Turn on application mode
|
||||
*switch_app = 1;
|
||||
|
||||
// Should NOT be able to read from UDS in app-mode.
|
||||
wordcpy(uds_local, (void *)uds, 8);
|
||||
if (!memeq(uds_local, uds_zeros, 8 * 4)) {
|
||||
test_puts("FAIL: Could read from UDS in app-mode!\r\n");
|
||||
anyfailed = 1;
|
||||
}
|
||||
|
||||
// TODO test UDA once we have in in real hw
|
||||
// // Now we should NOT be able to read from UDA.
|
||||
// wordcpy(uda_local, (void *)uda, UDA_WORDS);
|
||||
// if (!memeq(uda_local, uda_zeros, UDA_WORDS*4)) {
|
||||
// test_puts("FAIL: Could read from UDA in app-mode!\r\n");
|
||||
// anyfailed = 1;
|
||||
// }
|
||||
|
||||
uint32_t cdi_local[8];
|
||||
uint32_t cdi_local2[8];
|
||||
uint32_t cdi_zeros[8];
|
||||
memset(cdi_zeros, 0, 8 * 4);
|
||||
wordcpy(cdi_local, (void *)cdi, 8);
|
||||
// Write to CDI should NOT have any effect in app mode.
|
||||
wordcpy((void *)cdi, cdi_zeros, 8);
|
||||
wordcpy(cdi_local2, (void *)cdi, 8);
|
||||
if (!memeq(cdi_local, cdi_local2, 8 * 4)) {
|
||||
test_puts("FAIL: Could write to CDI in app-mode!\r\n");
|
||||
anyfailed = 1;
|
||||
}
|
||||
|
||||
if (anyfailed) {
|
||||
test_puts("Some test failed!\r\n");
|
||||
} else {
|
||||
test_puts("All tests passed.\r\n");
|
||||
}
|
||||
|
||||
test_puts("Now echoing what you type...\r\n");
|
||||
for (;;) {
|
||||
in = readbyte(); // blocks
|
||||
writebyte(in);
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue