From 22f4dca88cc008287b1ef01bb4da0d46cbcf76d1 Mon Sep 17 00:00:00 2001 From: iceman1001 Date: Wed, 21 Sep 2016 19:03:32 +0200 Subject: [PATCH] CHG: extracted some timers functionality, to get unified access to a timer/clock which counts in ticks. Moved stuff from util.c --- armsrc/Makefile | 3 +- armsrc/legicrf.c | 115 +++++++++------------- armsrc/legicrf.h | 5 + armsrc/ticks.c | 235 ++++++++++++++++++++++++++++++++++++++++++++ armsrc/ticks.h | 47 +++++++++ armsrc/util.c | 184 ---------------------------------- armsrc/util.h | 16 +-- client/cmdhflegic.c | 14 +-- common/crc.c | 26 +++++ common/crc.h | 1 + 10 files changed, 372 insertions(+), 274 deletions(-) create mode 100644 armsrc/ticks.c create mode 100644 armsrc/ticks.h diff --git a/armsrc/Makefile b/armsrc/Makefile index 7986dd7f..bfc5cbf2 100644 --- a/armsrc/Makefile +++ b/armsrc/Makefile @@ -50,7 +50,8 @@ THUMBSRC = start.c \ util.c \ string.c \ usb_cdc.c \ - cmd.c + cmd.c \ + ticks.c # These are to be compiled in ARM mode ARMSRC = fpgaloader.c \ diff --git a/armsrc/legicrf.c b/armsrc/legicrf.c index 2883bdfc..e8a2e1aa 100644 --- a/armsrc/legicrf.c +++ b/armsrc/legicrf.c @@ -7,7 +7,6 @@ //----------------------------------------------------------------------------- // LEGIC RF simulation code //----------------------------------------------------------------------------- - #include "legicrf.h" static struct legic_frame { @@ -73,7 +72,7 @@ static void setup_timer(void) { //#define RWD_TIME_0 90 /* RWD_TIME_PAUSE off, 40us on = 60us */ //#define RWD_TIME_PAUSE 30 /* 20us */ -// testing calculating in ticks instead of (us) microseconds. +// testing calculating in (us) microseconds. #define RWD_TIME_1 120 // READER_TIME_PAUSE 20us off, 80us on = 100us 80 * 1.5 == 120ticks #define RWD_TIME_0 60 // READER_TIME_PAUSE 20us off, 40us on = 60us 40 * 1.5 == 60ticks #define RWD_TIME_PAUSE 30 // 20us == 20 * 1.5 == 30ticks */ @@ -107,36 +106,17 @@ uint32_t sendFrameStop = 0; #ifndef COIL_PULSE # define COIL_PULSE(x) { \ SHORT_COIL; \ - Wait(RWD_TIME_PAUSE); \ + WaitTicks(RWD_TIME_PAUSE); \ OPEN_COIL; \ - Wait((x)); \ + WaitTicks((x)); \ } #endif -#ifndef GET_TICKS -# define GET_TICKS AT91C_BASE_TC0->TC_CV -#endif // ToDo: define a meaningful maximum size for auth_table. The bigger this is, the lower will be the available memory for traces. // Historically it used to be FREE_BUFFER_SIZE, which was 2744. #define LEGIC_CARD_MEMSIZE 1024 static uint8_t* cardmem; -static void Wait(uint32_t time){ - if ( time == 0 ) return; - time += GET_TICKS; - while (GET_TICKS < time); -} -// Starts Clock and waits until its reset -static void Reset(AT91PS_TC clock){ - clock->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; - while(clock->TC_CV > 1) ; -} - -// Starts Clock and waits until its reset -static void ResetClock(void){ - Reset(timer); -} - static void frame_append_bit(struct legic_frame * const f, int bit) { // Overflow, won't happen if (f->bits >= 31) return; @@ -166,8 +146,7 @@ static void frame_clean(struct legic_frame * const f) { */ /* Generate Keystream */ -static uint32_t get_key_stream(int skip, int count) -{ +uint32_t get_key_stream(int skip, int count) { uint32_t key = 0; int i; @@ -175,7 +154,7 @@ static uint32_t get_key_stream(int skip, int count) legic_prng_bc += prng_timer->TC_CV; // reset the prng timer. - Reset(prng_timer); + ResetTimer(prng_timer); /* If skip == -1, forward prng time based */ if(skip == -1) { @@ -209,7 +188,7 @@ static uint32_t get_key_stream(int skip, int count) /* Send a frame in tag mode, the FPGA must have been set up by * LegicRfSimulate */ -static void frame_send_tag(uint16_t response, uint8_t bits, uint8_t crypt) { +void frame_send_tag(uint16_t response, uint8_t bits, uint8_t crypt) { /* Bitbang the response */ LOW(GPIO_SSC_DOUT); AT91C_BASE_PIOA->PIO_OER = GPIO_SSC_DOUT; @@ -222,7 +201,7 @@ static void frame_send_tag(uint16_t response, uint8_t bits, uint8_t crypt) { } /* Wait for the frame start */ - Wait( TAG_FRAME_WAIT ); + WaitUS( TAG_FRAME_WAIT ); uint8_t bit = 0; for(int i = 0; i < bits; i++) { @@ -235,7 +214,7 @@ static void frame_send_tag(uint16_t response, uint8_t bits, uint8_t crypt) { else LOW(GPIO_SSC_DOUT); - Wait(100); + WaitUS(100); } LOW(GPIO_SSC_DOUT); } @@ -243,7 +222,7 @@ static void frame_send_tag(uint16_t response, uint8_t bits, uint8_t crypt) { /* Send a frame in reader mode, the FPGA must have been set up by * LegicRfReader */ -static void frame_sendAsReader(uint32_t data, uint8_t bits){ +void frame_sendAsReader(uint32_t data, uint8_t bits){ uint32_t starttime = GET_TICKS, send = 0; uint16_t mask = 1; @@ -298,14 +277,13 @@ static void frame_sendAsReader(uint32_t data, uint8_t bits){ static void frame_receiveAsReader(struct legic_frame * const f, uint8_t bits) { frame_clean(f); + if ( bits > 32 ) return; - uint8_t i = 0, edges = 0; + uint8_t i = bits, edges = 0; uint16_t lsfr = 0; uint32_t the_bit = 1, next_bit_at = 0, data; int old_level = 0, level = 0; - if(bits > 32) bits = 32; - AT91C_BASE_PIOA->PIO_ODR = GPIO_SSC_DIN; AT91C_BASE_PIOA->PIO_PER = GPIO_SSC_DIN; @@ -320,14 +298,14 @@ static void frame_receiveAsReader(struct legic_frame * const f, uint8_t bits) { data = lsfr; //FIXED time between sending frame and now listening frame. 330us - Wait( TAG_FRAME_WAIT - ( GET_TICKS - sendFrameStop ) ); - //Wait( TAG_FRAME_WAIT ); + //WaitTicks( GET_TICKS - sendFrameStop - TAG_FRAME_WAIT); + WaitTicks( 490 ); uint32_t starttime = GET_TICKS; next_bit_at = GET_TICKS + TAG_BIT_PERIOD; - for( i = 0; i < bits; i++) { + while ( i-- ){ edges = 0; while ( GET_TICKS < next_bit_at) { @@ -341,7 +319,7 @@ static void frame_receiveAsReader(struct legic_frame * const f, uint8_t bits) { next_bit_at += TAG_BIT_PERIOD; // We expect 42 edges == ONE - if(edges > 20 && edges < 64) + if(edges > 30 && edges < 64) data ^= the_bit; the_bit <<= 1; @@ -370,12 +348,12 @@ static void frame_receiveAsReader(struct legic_frame * const f, uint8_t bits) { // Setup pm3 as a Legic Reader static uint32_t setup_phase_reader(uint8_t iv) { - + // Switch on carrier and let the tag charge for 1ms HIGH(GPIO_SSC_DOUT); - SpinDelay(300); + WaitUS(300); - ResetUSClock(); + ResetTicks(); // no keystream yet legic_prng_init(0); @@ -389,8 +367,8 @@ static uint32_t setup_phase_reader(uint8_t iv) { frame_receiveAsReader(¤t_frame, 6); // fixed delay before sending ack. - Wait(360); // 240us = 360tick - legic_prng_forward(2); //240us / 100 == 2.4 iterations + WaitTicks(387); // 244us + legic_prng_forward(3); //240us / 100 == 2.4 iterations // Send obsfuscated acknowledgment frame. // 0x19 = 0x18 MIM22, 0x01 LSB READCMD @@ -402,17 +380,13 @@ static uint32_t setup_phase_reader(uint8_t iv) { default: break; } return current_frame.data; - - // fixed delay after setup phase. - Wait(375); // 260us == 375 ticks - legic_prng_forward(2);// 260us / 100 == 2.6 iterations } -static void LegicCommonInit(void) { +static void LegicCommonInit(void) { + FpgaDownloadAndGo(FPGA_BITSTREAM_HF); FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_TX); SetAdcMuxFor(GPIO_MUXSEL_HIPKD); - FpgaSetupSsc(); /* Bitbang the transmitter */ LOW(GPIO_SSC_DOUT); @@ -427,14 +401,15 @@ static void LegicCommonInit(void) { set_tracing(TRUE); crc_init(&legic_crc, 4, 0x19 >> 1, 0x5, 0); - StartCountUS(); + StartTicks(); } // Switch off carrier, make sure tag is reset static void switch_off_tag_rwd(void) { LOW(GPIO_SSC_DOUT); - SpinDelay(10); + WaitUS(200); WDT_HIT(); + Dbprintf("Exit Switch_off_tag_rwd"); } // calculate crc4 for a legic READ command @@ -451,6 +426,15 @@ static uint32_t legic4Crc(uint8_t legicCmd, uint16_t byte_index, uint8_t value, int legic_read_byte(int byte_index, int cmd_sz) { + // (us)| ticks + // ------------- + // 330 | 495 + // 460 | 690 + // 258 | 387 + // 244 | 366 + WaitTicks(332); + legic_prng_forward(2); // 460 / 100 = 4.6 iterations + uint8_t byte = 0, crc = 0, calcCrc = 0; uint32_t cmd = (byte_index << 1) | LEGIC_READ; @@ -466,9 +450,8 @@ int legic_read_byte(int byte_index, int cmd_sz) { return -1; } - Wait(690); // 460us == 690ticks - legic_prng_forward(4); // 460 / 100 = 4.6 iterations - + +// legic_prng_forward(2); // 460 / 100 = 4.6 iterations return byte; } @@ -504,7 +487,7 @@ int legic_write_byte(uint8_t byte, uint16_t addr, uint8_t addr_sz) { legic_prng_forward(2); /* we wait anyways */ - Wait(TAG_FRAME_WAIT); + WaitUS(TAG_FRAME_WAIT); frame_sendAsReader(cmd, cmd_sz); @@ -516,7 +499,7 @@ int legic_write_byte(uint8_t byte, uint16_t addr, uint8_t addr_sz) { int t, old_level = 0, edges = 0; int next_bit_at = 0; - Wait(TAG_FRAME_WAIT); + WaitUS(TAG_FRAME_WAIT); for( t = 0; t < 80; ++t) { edges = 0; @@ -532,13 +515,13 @@ int legic_write_byte(uint8_t byte, uint16_t addr, uint8_t addr_sz) { int t = timer->TC_CV; int c = t / TAG_BIT_PERIOD; - ResetClock(); + ResetTimer(timer); legic_prng_forward(c); return 0; } } - ResetClock(); + ResetTimer(timer); return -1; } @@ -802,7 +785,7 @@ static void frame_handle_tag(struct legic_frame const * const f) LED_C_ON(); // Reset prng timer - Reset(prng_timer); + ResetTimer(prng_timer); legic_prng_init(f->data); frame_send_tag(0x3d, 6, 1); /* 0x3d^0x26 = 0x1B */ @@ -812,8 +795,8 @@ static void frame_handle_tag(struct legic_frame const * const f) legic_prng_iv = f->data; - ResetClock(); - Wait(280); + ResetTimer(timer); + WaitUS(280); return; } @@ -824,8 +807,8 @@ static void frame_handle_tag(struct legic_frame const * const f) if((f->bits == 6) && (f->data == xored)) { legic_state = STATE_CON; - ResetClock(); - Wait(200); + ResetTimer(timer); + WaitUS(200); return; } else { @@ -851,9 +834,9 @@ static void frame_handle_tag(struct legic_frame const * const f) frame_send_tag(hash | data, 12, 1); - ResetClock(); + ResetTimer(timer); legic_prng_forward(2); - Wait(180); + WaitUS(180); return; } } @@ -1004,10 +987,6 @@ void LegicRfSimulate(int phase, int frame, int reqresp) LEDsoff(); } -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- - - //----------------------------------------------------------------------------- // Code up a string of octets at layer 2 (including CRC, we don't generate // that here) so that they can be transmitted to the reader. Doesn't transmit diff --git a/armsrc/legicrf.h b/armsrc/legicrf.h index 4e3177ee..2008f5b9 100644 --- a/armsrc/legicrf.h +++ b/armsrc/legicrf.h @@ -17,6 +17,7 @@ #include "string.h" #include "legic_prng.h" // legic PRNG impl #include "crc.h" // legic crc-4 +#include "ticks.h" // timers #define LEGIC_READ 0x01 #define LEGIC_WRITE 0x00 @@ -26,6 +27,10 @@ extern int LegicRfReader(int offset, int bytes, int iv); extern void LegicRfWriter(int offset, int bytes, int iv); extern void LegicRfRawWriter(int address, int data, int iv); +uint32_t get_key_stream(int skip, int count); +void frame_send_tag(uint16_t response, uint8_t bits, uint8_t crypt); +void frame_sendAsReader(uint32_t data, uint8_t bits); + int ice_legic_select_card(); void ice_legic_setup(); diff --git a/armsrc/ticks.c b/armsrc/ticks.c new file mode 100644 index 00000000..43b006ff --- /dev/null +++ b/armsrc/ticks.c @@ -0,0 +1,235 @@ +//----------------------------------------------------------------------------- +// Jonathan Westhues, Sept 2005 +// Iceman, Sept 2016 +// +// This code is licensed to you under the terms of the GNU GPL, version 2 or, +// at your option, any later version. See the LICENSE.txt file for the text of +// the license. +//----------------------------------------------------------------------------- +// Timers, Clocks functions used in LF or Legic where you would need detailed time. +//----------------------------------------------------------------------------- + +#include "ticks.h" + +// attempt at high resolution microsecond timer +// beware: timer counts in 21.3uS increments (1024/48Mhz) +void SpinDelayUs(int us) { + int ticks = (48 * us) >> 10; + + // Borrow a PWM unit for my real-time clock + AT91C_BASE_PWMC->PWMC_ENA = PWM_CHANNEL(0); + + // 48 MHz / 1024 gives 46.875 kHz + AT91C_BASE_PWMC_CH0->PWMC_CMR = PWM_CH_MODE_PRESCALER(10); + AT91C_BASE_PWMC_CH0->PWMC_CDTYR = 0; + AT91C_BASE_PWMC_CH0->PWMC_CPRDR = 0xffff; + + uint16_t start = AT91C_BASE_PWMC_CH0->PWMC_CCNTR; + + for(;;) { + uint16_t now = AT91C_BASE_PWMC_CH0->PWMC_CCNTR; + if (now == (uint16_t)(start + ticks)) + return; + + WDT_HIT(); + } +} + +void SpinDelay(int ms) { + // convert to uS and call microsecond delay function + SpinDelayUs(ms*1000); +} +// ------------------------------------------------------------------------- +// timer lib +// ------------------------------------------------------------------------- +// test procedure: +// +// ti = GetTickCount(); +// SpinDelay(1000); +// ti = GetTickCount() - ti; +// Dbprintf("timer(1s): %d t=%d", ti, GetTickCount()); + +void StartTickCount() { + // This timer is based on the slow clock. The slow clock frequency is between 22kHz and 40kHz. + // We can determine the actual slow clock frequency by looking at the Main Clock Frequency Register. + uint16_t mainf = AT91C_BASE_PMC->PMC_MCFR & 0xffff; // = 16 * main clock frequency (16MHz) / slow clock frequency + // set RealTimeCounter divider to count at 1kHz: + AT91C_BASE_RTTC->RTTC_RTMR = AT91C_RTTC_RTTRST | ((256000 + (mainf/2)) / mainf); + // note: worst case precision is approx 2.5% +} + +/* +* Get the current count. +*/ +uint32_t RAMFUNC GetTickCount(){ + return AT91C_BASE_RTTC->RTTC_RTVR;// was * 2; +} + +// ------------------------------------------------------------------------- +// microseconds timer +// ------------------------------------------------------------------------- +void StartCountUS() { + AT91C_BASE_PMC->PMC_PCER |= (1 << 12) | (1 << 13) | (1 << 14); + AT91C_BASE_TCB->TCB_BMR = AT91C_TCB_TC0XC0S_NONE | AT91C_TCB_TC1XC1S_TIOA0 | AT91C_TCB_TC2XC2S_NONE; + + // fast clock + // tick=1.5mks + AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; // timer disable + AT91C_BASE_TC0->TC_CMR = AT91C_TC_CLKS_TIMER_DIV3_CLOCK | // MCK(48MHz) / 32 + AT91C_TC_WAVE | AT91C_TC_WAVESEL_UP_AUTO | AT91C_TC_ACPA_CLEAR | + AT91C_TC_ACPC_SET | AT91C_TC_ASWTRG_SET; + AT91C_BASE_TC0->TC_RA = 1; + AT91C_BASE_TC0->TC_RC = 0xBFFF + 1; // 0xC000 + + AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; // timer disable + AT91C_BASE_TC1->TC_CMR = AT91C_TC_CLKS_XC1; // from timer 0 + + AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; + AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; + AT91C_BASE_TCB->TCB_BCR = 1; + + while (AT91C_BASE_TC1->TC_CV >= 1); +} + +uint32_t RAMFUNC GetCountUS(){ + //return (AT91C_BASE_TC1->TC_CV * 0x8000) + ((AT91C_BASE_TC0->TC_CV / 15) * 10); + // By suggestion from PwPiwi, http://www.proxmark.org/forum/viewtopic.php?pid=17548#p17548 + return (AT91C_BASE_TC1->TC_CV * 0x8000) + ((AT91C_BASE_TC0->TC_CV * 2) / 3); +} +void ResetUSClock(void) { + //enable clock of timer and software trigger + AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; + AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; + while (AT91C_BASE_TC1->TC_CV >= 1); +} +// attempt at high resolution microsecond timer +// beware: timer counts in 21.3uS increments (1024/48Mhz) +void SpinDelayCountUs(uint32_t us) { + if (us < 8) return; + us += GetCountUS(); + while ( GetCountUS() < us ){} +} +// static uint32_t GlobalUsCounter = 0; +// uint32_t RAMFUNC GetDeltaCountUS(){ + // uint32_t g_cnt = GetCountUS(); + // uint32_t g_res = g_cnt - GlobalUsCounter; + // GlobalUsCounter = g_cnt; + // return g_res; +// } +// ------------------------------------------------------------------------- +// Timer for iso14443 commands. Uses ssp_clk from FPGA +// ------------------------------------------------------------------------- +void StartCountSspClk() { + AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_TC0) | (1 << AT91C_ID_TC1) | (1 << AT91C_ID_TC2); // Enable Clock to all timers + AT91C_BASE_TCB->TCB_BMR = AT91C_TCB_TC0XC0S_TIOA1 // XC0 Clock = TIOA1 + | AT91C_TCB_TC1XC1S_NONE // XC1 Clock = none + | AT91C_TCB_TC2XC2S_TIOA0; // XC2 Clock = TIOA0 + + // configure TC1 to create a short pulse on TIOA1 when a rising edge on TIOB1 (= ssp_clk from FPGA) occurs: + AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; // disable TC1 + AT91C_BASE_TC1->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK // TC1 Clock = MCK(48MHz)/2 = 24MHz + | AT91C_TC_CPCSTOP // Stop clock on RC compare + | AT91C_TC_EEVTEDG_RISING // Trigger on rising edge of Event + | AT91C_TC_EEVT_TIOB // Event-Source: TIOB1 (= ssp_clk from FPGA = 13,56MHz/16) + | AT91C_TC_ENETRG // Enable external trigger event + | AT91C_TC_WAVESEL_UP // Upmode without automatic trigger on RC compare + | AT91C_TC_WAVE // Waveform Mode + | AT91C_TC_AEEVT_SET // Set TIOA1 on external event + | AT91C_TC_ACPC_CLEAR; // Clear TIOA1 on RC Compare + AT91C_BASE_TC1->TC_RC = 0x04; // RC Compare value = 0x04 + + // use TC0 to count TIOA1 pulses + AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; // disable TC0 + AT91C_BASE_TC0->TC_CMR = AT91C_TC_CLKS_XC0 // TC0 clock = XC0 clock = TIOA1 + | AT91C_TC_WAVE // Waveform Mode + | AT91C_TC_WAVESEL_UP // just count + | AT91C_TC_ACPA_CLEAR // Clear TIOA0 on RA Compare + | AT91C_TC_ACPC_SET; // Set TIOA0 on RC Compare + AT91C_BASE_TC0->TC_RA = 1; // RA Compare value = 1; pulse width to TC2 + AT91C_BASE_TC0->TC_RC = 0; // RC Compare value = 0; increment TC2 on overflow + + // use TC2 to count TIOA0 pulses (giving us a 32bit counter (TC0/TC2) clocked by ssp_clk) + AT91C_BASE_TC2->TC_CCR = AT91C_TC_CLKDIS; // disable TC2 + AT91C_BASE_TC2->TC_CMR = AT91C_TC_CLKS_XC2 // TC2 clock = XC2 clock = TIOA0 + | AT91C_TC_WAVE // Waveform Mode + | AT91C_TC_WAVESEL_UP; // just count + + AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; // enable and reset TC0 + AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; // enable and reset TC1 + AT91C_BASE_TC2->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; // enable and reset TC2 + + // synchronize the counter with the ssp_frame signal. + // Note: FPGA must be in any iso14443 mode, otherwise the frame signal would not be present + while(!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_FRAME)); // wait for ssp_frame to go high (start of frame) + while(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_FRAME); // wait for ssp_frame to be low + while(!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK)); // wait for ssp_clk to go high + + // note: up to now two ssp_clk rising edges have passed since the rising edge of ssp_frame + // it is now safe to assert a sync signal. This sets all timers to 0 on next active clock edge + AT91C_BASE_TCB->TCB_BCR = 1; // assert Sync (set all timers to 0 on next active clock edge) + // at the next (3rd) ssp_clk rising edge, TC1 will be reset (and not generate a clock signal to TC0) + // at the next (4th) ssp_clk rising edge, TC0 (the low word of our counter) will be reset. From now on, + // whenever the last three bits of our counter go 0, we can be sure to be in the middle of a frame transfer. + // (just started with the transfer of the 4th Bit). + + // The high word of the counter (TC2) will not reset until the low word (TC0) overflows. + // Therefore need to wait quite some time before we can use the counter. + while (AT91C_BASE_TC2->TC_CV >= 1); +} +void ResetSspClk(void) { + //enable clock of timer and software trigger + AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; + AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; + AT91C_BASE_TC2->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; +} + +uint32_t RAMFUNC GetCountSspClk(){ + + uint32_t tmp_count = (AT91C_BASE_TC2->TC_CV << 16) | AT91C_BASE_TC0->TC_CV; + if ((tmp_count & 0x0000ffff) == 0) //small chance that we may have missed an increment in TC2 + return (AT91C_BASE_TC2->TC_CV << 16); + return tmp_count; +} + + +void StartTicks(void){ + //initialization of the timer + AT91C_BASE_PMC->PMC_PCER |= (1 << 12) | (1 << 13) | (1 << 14); + AT91C_BASE_TCB->TCB_BMR = AT91C_TCB_TC0XC0S_NONE | AT91C_TCB_TC1XC1S_TIOA0 | AT91C_TCB_TC2XC2S_NONE; + + // fast clock TC0 + // tick=1.5mks + AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; // timer disable + AT91C_BASE_TC0->TC_CMR = AT91C_TC_CLKS_TIMER_DIV3_CLOCK; //clock at 48/32 MHz + + // Enable and reset timer + AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; + AT91C_BASE_TCB->TCB_BCR = 1; + // wait until timer becomes zero. + while (AT91C_BASE_TC0->TC_CV > 1); +} +// Wait - Spindelay in ticks. +// if called with a high number, this will trigger the WDT... +void WaitTicks(uint32_t ticks){ + if ( ticks == 0 ) return; + ticks += GET_TICKS; + while (GET_TICKS < ticks); +} +// Wait / Spindelay in us (microseconds) +// 1us = 1.5ticks. +void WaitUS(uint16_t us){ + if ( us == 0 ) return; + WaitTicks( (uint32_t)(us * 1.5) ); +} +void WaitMS(uint16_t ms){ + if (ms == 0) return; + WaitTicks( (uint32_t)(ms * 1500) ); +} +// Starts Clock and waits until its reset +void ResetTicks(){ + ResetTimer(AT91C_BASE_TC0); +} +void ResetTimer(AT91PS_TC timer){ + timer->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; + while(timer->TC_CV > 1) ; +} diff --git a/armsrc/ticks.h b/armsrc/ticks.h new file mode 100644 index 00000000..050cb6ae --- /dev/null +++ b/armsrc/ticks.h @@ -0,0 +1,47 @@ +//----------------------------------------------------------------------------- +// Jonathan Westhues, Aug 2005 +// Iceman, Sept 2016 +// +// This code is licensed to you under the terms of the GNU GPL, version 2 or, +// at your option, any later version. See the LICENSE.txt file for the text of +// the license. +//----------------------------------------------------------------------------- +// Timers, Clocks functions used in LF or Legic where you would need detailed time. +//----------------------------------------------------------------------------- + +#ifndef __TICKS_H +#define __TICKS_H + +#include +#include +#include "common.h" +#include "apps.h" +#include "proxmark3.h" + +#ifndef GET_TICKS +# define GET_TICKS AT91C_BASE_TC0->TC_CV +#endif + +void SpinDelay(int ms); +void SpinDelayUs(int us); + +void StartTickCount(void); +uint32_t RAMFUNC GetTickCount(void); + +void StartCountUS(void); +uint32_t RAMFUNC GetCountUS(void); +void ResetUSClock(void); +void SpinDelayCountUs(uint32_t us); +//uint32_t RAMFUNC GetDeltaCountUS(void); + +void StartCountSspClk(); +void ResetSspClk(void); +uint32_t RAMFUNC GetCountSspClk(); + +extern void StartTicks(void); +extern void WaitTicks(uint32_t ticks); +extern void WaitUS(uint16_t us); +extern void WaitMS(uint16_t ms); +extern void ResetTicks(); +extern void ResetTimer(AT91PS_TC timer); +#endif \ No newline at end of file diff --git a/armsrc/util.c b/armsrc/util.c index be6170d3..1716a113 100644 --- a/armsrc/util.c +++ b/armsrc/util.c @@ -233,35 +233,6 @@ int BUTTON_HELD(int ms) { return BUTTON_ERROR; } -// attempt at high resolution microsecond timer -// beware: timer counts in 21.3uS increments (1024/48Mhz) -void SpinDelayUs(int us) { - int ticks = (48 * us) >> 10; - - // Borrow a PWM unit for my real-time clock - AT91C_BASE_PWMC->PWMC_ENA = PWM_CHANNEL(0); - - // 48 MHz / 1024 gives 46.875 kHz - AT91C_BASE_PWMC_CH0->PWMC_CMR = PWM_CH_MODE_PRESCALER(10); - AT91C_BASE_PWMC_CH0->PWMC_CDTYR = 0; - AT91C_BASE_PWMC_CH0->PWMC_CPRDR = 0xffff; - - uint16_t start = AT91C_BASE_PWMC_CH0->PWMC_CCNTR; - - for(;;) { - uint16_t now = AT91C_BASE_PWMC_CH0->PWMC_CCNTR; - if (now == (uint16_t)(start + ticks)) - return; - - WDT_HIT(); - } -} - -void SpinDelay(int ms) { - // convert to uS and call microsecond delay function - SpinDelayUs(ms*1000); -} - /* Similar to FpgaGatherVersion this formats stored version information * into a string representation. It takes a pointer to the struct version_information, * verifies the magic properties, then stores a formatted string, prefixed by @@ -295,158 +266,3 @@ void FormatVersionInformation(char *dst, int len, const char *prefix, void *vers strncat(dst, v->buildtime, len - strlen(dst) - 1); strncat(dst, "\n", len - strlen(dst) - 1); } - -// ------------------------------------------------------------------------- -// timer lib -// ------------------------------------------------------------------------- -// test procedure: -// -// ti = GetTickCount(); -// SpinDelay(1000); -// ti = GetTickCount() - ti; -// Dbprintf("timer(1s): %d t=%d", ti, GetTickCount()); - -void StartTickCount() { - // This timer is based on the slow clock. The slow clock frequency is between 22kHz and 40kHz. - // We can determine the actual slow clock frequency by looking at the Main Clock Frequency Register. - uint16_t mainf = AT91C_BASE_PMC->PMC_MCFR & 0xffff; // = 16 * main clock frequency (16MHz) / slow clock frequency - // set RealTimeCounter divider to count at 1kHz: - AT91C_BASE_RTTC->RTTC_RTMR = AT91C_RTTC_RTTRST | ((256000 + (mainf/2)) / mainf); - // note: worst case precision is approx 2.5% -} - -/* -* Get the current count. -*/ -uint32_t RAMFUNC GetTickCount(){ - return AT91C_BASE_RTTC->RTTC_RTVR;// was * 2; -} - -// ------------------------------------------------------------------------- -// microseconds timer -// ------------------------------------------------------------------------- -void StartCountUS() { - AT91C_BASE_PMC->PMC_PCER |= (0x1 << 12) | (0x1 << 13) | (0x1 << 14); -// AT91C_BASE_TCB->TCB_BMR = AT91C_TCB_TC1XC1S_TIOA0; - AT91C_BASE_TCB->TCB_BMR = AT91C_TCB_TC0XC0S_NONE | AT91C_TCB_TC1XC1S_TIOA0 | AT91C_TCB_TC2XC2S_NONE; - - // fast clock - AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; // timer disable - AT91C_BASE_TC0->TC_CMR = AT91C_TC_CLKS_TIMER_DIV3_CLOCK | // MCK(48MHz)/32 -- tick=1.5mks - AT91C_TC_WAVE | AT91C_TC_WAVESEL_UP_AUTO | AT91C_TC_ACPA_CLEAR | - AT91C_TC_ACPC_SET | AT91C_TC_ASWTRG_SET; - AT91C_BASE_TC0->TC_RA = 1; - AT91C_BASE_TC0->TC_RC = 0xBFFF + 1; // 0xC000 - - AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; // timer disable - AT91C_BASE_TC1->TC_CMR = AT91C_TC_CLKS_XC1; // from timer 0 - - AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; - AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; - AT91C_BASE_TCB->TCB_BCR = 1; - - while (AT91C_BASE_TC1->TC_CV >= 1); -} - -uint32_t RAMFUNC GetCountUS(){ - //return (AT91C_BASE_TC1->TC_CV * 0x8000) + ((AT91C_BASE_TC0->TC_CV / 15) * 10); - // By suggestion from PwPiwi, http://www.proxmark.org/forum/viewtopic.php?pid=17548#p17548 - return (AT91C_BASE_TC1->TC_CV * 0x8000) + ((AT91C_BASE_TC0->TC_CV * 2) / 3); -} -void ResetUSClock(void) { - //enable clock of timer and software trigger - AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; - AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; - while (AT91C_BASE_TC1->TC_CV >= 1); -} -// attempt at high resolution microsecond timer -// beware: timer counts in 21.3uS increments (1024/48Mhz) -void SpinDelayCountUs(uint32_t us) { - if (us < 8) return; - us += GetCountUS(); - while ( GetCountUS() < us ){} -} -// static uint32_t GlobalUsCounter = 0; - -// uint32_t RAMFUNC GetDeltaCountUS(){ - // uint32_t g_cnt = GetCountUS(); - // uint32_t g_res = g_cnt - GlobalUsCounter; - // GlobalUsCounter = g_cnt; - // return g_res; -// } - - -// ------------------------------------------------------------------------- -// Timer for iso14443 commands. Uses ssp_clk from FPGA -// ------------------------------------------------------------------------- -void StartCountSspClk() { - AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_TC0) | (1 << AT91C_ID_TC1) | (1 << AT91C_ID_TC2); // Enable Clock to all timers - AT91C_BASE_TCB->TCB_BMR = AT91C_TCB_TC0XC0S_TIOA1 // XC0 Clock = TIOA1 - | AT91C_TCB_TC1XC1S_NONE // XC1 Clock = none - | AT91C_TCB_TC2XC2S_TIOA0; // XC2 Clock = TIOA0 - - // configure TC1 to create a short pulse on TIOA1 when a rising edge on TIOB1 (= ssp_clk from FPGA) occurs: - AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; // disable TC1 - AT91C_BASE_TC1->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK // TC1 Clock = MCK(48MHz)/2 = 24MHz - | AT91C_TC_CPCSTOP // Stop clock on RC compare - | AT91C_TC_EEVTEDG_RISING // Trigger on rising edge of Event - | AT91C_TC_EEVT_TIOB // Event-Source: TIOB1 (= ssp_clk from FPGA = 13,56MHz/16) - | AT91C_TC_ENETRG // Enable external trigger event - | AT91C_TC_WAVESEL_UP // Upmode without automatic trigger on RC compare - | AT91C_TC_WAVE // Waveform Mode - | AT91C_TC_AEEVT_SET // Set TIOA1 on external event - | AT91C_TC_ACPC_CLEAR; // Clear TIOA1 on RC Compare - AT91C_BASE_TC1->TC_RC = 0x04; // RC Compare value = 0x04 - - // use TC0 to count TIOA1 pulses - AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; // disable TC0 - AT91C_BASE_TC0->TC_CMR = AT91C_TC_CLKS_XC0 // TC0 clock = XC0 clock = TIOA1 - | AT91C_TC_WAVE // Waveform Mode - | AT91C_TC_WAVESEL_UP // just count - | AT91C_TC_ACPA_CLEAR // Clear TIOA0 on RA Compare - | AT91C_TC_ACPC_SET; // Set TIOA0 on RC Compare - AT91C_BASE_TC0->TC_RA = 1; // RA Compare value = 1; pulse width to TC2 - AT91C_BASE_TC0->TC_RC = 0; // RC Compare value = 0; increment TC2 on overflow - - // use TC2 to count TIOA0 pulses (giving us a 32bit counter (TC0/TC2) clocked by ssp_clk) - AT91C_BASE_TC2->TC_CCR = AT91C_TC_CLKDIS; // disable TC2 - AT91C_BASE_TC2->TC_CMR = AT91C_TC_CLKS_XC2 // TC2 clock = XC2 clock = TIOA0 - | AT91C_TC_WAVE // Waveform Mode - | AT91C_TC_WAVESEL_UP; // just count - - AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; // enable and reset TC0 - AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; // enable and reset TC1 - AT91C_BASE_TC2->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; // enable and reset TC2 - - // synchronize the counter with the ssp_frame signal. - // Note: FPGA must be in any iso14443 mode, otherwise the frame signal would not be present - while(!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_FRAME)); // wait for ssp_frame to go high (start of frame) - while(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_FRAME); // wait for ssp_frame to be low - while(!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK)); // wait for ssp_clk to go high - - // note: up to now two ssp_clk rising edges have passed since the rising edge of ssp_frame - // it is now safe to assert a sync signal. This sets all timers to 0 on next active clock edge - AT91C_BASE_TCB->TCB_BCR = 1; // assert Sync (set all timers to 0 on next active clock edge) - // at the next (3rd) ssp_clk rising edge, TC1 will be reset (and not generate a clock signal to TC0) - // at the next (4th) ssp_clk rising edge, TC0 (the low word of our counter) will be reset. From now on, - // whenever the last three bits of our counter go 0, we can be sure to be in the middle of a frame transfer. - // (just started with the transfer of the 4th Bit). - - // The high word of the counter (TC2) will not reset until the low word (TC0) overflows. - // Therefore need to wait quite some time before we can use the counter. - while (AT91C_BASE_TC2->TC_CV >= 1); -} -void ResetSspClk(void) { - //enable clock of timer and software trigger - AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; - AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; - AT91C_BASE_TC2->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; -} - -uint32_t RAMFUNC GetCountSspClk(){ - uint32_t tmp_count = (AT91C_BASE_TC2->TC_CV << 16) | AT91C_BASE_TC0->TC_CV; - if ((tmp_count & 0x0000ffff) == 0) //small chance that we may have missed an increment in TC2 - return (AT91C_BASE_TC2->TC_CV << 16); - return tmp_count; -} - diff --git a/armsrc/util.h b/armsrc/util.h index 3ff70dd4..d3235292 100644 --- a/armsrc/util.h +++ b/armsrc/util.h @@ -18,6 +18,7 @@ #include "apps.h" #include "BigBuf.h" #include "proxmark3.h" +#include "ticks.h" #define BYTEx(x, n) (((x) >> (n * 8)) & 0xff ) @@ -51,25 +52,10 @@ void rol(uint8_t *data, const size_t len); void lsl (uint8_t *data, size_t len); int32_t le24toh (uint8_t data[3]); -void SpinDelay(int ms); -void SpinDelayUs(int us); void LED(int led, int ms); void LEDsoff(); int BUTTON_CLICKED(int ms); int BUTTON_HELD(int ms); void FormatVersionInformation(char *dst, int len, const char *prefix, void *version_information); -void StartTickCount(); -uint32_t RAMFUNC GetTickCount(); - -void StartCountUS(); -uint32_t RAMFUNC GetCountUS(); -void ResetUSClock(void); -void SpinDelayCountUs(uint32_t us); -//uint32_t RAMFUNC GetDeltaCountUS(); - -void StartCountSspClk(); -void ResetSspClk(void); -uint32_t RAMFUNC GetCountSspClk(); - #endif diff --git a/client/cmdhflegic.c b/client/cmdhflegic.c index 2cfb286e..b52034dc 100644 --- a/client/cmdhflegic.c +++ b/client/cmdhflegic.c @@ -404,13 +404,15 @@ int CmdLegicRFRead(const char *Cmd) { PrintAndLog("Current IV: 0x%02x", IV); // get some prng bytes from - uint8_t temp[12]; + uint8_t temp[32]; legic_prng_init(IV); - for ( uint8_t j = 0; j < sizeof(temp); ++j) - temp[j] = legic_prng_get_bits(8); - - PrintAndLog("PRNG: %s", sprint_hex(temp, sizeof(temp))); - + for ( uint8_t j = 0; j < sizeof(temp); ++j) { + temp[j] = legic_prng_get_bit(1); + legic_prng_forward(1); + //PrintAndLog("PRNG: %s", sprint_hex(temp, sizeof(temp))); + } + PrintAndLog("PRNG: %s", sprint_bin(temp, sizeof(temp))); + UsbCommand c = {CMD_READER_LEGIC_RF, {offset, len, IV}}; clearCommandBuffer(); SendCommand(&c); diff --git a/common/crc.c b/common/crc.c index 72e6f024..2f11f5f4 100644 --- a/common/crc.c +++ b/common/crc.c @@ -43,6 +43,8 @@ void crc_update(crc_t *crc, uint32_t indata, int data_width){ crc->state ^= indata << (crc->order - data_width); for( uint8_t bit = data_width; bit > 0; --bit) { + + // Try to divide the current data bit. if (crc->state & crc->topbit) crc->state = (crc->state << 1) ^ crc->polynom; @@ -51,6 +53,22 @@ void crc_update(crc_t *crc, uint32_t indata, int data_width){ } } +void crc_update2(crc_t *crc, uint32_t data, int data_width) +{ + if (crc->refin) data = reflect(data, data_width); + + int i; + for(i=0; istate; + crc->state = crc->state >> 1; + if( (oldstate^data) & 1 ) { + crc->state ^= crc->polynom; + } + data >>= 1; + } +} + + uint32_t crc_finish(crc_t *crc) { uint32_t val = crc->state; if (crc->refout) val = reflect(val, crc->order); @@ -83,6 +101,14 @@ uint32_t CRC8Maxim(uint8_t *buff, size_t size) { } // width=4 poly=0xC, reversed poly=0x7 init=0x5 refin=true refout=true xorout=0x0000 check= name="CRC-4/LEGIC" +uint32_t CRC4Legic(uint8_t *cmd, size_t size) { + crc_t crc; + crc_init_ref(&crc, 4, 0x19 >> 1, 0x5, 0, TRUE, TRUE); + crc_update2(&crc, 1, 1); /* CMD_READ */ + crc_update2(&crc, cmd[0], 8); + crc_update2(&crc, cmd[1], 8); + return reflect(crc_finish(&crc), 4); +} // width=8 poly=0x63, reversed poly=0x8D init=0x55 refin=true refout=true xorout=0x0000 check=0xC6 name="CRC-8/LEGIC" // the CRC needs to be reversed before returned. uint32_t CRC8Legic(uint8_t *buff, size_t size) { diff --git a/common/crc.h b/common/crc.h index d7314379..56f04357 100644 --- a/common/crc.h +++ b/common/crc.h @@ -44,6 +44,7 @@ extern void crc_init(crc_t *crc, int order, uint32_t polynom, uint32_t initial_v * data_width lower-most bits are used). */ extern void crc_update(crc_t *crc, uint32_t data, int data_width); +extern void crc_update2(crc_t *crc, uint32_t data, int data_width); /* Clean the crc state, e.g. reset it to initial_value */ extern void crc_clear(crc_t *crc); -- 2.39.2