From 50b1aff6f6f2a3a127f6121c5dedd8c2fa5a1c4d Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 14 Nov 2010 23:04:16 +0100 Subject: Initial version of a SAM7 USART based ISO7816-3 T=0 sniffer --- firmware/src/simtrace/iso7816_uart.c | 399 ++++++++++++++++++++++++++++++ firmware/src/simtrace/main_simtrace.c | 98 ++++++++ firmware/src/simtrace/usb_strings_app.txt | 6 + 3 files changed, 503 insertions(+) create mode 100644 firmware/src/simtrace/iso7816_uart.c create mode 100644 firmware/src/simtrace/main_simtrace.c create mode 100644 firmware/src/simtrace/usb_strings_app.txt (limited to 'firmware/src/simtrace') diff --git a/firmware/src/simtrace/iso7816_uart.c b/firmware/src/simtrace/iso7816_uart.c new file mode 100644 index 0000000..9022830 --- /dev/null +++ b/firmware/src/simtrace/iso7816_uart.c @@ -0,0 +1,399 @@ +/* Driver for AT91SAM7 USART0 in ISO7816-3 mode + * (C) 2010 by Harald Welte + */ + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "../simtrace.h" +#include "../openpcd.h" + +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) + +static const AT91PS_USART usart = AT91C_BASE_US0; + +enum iso7816_3_state { + ISO7816_S_RESET, /* in Reset */ + ISO7816_S_WAIT_ATR, /* waiting for ATR to start */ + ISO7816_S_IN_ATR, + ISO7816_S_WAIT_READER, /* waiting for data from reader */ + ISO7816_S_WAIT_CARD, /* waiting for data from card */ +}; + +enum atr_state { + ATR_S_WAIT_TS, + ATR_S_WAIT_T0, + ATR_S_WAIT_TA, + ATR_S_WAIT_TB, + ATR_S_WAIT_TC, + ATR_S_WAIT_TD, + ATR_S_WAIT_HIST, + ATR_S_WAIT_TCK, + ATR_S_DONE, +}; + +struct iso7816_3_handle { + enum iso7816_3_state state; + + u_int8_t fi; + u_int8_t di; + + u_int8_t atr_idx; + u_int8_t atr_hist_len; + u_int8_t atr_last_td; + enum atr_state atr_state; + u_int8_t atr[64]; + + u_int16_t apdu_len; + u_int16_t apdu_idx; +}; + +struct iso7816_3_handle isoh; + + +/* Table 6 from ISO 7816-3 */ +static const u_int16_t fi_table[] = { + 0, 372, 558, 744, 1116, 1488, 1860, 0, + 0, 512, 768, 1024, 1536, 2048, 0, 0 +}; + +/* Table 7 from ISO 7816-3 */ +static const u_int8_t di_table[] = { + 0, 1, 2, 4, 8, 16, 0, 0, + 0, 0, 2, 4, 8, 16, 32, 64, +}; + +static int compute_fidi_ratio(u_int8_t fi, u_int8_t di) +{ + u_int16_t f, d; + int ret; + + if (fi >= ARRAY_SIZE(fi_table) || + di >= ARRAY_SIZE(di_table)) + return -EINVAL; + + f = fi_table[fi]; + if (f == 0) + return -EINVAL; + + d = di_table[di]; + if (d == 0) + return -EINVAL; + + if (di < 8) + ret = f / d; + else + ret = f * d; + + return ret; +} + +static void set_atr_state(struct iso7816_3_handle *ih, enum atr_state new_atrs) +{ + if (new_atrs == ATR_S_WAIT_TS) { + ih->atr_idx = 0; + ih->atr_hist_len = 0; + ih->atr_last_td = 0; + memset(ih->atr, 0, sizeof(ih->atr)); + } else if (ih->atr_state == new_atrs) + return; + + //DEBUGPCR("ATR state %u -> %u", ih->atr_state, new_atrs); + ih->atr_state = new_atrs; +} + +static void set_state(struct iso7816_3_handle *ih, enum iso7816_3_state new_state) +{ + if (new_state == ISO7816_S_WAIT_ATR) { + int rc; + /* Initial Fi / Di ratio */ + ih->fi = 1; + ih->di = 1; + rc = compute_fidi_ratio(ih->fi, ih->di); + DEBUGPCRF("computed Fi(%u) Di(%u) ratio: %d", ih->fi, ih->di, rc); + usart->US_FIDI = rc & 0x3ff; + set_atr_state(ih, ATR_S_WAIT_TS); + } else if (new_state == ISO7816_S_WAIT_READER) { + /* CLA INS P1 P2 LEN */ + ih->apdu_len = 5; + ih->apdu_idx = 0; + } else if (new_state == ISO7816_S_WAIT_CARD) { + /* 8.2.2 procedure bytes sent by the card */ + /* FIXME: NULL byte and similar oddities */ + ih->apdu_len += 2; + } + + if (ih->state == new_state) + return; + + DEBUGPCR("7816 state %u -> %u", ih->state, new_state); + ih->state = new_state; +} + +/* determine the next ATR state based on received interface byte */ +static enum atr_state next_intb_state(struct iso7816_3_handle *ih, u_int8_t ch) +{ + switch (ih->atr_state) { + case ATR_S_WAIT_TD: + case ATR_S_WAIT_T0: + ih->atr_last_td = ch; + goto from_td; + case ATR_S_WAIT_TC: + goto from_tc; + case ATR_S_WAIT_TB: + goto from_tb; + case ATR_S_WAIT_TA: + if ((ih->atr_last_td & 0x0f) == 0) { + /* This must be TA1 */ + ih->fi = ch >> 4; + ih->di = ch & 0xf; + DEBUGPCR("found Fi=%u Di=%u", ih->fi, ih->di); + } + goto from_ta; + } + + DEBUGPCR("something wrong, old_state != TA"); + return ATR_S_WAIT_TCK; + +from_td: + if (ih->atr_last_td & 0x10) + return ATR_S_WAIT_TA; +from_ta: + if (ih->atr_last_td & 0x20) + return ATR_S_WAIT_TB; +from_tb: + if (ih->atr_last_td & 0x40) + return ATR_S_WAIT_TC; +from_tc: + if (ih->atr_last_td & 0x80) + return ATR_S_WAIT_TD; + + return ATR_S_WAIT_HIST; +} + +/* process an incomng ATR byte */ +static enum iso7816_3_state +process_byte_atr(struct iso7816_3_handle *ih, u_int8_t byte) +{ + int rc; + + /* add byte to ATR buffer */ + ih->atr[ih->atr_idx] = byte; + ih->atr_idx++; + + switch (ih->atr_state) { + case ATR_S_WAIT_TS: + /* FIXME: if we don't have the RST line we might get this */ + if (byte == 0) { + ih->atr_idx--; + break; + } + /* FIXME: check inverted logic */ + set_atr_state(ih, ATR_S_WAIT_T0); + break; + case ATR_S_WAIT_T0: + ih->atr_hist_len = byte & 0xf; + set_atr_state(ih, next_intb_state(ih, byte & 0xf0)); + break; + case ATR_S_WAIT_TA: + case ATR_S_WAIT_TB: + case ATR_S_WAIT_TC: + case ATR_S_WAIT_TD: + set_atr_state(ih, next_intb_state(ih, byte)); + break; + case ATR_S_WAIT_HIST: + ih->atr_hist_len--; + if (ih->atr_hist_len == 0) + set_atr_state(ih, ATR_S_WAIT_TCK); + break; + case ATR_S_WAIT_TCK: + /* FIXME: process TCK */ + set_atr_state(ih, ATR_S_DONE); + /* FIXME: update Fi/Di */ + rc = compute_fidi_ratio(ih->fi, ih->di); + if (rc > 0 && rc < 0x400) { + DEBUGPCR("computed FiDi ratio %d", rc); + /* update baud rate generator in UART */ + usart->US_CR |= AT91C_US_RXDIS| AT91C_US_RSTRX; + usart->US_FIDI = rc & 0x3ff; + usart->US_CR |= AT91C_US_RXEN; + } else + DEBUGPCRF("computed FiDi ratio %d unsupported", rc); + return ISO7816_S_WAIT_READER; + } + + return ISO7816_S_IN_ATR; +} + +/* process an incomng byte from the reader */ +static enum iso7816_3_state +process_byte_reader(struct iso7816_3_handle *ih, u_int8_t byte) +{ + /* add response length to total number of expected bytes */ + if (ih->apdu_idx == 4) + ih->apdu_len += byte; + + ih->apdu_idx++; + + /* once we have received all bytes, transition to card response */ + if (ih->apdu_idx == ih->apdu_len) + return ISO7816_S_WAIT_CARD; + + return ISO7816_S_WAIT_READER; +} + +/* process an incomng byte from the card */ +static enum iso7816_3_state +process_byte_card(struct iso7816_3_handle *ih, u_int8_t byte) +{ + ih->apdu_idx++; + + /* once we have received all bytes, apdu is finished */ + if (ih->apdu_idx == ih->apdu_len) + return ISO7816_S_WAIT_READER; + + return ISO7816_S_WAIT_CARD; +} + + +void process_byte(struct iso7816_3_handle *ih, u_int8_t byte) +{ + int new_state = -1; + + switch (ih->state) { + case ISO7816_S_RESET: + break; + case ISO7816_S_WAIT_ATR: + case ISO7816_S_IN_ATR: + new_state = process_byte_atr(ih, byte); + break; + case ISO7816_S_WAIT_READER: + new_state = process_byte_reader(ih, byte); + break; + case ISO7816_S_WAIT_CARD: + //new_state = process_byte_card(ih, byte); + break; + } + + if (new_state != -1) + set_state(ih, new_state); +} + +static int __ramfunc usart_irq(void) +{ + u_int32_t csr = usart->US_CSR; + u_int8_t octet; + + //DEBUGP("USART IRQ, CSR=0x%08x\n", csr); + + if (csr & AT91C_US_RXRDY) { + /* at least one character received */ + octet = usart->US_RHR & 0xff; + DEBUGP("%02x ", octet); + process_byte(&isoh, octet); + } + + if (csr & AT91C_US_TXRDY) { + /* nothing to transmit anymore */ + } + + if (csr & (AT91C_US_PARE|AT91C_US_FRAME|AT91C_US_OVRE)) { + /* some error has occurrerd */ + } +} + +void iso_uart_dump(void) +{ + u_int32_t csr = usart->US_CSR; + + DEBUGPCR("USART CSR=0x%08x", csr); +} + +void iso_uart_rst(unsigned int state) +{ + DEBUGPCR("USART nRST set state=%u", state); + switch (state) { + case 0: + AT91F_PIO_ClearOutput(AT91C_BASE_PIOA, SIMTRACE_PIO_nRST); + AT91F_PIO_CfgOutput(AT91C_BASE_PIOA, SIMTRACE_PIO_nRST); + break; + case 1: + AT91F_PIO_SetOutput(AT91C_BASE_PIOA, SIMTRACE_PIO_nRST); + AT91F_PIO_CfgOutput(AT91C_BASE_PIOA, SIMTRACE_PIO_nRST); + break; + default: + AT91F_PIO_CfgInput(AT91C_BASE_PIOA, SIMTRACE_PIO_nRST); + break; + } +} + +void iso_uart_rx_mode(void) +{ + DEBUGPCR("USART Entering Rx Mode"); + /* Enable receive interrupts */ + usart->US_IER = AT91C_US_RXRDY | AT91C_US_OVRE | AT91C_US_FRAME | + AT91C_US_PARE | AT91C_US_NACK | AT91C_US_ITERATION; + + /* Enable the receiver */ + usart->US_CR = AT91C_US_RXEN; + + set_state(&isoh, ISO7816_S_WAIT_ATR); +} + +void iso_uart_clk_master(unsigned int master) +{ + DEBUGPCR("USART Clock Master %u", master); + if (master) { + usart->US_MR = AT91C_US_USMODE_ISO7816_0 | AT91C_US_CLKS_CLOCK | + AT91C_US_CHRL_8_BITS | AT91C_US_NBSTOP_1_BIT | + AT91C_US_CKLO; + usart->US_BRGR = (0x0000 << 16) | 16; + } else { + usart->US_MR = AT91C_US_USMODE_ISO7816_0 | AT91C_US_CLKS_EXT | + AT91C_US_CHRL_8_BITS | AT91C_US_NBSTOP_1_BIT | + AT91C_US_CKLO; + usart->US_BRGR = (0x0000 << 16) | 0x0001; + } +} + +void iso_uart_init(void) +{ + DEBUGPCR("USART Initializing"); + + AT91F_US0_CfgPMC(); + + /* configure all 3 signals as input */ + AT91F_PIO_CfgPeriph(AT91C_BASE_PIOA, SIMTRACE_PIO_IO, SIMTRACE_PIO_CLK); + + AT91F_PIO_CfgInput(AT91C_BASE_PIOA, SIMTRACE_PIO_nRST); + + AT91F_AIC_ConfigureIt(AT91C_BASE_AIC, AT91C_ID_US0, + OPENPCD_IRQ_PRIO_USART, + AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL, &usart_irq); + + AT91F_AIC_EnableIt(AT91C_BASE_AIC, AT91C_ID_US0); + + usart->US_CR = AT91C_US_RXDIS | AT91C_US_TXDIS | (AT91C_US_RSTRX | AT91C_US_RSTTX); + /* FIXME: wait for some time */ + usart->US_CR = AT91C_US_RXDIS | AT91C_US_TXDIS; + + usart->US_MR = AT91C_US_USMODE_ISO7816_0 | AT91C_US_CLKS_EXT | + AT91C_US_CHRL_8_BITS | AT91C_US_NBSTOP_1_BIT | + AT91C_US_CKLO; + + /* Disable all interrupts */ + usart->US_IDR = 0xff; + /* Clock Divider = 1, i.e. no division of SCLK */ + usart->US_BRGR = (0x0000 << 16) | 0x0001; + /* Disable Receiver Time-out */ + usart->US_RTOR = 0; + /* Disable Transmitter Timeguard */ + usart->US_TTGR = 0; +} diff --git a/firmware/src/simtrace/main_simtrace.c b/firmware/src/simtrace/main_simtrace.c new file mode 100644 index 0000000..d5a22dd --- /dev/null +++ b/firmware/src/simtrace/main_simtrace.c @@ -0,0 +1,98 @@ +/* OpenPICC Main Program + * (C) 2006 by Harald Welte + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + + +#include +#include +#include +#include +#include +#include +#include +#include "../openpcd.h" +#include +#include +#include +#include + +//#include + +void _init_func(void) +{ + /* low-level hardware initialization */ + pio_irq_init(); + iso_uart_init(); + + /* high-level protocol */ + //opicc_usbapi_init(); + led_switch(1, 0); + led_switch(2, 1); +} + +static void help(void) +{ + DEBUGPCR("r: iso uart Rx mode\r\n" + "c: toggle clock master/slave\r\n" + "l: set nRST to low (active)\r\n" + "h: set nRST to high (inactive)\r\n" + "o: set nRST to input\r\n"); +} + +int _main_dbgu(char key) +{ + static int i = 0; + DEBUGPCRF("main_dbgu"); + + switch (key) { + case 'r': + iso_uart_rx_mode(); + break; + case 'c': + iso_uart_clk_master(i++ & 1); + break; + case 'l': + iso_uart_rst(0); + break; + case 'h': + iso_uart_rst(1); + break; + case 'o': + iso_uart_rst(2); + break; + case 'd': + iso_uart_dump(); + break; + case '?': + help(); + break; + } + + return -EINVAL; +} + +void _main_func(void) +{ + /* first we try to get rid of pending to-be-sent stuff */ + usb_out_process(); + + /* next we deal with incoming reqyests from USB EP1 (OUT) */ + usb_in_process(); + + udp_unthrottle(); +} diff --git a/firmware/src/simtrace/usb_strings_app.txt b/firmware/src/simtrace/usb_strings_app.txt new file mode 100644 index 0000000..c1d3c95 --- /dev/null +++ b/firmware/src/simtrace/usb_strings_app.txt @@ -0,0 +1,6 @@ +SimTrace DFU Interface - Application Partition +SimTrace DFU Interface - Bootloader Partition +hmw-consulting.de +SimTrace SIM Sniffer - Runtime Mode +SimTrace Runtime Configuration +SimTrace Runtime Interface -- cgit v1.2.3 From 9520b0bea118668d81e3e1a53cdc2e1b43f169f9 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 14 Nov 2010 23:44:46 +0100 Subject: simtrace: introduce RST pin handling --- firmware/src/simtrace/iso7816_uart.c | 44 ++++++++++++++++++++++++++---------- 1 file changed, 32 insertions(+), 12 deletions(-) (limited to 'firmware/src/simtrace') diff --git a/firmware/src/simtrace/iso7816_uart.c b/firmware/src/simtrace/iso7816_uart.c index 9022830..6ed797c 100644 --- a/firmware/src/simtrace/iso7816_uart.c +++ b/firmware/src/simtrace/iso7816_uart.c @@ -11,6 +11,7 @@ #include #include +#include #include "../simtrace.h" #include "../openpcd.h" @@ -111,14 +112,18 @@ static void set_atr_state(struct iso7816_3_handle *ih, enum atr_state new_atrs) static void set_state(struct iso7816_3_handle *ih, enum iso7816_3_state new_state) { - if (new_state == ISO7816_S_WAIT_ATR) { + if (new_state == ISO7816_S_RESET) { + usart->US_CR |= AT91C_US_RXDIS | AT91C_US_RSTRX; + } else if (new_state == ISO7816_S_WAIT_ATR) { int rc; /* Initial Fi / Di ratio */ ih->fi = 1; ih->di = 1; rc = compute_fidi_ratio(ih->fi, ih->di); DEBUGPCRF("computed Fi(%u) Di(%u) ratio: %d", ih->fi, ih->di, rc); + usart->US_CR |= AT91C_US_RXDIS | AT91C_US_RSTRX; usart->US_FIDI = rc & 0x3ff; + usart->US_CR |= AT91C_US_RXEN; set_atr_state(ih, ATR_S_WAIT_TS); } else if (new_state == ISO7816_S_WAIT_READER) { /* CLA INS P1 P2 LEN */ @@ -157,11 +162,11 @@ static enum atr_state next_intb_state(struct iso7816_3_handle *ih, u_int8_t ch) DEBUGPCR("found Fi=%u Di=%u", ih->fi, ih->di); } goto from_ta; + default: + DEBUGPCR("something wrong, old_state != TA"); + return ATR_S_WAIT_TCK; } - DEBUGPCR("something wrong, old_state != TA"); - return ATR_S_WAIT_TCK; - from_td: if (ih->atr_last_td & 0x10) return ATR_S_WAIT_TA; @@ -278,7 +283,7 @@ void process_byte(struct iso7816_3_handle *ih, u_int8_t byte) new_state = process_byte_reader(ih, byte); break; case ISO7816_S_WAIT_CARD: - //new_state = process_byte_card(ih, byte); + new_state = process_byte_card(ih, byte); break; } @@ -286,7 +291,7 @@ void process_byte(struct iso7816_3_handle *ih, u_int8_t byte) set_state(ih, new_state); } -static int __ramfunc usart_irq(void) +static __ramfunc void usart_irq(void) { u_int32_t csr = usart->US_CSR; u_int8_t octet; @@ -309,6 +314,18 @@ static int __ramfunc usart_irq(void) } } +/* handler for the RST input pin state change */ +static void reset_pin_irq(u_int32_t pio) +{ + if (!AT91F_PIO_IsInputSet(AT91C_BASE_PIOA, pio)) { + DEBUGPCR("nRST"); + set_state(&isoh, ISO7816_S_RESET); + } else { + DEBUGPCR("RST"); + set_state(&isoh, ISO7816_S_WAIT_ATR); + } +} + void iso_uart_dump(void) { u_int32_t csr = usart->US_CSR; @@ -318,7 +335,7 @@ void iso_uart_dump(void) void iso_uart_rst(unsigned int state) { - DEBUGPCR("USART nRST set state=%u", state); + DEBUGPCR("USART set nRST set state=%u", state); switch (state) { case 0: AT91F_PIO_ClearOutput(AT91C_BASE_PIOA, SIMTRACE_PIO_nRST); @@ -341,10 +358,9 @@ void iso_uart_rx_mode(void) usart->US_IER = AT91C_US_RXRDY | AT91C_US_OVRE | AT91C_US_FRAME | AT91C_US_PARE | AT91C_US_NACK | AT91C_US_ITERATION; - /* Enable the receiver */ - usart->US_CR = AT91C_US_RXEN; - set_state(&isoh, ISO7816_S_WAIT_ATR); + /* call interrupt handler once to set initial state RESET / ATR */ + reset_pin_irq(SIMTRACE_PIO_nRST); } void iso_uart_clk_master(unsigned int master) @@ -367,23 +383,23 @@ void iso_uart_init(void) { DEBUGPCR("USART Initializing"); + /* make sure we get clock from the power management controller */ AT91F_US0_CfgPMC(); /* configure all 3 signals as input */ AT91F_PIO_CfgPeriph(AT91C_BASE_PIOA, SIMTRACE_PIO_IO, SIMTRACE_PIO_CLK); - AT91F_PIO_CfgInput(AT91C_BASE_PIOA, SIMTRACE_PIO_nRST); AT91F_AIC_ConfigureIt(AT91C_BASE_AIC, AT91C_ID_US0, OPENPCD_IRQ_PRIO_USART, AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL, &usart_irq); - AT91F_AIC_EnableIt(AT91C_BASE_AIC, AT91C_ID_US0); usart->US_CR = AT91C_US_RXDIS | AT91C_US_TXDIS | (AT91C_US_RSTRX | AT91C_US_RSTTX); /* FIXME: wait for some time */ usart->US_CR = AT91C_US_RXDIS | AT91C_US_TXDIS; + /* ISO7816 T=0 mode with external clock input */ usart->US_MR = AT91C_US_USMODE_ISO7816_0 | AT91C_US_CLKS_EXT | AT91C_US_CHRL_8_BITS | AT91C_US_NBSTOP_1_BIT | AT91C_US_CKLO; @@ -396,4 +412,8 @@ void iso_uart_init(void) usart->US_RTOR = 0; /* Disable Transmitter Timeguard */ usart->US_TTGR = 0; + + pio_irq_register(SIMTRACE_PIO_nRST, &reset_pin_irq); + AT91F_PIO_CfgInputFilter(AT91C_BASE_PIOA, SIMTRACE_PIO_nRST); + pio_irq_enable(SIMTRACE_PIO_nRST); } -- cgit v1.2.3 From 3c29506f17ff4a30a3d988361c67d2ec1af13eeb Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Thu, 18 Nov 2010 14:09:31 +0100 Subject: simtrace: add TC based waiting time counter, signal ATR / expiry via USB --- firmware/src/simtrace/iso7816_uart.c | 226 +++++++++++++++++++++++----------- firmware/src/simtrace/iso7816_uart.h | 6 + firmware/src/simtrace/main_simtrace.c | 10 +- firmware/src/simtrace/tc_etu.c | 124 +++++++++++++++++++ firmware/src/simtrace/tc_etu.h | 4 + 5 files changed, 292 insertions(+), 78 deletions(-) create mode 100644 firmware/src/simtrace/iso7816_uart.h create mode 100644 firmware/src/simtrace/tc_etu.c create mode 100644 firmware/src/simtrace/tc_etu.h (limited to 'firmware/src/simtrace') diff --git a/firmware/src/simtrace/iso7816_uart.c b/firmware/src/simtrace/iso7816_uart.c index 6ed797c..18335f6 100644 --- a/firmware/src/simtrace/iso7816_uart.c +++ b/firmware/src/simtrace/iso7816_uart.c @@ -1,5 +1,20 @@ -/* Driver for AT91SAM7 USART0 in ISO7816-3 mode +/* Driver for AT91SAM7 USART0 in ISO7816-3 mode for passive sniffing * (C) 2010 by Harald Welte + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * */ #include @@ -9,6 +24,8 @@ #include #include +#include + #include #include #include @@ -23,11 +40,12 @@ static const AT91PS_USART usart = AT91C_BASE_US0; enum iso7816_3_state { ISO7816_S_RESET, /* in Reset */ ISO7816_S_WAIT_ATR, /* waiting for ATR to start */ - ISO7816_S_IN_ATR, - ISO7816_S_WAIT_READER, /* waiting for data from reader */ - ISO7816_S_WAIT_CARD, /* waiting for data from card */ + ISO7816_S_IN_ATR, /* while we are receiving the ATR */ + ISO7816_S_WAIT_APDU, /* waiting for start of new APDU */ + ISO7816_S_IN_APDU, /* inside a single APDU */ }; +/* detailed sub-states of ISO7816_S_IN_ATR */ enum atr_state { ATR_S_WAIT_TS, ATR_S_WAIT_T0, @@ -45,6 +63,8 @@ struct iso7816_3_handle { u_int8_t fi; u_int8_t di; + u_int8_t wi; + u_int32_t waiting_time; u_int8_t atr_idx; u_int8_t atr_hist_len; @@ -52,8 +72,9 @@ struct iso7816_3_handle { enum atr_state atr_state; u_int8_t atr[64]; - u_int16_t apdu_len; - u_int16_t apdu_idx; + struct simtrace_hdr sh; + + struct req_ctx *rctx; }; struct iso7816_3_handle isoh; @@ -71,6 +92,7 @@ static const u_int8_t di_table[] = { 0, 0, 2, 4, 8, 16, 32, 64, }; +/* compute the F/D ratio based on Fi and Di values */ static int compute_fidi_ratio(u_int8_t fi, u_int8_t di) { u_int16_t f, d; @@ -96,6 +118,43 @@ static int compute_fidi_ratio(u_int8_t fi, u_int8_t di) return ret; } +static void refill_rctx(struct iso7816_3_handle *ih) +{ + struct req_ctx *rctx; + + rctx = req_ctx_find_get(0, RCTX_STATE_FREE, + RCTX_STATE_LIBRFID_BUSY); + if (!rctx) { + ih->rctx = NULL; + return; + } + + ih->sh.cmd = SIMTRACE_MSGT_DATA; + + /* reserve spece at start of rctx */ + rctx->tot_len = sizeof(struct simtrace_hdr); + + ih->rctx = rctx; +} + +static void send_rctx(struct iso7816_3_handle *ih) +{ + struct req_ctx *rctx = ih->rctx; + + if (!rctx) + return; + + /* copy the simtrace header */ + memcpy(rctx->data, &ih->sh, sizeof(ih->sh)); + + req_ctx_set_state(rctx, RCTX_STATE_UDP_EP2_PENDING); + + memset(&ih->sh, 0, sizeof(ih->sh)); + ih->rctx = NULL; +} + + +/* Update the ATR sub-state */ static void set_atr_state(struct iso7816_3_handle *ih, enum atr_state new_atrs) { if (new_atrs == ATR_S_WAIT_TS) { @@ -110,30 +169,48 @@ static void set_atr_state(struct iso7816_3_handle *ih, enum atr_state new_atrs) ih->atr_state = new_atrs; } +#define ISO7816_3_INIT_WTIME 9600 +#define ISO7816_3_DEFAULT_WI 10 + +static void update_fidi(struct iso7816_3_handle *ih) +{ + int rc; + + rc = compute_fidi_ratio(ih->fi, ih->di); + if (rc > 0 && rc < 0x400) { + DEBUGPCR("computed Fi(%u) Di(%u) ratio: %d", ih->fi, ih->di, rc); + /* make sure UART uses new F/D ratio */ + usart->US_CR |= AT91C_US_RXDIS | AT91C_US_RSTRX; + usart->US_FIDI = rc & 0x3ff; + usart->US_CR |= AT91C_US_RXEN | AT91C_US_STTTO; + /* notify ETU timer about this */ + tc_etu_set_etu(rc); + } else + DEBUGPCRF("computed FiDi ratio %d unsupported", rc); +} + +/* Update the ISO 7816-3 APDU receiver state */ static void set_state(struct iso7816_3_handle *ih, enum iso7816_3_state new_state) { if (new_state == ISO7816_S_RESET) { usart->US_CR |= AT91C_US_RXDIS | AT91C_US_RSTRX; } else if (new_state == ISO7816_S_WAIT_ATR) { - int rc; - /* Initial Fi / Di ratio */ + /* Reset to initial Fi / Di ratio */ ih->fi = 1; ih->di = 1; - rc = compute_fidi_ratio(ih->fi, ih->di); - DEBUGPCRF("computed Fi(%u) Di(%u) ratio: %d", ih->fi, ih->di, rc); - usart->US_CR |= AT91C_US_RXDIS | AT91C_US_RSTRX; - usart->US_FIDI = rc & 0x3ff; - usart->US_CR |= AT91C_US_RXEN; + update_fidi(ih); + /* initialize todefault WI, this will be overwritten if we + * receive TC2, and it will be programmed into hardware after + * ATR is finished */ + ih->wi = ISO7816_3_DEFAULT_WI; + /* update waiting time to initial waiting time */ + ih->waiting_time = ISO7816_3_INIT_WTIME; + tc_etu_set_wtime(ih->waiting_time); + /* Set ATR sub-state to initial state */ set_atr_state(ih, ATR_S_WAIT_TS); - } else if (new_state == ISO7816_S_WAIT_READER) { - /* CLA INS P1 P2 LEN */ - ih->apdu_len = 5; - ih->apdu_idx = 0; - } else if (new_state == ISO7816_S_WAIT_CARD) { - /* 8.2.2 procedure bytes sent by the card */ - /* FIXME: NULL byte and similar oddities */ - ih->apdu_len += 2; - } + /* Notice that we are just coming out of reset */ + ih->sh.flags |= SIMTRACE_FLAG_ATR; + } if (ih->state == new_state) return; @@ -151,6 +228,10 @@ static enum atr_state next_intb_state(struct iso7816_3_handle *ih, u_int8_t ch) ih->atr_last_td = ch; goto from_td; case ATR_S_WAIT_TC: + if ((ih->atr_last_td & 0x0f) == 0x02) { + /* TC2 contains WI */ + ih->wi = ch; + } goto from_tc; case ATR_S_WAIT_TB: goto from_tb; @@ -204,7 +285,9 @@ process_byte_atr(struct iso7816_3_handle *ih, u_int8_t byte) set_atr_state(ih, ATR_S_WAIT_T0); break; case ATR_S_WAIT_T0: + /* obtain the number of historical bytes */ ih->atr_hist_len = byte & 0xf; + /* Mask out the hist-byte-length to indiicate T=0 */ set_atr_state(ih, next_intb_state(ih, byte & 0xf0)); break; case ATR_S_WAIT_TA: @@ -215,62 +298,31 @@ process_byte_atr(struct iso7816_3_handle *ih, u_int8_t byte) break; case ATR_S_WAIT_HIST: ih->atr_hist_len--; + /* after all historical bytes are recieved, go to TCK */ if (ih->atr_hist_len == 0) set_atr_state(ih, ATR_S_WAIT_TCK); break; case ATR_S_WAIT_TCK: - /* FIXME: process TCK */ + /* FIXME: process and verify the TCK */ set_atr_state(ih, ATR_S_DONE); - /* FIXME: update Fi/Di */ - rc = compute_fidi_ratio(ih->fi, ih->di); - if (rc > 0 && rc < 0x400) { - DEBUGPCR("computed FiDi ratio %d", rc); - /* update baud rate generator in UART */ - usart->US_CR |= AT91C_US_RXDIS| AT91C_US_RSTRX; - usart->US_FIDI = rc & 0x3ff; - usart->US_CR |= AT91C_US_RXEN; - } else - DEBUGPCRF("computed FiDi ratio %d unsupported", rc); - return ISO7816_S_WAIT_READER; + /* update baud rate generator with Fi/Di */ + update_fidi(ih); + /* update the waiting time */ + ih->waiting_time = 960 * di_table[ih->di] * ih->wi; + tc_etu_set_wtime(ih->waiting_time); + return ISO7816_S_WAIT_APDU; } return ISO7816_S_IN_ATR; } -/* process an incomng byte from the reader */ -static enum iso7816_3_state -process_byte_reader(struct iso7816_3_handle *ih, u_int8_t byte) -{ - /* add response length to total number of expected bytes */ - if (ih->apdu_idx == 4) - ih->apdu_len += byte; - - ih->apdu_idx++; - - /* once we have received all bytes, transition to card response */ - if (ih->apdu_idx == ih->apdu_len) - return ISO7816_S_WAIT_CARD; - - return ISO7816_S_WAIT_READER; -} - -/* process an incomng byte from the card */ -static enum iso7816_3_state -process_byte_card(struct iso7816_3_handle *ih, u_int8_t byte) -{ - ih->apdu_idx++; - - /* once we have received all bytes, apdu is finished */ - if (ih->apdu_idx == ih->apdu_len) - return ISO7816_S_WAIT_READER; - - return ISO7816_S_WAIT_CARD; -} - - -void process_byte(struct iso7816_3_handle *ih, u_int8_t byte) +static void process_byte(struct iso7816_3_handle *ih, u_int8_t byte) { int new_state = -1; + struct req_ctx *rctx; + + if (!ih->rctx) + refill_rctx(ih); switch (ih->state) { case ISO7816_S_RESET: @@ -279,18 +331,40 @@ void process_byte(struct iso7816_3_handle *ih, u_int8_t byte) case ISO7816_S_IN_ATR: new_state = process_byte_atr(ih, byte); break; - case ISO7816_S_WAIT_READER: - new_state = process_byte_reader(ih, byte); - break; - case ISO7816_S_WAIT_CARD: - new_state = process_byte_card(ih, byte); + case ISO7816_S_WAIT_APDU: + case ISO7816_S_IN_APDU: + new_state = ISO7816_S_IN_APDU; break; } + rctx = ih->rctx; + if (!rctx) { + DEBUGPCR("==> Lost byte, missing rctx"); + return; + } + + /* store the byte in the USB request context */ + rctx->data[rctx->tot_len] = byte; + rctx->tot_len++; + + if (rctx->tot_len >= rctx->size) + send_rctx(ih); + if (new_state != -1) set_state(ih, new_state); } +/* timeout of work waiting time during receive */ +void iso7816_wtime_expired(void) +{ + /* Always flush the URB at Rx timeout as this indicates end of APDU */ + if (isoh.rctx) { + isoh.sh.flags |= SIMTRACE_FLAG_WTIME_EXP; + send_rctx(&isoh); + } + set_state(&isoh, ISO7816_S_WAIT_APDU); +} + static __ramfunc void usart_irq(void) { u_int32_t csr = usart->US_CSR; @@ -301,7 +375,7 @@ static __ramfunc void usart_irq(void) if (csr & AT91C_US_RXRDY) { /* at least one character received */ octet = usart->US_RHR & 0xff; - DEBUGP("%02x ", octet); + //DEBUGP("%02x ", octet); process_byte(&isoh, octet); } @@ -310,7 +384,7 @@ static __ramfunc void usart_irq(void) } if (csr & (AT91C_US_PARE|AT91C_US_FRAME|AT91C_US_OVRE)) { - /* some error has occurrerd */ + /* FIXME: some error has occurrerd */ } } @@ -358,7 +432,6 @@ void iso_uart_rx_mode(void) usart->US_IER = AT91C_US_RXRDY | AT91C_US_OVRE | AT91C_US_FRAME | AT91C_US_PARE | AT91C_US_NACK | AT91C_US_ITERATION; - /* call interrupt handler once to set initial state RESET / ATR */ reset_pin_irq(SIMTRACE_PIO_nRST); } @@ -383,6 +456,8 @@ void iso_uart_init(void) { DEBUGPCR("USART Initializing"); + refill_rctx(&isoh); + /* make sure we get clock from the power management controller */ AT91F_US0_CfgPMC(); @@ -395,7 +470,8 @@ void iso_uart_init(void) AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL, &usart_irq); AT91F_AIC_EnableIt(AT91C_BASE_AIC, AT91C_ID_US0); - usart->US_CR = AT91C_US_RXDIS | AT91C_US_TXDIS | (AT91C_US_RSTRX | AT91C_US_RSTTX); + usart->US_CR = AT91C_US_RXDIS | AT91C_US_TXDIS | + (AT91C_US_RSTRX | AT91C_US_RSTTX); /* FIXME: wait for some time */ usart->US_CR = AT91C_US_RXDIS | AT91C_US_TXDIS; diff --git a/firmware/src/simtrace/iso7816_uart.h b/firmware/src/simtrace/iso7816_uart.h new file mode 100644 index 0000000..ed1c898 --- /dev/null +++ b/firmware/src/simtrace/iso7816_uart.h @@ -0,0 +1,6 @@ + +void iso_uart_dump(void); +void iso_uart_rst(unsigned int state); +void iso_uart_rx_mode(void); +void iso_uart_clk_master(unsigned int master); +void iso_uart_init(void); diff --git a/firmware/src/simtrace/main_simtrace.c b/firmware/src/simtrace/main_simtrace.c index d5a22dd..5e4302e 100644 --- a/firmware/src/simtrace/main_simtrace.c +++ b/firmware/src/simtrace/main_simtrace.c @@ -27,22 +27,26 @@ #include #include "../openpcd.h" #include -#include -#include #include -//#include +#include +#include void _init_func(void) { /* low-level hardware initialization */ pio_irq_init(); iso_uart_init(); + tc_etu_init(); + + usbtest_init(); /* high-level protocol */ //opicc_usbapi_init(); led_switch(1, 0); led_switch(2, 1); + + iso_uart_rx_mode(); } static void help(void) diff --git a/firmware/src/simtrace/tc_etu.c b/firmware/src/simtrace/tc_etu.c new file mode 100644 index 0000000..93d2da0 --- /dev/null +++ b/firmware/src/simtrace/tc_etu.c @@ -0,0 +1,124 @@ +/* SimTrace TC (Timer / Clock) support code + * (C) 2006 by Harald Welte + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include + +#include "../openpcd.h" + +static AT91PS_TCB tcb; +static AT91PS_TC tcetu = AT91C_BASE_TC0; + +static u_int16_t waiting_time = 9600; +static u_int16_t clocks_per_etu = 372; +static u_int16_t wait_events; + +static __ramfunc void tc_etu_irq(void) +{ + u_int32_t sr = tcetu->TC_SR; + static u_int16_t nr_events; + + if (sr & AT91C_TC_ETRGS) { + /* external trigger, i.e. we have seen a bit on I/O */ + //DEBUGPCR("tE"); + nr_events = 0; + /* Make sure we don't accept any additional external trigger */ + tcetu->TC_CMR &= ~AT91C_TC_ENETRG; + } + + if (sr & AT91C_TC_CPCS) { + /* Compare C event has occurred, i.e. 1 etu expired */ + //DEBUGPCR("tC"); + nr_events++; + if (nr_events >= wait_events) { + /* enable external triggers again to catch start bit */ + tcetu->TC_CMR |= AT91C_TC_ENETRG; + + /* disable and re-enable clock to make it stop */ + tcetu->TC_CCR = AT91C_TC_CLKDIS; + tcetu->TC_CCR = AT91C_TC_CLKEN; + + //DEBUGPCR("%u", nr_events); + + /* Indicate that the waiting time has expired */ + iso7816_wtime_expired(); + } + } +} + +static void recalc_nr_events(void) +{ + wait_events = waiting_time/12; + /* clocks_per_etu * 12 equals 'sbit + 8 data bits + parity + 2 stop bits */ + tcetu->TC_RC = clocks_per_etu * 12; +} + +void tc_etu_set_wtime(u_int16_t wtime) +{ + waiting_time = wtime; + recalc_nr_events(); +} + +void tc_etu_set_etu(u_int16_t etu) +{ + clocks_per_etu = etu; + recalc_nr_events(); +} + +void tc_etu_init(void) +{ + /* Cfg PA4(TCLK0), PA0(TIOA0), PA1(TIOB0) */ + AT91F_PIO_CfgPeriph(AT91C_BASE_PIOA, 0, + AT91C_PA4_TCLK0 | AT91C_PA0_TIOA0 | AT91C_PA1_TIOB0); + + AT91F_PMC_EnablePeriphClock(AT91C_BASE_PMC, + ((unsigned int) 1 << AT91C_ID_TC0)); + + /* Connect TCLK0 to XC0 */ + tcb->TCB_BMR &= ~(AT91C_TCB_TC0XC0S); + tcb->TCB_BMR |= AT91C_TCB_TC0XC0S_TCLK0; + + /* Register Interrupt handler */ + AT91F_AIC_ConfigureIt(AT91C_BASE_AIC, AT91C_ID_TC0, + OPENPCD_IRQ_PRIO_TC_FDT, + AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL, &tc_etu_irq); + AT91F_AIC_EnableIt(AT91C_BASE_AIC, AT91C_ID_TC0); + + /* enable interrupts for Compare-C and External Trigger */ + tcetu->TC_IER = AT91C_TC_CPCS | AT91C_TC_ETRGS; + + tcetu->TC_CMR = AT91C_TC_CLKS_XC0 | /* XC0 (TCLK0) clock */ + AT91C_TC_WAVE | /* Wave Mode */ + AT91C_TC_ETRGEDG_FALLING |/* Ext trig on falling edge */ + AT91C_TC_EEVT_TIOB | /* Ext trigger is TIOB0 */ + AT91C_TC_ENETRG | /* Enable ext. trigger */ + AT91C_TC_WAVESEL_UP_AUTO |/* Wave mode UP */ + AT91C_TC_ACPA_SET | /* Set TIOA0 on A compare */ + AT91C_TC_ACPC_CLEAR | /* Clear TIOA0 on C compare */ + AT91C_TC_ASWTRG_CLEAR; /* Clear TIOa0 on software trigger */ + + tc_etu_set_etu(372); + + /* Enable master clock for TC0 */ + tcetu->TC_CCR = AT91C_TC_CLKEN; + + /* Reset to start timers */ + tcb->TCB_BCR = 1; +} diff --git a/firmware/src/simtrace/tc_etu.h b/firmware/src/simtrace/tc_etu.h new file mode 100644 index 0000000..59d9031 --- /dev/null +++ b/firmware/src/simtrace/tc_etu.h @@ -0,0 +1,4 @@ + +void tc_etu_set_wtime(u_int16_t wtime); +void tc_etu_set_etu(u_int16_t etu); +void tc_etu_init(void); -- cgit v1.2.3 From 450a9326082248bcf62920f3ee078df8dcb07310 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Thu, 18 Nov 2010 15:12:42 +0100 Subject: simtrace: Introduce code for proper handling of PTS / PPS --- firmware/src/simtrace/iso7816_uart.c | 160 ++++++++++++++++++++++++++++++++--- 1 file changed, 148 insertions(+), 12 deletions(-) (limited to 'firmware/src/simtrace') diff --git a/firmware/src/simtrace/iso7816_uart.c b/firmware/src/simtrace/iso7816_uart.c index 18335f6..12669c4 100644 --- a/firmware/src/simtrace/iso7816_uart.c +++ b/firmware/src/simtrace/iso7816_uart.c @@ -43,6 +43,7 @@ enum iso7816_3_state { ISO7816_S_IN_ATR, /* while we are receiving the ATR */ ISO7816_S_WAIT_APDU, /* waiting for start of new APDU */ ISO7816_S_IN_APDU, /* inside a single APDU */ + ISO7816_S_IN_PTS, /* while we are inside the PTS / PSS */ }; /* detailed sub-states of ISO7816_S_IN_ATR */ @@ -58,6 +59,29 @@ enum atr_state { ATR_S_DONE, }; +/* detailed sub-states of ISO7816_S_IN_PTS */ +enum pts_state { + PTS_S_WAIT_REQ_PTSS, + PTS_S_WAIT_REQ_PTS0, + PTS_S_WAIT_REQ_PTS1, + PTS_S_WAIT_REQ_PTS2, + PTS_S_WAIT_REQ_PTS3, + PTS_S_WAIT_REQ_PCK, + PTS_S_WAIT_RESP_PTSS = PTS_S_WAIT_REQ_PTSS | 0x10, + PTS_S_WAIT_RESP_PTS0 = PTS_S_WAIT_REQ_PTS0 | 0x10, + PTS_S_WAIT_RESP_PTS1 = PTS_S_WAIT_REQ_PTS1 | 0x10, + PTS_S_WAIT_RESP_PTS2 = PTS_S_WAIT_REQ_PTS2 | 0x10, + PTS_S_WAIT_RESP_PTS3 = PTS_S_WAIT_REQ_PTS3 | 0x10, + PTS_S_WAIT_RESP_PCK = PTS_S_WAIT_REQ_PCK | 0x10, +}; + +#define _PTSS 0 +#define _PTS0 1 +#define _PTS1 2 +#define _PTS2 3 +#define _PTS3 4 +#define _PCK 5 + struct iso7816_3_handle { enum iso7816_3_state state; @@ -66,12 +90,16 @@ struct iso7816_3_handle { u_int8_t wi; u_int32_t waiting_time; + enum atr_state atr_state; u_int8_t atr_idx; u_int8_t atr_hist_len; u_int8_t atr_last_td; - enum atr_state atr_state; u_int8_t atr[64]; + enum pts_state pts_state; + u_int8_t pts_req[6]; + u_int8_t pts_resp[6]; + struct simtrace_hdr sh; struct req_ctx *rctx; @@ -215,7 +243,7 @@ static void set_state(struct iso7816_3_handle *ih, enum iso7816_3_state new_stat if (ih->state == new_state) return; - DEBUGPCR("7816 state %u -> %u", ih->state, new_state); + //DEBUGPCR("7816 state %u -> %u", ih->state, new_state); ih->state = new_state; } @@ -236,12 +264,6 @@ static enum atr_state next_intb_state(struct iso7816_3_handle *ih, u_int8_t ch) case ATR_S_WAIT_TB: goto from_tb; case ATR_S_WAIT_TA: - if ((ih->atr_last_td & 0x0f) == 0) { - /* This must be TA1 */ - ih->fi = ch >> 4; - ih->di = ch & 0xf; - DEBUGPCR("found Fi=%u Di=%u", ih->fi, ih->di); - } goto from_ta; default: DEBUGPCR("something wrong, old_state != TA"); @@ -268,8 +290,6 @@ from_tc: static enum iso7816_3_state process_byte_atr(struct iso7816_3_handle *ih, u_int8_t byte) { - int rc; - /* add byte to ATR buffer */ ih->atr[ih->atr_idx] = byte; ih->atr_idx++; @@ -305,8 +325,6 @@ process_byte_atr(struct iso7816_3_handle *ih, u_int8_t byte) case ATR_S_WAIT_TCK: /* FIXME: process and verify the TCK */ set_atr_state(ih, ATR_S_DONE); - /* update baud rate generator with Fi/Di */ - update_fidi(ih); /* update the waiting time */ ih->waiting_time = 960 * di_table[ih->di] * ih->wi; tc_etu_set_wtime(ih->waiting_time); @@ -316,6 +334,113 @@ process_byte_atr(struct iso7816_3_handle *ih, u_int8_t byte) return ISO7816_S_IN_ATR; } +/* Update the ATR sub-state */ +static void set_pts_state(struct iso7816_3_handle *ih, enum pts_state new_ptss) +{ + //DEBUGPCR("PTS state %u -> %u", ih->pts_state, new_ptss); + ih->pts_state = new_ptss; +} + +/* Determine the next PTS state */ +static enum pts_state next_pts_state(struct iso7816_3_handle *ih) +{ + u_int8_t is_resp = ih->pts_state & 0x10; + u_int8_t sstate = ih->pts_state & 0x0f; + u_int8_t *pts_ptr; + + if (!is_resp) + pts_ptr = ih->pts_req; + else + pts_ptr = ih->pts_resp; + + switch (sstate) { + case PTS_S_WAIT_REQ_PTSS: + goto from_ptss; + case PTS_S_WAIT_REQ_PTS0: + goto from_pts0; + case PTS_S_WAIT_REQ_PTS1: + goto from_pts1; + case PTS_S_WAIT_REQ_PTS2: + goto from_pts2; + case PTS_S_WAIT_REQ_PTS3: + goto from_pts3; + } + + if (ih->pts_state == PTS_S_WAIT_REQ_PCK) + return PTS_S_WAIT_RESP_PTSS; + +from_ptss: + return PTS_S_WAIT_REQ_PTS0 | is_resp; +from_pts0: + if (pts_ptr[_PTS0] & (1 << 4)) + return PTS_S_WAIT_REQ_PTS1 | is_resp; +from_pts1: + if (pts_ptr[_PTS0] & (1 << 5)) + return PTS_S_WAIT_REQ_PTS2 | is_resp; +from_pts2: + if (pts_ptr[_PTS0] & (1 << 6)) + return PTS_S_WAIT_REQ_PTS3 | is_resp; +from_pts3: + return PTS_S_WAIT_REQ_PCK | is_resp; +} + +static enum iso7816_3_state +process_byte_pts(struct iso7816_3_handle *ih, u_int8_t byte) +{ + switch (ih->pts_state) { + case PTS_S_WAIT_REQ_PTSS: + ih->pts_req[_PTSS] = byte; + break; + case PTS_S_WAIT_REQ_PTS0: + ih->pts_req[_PTS0] = byte; + break; + case PTS_S_WAIT_REQ_PTS1: + ih->pts_req[_PTS1] = byte; + break; + case PTS_S_WAIT_REQ_PTS2: + ih->pts_req[_PTS2] = byte; + break; + case PTS_S_WAIT_REQ_PTS3: + ih->pts_req[_PTS3] = byte; + break; + case PTS_S_WAIT_REQ_PCK: + /* FIXME: check PCK */ + ih->pts_req[_PCK] = byte; + break; + case PTS_S_WAIT_RESP_PTSS: + ih->pts_resp[_PTSS] = byte; + break; + case PTS_S_WAIT_RESP_PTS0: + ih->pts_resp[_PTS0] = byte; + break; + case PTS_S_WAIT_RESP_PTS1: + /* This must be TA1 */ + ih->fi = byte >> 4; + ih->di = byte & 0xf; + DEBUGPCR("found Fi=%u Di=%u", ih->fi, ih->di); + ih->pts_resp[_PTS1] = byte; + break; + case PTS_S_WAIT_RESP_PTS2: + ih->pts_resp[_PTS2] = byte; + break; + case PTS_S_WAIT_RESP_PTS3: + ih->pts_resp[_PTS3] = byte; + break; + case PTS_S_WAIT_RESP_PCK: + ih->pts_resp[_PCK] = byte; + /* FIXME: check PCK */ + set_pts_state(ih, PTS_S_WAIT_REQ_PTSS); + /* update baud rate generator with Fi/Di */ + update_fidi(ih); + /* Wait for the next APDU */ + return ISO7816_S_WAIT_APDU; + } + /* calculate the next state and set it */ + set_pts_state(ih, next_pts_state(ih)); + + return ISO7816_S_IN_PTS; +} + static void process_byte(struct iso7816_3_handle *ih, u_int8_t byte) { int new_state = -1; @@ -332,9 +457,16 @@ static void process_byte(struct iso7816_3_handle *ih, u_int8_t byte) new_state = process_byte_atr(ih, byte); break; case ISO7816_S_WAIT_APDU: + if (byte == 0xff) { + new_state = process_byte_pts(ih, byte); + goto out_silent; + } case ISO7816_S_IN_APDU: new_state = ISO7816_S_IN_APDU; break; + case ISO7816_S_IN_PTS: + new_state = process_byte_pts(ih, byte); + goto out_silent; } rctx = ih->rctx; @@ -350,6 +482,7 @@ static void process_byte(struct iso7816_3_handle *ih, u_int8_t byte) if (rctx->tot_len >= rctx->size) send_rctx(ih); +out_silent: if (new_state != -1) set_state(ih, new_state); } @@ -362,6 +495,9 @@ void iso7816_wtime_expired(void) isoh.sh.flags |= SIMTRACE_FLAG_WTIME_EXP; send_rctx(&isoh); } + if (isoh.state == ISO7816_S_IN_PTS) { + /* Timout during PTS: Card does not support PTS */ + } set_state(&isoh, ISO7816_S_WAIT_APDU); } -- cgit v1.2.3 From 629c4f81b89c41ffc2006b7af06ae734cdcbc864 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Thu, 18 Nov 2010 15:29:43 +0100 Subject: simtrace: fix problems causing bogus waiting time expirations --- firmware/src/simtrace/tc_etu.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'firmware/src/simtrace') diff --git a/firmware/src/simtrace/tc_etu.c b/firmware/src/simtrace/tc_etu.c index 93d2da0..fc52033 100644 --- a/firmware/src/simtrace/tc_etu.c +++ b/firmware/src/simtrace/tc_etu.c @@ -40,7 +40,10 @@ static __ramfunc void tc_etu_irq(void) //DEBUGPCR("tE"); nr_events = 0; /* Make sure we don't accept any additional external trigger */ - tcetu->TC_CMR &= ~AT91C_TC_ENETRG; + /* Enabling the line below will cause race conditions. We + * thus re-trigger at all zero-bits in the byte and thus wait + * up to 12 etu longer than required */ + //tcetu->TC_CMR &= ~AT91C_TC_ENETRG; } if (sr & AT91C_TC_CPCS) { @@ -74,6 +77,7 @@ void tc_etu_set_wtime(u_int16_t wtime) { waiting_time = wtime; recalc_nr_events(); + //DEBUGPCR("wtime=%u, actually waiting %u", wtime, wait_events * 12); } void tc_etu_set_etu(u_int16_t etu) -- cgit v1.2.3 From de125b725076e84134d5e9e9d3c56d3ef0bcf075 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 21 Nov 2010 20:18:23 +0100 Subject: simtrace: Make sure ATR is sent in its own RCTX and we re-allocate in time --- firmware/src/simtrace/iso7816_uart.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'firmware/src/simtrace') diff --git a/firmware/src/simtrace/iso7816_uart.c b/firmware/src/simtrace/iso7816_uart.c index 12669c4..cd1a2f0 100644 --- a/firmware/src/simtrace/iso7816_uart.c +++ b/firmware/src/simtrace/iso7816_uart.c @@ -102,6 +102,7 @@ struct iso7816_3_handle { struct simtrace_hdr sh; + int rctx_must_be_sent; struct req_ctx *rctx; }; @@ -325,6 +326,8 @@ process_byte_atr(struct iso7816_3_handle *ih, u_int8_t byte) case ATR_S_WAIT_TCK: /* FIXME: process and verify the TCK */ set_atr_state(ih, ATR_S_DONE); + /* send off the USB context */ + ih->rctx_must_be_sent = 1; /* update the waiting time */ ih->waiting_time = 960 * di_table[ih->di] * ih->wi; tc_etu_set_wtime(ih->waiting_time); @@ -469,6 +472,11 @@ static void process_byte(struct iso7816_3_handle *ih, u_int8_t byte) goto out_silent; } + /* The USB buffer could be gone in case the timer expired or code above + * this line explicitly sent it off */ + if (!ih->rctx) + refill_rctx(ih); + rctx = ih->rctx; if (!rctx) { DEBUGPCR("==> Lost byte, missing rctx"); @@ -479,8 +487,10 @@ static void process_byte(struct iso7816_3_handle *ih, u_int8_t byte) rctx->data[rctx->tot_len] = byte; rctx->tot_len++; - if (rctx->tot_len >= rctx->size) + if (rctx->tot_len >= rctx->size || ih->rctx_must_be_sent) { + ih->rctx_must_be_sent = 0; send_rctx(ih); + } out_silent: if (new_state != -1) -- cgit v1.2.3 From 9fa56a331ce29305835b9561ed9cc3ef169be1b9 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Thu, 9 Dec 2010 23:31:40 +0800 Subject: add missing usb_strings_dfu.txt file to simtrace directory --- firmware/src/simtrace/usb_strings_dfu.txt | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 firmware/src/simtrace/usb_strings_dfu.txt (limited to 'firmware/src/simtrace') diff --git a/firmware/src/simtrace/usb_strings_dfu.txt b/firmware/src/simtrace/usb_strings_dfu.txt new file mode 100644 index 0000000..ec93813 --- /dev/null +++ b/firmware/src/simtrace/usb_strings_dfu.txt @@ -0,0 +1,5 @@ +hmw-consulting.de +SimTrace RFID Simulator - DFU Mode +SimTrace DFU Configuration +SimTrace DFU Interface - Application Partition +SimTrace DFU Interface - Bootloader Partition -- cgit v1.2.3 From c50a7dc7063d4846b10c7d2b4b4020b239b84b7d Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Mon, 31 Jan 2011 11:49:47 +0100 Subject: typo: Fix typo, transform reqyests to requests. --- firmware/src/simtrace/main_simtrace.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'firmware/src/simtrace') diff --git a/firmware/src/simtrace/main_simtrace.c b/firmware/src/simtrace/main_simtrace.c index 5e4302e..740d35d 100644 --- a/firmware/src/simtrace/main_simtrace.c +++ b/firmware/src/simtrace/main_simtrace.c @@ -95,7 +95,7 @@ void _main_func(void) /* first we try to get rid of pending to-be-sent stuff */ usb_out_process(); - /* next we deal with incoming reqyests from USB EP1 (OUT) */ + /* next we deal with incoming requests from USB EP1 (OUT) */ usb_in_process(); udp_unthrottle(); -- cgit v1.2.3 From a59c6e2073d8f6126429b7ad17459a3b42237cde Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Wed, 15 Jun 2011 10:33:46 +0200 Subject: update USB strings (company name and some copy+paste mistakes) --- firmware/src/simtrace/usb_strings_app.txt | 2 +- firmware/src/simtrace/usb_strings_dfu.txt | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'firmware/src/simtrace') diff --git a/firmware/src/simtrace/usb_strings_app.txt b/firmware/src/simtrace/usb_strings_app.txt index c1d3c95..ba24b2b 100644 --- a/firmware/src/simtrace/usb_strings_app.txt +++ b/firmware/src/simtrace/usb_strings_app.txt @@ -1,6 +1,6 @@ SimTrace DFU Interface - Application Partition SimTrace DFU Interface - Bootloader Partition -hmw-consulting.de +sysmocom - systems for mobile communications GmbH SimTrace SIM Sniffer - Runtime Mode SimTrace Runtime Configuration SimTrace Runtime Interface diff --git a/firmware/src/simtrace/usb_strings_dfu.txt b/firmware/src/simtrace/usb_strings_dfu.txt index ec93813..ae2ff6a 100644 --- a/firmware/src/simtrace/usb_strings_dfu.txt +++ b/firmware/src/simtrace/usb_strings_dfu.txt @@ -1,5 +1,5 @@ -hmw-consulting.de -SimTrace RFID Simulator - DFU Mode +sysmocom - systems for mobile communications GmbH +SimTrace SIM Sniffer - DFU Mode SimTrace DFU Configuration SimTrace DFU Interface - Application Partition SimTrace DFU Interface - Bootloader Partition -- cgit v1.2.3 From cda126a7ef6fbb54a18a4786c15117800a13f7b3 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Thu, 16 Jun 2011 21:16:13 +0200 Subject: simtrace: add support for the analog bus switch --- firmware/src/simtrace/main_simtrace.c | 11 ++++- firmware/src/simtrace/sim_switch.c | 76 +++++++++++++++++++++++++++++++++++ firmware/src/simtrace/sim_switch.h | 7 ++++ 3 files changed, 93 insertions(+), 1 deletion(-) create mode 100644 firmware/src/simtrace/sim_switch.c create mode 100644 firmware/src/simtrace/sim_switch.h (limited to 'firmware/src/simtrace') diff --git a/firmware/src/simtrace/main_simtrace.c b/firmware/src/simtrace/main_simtrace.c index 740d35d..581fd59 100644 --- a/firmware/src/simtrace/main_simtrace.c +++ b/firmware/src/simtrace/main_simtrace.c @@ -31,6 +31,7 @@ #include #include +#include void _init_func(void) { @@ -38,6 +39,7 @@ void _init_func(void) pio_irq_init(); iso_uart_init(); tc_etu_init(); + sim_switch_init(); usbtest_init(); @@ -55,7 +57,9 @@ static void help(void) "c: toggle clock master/slave\r\n" "l: set nRST to low (active)\r\n" "h: set nRST to high (inactive)\r\n" - "o: set nRST to input\r\n"); + "o: set nRST to input\r\n" + "s: disconnect SIM bus switch\r\n" + "S: connect SIM bus switch\r\n"); } int _main_dbgu(char key) @@ -64,6 +68,11 @@ int _main_dbgu(char key) DEBUGPCRF("main_dbgu"); switch (key) { + case 's': + sim_switch_mode(0, 0); + break; + case 'S': + sim_switch_mode(1, 1); case 'r': iso_uart_rx_mode(); break; diff --git a/firmware/src/simtrace/sim_switch.c b/firmware/src/simtrace/sim_switch.c new file mode 100644 index 0000000..4f5621c --- /dev/null +++ b/firmware/src/simtrace/sim_switch.c @@ -0,0 +1,76 @@ +/* + * (C) 2011 by Harald Welte + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include "../simtrace.h" +#include "../openpcd.h" + +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) + +void sim_switch_mode(int connect_io, int connect_misc) +{ + if (connect_io) + AT91F_PIO_SetOutput(AT91C_BASE_PIOA, SIMTRACE_PIO_IO_SW); + else + AT91F_PIO_ClearOutput(AT91C_BASE_PIOA, SIMTRACE_PIO_IO_SW); + + if (connect_misc) + AT91F_PIO_SetOutput(AT91C_BASE_PIOA, SIMTRACE_PIO_SC_SW); + else + AT91F_PIO_ClearOutput(AT91C_BASE_PIOA, SIMTRACE_PIO_SC_SW); +} + +static void sw_sim_irq(u_int32_t pio) +{ + + if (!AT91F_PIO_IsInputSet(AT91C_BASE_PIOA, pio)) + DEBUGPCR("SIM card inserted"); + else + DEBUGPCR("SIM card removed"); +} + +void sim_switch_init(void) +{ + DEBUGPCR("ISO_SW Initializing"); + + /* make sure we get clock from the power management controller */ + AT91F_US0_CfgPMC(); + + /* configure both signals as output */ + AT91F_PIO_CfgOutput(AT91C_BASE_PIOA, SIMTRACE_PIO_SC_SW | + SIMTRACE_PIO_IO_SW); + + /* configure sim card detect */ + AT91F_PIO_CfgInput(AT91C_BASE_PIOA, SIMTRACE_PIO_SW_SIM); + AT91F_PIO_CfgInputFilter(AT91C_BASE_PIOA, SIMTRACE_PIO_SW_SIM); + pio_irq_register(SIMTRACE_PIO_SW_SIM, &sw_sim_irq); + pio_irq_enable(SIMTRACE_PIO_SW_SIM); +} diff --git a/firmware/src/simtrace/sim_switch.h b/firmware/src/simtrace/sim_switch.h new file mode 100644 index 0000000..01a6a66 --- /dev/null +++ b/firmware/src/simtrace/sim_switch.h @@ -0,0 +1,7 @@ +#ifndef SIMTRACE_ISO_SW_H +#define SIMTRACE_ISO_SW_H + +void sim_switch_mode(int connect_io, int connect_misc); +void sim_switch_init(void); + +#endif -- cgit v1.2.3 From ebaba1be96a6970705eb805dc3afc1d54f489ac8 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Fri, 17 Jun 2011 09:55:18 +0200 Subject: simtrace: introduce mode sniffer / mitm switching --- firmware/src/simtrace/main_simtrace.c | 48 +++++++++++++++++++++++++++++++++-- firmware/src/simtrace/sim_switch.c | 8 +++--- 2 files changed, 50 insertions(+), 6 deletions(-) (limited to 'firmware/src/simtrace') diff --git a/firmware/src/simtrace/main_simtrace.c b/firmware/src/simtrace/main_simtrace.c index 581fd59..8945a56 100644 --- a/firmware/src/simtrace/main_simtrace.c +++ b/firmware/src/simtrace/main_simtrace.c @@ -26,6 +26,7 @@ #include #include #include "../openpcd.h" +#include "../simtrace.h" #include #include @@ -51,6 +52,49 @@ void _init_func(void) iso_uart_rx_mode(); } +enum simtrace_md { + SIMTRACE_MD_OFF, + SIMTRACE_MD_SNIFFER, + SIMTRACE_MD_MITM, +}; + +#define UART1_PINS (SIMTRACE_PIO_nRST_PH | \ + SIMTRACE_PIO_CLK_PH | \ + SIMTRACE_PIO_CLK_PH_T | \ + SIMTRACE_PIO_IO_PH_RX | \ + SIMTRACE_PIO_IO_PH_TX) + +#define UART0_PINS (SIMTRACE_PIO_nRST | \ + SIMTRACE_PIO_CLK | \ + SIMTRACE_PIO_CLK_T | \ + SIMTRACE_PIO_IO | \ + SIMTRACE_PIO_IO_T) + +static void simtrace_set_mode(enum simtrace_md mode) +{ + switch (mode) { + case SIMTRACE_MD_SNIFFER: + DEBUGPCR("MODE: SNIFFER\n"); + /* switch UART1 pins to input, no pull-up */ + AT91F_PIO_CfgInput(AT91C_BASE_PIOA, UART1_PINS); + AT91F_PIO_CfgPullupDis(AT91C_BASE_PIOA, UART1_PINS); + AT91F_PIO_CfgInput(AT91C_BASE_PIOA, SIMTRACE_PIO_VCC_SIM); + AT91F_PIO_CfgPullupDis(AT91C_BASE_PIOA, SIMTRACE_PIO_VCC_SIM); + /* switch UART0 pins to 'ISO7816 card mode' */ + AT91F_PIO_CfgInput(AT91C_BASE_PIOA, UART0_PINS); + AT91F_PIO_CfgPullupDis(AT91C_BASE_PIOA, UART0_PINS); + AT91F_PIO_CfgPeriph(AT91C_BASE_PIOA, SIMTRACE_PIO_IO, SIMTRACE_PIO_CLK); + sim_switch_mode(1, 1); + break; + case SIMTRACE_MD_MITM: + DEBUGPCR("MODE: MITM\n"); + /* switch UART1 pins to 'ISO7816 card mode' */ + /* switch UART0 pins to 'ISO7816 reader mode' */ + sim_switch_mode(0, 0); + break; + } +} + static void help(void) { DEBUGPCR("r: iso uart Rx mode\r\n" @@ -69,10 +113,10 @@ int _main_dbgu(char key) switch (key) { case 's': - sim_switch_mode(0, 0); + simtrace_set_mode(SIMTRACE_MD_MITM); break; case 'S': - sim_switch_mode(1, 1); + simtrace_set_mode(SIMTRACE_MD_SNIFFER); case 'r': iso_uart_rx_mode(); break; diff --git a/firmware/src/simtrace/sim_switch.c b/firmware/src/simtrace/sim_switch.c index 4f5621c..118437a 100644 --- a/firmware/src/simtrace/sim_switch.c +++ b/firmware/src/simtrace/sim_switch.c @@ -38,14 +38,14 @@ void sim_switch_mode(int connect_io, int connect_misc) { if (connect_io) - AT91F_PIO_SetOutput(AT91C_BASE_PIOA, SIMTRACE_PIO_IO_SW); - else AT91F_PIO_ClearOutput(AT91C_BASE_PIOA, SIMTRACE_PIO_IO_SW); + else + AT91F_PIO_SetOutput(AT91C_BASE_PIOA, SIMTRACE_PIO_IO_SW); if (connect_misc) - AT91F_PIO_SetOutput(AT91C_BASE_PIOA, SIMTRACE_PIO_SC_SW); - else AT91F_PIO_ClearOutput(AT91C_BASE_PIOA, SIMTRACE_PIO_SC_SW); + else + AT91F_PIO_SetOutput(AT91C_BASE_PIOA, SIMTRACE_PIO_SC_SW); } static void sw_sim_irq(u_int32_t pio) -- cgit v1.2.3 From db3dca00622c1c390e46315c0caaf93e3ed7bded Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Tue, 21 Jun 2011 09:32:28 +0200 Subject: simtrace: add VCC_PHINE IRQ detection --- firmware/src/simtrace/sim_switch.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'firmware/src/simtrace') diff --git a/firmware/src/simtrace/sim_switch.c b/firmware/src/simtrace/sim_switch.c index 118437a..f83290f 100644 --- a/firmware/src/simtrace/sim_switch.c +++ b/firmware/src/simtrace/sim_switch.c @@ -57,6 +57,14 @@ static void sw_sim_irq(u_int32_t pio) DEBUGPCR("SIM card removed"); } +static void vcc_phone_irq(u_int32_t pio) +{ + if (!AT91F_PIO_IsInputSet(AT91C_BASE_PIOA, pio)) + DEBUGPCR("VCC_PHONE off"); + else + DEBUGPCR("VCC_PHONE on"); +} + void sim_switch_init(void) { DEBUGPCR("ISO_SW Initializing"); @@ -73,4 +81,15 @@ void sim_switch_init(void) AT91F_PIO_CfgInputFilter(AT91C_BASE_PIOA, SIMTRACE_PIO_SW_SIM); pio_irq_register(SIMTRACE_PIO_SW_SIM, &sw_sim_irq); pio_irq_enable(SIMTRACE_PIO_SW_SIM); + /* configure VCC_PHONE detection */ + AT91F_PIO_CfgInput(AT91C_BASE_PIOA, SIMTRACE_PIO_VCC_PHONE); + AT91F_PIO_CfgPullupDis(AT91C_BASE_PIOA, SIMTRACE_PIO_VCC_PHONE); + AT91F_PIO_CfgInputFilter(AT91C_BASE_PIOA, SIMTRACE_PIO_VCC_PHONE); + pio_irq_register(SIMTRACE_PIO_VCC_PHONE, &vcc_phone_irq); + pio_irq_enable(SIMTRACE_PIO_VCC_PHONE); + +#if 0 + AT91F_ADC_CfgPMC(); + AT91F_ADC_EnableChannel(AT91C_BASE_ADC, AT91C_ADC_CH7); +#endif } -- cgit v1.2.3 From e95ccd8f1db1f43d729153a30f3b5cf84cbc6606 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Tue, 21 Jun 2011 09:32:48 +0200 Subject: simtrace: switch VCC_SIM into output mode, as we use it to supply Vcc This is just a temp rework in the 1st generation prototype, as the bus switch has too high resistance for passing throuhg Vcc from the phone to the SIM. --- firmware/src/simtrace/main_simtrace.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'firmware/src/simtrace') diff --git a/firmware/src/simtrace/main_simtrace.c b/firmware/src/simtrace/main_simtrace.c index 8945a56..ed2921c 100644 --- a/firmware/src/simtrace/main_simtrace.c +++ b/firmware/src/simtrace/main_simtrace.c @@ -75,11 +75,17 @@ static void simtrace_set_mode(enum simtrace_md mode) switch (mode) { case SIMTRACE_MD_SNIFFER: DEBUGPCR("MODE: SNIFFER\n"); + /* switch UART1 pins to input, no pull-up */ AT91F_PIO_CfgInput(AT91C_BASE_PIOA, UART1_PINS); AT91F_PIO_CfgPullupDis(AT91C_BASE_PIOA, UART1_PINS); - AT91F_PIO_CfgInput(AT91C_BASE_PIOA, SIMTRACE_PIO_VCC_SIM); - AT91F_PIO_CfgPullupDis(AT91C_BASE_PIOA, SIMTRACE_PIO_VCC_SIM); + + /* switch VCC_SIM pin into output mode, as in the first + * generation prototype we use it directly to supply Vcc + * to the SIM */ + AT91F_PIO_CfgOutput(AT91C_BASE_PIOA, SIMTRACE_PIO_VCC_SIM); + AT91F_PIO_SetOutput(AT91C_BASE_PIOA, SIMTRACE_PIO_VCC_SIM); + /* switch UART0 pins to 'ISO7816 card mode' */ AT91F_PIO_CfgInput(AT91C_BASE_PIOA, UART0_PINS); AT91F_PIO_CfgPullupDis(AT91C_BASE_PIOA, UART0_PINS); -- cgit v1.2.3 From 30cb576ca5ed5281e997333fd522440faa595565 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Thu, 30 Jun 2011 13:55:00 +0200 Subject: simtrace: initialize sniffer mode right after start-up --- firmware/src/simtrace/main_simtrace.c | 40 +++++++++++++++++++---------------- 1 file changed, 22 insertions(+), 18 deletions(-) (limited to 'firmware/src/simtrace') diff --git a/firmware/src/simtrace/main_simtrace.c b/firmware/src/simtrace/main_simtrace.c index ed2921c..f919690 100644 --- a/firmware/src/simtrace/main_simtrace.c +++ b/firmware/src/simtrace/main_simtrace.c @@ -34,24 +34,6 @@ #include #include -void _init_func(void) -{ - /* low-level hardware initialization */ - pio_irq_init(); - iso_uart_init(); - tc_etu_init(); - sim_switch_init(); - - usbtest_init(); - - /* high-level protocol */ - //opicc_usbapi_init(); - led_switch(1, 0); - led_switch(2, 1); - - iso_uart_rx_mode(); -} - enum simtrace_md { SIMTRACE_MD_OFF, SIMTRACE_MD_SNIFFER, @@ -101,6 +83,26 @@ static void simtrace_set_mode(enum simtrace_md mode) } } +void _init_func(void) +{ + /* low-level hardware initialization */ + pio_irq_init(); + iso_uart_init(); + tc_etu_init(); + sim_switch_init(); + + usbtest_init(); + + /* high-level protocol */ + //opicc_usbapi_init(); + led_switch(1, 0); + led_switch(2, 1); + + iso_uart_rx_mode(); + simtrace_set_mode(SIMTRACE_MD_SNIFFER); +} + + static void help(void) { DEBUGPCR("r: iso uart Rx mode\r\n" @@ -108,6 +110,7 @@ static void help(void) "l: set nRST to low (active)\r\n" "h: set nRST to high (inactive)\r\n" "o: set nRST to input\r\n" + "r: set Rx mode for UART\r\n" "s: disconnect SIM bus switch\r\n" "S: connect SIM bus switch\r\n"); } @@ -123,6 +126,7 @@ int _main_dbgu(char key) break; case 'S': simtrace_set_mode(SIMTRACE_MD_SNIFFER); + break; case 'r': iso_uart_rx_mode(); break; -- cgit v1.2.3 From de0d7e35eed67bab478fda9eee7cb9edb1f34f04 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sat, 30 Jul 2011 00:39:22 +0200 Subject: simtrace: add some early spi flash utility routines This also adds a new 'main_factory' target for simtrace --- firmware/src/simtrace/main_factory.c | 80 +++++++++++++++++++ firmware/src/simtrace/spi_flash.c | 144 +++++++++++++++++++++++++++++++++++ 2 files changed, 224 insertions(+) create mode 100644 firmware/src/simtrace/main_factory.c create mode 100644 firmware/src/simtrace/spi_flash.c (limited to 'firmware/src/simtrace') diff --git a/firmware/src/simtrace/main_factory.c b/firmware/src/simtrace/main_factory.c new file mode 100644 index 0000000..3585fa6 --- /dev/null +++ b/firmware/src/simtrace/main_factory.c @@ -0,0 +1,80 @@ +/* SIMtrace factory programming + * (C) 2011 by Harald Welte + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + + +#include +#include +#include +#include +#include +#include +#include +#include "../openpcd.h" +#include "../simtrace.h" +#include +#include + +#include +#include +#include + +void _init_func(void) +{ + /* low-level hardware initialization */ + pio_irq_init(); + spiflash_init(); + + /* high-level protocol */ + //opicc_usbapi_init(); + led_switch(1, 0); + led_switch(2, 1); +} + +static void help(void) +{ + DEBUGPCR("f: read flash ID\r\n"); +} + +int _main_dbgu(char key) +{ + static int i = 0; + DEBUGPCRF("main_dbgu"); + + switch (key) { + case 'f': + spiflash_id(); + break; + case '?': + help(); + break; + } + + return -EINVAL; +} + +void _main_func(void) +{ + /* first we try to get rid of pending to-be-sent stuff */ + usb_out_process(); + + /* next we deal with incoming requests from USB EP1 (OUT) */ + usb_in_process(); + + udp_unthrottle(); +} diff --git a/firmware/src/simtrace/spi_flash.c b/firmware/src/simtrace/spi_flash.c new file mode 100644 index 0000000..98bc369 --- /dev/null +++ b/firmware/src/simtrace/spi_flash.c @@ -0,0 +1,144 @@ +/* Driver for a SST25VF040B spi flash attached to AT91SAM7 SPI + * (C) 2011 by Harald Welte + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include "../simtrace.h" +#include "../openpcd.h" + +#define DEBUGPSPI DEBUGP +//#define DEBUGPSPI(x, y ...) do { } while (0) + +static const AT91PS_SPI pSPI = AT91C_BASE_SPI; + +void spiflash_write_protect(int on) +{ + if (on) + AT91F_PIO_ClearOutput(AT91C_BASE_PIOA, PIO_SPIF_nWP); + else + AT91F_PIO_SetOutput(AT91C_BASE_PIOA, PIO_SPIF_nWP); +} + +#define SPI_PERIPHA (PIO_SPIF_SCK|PIO_SPIF_MOSI|PIO_SPIF_MISO|PIO_SPIF_nCS) + +static __ramfunc void spi_irq(void) +{ + u_int32_t status = pSPI->SPI_SR; + + AT91F_AIC_ClearIt(AT91C_BASE_AIC, AT91C_ID_SPI); +} + +void spiflash_init(void) +{ + DEBUGP("spiflash_init\r\n"); + + /* activate and enable the write protection */ + AT91F_PIO_CfgPullupDis(AT91C_BASE_PIOA, PIO_SPIF_nWP); + AT91F_PIO_CfgOutput(AT91C_BASE_PIOA, PIO_SPIF_nWP); + spiflash_write_protect(1); + + /* Configure PIOs for SCK, MOSI, MISO and nCS */ + AT91F_PIO_CfgPeriph(AT91C_BASE_PIOA, SPI_PERIPHA, 0); + + AT91F_SPI_CfgPMC(); + /* Spansion flash in v1.0p only supprts Mode 3 or Mode 0 */ + /* Mode 3: CPOL=1 nCPHA=0 CSAAT=0 BITS=0(8) MCK/2 */ + AT91F_SPI_CfgCs(AT91C_BASE_SPI, 0, AT91C_SPI_CPOL | + AT91C_SPI_BITS_8 | + (64 << 8)); + + /* SPI master mode, fixed CS, CS = 0 */ + AT91F_SPI_CfgMode(AT91C_BASE_SPI, AT91C_SPI_MSTR | + AT91C_SPI_PS_FIXED | + (0 << 16)); + + /* configure interrupt controller for SPI IRQ */ + AT91F_AIC_ConfigureIt(AT91C_BASE_AIC, AT91C_ID_SPI, + OPENPCD_IRQ_PRIO_SPI, + AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL, &spi_irq); + //AT91F_AIC_EnableIt(AT91C_BASE_AIC, AT91C_ID_SPI); + + /* Enable the SPI Controller */ + AT91F_SPI_Enable(AT91C_BASE_SPI); + AT91F_SPI_EnableIt(AT91C_BASE_SPI, AT91C_SPI_MODF | + AT91C_SPI_OVRES | + AT91C_SPI_ENDRX | + AT91C_SPI_ENDTX); +} + +static int spi_transceive(const u_int8_t *tx_data, u_int16_t tx_len, + u_int8_t *rx_data, u_int16_t *rx_len) +{ + u_int16_t tx_cur = 0; + u_int16_t rx_len_max = 0; + u_int16_t rx_cnt = 0; + + DEBUGPSPI("spi_transceive: enter(tx_len=%u) ", tx_len); + + if (rx_len) { + rx_len_max = *rx_len; + *rx_len = 0; + } + + //AT91F_SPI_Enable(pSPI); + while (1) { + u_int32_t sr = pSPI->SPI_SR; + u_int8_t tmp; + if (sr & AT91C_SPI_RDRF) { + tmp = pSPI->SPI_RDR; + rx_cnt++; + if (rx_len && *rx_len < rx_len_max) + rx_data[(*rx_len)++] = tmp; + } + if (sr & AT91C_SPI_TDRE) { + if (tx_len > tx_cur) + pSPI->SPI_TDR = tx_data[tx_cur++]; + } + if (tx_cur >= tx_len && rx_cnt >= tx_len) + break; + } + //AT91F_SPI_Disable(pSPI); + if (rx_data) + DEBUGPSPI(" leave(%02x %02x)\r\n", rx_data[0], rx_data[1]); + else + DEBUGPSPI("leave()\r\n"); + + return 0; +} + +void spiflash_id(void) +{ + const u_int8_t tx_data[] = { 0x9f, 0, 0, 0 }; + u_int8_t rx_data[] = { 0,0,0,0 }; + u_int16_t rx_len = sizeof(rx_data); + + spi_transceive(tx_data, sizeof(tx_data), rx_data, &rx_len); + DEBUGP("SPI ID: %02x %02x %02x\n", rx_data[1], rx_data[2], rx_data[3]); +} -- cgit v1.2.3 From e3d1fd9bbdb789196c25bdd5eb7536cda5ba39f3 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sat, 30 Jul 2011 02:08:36 +0200 Subject: DFU: add third 'alternate configuration' for RAM load This will allow us to load code directly into RAM without going through flash. --- firmware/src/simtrace/usb_strings_app.txt | 1 + firmware/src/simtrace/usb_strings_dfu.txt | 1 + 2 files changed, 2 insertions(+) (limited to 'firmware/src/simtrace') diff --git a/firmware/src/simtrace/usb_strings_app.txt b/firmware/src/simtrace/usb_strings_app.txt index ba24b2b..02cf326 100644 --- a/firmware/src/simtrace/usb_strings_app.txt +++ b/firmware/src/simtrace/usb_strings_app.txt @@ -1,5 +1,6 @@ SimTrace DFU Interface - Application Partition SimTrace DFU Interface - Bootloader Partition +SimTrace DFU Interface - RAM sysmocom - systems for mobile communications GmbH SimTrace SIM Sniffer - Runtime Mode SimTrace Runtime Configuration diff --git a/firmware/src/simtrace/usb_strings_dfu.txt b/firmware/src/simtrace/usb_strings_dfu.txt index ae2ff6a..2f65684 100644 --- a/firmware/src/simtrace/usb_strings_dfu.txt +++ b/firmware/src/simtrace/usb_strings_dfu.txt @@ -3,3 +3,4 @@ SimTrace SIM Sniffer - DFU Mode SimTrace DFU Configuration SimTrace DFU Interface - Application Partition SimTrace DFU Interface - Bootloader Partition +SimTrace DFU Interface - RAM -- cgit v1.2.3