diff --git a/firmware/iso7816soc-usb/.gitignore b/firmware/iso7816soc-usb/.gitignore new file mode 100644 index 0000000..4e2c385 --- /dev/null +++ b/firmware/iso7816soc-usb/.gitignore @@ -0,0 +1,4 @@ +*.bin +*.elf +*.o +*.gen.h diff --git a/firmware/iso7816soc-usb/Makefile b/firmware/iso7816soc-usb/Makefile new file mode 100644 index 0000000..2c6ddff --- /dev/null +++ b/firmware/iso7816soc-usb/Makefile @@ -0,0 +1,62 @@ +BOARD ?= icebreaker +CROSS ?= riscv-none-embed- +CC = $(CROSS)gcc +OBJCOPY = $(CROSS)objcopy +ICEPROG = iceprog + +BOARD_DEFINE=BOARD_$(shell echo $(BOARD) | tr a-z\- A-Z_) +CFLAGS=-Wall -Os -march=rv32i -mabi=ilp32 -ffreestanding -flto -nostartfiles -fomit-frame-pointer -Wl,--gc-section --specs=nano.specs -D$(BOARD_DEFINE) -I. -I../common + +HEADERS_common=$(addprefix ../common/, \ + config.h \ + console.h \ + led.h \ + mini-printf.h \ + misc.h \ + no2iso7816.h \ + spi.h \ + utils.h \ +) + +SOURCES_common=$(addprefix ../common/, \ + start.S \ + console.c \ + led.c \ + mini-printf.c \ + misc.c \ + no2iso7816.c \ + spi.c \ + utils.c \ +) + +NO2USB_FW_VERSION=0 +include ../../gateware/cores/no2usb/fw/fw.mk +CFLAGS += $(INC_no2usb) +HEADERS_common += $(HEADERS_no2usb) +SOURCES_common += $(SOURCES_no2usb) + +HEADERS_app=\ + usb_str_app.gen.h \ + $(NULL) + +SOURCES_app=\ + fw_app.c \ + usb_desc_app.c \ + $(NULL) + + +all: fw_app.bin + +fw_app.elf: ../common/lnk-app.lds $(HEADERS_app) $(SOURCES_app) $(HEADERS_common) $(SOURCES_common) + $(CC) $(CFLAGS) -Wl,-Bstatic,-T,../common/lnk-app.lds,--strip-debug -o $@ $(SOURCES_common) $(SOURCES_app) + +%.bin: %.elf + $(OBJCOPY) -O binary $< $@ + +prog: fw_app.bin + $(ICEPROG) -o 640k $< + +clean: + rm -f *.bin *.hex *.elf *.o *.gen.h + +.PHONY: prog clean diff --git a/firmware/iso7816soc-usb/fw_app.c b/firmware/iso7816soc-usb/fw_app.c new file mode 100644 index 0000000..6746a88 --- /dev/null +++ b/firmware/iso7816soc-usb/fw_app.c @@ -0,0 +1,265 @@ +/* + * fw_app.c + * + * Copyright (C) 2021-2022 Sylvain Munaut + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include + +#include "console.h" +#include "led.h" +#include "mini-printf.h" +#include "misc.h" +#include "no2iso7816.h" +#include "spi.h" +#include "utils.h" + +#include "config.h" + +#include +#include + + +// --------------------------------------------------------------------------- +// ISO7816 test +// --------------------------------------------------------------------------- + +static void +iso7816_read_data(const char *desc) +{ + printf("%s :", desc); + while (1) { + int v = iso7816_get_char(); + if (v < 0) + break; + printf(" %02x", v); + } + printf("\n"); +} + +static void +iso7816_test() +{ + /* Setup core with default params */ + iso7816_init(4); + + /* Power up card */ + ncn8025_power_up(); + wait(1000); // 100_000 us + + /* Read ATR */ + iso7816_read_data("ATR"); + + /* Send PPS Request */ + iso7816_put_char(0xff); // PPPS + iso7816_put_char(0x10); // PPS0 + iso7816_put_char(0x96); // PPS1 + iso7816_put_char(0x79); // PCK + + wait(100); // 10_000 us + + /* Read PPS response */ + iso7816_read_data("PPS Response"); + + /* Switch core to higher speed */ + iso7816_setup_brg(512, 32, 4); + + /* Test APDU */ + iso7816_put_char(0xA0); + iso7816_put_char(0xC0); + iso7816_put_char(0x00); + iso7816_put_char(0x00); + iso7816_put_char(0x1A); + + wait(10000); // 100_000 us + + iso7816_read_data("APDU"); +} + + +// --------------------------------------------------------------------------- +// USB integration +// --------------------------------------------------------------------------- + +extern const struct usb_stack_descriptors app_stack_desc; + +void +usb_dfu_rt_cb_reboot(void) +{ + /* Force re-enumeration */ + usb_disconnect(); + + /* Reboot to bootloader */ + reboot(1); +} + +static void +serial_no_init() +{ + uint8_t buf[8]; + char *id, *desc; + int i; + + flash_manuf_id(buf); + printf("Flash Manufacturer : %s\n", hexstr(buf, 3, true)); + + flash_unique_id(buf); + printf("Flash Unique ID : %s\n", hexstr(buf, 8, true)); + + /* Overwrite descriptor string */ + /* In theory in rodata ... but nothing is ro here */ + id = hexstr(buf, 8, false); + desc = (char*)app_stack_desc.str[1]; + for (i=0; i<16; i++) + desc[2 + (i << 1)] = id[i]; +} + + +// --------------------------------------------------------------------------- +// Main +// --------------------------------------------------------------------------- + +void main() +{ + int cmd = 0; + bool card_pwr = false; + bool card_rst = true; + bool card_clk = false; + + /* Init console IO */ + console_init(); + puts("Booting App image..\n"); + + /* LED */ + led_init(); + led_color(48, 96, 5); + led_blink(true, 200, 1000); + led_breathe(true, 100, 200); + led_state(true); + + /* Setup NCN8025 */ + ncn8025_init(); + + /* SPI */ + spi_init(); + + /* Setup USB */ + serial_no_init(); + usb_init(&app_stack_desc); + usb_dfu_rt_init(); + usb_connect(); + + /* Main loop */ + while (1) + { + /* Prompt ? */ + if (cmd >= 0) + printf("Command> "); + + /* Poll for command */ + cmd = getchar_nowait(); + + if (cmd >= 0) { + if (cmd > 32 && cmd < 127) + putchar(cmd); + putchar('\r'); + putchar('\n'); + + switch (cmd) + { + /* Select voltage */ + case 'q': + printf("Voltage 1V8\n"); + ncn8025_set_vsel(1800); + break; + case 'w': + printf("Voltage 3V\n"); + ncn8025_set_vsel(3000); + break; + case 'e': + printf("Voltage 5V\n"); + ncn8025_set_vsel(5000); + break; + + /* Select clock div */ + case '1': + printf("Divider 1:1 (20 MHz)\n"); + ncn8025_set_clk_div(1); + break; + case '2': + printf("Divider 1:2 (10 MHz)\n"); + ncn8025_set_clk_div(2); + break; + case '4': + printf("Divider 1:4 (5 MHz)\n"); + ncn8025_set_clk_div(4); + break; + case '8': + printf("Divider 1:8 (2.5 MHz)\n"); + ncn8025_set_clk_div(8); + break; + + /* Toggle reset */ + case 'r': + card_rst ^= 1; + printf("Card reset: %s\n", card_rst ? "Asserted" : "not asserted"); + ncn8025_set_ll(card_pwr, card_rst, card_clk); + break; + + /* Toggle power */ + case 'p': + card_pwr ^= 1; + printf("Card power: %s\n", card_pwr ? "Enabled" : "Disabled"); + ncn8025_set_ll(card_pwr, card_rst, card_clk); + break; + + /* Toggle clock */ + case 'c': + card_clk ^= 1; + printf("Card clock: %s\n", card_clk ? "Active" : "Inactive"); + ncn8025_set_ll(card_pwr, card_rst, card_clk); + break; + + /* Probe int_n */ + case 'i': + printf("INT_N: %s\n", ncn8025_get_int_n() ? "High" : "Low"); + break; + + /* Power 'up' sequence */ + case 'u': + ncn8025_power_up(); + break; + + /* Power 'down' sequence */ + case 'd': + ncn8025_power_down(); + break; + + case 's': + iso7816_debug(); + break; + + case 'S': + iso7816_init(4); + break; + + case 'T': + iso7816_test(); + break; + + case 'R': + printf("%08x\n", iso7816_get_char()); + break; + + default: + break; + } + } + + /* USB poll */ + usb_poll(); + } +} diff --git a/firmware/iso7816soc-usb/usb_desc_app.c b/firmware/iso7816soc-usb/usb_desc_app.c new file mode 100644 index 0000000..4983467 --- /dev/null +++ b/firmware/iso7816soc-usb/usb_desc_app.c @@ -0,0 +1,85 @@ +/* + * usb_desc_app.c + * + * Copyright (C) 2019-2022 Sylvain Munaut + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include + + +static const struct { + /* Configuration */ + struct usb_conf_desc conf; + + /* DFU Runtime */ + struct { + struct usb_intf_desc intf; + struct usb_dfu_func_desc func; + } __attribute__ ((packed)) dfu; +} __attribute__ ((packed)) _app_conf_desc = { + .conf = { + .bLength = sizeof(struct usb_conf_desc), + .bDescriptorType = USB_DT_CONF, + .wTotalLength = sizeof(_app_conf_desc), + .bNumInterfaces = 1, + .bConfigurationValue = 1, + .iConfiguration = 4, + .bmAttributes = 0x80, + .bMaxPower = 0x32, /* 100 mA */ + }, + .dfu = { + .intf = { + .bLength = sizeof(struct usb_intf_desc), + .bDescriptorType = USB_DT_INTF, + .bInterfaceNumber = 0, + .bAlternateSetting = 0, + .bNumEndpoints = 0, + .bInterfaceClass = USB_CLS_APP_SPECIFIC, + .bInterfaceSubClass = 0x01, + .bInterfaceProtocol = 0x01, + .iInterface = 5, + }, + .func = { + .bLength = sizeof(struct usb_dfu_func_desc), + .bDescriptorType = USB_DFU_DT_FUNC, + .bmAttributes = 0x0d, + .wDetachTimeOut = 0, + .wTransferSize = 4096, + .bcdDFUVersion = 0x0101, + }, + }, +}; + +static const struct usb_conf_desc * const _conf_desc_array[] = { + &_app_conf_desc.conf, +}; + +static const struct usb_dev_desc _dev_desc = { + .bLength = sizeof(struct usb_dev_desc), + .bDescriptorType = USB_DT_DEV, + .bcdUSB = 0x0200, + .bDeviceClass = 0, + .bDeviceSubClass = 0, + .bDeviceProtocol = 0, + .bMaxPacketSize0 = 64, + .idVendor = 0x1d50, + .idProduct = 0x6147, + .bcdDevice = 0x0001, /* v0.1 */ + .iManufacturer = 2, + .iProduct = 3, + .iSerialNumber = 1, + .bNumConfigurations = num_elem(_conf_desc_array), +}; + +#include "usb_str_app.gen.h" + +const struct usb_stack_descriptors app_stack_desc = { + .dev = &_dev_desc, + .conf = _conf_desc_array, + .n_conf = num_elem(_conf_desc_array), + .str = _str_desc_array, + .n_str = num_elem(_str_desc_array), +}; diff --git a/firmware/iso7816soc-usb/usb_str_app.txt b/firmware/iso7816soc-usb/usb_str_app.txt new file mode 100644 index 0000000..7cf1efe --- /dev/null +++ b/firmware/iso7816soc-usb/usb_str_app.txt @@ -0,0 +1,5 @@ +0000000000000000 +osmocom +ISO7816 USB SoC +Main +DFU runtime