mirror of
https://github.com/tillitis/tillitis-key1.git
synced 2025-03-12 18:16:55 -04:00

Introduce new syscall TK1_SYSCALL_GET_VIDPID to get Vendor ID and Product ID from the protected Unique Device Identification number. UDI is protected from device apps to protect the serial number, so apps won't know the exact TKey they are running on other than the CDI. It may, however, be important to know what *kind* of TKey they are running on, so we want to expose the Vendor ID and Product ID. - fpga: Allow UDI to be read when doing syscalls. - Add the new syscall to firmware. - Add test to testapp directly after negative test of reading UDI to read out VID/PID through a syscall.
272 lines
6.4 KiB
C
272 lines
6.4 KiB
C
/*
|
|
* Copyright (C) 2022, 2023 - Tillitis AB
|
|
* SPDX-License-Identifier: GPL-2.0-only
|
|
*/
|
|
|
|
#include "../tk1/led.h"
|
|
#include "../tk1/lib.h"
|
|
#include "../tk1/proto.h"
|
|
#include "../tk1/syscall_num.h"
|
|
#include "../tk1/types.h"
|
|
#include "../tk1_mem.h"
|
|
#include "syscall.h"
|
|
|
|
#define USBMODE_PACKET_SIZE 64
|
|
|
|
// clang-format off
|
|
volatile uint32_t *tk1name0 = (volatile uint32_t *)TK1_MMIO_TK1_NAME0;
|
|
volatile uint32_t *tk1name1 = (volatile uint32_t *)TK1_MMIO_TK1_NAME1;
|
|
volatile uint32_t *uds = (volatile uint32_t *)TK1_MMIO_UDS_FIRST;
|
|
volatile uint32_t *cdi = (volatile uint32_t *)TK1_MMIO_TK1_CDI_FIRST;
|
|
volatile uint32_t *udi = (volatile uint32_t *)TK1_MMIO_TK1_UDI_FIRST;
|
|
volatile uint8_t *fw_ram = (volatile uint8_t *)TK1_MMIO_FW_RAM_BASE;
|
|
volatile uint32_t *timer = (volatile uint32_t *)TK1_MMIO_TIMER_TIMER;
|
|
volatile uint32_t *timer_prescaler = (volatile uint32_t *)TK1_MMIO_TIMER_PRESCALER;
|
|
volatile uint32_t *timer_status = (volatile uint32_t *)TK1_MMIO_TIMER_STATUS;
|
|
volatile uint32_t *timer_ctrl = (volatile uint32_t *)TK1_MMIO_TIMER_CTRL;
|
|
volatile uint32_t *trng_status = (volatile uint32_t *)TK1_MMIO_TRNG_STATUS;
|
|
volatile uint32_t *trng_entropy = (volatile uint32_t *)TK1_MMIO_TRNG_ENTROPY;
|
|
// clang-format on
|
|
|
|
#define UDS_WORDS 8
|
|
#define UDI_WORDS 2
|
|
#define CDI_WORDS 8
|
|
|
|
static void write_with_header(const uint8_t *buf, size_t nbytes, enum mode mode)
|
|
{
|
|
// Append USB Mode Protocol header:
|
|
// 1 byte mode
|
|
// 1 byte length
|
|
writebyte(mode);
|
|
writebyte(nbytes);
|
|
|
|
for (int i = 0; i < nbytes; i++) {
|
|
writebyte(buf[i]);
|
|
}
|
|
}
|
|
|
|
static void write(const uint8_t *buf, size_t nbytes)
|
|
{
|
|
uint8_t len;
|
|
|
|
while (nbytes > 0) {
|
|
// We split the data into chunks that will fit in the
|
|
// USB Mode Protocol with some spare change.
|
|
len =
|
|
nbytes < USBMODE_PACKET_SIZE ? nbytes : USBMODE_PACKET_SIZE;
|
|
|
|
write_with_header((const uint8_t *)buf, len, MODE_CDC);
|
|
|
|
buf += len;
|
|
nbytes -= len;
|
|
}
|
|
}
|
|
|
|
unsigned strlen(const char *str)
|
|
{
|
|
const char *s;
|
|
|
|
for (s = str; *s; ++s)
|
|
;
|
|
|
|
return (s - str);
|
|
}
|
|
|
|
void puts(char *buf)
|
|
{
|
|
size_t nbytes = strlen(buf);
|
|
|
|
write((const uint8_t *)buf, nbytes);
|
|
}
|
|
|
|
void hex(uint8_t buf[2], const uint8_t c)
|
|
{
|
|
unsigned int upper = (c >> 4) & 0xf;
|
|
unsigned int lower = c & 0xf;
|
|
|
|
buf[0] = upper < 10 ? '0' + upper : 'a' - 10 + upper;
|
|
buf[1] = lower < 10 ? '0' + lower : 'a' - 10 + lower;
|
|
}
|
|
|
|
void puthex(uint8_t c)
|
|
{
|
|
uint8_t buf[2];
|
|
|
|
hex(buf, c);
|
|
write(buf, 2);
|
|
}
|
|
|
|
void puthexn(uint8_t *p, int n)
|
|
{
|
|
for (int i = 0; i < n; i++) {
|
|
puthex(p[i]);
|
|
}
|
|
}
|
|
|
|
void reverseword(uint32_t *wordp)
|
|
{
|
|
*wordp = ((*wordp & 0xff000000) >> 24) | ((*wordp & 0x00ff0000) >> 8) |
|
|
((*wordp & 0x0000ff00) << 8) | ((*wordp & 0x000000ff) << 24);
|
|
}
|
|
|
|
uint32_t wait_timer_tick(uint32_t last_timer)
|
|
{
|
|
uint32_t newtimer;
|
|
for (;;) {
|
|
newtimer = *timer;
|
|
if (newtimer != last_timer) {
|
|
return newtimer;
|
|
}
|
|
}
|
|
}
|
|
|
|
void failmsg(char *s)
|
|
{
|
|
puts("FAIL: ");
|
|
puts(s);
|
|
puts("\r\n");
|
|
}
|
|
|
|
int main(void)
|
|
{
|
|
uint8_t in = 0;
|
|
uint8_t mode = 0;
|
|
uint8_t mode_bytes_left = 0;
|
|
|
|
set_led(LED_BLUE);
|
|
|
|
// Wait for terminal program and a character to be typed
|
|
in = readbyte(&mode, &mode_bytes_left);
|
|
|
|
puts("\r\nI'm testapp on:");
|
|
// Output the TK1 core's NAME0 and NAME1
|
|
uint32_t name;
|
|
wordcpy_s(&name, 1, (void *)tk1name0, 1);
|
|
reverseword(&name);
|
|
write((const uint8_t *)&name, 4);
|
|
puts(" ");
|
|
wordcpy_s(&name, 1, (void *)tk1name1, 1);
|
|
reverseword(&name);
|
|
write((const uint8_t *)&name, 4);
|
|
puts("\r\n");
|
|
|
|
uint32_t zeros[8];
|
|
memset(zeros, 0, 8 * 4);
|
|
|
|
int anyfailed = 0;
|
|
|
|
uint32_t uds_local[UDS_WORDS];
|
|
uint32_t udi_local[UDI_WORDS];
|
|
|
|
// Should NOT be able to read from UDS in app-mode.
|
|
wordcpy_s(uds_local, UDS_WORDS, (void *)uds, UDS_WORDS);
|
|
if (!memeq(uds_local, zeros, UDS_WORDS * 4)) {
|
|
failmsg("Read from UDS in app-mode");
|
|
anyfailed = 1;
|
|
}
|
|
|
|
// Should NOT be able to read from UDI in app-mode.
|
|
wordcpy_s(udi_local, UDI_WORDS, (void *)udi, UDI_WORDS);
|
|
if (!memeq(udi_local, zeros, UDI_WORDS * 4)) {
|
|
failmsg("Read from UDI in app-mode");
|
|
anyfailed = 1;
|
|
}
|
|
|
|
// But a syscall to get parts of UDI should be able to run
|
|
int vidpid = syscall(TK1_SYSCALL_GET_VIDPID, 0);
|
|
|
|
if (vidpid != 0x00010203) {
|
|
failmsg("Expected VID/PID to be 0x00010203");
|
|
anyfailed = 1;
|
|
}
|
|
|
|
uint32_t cdi_local[CDI_WORDS];
|
|
uint32_t cdi_local2[CDI_WORDS];
|
|
wordcpy_s(cdi_local, CDI_WORDS, (void *)cdi, CDI_WORDS);
|
|
|
|
// Write to CDI should NOT have any effect in app mode.
|
|
wordcpy_s((void *)cdi, CDI_WORDS, zeros, CDI_WORDS);
|
|
wordcpy_s(cdi_local2, CDI_WORDS, (void *)cdi, CDI_WORDS);
|
|
if (!memeq(cdi_local, cdi_local2, CDI_WORDS * 4)) {
|
|
failmsg("Write to CDI in app-mode");
|
|
anyfailed = 1;
|
|
}
|
|
|
|
// Test FW_RAM.
|
|
*fw_ram = 0x21;
|
|
if (*fw_ram == 0x21) {
|
|
failmsg("Write and read FW RAM in app-mode");
|
|
anyfailed = 1;
|
|
}
|
|
|
|
puts("\r\nTesting timer... 3");
|
|
// Matching clock at 21 MHz, giving us timer in seconds
|
|
*timer_prescaler = 21 * 1000000;
|
|
|
|
// Test timer expiration after 1s
|
|
*timer = 1;
|
|
// Start the timer
|
|
*timer_ctrl = (1 << TK1_MMIO_TIMER_CTRL_START_BIT);
|
|
while (*timer_status & (1 << TK1_MMIO_TIMER_STATUS_RUNNING_BIT)) {
|
|
}
|
|
// Now timer has expired and is ready to run again
|
|
puts(" 2");
|
|
|
|
// Test to interrupt a timer - and reads from timer register
|
|
// Starting 10s timer and interrupting it in 3s...
|
|
*timer = 10;
|
|
*timer_ctrl = (1 << TK1_MMIO_TIMER_CTRL_START_BIT);
|
|
uint32_t last_timer = 10;
|
|
for (int i = 0; i < 3; i++) {
|
|
last_timer = wait_timer_tick(last_timer);
|
|
}
|
|
|
|
// Stop the timer
|
|
*timer_ctrl = (1 << TK1_MMIO_TIMER_CTRL_STOP_BIT);
|
|
puts(" 1. done.\r\n");
|
|
|
|
if (*timer_status & (1 << TK1_MMIO_TIMER_STATUS_RUNNING_BIT)) {
|
|
failmsg("Timer didn't stop");
|
|
anyfailed = 1;
|
|
}
|
|
|
|
if (*timer != 10) {
|
|
failmsg("Timer didn't reset to 10");
|
|
anyfailed = 1;
|
|
}
|
|
|
|
// Check and display test results.
|
|
puts("\r\n--> ");
|
|
if (anyfailed) {
|
|
puts("Some test FAILED!\r\n");
|
|
} else {
|
|
puts("All tests passed.\r\n");
|
|
}
|
|
|
|
puts("\r\nHere are 256 bytes from the TRNG:\r\n");
|
|
for (int j = 0; j < 8; j++) {
|
|
for (int i = 0; i < 8; i++) {
|
|
while ((*trng_status &
|
|
(1 << TK1_MMIO_TRNG_STATUS_READY_BIT)) == 0) {
|
|
}
|
|
uint32_t rnd = *trng_entropy;
|
|
puthexn((uint8_t *)&rnd, 4);
|
|
puts(" ");
|
|
}
|
|
puts("\r\n");
|
|
}
|
|
puts("\r\n");
|
|
|
|
puts("Now echoing what you type...Type + to reset device\r\n");
|
|
for (;;) {
|
|
in = readbyte(&mode, &mode_bytes_left);
|
|
if (in == '+') {
|
|
syscall(TK1_SYSCALL_RESET, 0);
|
|
}
|
|
|
|
writebyte(MODE_CDC);
|
|
writebyte(1);
|
|
writebyte(in);
|
|
}
|
|
}
|