Bootrom: Enable serial number from flash

* Add `.ramfunc` section to bootrom loader script
* exclude spiffs functionality from flashmem.h/flashmem.c
   (allows bootrom to use flashmem)
* hide unused tick.h / flashmem.h functions from bootrom
   (not technically necessary; see comments)
* bootrom: add source files, include path, and defines when
  `PLATFORM_DEFS` defines `WITH_FLASH`
* Define `AS_BOOTROM` to indicate code is building for bootrom
This commit is contained in:
Henry Gabryjelski 2023-02-17 16:59:00 -08:00
commit 44676bde72
9 changed files with 373 additions and 272 deletions

View file

@ -2684,7 +2684,7 @@ void __attribute__((noreturn)) AppMain(void) {
if (FlashInit()) {
uint64_t flash_uniqueID = 0;
if (!Flash_CheckBusy(BUSY_TIMEOUT)) { // OK because firmware was built for devices with flash
Flash_UniqueID((uint8_t*)&(flash_uniqueID));
Flash_UniqueID((uint8_t*)(&flash_uniqueID));
}
FlashStop();
usb_update_serial(flash_uniqueID);

View file

@ -34,11 +34,17 @@ VERSIONSRC = version_pm3.c
# THUMBSRC :=
# stdint.h provided locally until GCC 4.5 becomes C99 compliant
APP_CFLAGS = -I. -ffunction-sections -fdata-sections
APP_CFLAGS = -I. -ffunction-sections -fdata-sections -DAS_BOOTROM
# stack-protect , no-pie reduces size on Gentoo Hardened 8.2 gcc, no-common makes sure uninitialized vars don't end up in COMMON area
APP_CFLAGS += -fno-stack-protector -fno-pie -fno-common
ifneq (,$(findstring WITH_FLASH,$(PLATFORM_DEFS)))
APP_CFLAGS += -DWITH_FLASH
APP_CFLAGS += -I../common_arm
THUMBSRC += flashmem.c ticks.c
endif
# Do not move this inclusion before the definition of {THUMB,ASM,ARM}SRC
include ../common_arm/Makefile.common

View file

@ -20,6 +20,10 @@
#include "clocks.h"
#include "usb_cdc.h"
#ifdef WITH_FLASH
#include "flashmem.h"
#endif
#include "proxmark3_arm.h"
#define DEBUG 0
@ -214,8 +218,18 @@ static void flash_mode(void) {
bootrom_unlocked = false;
uint8_t rx[sizeof(PacketCommandOLD)];
g_common_area.command = COMMON_AREA_COMMAND_NONE;
if (!g_common_area.flags.button_pressed && BUTTON_PRESS())
if (!g_common_area.flags.button_pressed && BUTTON_PRESS()) {
g_common_area.flags.button_pressed = 1;
}
#ifdef WITH_FLASH
if (FlashInit()) { // checks for existence of flash also ... OK because bootrom was built for devices with flash
uint64_t flash_uniqueID = 0;
Flash_UniqueID((uint8_t*)&flash_uniqueID);
FlashStop();
usb_update_serial(flash_uniqueID);
}
#endif
usb_enable();

View file

@ -53,6 +53,7 @@ SECTIONS
*(.rodata.*)
*(.data)
*(.data.*)
*(.ramfunc)
. = ALIGN(4);
} >ram AT>bootphase2 :phase2

View file

@ -20,7 +20,11 @@
#include "proxmark3_arm.h"
#include "ticks.h"
#ifndef AS_BOOTROM
#include "dbprint.h"
#endif // AS_BOOTROM
#include "string.h"
#include "usb_cdc.h"
@ -37,197 +41,13 @@
static uint32_t FLASHMEM_SPIBAUDRATE = FLASH_BAUD;
#define FASTFLASH (FLASHMEM_SPIBAUDRATE > FLASH_MINFAST)
#ifndef AS_BOOTROM
void FlashmemSetSpiBaudrate(uint32_t baudrate) {
FLASHMEM_SPIBAUDRATE = baudrate;
Dbprintf("Spi Baudrate : %dMHz", FLASHMEM_SPIBAUDRATE / 1000000);
}
// initialize
bool FlashInit(void) {
FlashSetup(FLASHMEM_SPIBAUDRATE);
StartTicks();
if (Flash_CheckBusy(BUSY_TIMEOUT)) {
StopTicks();
return false;
}
return true;
}
void FlashSetup(uint32_t baudrate) {
//WDT_DISABLE
AT91C_BASE_WDTC->WDTC_WDMR = AT91C_WDTC_WDDIS;
// PA10 -> SPI_NCS2 chip select (FLASHMEM)
// PA11 -> SPI_NCS0 chip select (FPGA)
// PA12 -> SPI_MISO Master-In Slave-Out
// PA13 -> SPI_MOSI Master-Out Slave-In
// PA14 -> SPI_SPCK Serial Clock
// Disable PIO control of the following pins, allows use by the SPI peripheral
AT91C_BASE_PIOA->PIO_PDR |= (GPIO_NCS0 | GPIO_MISO | GPIO_MOSI | GPIO_SPCK | GPIO_NCS2);
// Pull-up Enable
AT91C_BASE_PIOA->PIO_PPUER |= (GPIO_NCS0 | GPIO_MISO | GPIO_MOSI | GPIO_SPCK | GPIO_NCS2);
// Peripheral A
AT91C_BASE_PIOA->PIO_ASR |= (GPIO_NCS0 | GPIO_MISO | GPIO_MOSI | GPIO_SPCK);
// Peripheral B
AT91C_BASE_PIOA->PIO_BSR |= GPIO_NCS2;
//enable the SPI Peripheral clock
AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_SPI);
//reset spi needs double SWRST, see atmel's errata on this case
AT91C_BASE_SPI->SPI_CR = AT91C_SPI_SWRST;
AT91C_BASE_SPI->SPI_CR = AT91C_SPI_SWRST;
// Enable SPI
AT91C_BASE_SPI->SPI_CR = AT91C_SPI_SPIEN;
// NPCS2 Mode 0
AT91C_BASE_SPI->SPI_MR =
(0 << 24) | // Delay between chip selects = DYLBCS/MCK BUT:
// If DLYBCS is less than or equal to six, six MCK periods
// will be inserted by default.
SPI_PCS(SPI_CSR_NUM) | // Peripheral Chip Select (selects SPI_NCS2 or PA10)
(0 << 7) | // Disable LLB (1=MOSI2MISO test mode)
(1 << 4) | // Disable ModeFault Protection
(0 << 3) | // makes spi operate at MCK (1 is MCK/2)
(0 << 2) | // Chip selects connected directly to peripheral
AT91C_SPI_PS_FIXED | // Fixed Peripheral Select
AT91C_SPI_MSTR; // Master Mode
uint8_t csaat = 1;
uint32_t dlybct = 0;
uint8_t ncpha = 1;
uint8_t cpol = 0;
if (baudrate > FLASH_MINFAST) {
baudrate = FLASH_FASTBAUD;
//csaat = 0;
dlybct = 1500;
ncpha = 0;
cpol = 0;
}
AT91C_BASE_SPI->SPI_CSR[2] =
SPI_DLYBCT(dlybct, MCK) | // Delay between Consecutive Transfers (32 MCK periods)
SPI_DLYBS(0, MCK) | // Delay Beforce SPCK CLock
SPI_SCBR(baudrate, MCK) | // SPI Baudrate Selection
AT91C_SPI_BITS_8 | // Bits per Transfer (8 bits)
//AT91C_SPI_CSAAT | // Chip Select inactive after transfer
// 40.4.6.2 SPI: Bad tx_ready Behavior when CSAAT = 1 and SCBR = 1
// If the SPI is programmed with CSAAT = 1, SCBR(baudrate) = 1 and two transfers are performed consecutively on
// the same slave with an IDLE state between them, the tx_ready signal does not rise after the second data has been
// transferred in the shifter. This can imply for example, that the second data is sent twice.
// COLIN :: For now we STILL use CSAAT=1 to avoid having to (de)assert NPCS manually via PIO lines and we deal with delay
(csaat << 3) |
/* Spi modes:
Mode CPOL CPHA NCPHA
0 0 0 1 clock normally low read on rising edge
1 0 1 0 clock normally low read on falling edge
2 1 0 1 clock normally high read on falling edge
3 1 1 0 clock normally high read on rising edge
However, page 512 of the AT91SAM7Sx datasheet say "Note that in SPI
master mode the ATSAM7S512/256/128/64/321/32 does not sample the data
(MISO) on the opposite edge where data clocks out (MOSI) but the same
edge is used as shown in Figure 36-3 and Figure 36-4." Figure 36-3
shows that CPOL=NCPHA=0 or CPOL=NCPHA=1 samples on the rising edge and
that the data changes sometime after the rising edge (about 2 ns). To
be consistent with normal SPI operation, it is probably safe to say
that the data changes on the falling edge and should be sampled on the
rising edge. Therefore, it appears that NCPHA should be treated the
same as CPHA. Thus:
Mode CPOL CPHA NCPHA
0 0 0 0 clock normally low read on rising edge
1 0 1 1 clock normally low read on falling edge
2 1 0 0 clock normally high read on falling edge
3 1 1 1 clock normally high read on rising edge
Update: for 24MHz, writing is more stable with ncpha=1, else bitflips occur.
*/
(ncpha << 1) | // Clock Phase data captured on leading edge, changes on following edge
(cpol << 0); // Clock Polarity inactive state is logic 0
// read first, empty buffer
if (AT91C_BASE_SPI->SPI_RDR == 0) {};
}
void FlashStop(void) {
//Bof
//* Reset all the Chip Select register
AT91C_BASE_SPI->SPI_CSR[0] = 0;
AT91C_BASE_SPI->SPI_CSR[1] = 0;
AT91C_BASE_SPI->SPI_CSR[2] = 0;
AT91C_BASE_SPI->SPI_CSR[3] = 0;
// Reset the SPI mode
AT91C_BASE_SPI->SPI_MR = 0;
// Disable all interrupts
AT91C_BASE_SPI->SPI_IDR = 0xFFFFFFFF;
// SPI disable
AT91C_BASE_SPI->SPI_CR = AT91C_SPI_SPIDIS;
if (g_dbglevel > 3) Dbprintf("FlashStop");
StopTicks();
}
// send one byte over SPI
uint16_t FlashSendByte(uint32_t data) {
// wait until SPI is ready for transfer
//if you are checking for incoming data returned then the TXEMPTY flag is redundant
//while ((AT91C_BASE_SPI->SPI_SR & AT91C_SPI_TXEMPTY) == 0) {};
// send the data
AT91C_BASE_SPI->SPI_TDR = data;
//while ((AT91C_BASE_SPI->SPI_SR & AT91C_SPI_TDRE) == 0){};
// wait receive transfer is complete
while ((AT91C_BASE_SPI->SPI_SR & AT91C_SPI_RDRF) == 0) {};
// reading incoming data
return ((AT91C_BASE_SPI->SPI_RDR) & 0xFFFF);
}
// send last byte over SPI
uint16_t FlashSendLastByte(uint32_t data) {
return FlashSendByte(data | AT91C_SPI_LASTXFER);
}
// read state register 1
uint8_t Flash_ReadStat1(void) {
FlashSendByte(READSTAT1);
return FlashSendLastByte(0xFF);
}
bool Flash_CheckBusy(uint32_t timeout) {
WaitUS(WINBOND_WRITE_DELAY);
StartCountUS();
uint32_t _time = GetCountUS();
if (g_dbglevel > 3) Dbprintf("Checkbusy in...");
do {
if (!(Flash_ReadStat1() & BUSY)) {
return false;
}
} while ((GetCountUS() - _time) < timeout);
if (timeout <= (GetCountUS() - _time)) {
return true;
}
return false;
}
// read ID out
uint8_t Flash_ReadID(void) {
@ -250,28 +70,6 @@ uint8_t Flash_ReadID(void) {
return 0;
}
// read unique id for chip.
void Flash_UniqueID(uint8_t *uid) {
if (Flash_CheckBusy(BUSY_TIMEOUT)) return;
// reading unique serial number
FlashSendByte(UNIQUE_ID);
FlashSendByte(0xFF);
FlashSendByte(0xFF);
FlashSendByte(0xFF);
FlashSendByte(0xFF);
uid[7] = FlashSendByte(0xFF);
uid[6] = FlashSendByte(0xFF);
uid[5] = FlashSendByte(0xFF);
uid[4] = FlashSendByte(0xFF);
uid[3] = FlashSendByte(0xFF);
uid[2] = FlashSendByte(0xFF);
uid[1] = FlashSendByte(0xFF);
uid[0] = FlashSendLastByte(0xFF);
}
uint16_t Flash_ReadData(uint32_t address, uint8_t *out, uint16_t len) {
if (!FlashInit()) return 0;
@ -326,7 +124,6 @@ uint16_t Flash_ReadDataCont(uint32_t address, uint8_t *out, uint16_t len) {
return len;
}
////////////////////////////////////////
// Write data can only program one page. A page has 256 bytes.
// if len > 256, it might wrap around and overwrite pos 0.
@ -372,7 +169,6 @@ uint16_t Flash_WriteData(uint32_t address, uint8_t *in, uint16_t len) {
return len;
}
// length should never be zero
// Max 256 bytes write
// out-of-range
@ -571,7 +367,7 @@ void Flashmem_print_status(void) {
uint8_t uid[8] = {0, 0, 0, 0, 0, 0, 0, 0};
Flash_UniqueID(uid);
Dbprintf(" Unique ID............... 0x%02X%02X%02X%02X%02X%02X%02X%02X",
Dbprintf( " Unique ID............... " _YELLOW_("0x%02X%02X%02X%02X%02X%02X%02X%02X"),
uid[7], uid[6], uid[5], uid[4],
uid[3], uid[2], uid[1], uid[0]
);
@ -616,4 +412,217 @@ void Flashmem_print_info(void) {
FlashStop();
}
#endif // #ifndef AS_BOOTROM
// initialize
bool FlashInit(void) {
FlashSetup(FLASHMEM_SPIBAUDRATE);
StartTicks();
if (Flash_CheckBusy(BUSY_TIMEOUT)) {
StopTicks();
return false;
}
return true;
}
// read unique id for chip.
void Flash_UniqueID(uint8_t *uid) {
if (Flash_CheckBusy(BUSY_TIMEOUT)) return;
// reading unique serial number
FlashSendByte(UNIQUE_ID);
FlashSendByte(0xFF);
FlashSendByte(0xFF);
FlashSendByte(0xFF);
FlashSendByte(0xFF);
uid[7] = FlashSendByte(0xFF);
uid[6] = FlashSendByte(0xFF);
uid[5] = FlashSendByte(0xFF);
uid[4] = FlashSendByte(0xFF);
uid[3] = FlashSendByte(0xFF);
uid[2] = FlashSendByte(0xFF);
uid[1] = FlashSendByte(0xFF);
uid[0] = FlashSendLastByte(0xFF);
}
void FlashStop(void) {
//Bof
//* Reset all the Chip Select register
AT91C_BASE_SPI->SPI_CSR[0] = 0;
AT91C_BASE_SPI->SPI_CSR[1] = 0;
AT91C_BASE_SPI->SPI_CSR[2] = 0;
AT91C_BASE_SPI->SPI_CSR[3] = 0;
// Reset the SPI mode
AT91C_BASE_SPI->SPI_MR = 0;
// Disable all interrupts
AT91C_BASE_SPI->SPI_IDR = 0xFFFFFFFF;
// SPI disable
AT91C_BASE_SPI->SPI_CR = AT91C_SPI_SPIDIS;
#ifndef AS_BOOTROM
if (g_dbglevel > 3) Dbprintf("FlashStop");
#endif // AS_BOOTROM
StopTicks();
}
void FlashSetup(uint32_t baudrate) {
//WDT_DISABLE
AT91C_BASE_WDTC->WDTC_WDMR = AT91C_WDTC_WDDIS;
// PA10 -> SPI_NCS2 chip select (FLASHMEM)
// PA11 -> SPI_NCS0 chip select (FPGA)
// PA12 -> SPI_MISO Master-In Slave-Out
// PA13 -> SPI_MOSI Master-Out Slave-In
// PA14 -> SPI_SPCK Serial Clock
// Disable PIO control of the following pins, allows use by the SPI peripheral
AT91C_BASE_PIOA->PIO_PDR |= (GPIO_NCS0 | GPIO_MISO | GPIO_MOSI | GPIO_SPCK | GPIO_NCS2);
// Pull-up Enable
AT91C_BASE_PIOA->PIO_PPUER |= (GPIO_NCS0 | GPIO_MISO | GPIO_MOSI | GPIO_SPCK | GPIO_NCS2);
// Peripheral A
AT91C_BASE_PIOA->PIO_ASR |= (GPIO_NCS0 | GPIO_MISO | GPIO_MOSI | GPIO_SPCK);
// Peripheral B
AT91C_BASE_PIOA->PIO_BSR |= GPIO_NCS2;
//enable the SPI Peripheral clock
AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_SPI);
//reset spi needs double SWRST, see atmel's errata on this case
AT91C_BASE_SPI->SPI_CR = AT91C_SPI_SWRST;
AT91C_BASE_SPI->SPI_CR = AT91C_SPI_SWRST;
// Enable SPI
AT91C_BASE_SPI->SPI_CR = AT91C_SPI_SPIEN;
// NPCS2 Mode 0
AT91C_BASE_SPI->SPI_MR =
(0 << 24) | // Delay between chip selects = DYLBCS/MCK BUT:
// If DLYBCS is less than or equal to six, six MCK periods
// will be inserted by default.
SPI_PCS(SPI_CSR_NUM) | // Peripheral Chip Select (selects SPI_NCS2 or PA10)
(0 << 7) | // Disable LLB (1=MOSI2MISO test mode)
(1 << 4) | // Disable ModeFault Protection
(0 << 3) | // makes spi operate at MCK (1 is MCK/2)
(0 << 2) | // Chip selects connected directly to peripheral
AT91C_SPI_PS_FIXED | // Fixed Peripheral Select
AT91C_SPI_MSTR; // Master Mode
uint8_t csaat = 1;
uint32_t dlybct = 0;
uint8_t ncpha = 1;
uint8_t cpol = 0;
if (baudrate > FLASH_MINFAST) {
baudrate = FLASH_FASTBAUD;
//csaat = 0;
dlybct = 1500;
ncpha = 0;
cpol = 0;
}
AT91C_BASE_SPI->SPI_CSR[2] =
SPI_DLYBCT(dlybct, MCK) | // Delay between Consecutive Transfers (32 MCK periods)
SPI_DLYBS(0, MCK) | // Delay Beforce SPCK CLock
SPI_SCBR(baudrate, MCK) | // SPI Baudrate Selection
AT91C_SPI_BITS_8 | // Bits per Transfer (8 bits)
//AT91C_SPI_CSAAT | // Chip Select inactive after transfer
// 40.4.6.2 SPI: Bad tx_ready Behavior when CSAAT = 1 and SCBR = 1
// If the SPI is programmed with CSAAT = 1, SCBR(baudrate) = 1 and two transfers are performed consecutively on
// the same slave with an IDLE state between them, the tx_ready signal does not rise after the second data has been
// transferred in the shifter. This can imply for example, that the second data is sent twice.
// COLIN :: For now we STILL use CSAAT=1 to avoid having to (de)assert NPCS manually via PIO lines and we deal with delay
(csaat << 3) |
/* Spi modes:
Mode CPOL CPHA NCPHA
0 0 0 1 clock normally low read on rising edge
1 0 1 0 clock normally low read on falling edge
2 1 0 1 clock normally high read on falling edge
3 1 1 0 clock normally high read on rising edge
However, page 512 of the AT91SAM7Sx datasheet say "Note that in SPI
master mode the ATSAM7S512/256/128/64/321/32 does not sample the data
(MISO) on the opposite edge where data clocks out (MOSI) but the same
edge is used as shown in Figure 36-3 and Figure 36-4." Figure 36-3
shows that CPOL=NCPHA=0 or CPOL=NCPHA=1 samples on the rising edge and
that the data changes sometime after the rising edge (about 2 ns). To
be consistent with normal SPI operation, it is probably safe to say
that the data changes on the falling edge and should be sampled on the
rising edge. Therefore, it appears that NCPHA should be treated the
same as CPHA. Thus:
Mode CPOL CPHA NCPHA
0 0 0 0 clock normally low read on rising edge
1 0 1 1 clock normally low read on falling edge
2 1 0 0 clock normally high read on falling edge
3 1 1 1 clock normally high read on rising edge
Update: for 24MHz, writing is more stable with ncpha=1, else bitflips occur.
*/
(ncpha << 1) | // Clock Phase data captured on leading edge, changes on following edge
(cpol << 0); // Clock Polarity inactive state is logic 0
// read first, empty buffer
if (AT91C_BASE_SPI->SPI_RDR == 0) {};
}
bool Flash_CheckBusy(uint32_t timeout) {
WaitUS(WINBOND_WRITE_DELAY);
StartCountUS();
uint32_t _time = GetCountUS();
#ifndef AS_BOOTROM
if (g_dbglevel > 3) Dbprintf("Checkbusy in...");
#endif // AS_BOOTROM
do {
if (!(Flash_ReadStat1() & BUSY)) {
return false;
}
} while ((GetCountUS() - _time) < timeout);
if (timeout <= (GetCountUS() - _time)) {
return true;
}
return false;
}
// read state register 1
uint8_t Flash_ReadStat1(void) {
FlashSendByte(READSTAT1);
return FlashSendLastByte(0xFF);
}
// send one byte over SPI
uint16_t FlashSendByte(uint32_t data) {
// wait until SPI is ready for transfer
//if you are checking for incoming data returned then the TXEMPTY flag is redundant
//while ((AT91C_BASE_SPI->SPI_SR & AT91C_SPI_TXEMPTY) == 0) {};
// send the data
AT91C_BASE_SPI->SPI_TDR = data;
//while ((AT91C_BASE_SPI->SPI_SR & AT91C_SPI_TDRE) == 0){};
// wait receive transfer is complete
while ((AT91C_BASE_SPI->SPI_SR & AT91C_SPI_RDRF) == 0) {};
// reading incoming data
return ((AT91C_BASE_SPI->SPI_RDR) & 0xFFFF);
}
// send last byte over SPI
uint16_t FlashSendLastByte(uint32_t data) {
return FlashSendByte(data | AT91C_SPI_LASTXFER);
}

View file

@ -100,17 +100,67 @@
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
void FlashmemSetSpiBaudrate(uint32_t baudrate);
bool FlashInit(void);
void FlashSetup(uint32_t baudrate);
void Flash_UniqueID(uint8_t *uid);
void FlashStop(void);
bool Flash_WaitIdle(void);
void FlashSetup(uint32_t baudrate);
bool Flash_CheckBusy(uint32_t timeout);
uint8_t Flash_ReadStat1(void);
uint8_t Flash_ReadStat2(void);
uint16_t FlashSendByte(uint32_t data);
uint16_t FlashSendLastByte(uint32_t data);
#ifndef AS_BOOTROM
// Bootrom does not require these functions.
// Wrap in #ifndef to avoid accidental bloat of bootrom
// Bootrom needs only enough to get uniqueID from flash.
// It calls three functions. Full call trees listed:
//
// FlashInit()
// |
// \____ FlashSetup()
// | \____ leaf
// |
// \____ StartTicks()
// | \____ leaf
// |
// \____ Flash_CheckBusy() [*]
// | \____ WaitUS()
// | | \____ WaitTicks()
// | | \____ leaf
// | |
// | \____ StartCountUS()
// | | \____ leaf
// | |
// | \____ GetCountUS()
// | | \____ leaf
// | |
// | \____ Flash_ReadStat1()
// | \____ FlashSendByte()
// | | \____ leaf
// | |
// | \____ FlashSendLastByte()
// | \____ FlashSendByte()
// | \____ leaf
// |
// \____ StopTicks()
// \____ leaf
//
// Flash_UniqueID()
// \____ FlashCheckBusy() (see FlashInit)
// \____ FlashSendByteByte() (see FlashInit)
// \____ FlashSendByteLastByte() (see FlashInit)
//
//
// FlashStop() [*]
void FlashmemSetSpiBaudrate(uint32_t baudrate);
bool Flash_WaitIdle(void);
void Flash_TransferAdresse(uint32_t address);
bool Flash_CheckBusy(uint32_t timeout);
void Flash_WriteEnable(void);
bool Flash_WipeMemoryPage(uint8_t page);
@ -119,7 +169,6 @@ bool Flash_Erase4k(uint8_t block, uint8_t sector);
//bool Flash_Erase32k(uint32_t address);
bool Flash_Erase64k(uint8_t block);
void Flash_UniqueID(uint8_t *uid);
uint8_t Flash_ReadID(void);
uint16_t Flash_ReadData(uint32_t address, uint8_t *out, uint16_t len);
uint16_t Flash_ReadDataCont(uint32_t address, uint8_t *out, uint16_t len);
@ -128,6 +177,8 @@ uint16_t Flash_WriteData(uint32_t address, uint8_t *in, uint16_t len);
uint16_t Flash_WriteDataCont(uint32_t address, uint8_t *in, uint16_t len);
void Flashmem_print_status(void);
void Flashmem_print_info(void);
uint16_t FlashSendLastByte(uint32_t data);
#endif // #ifndef AS_BOOTROM
#endif

View file

@ -19,9 +19,13 @@
#include "ticks.h"
#include "proxmark3_arm.h"
#include "dbprint.h"
#ifndef AS_BOOTROM
#include "dbprint.h"
#endif
#ifndef AS_BOOTROM
// timer counts in 666ns increments (32/48MHz), rounding applies
// WARNING: timer can't measure more than 43ms (666ns * 0xFFFF)
void SpinDelayUsPrecision(int us) {
@ -117,40 +121,6 @@ uint32_t RAMFUNC GetTickCountDelta(uint32_t start_ticks) {
return (UINT32_MAX - start_ticks) + stop_ticks;
}
// -------------------------------------------------------------------------
// microseconds timer
// -------------------------------------------------------------------------
void StartCountUS(void) {
AT91C_BASE_PMC->PMC_PCER |= (1 << AT91C_ID_TC0) | (1 << AT91C_ID_TC1);
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;
// Assert a sync signal. This sets all timers to 0 on next active clock edge
AT91C_BASE_TCB->TCB_BCR = 1;
while (AT91C_BASE_TC1->TC_CV > 0);
}
uint32_t RAMFUNC GetCountUS(void) {
//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 ((uint32_t)AT91C_BASE_TC1->TC_CV) * 0x8000 + (((uint32_t)AT91C_BASE_TC0->TC_CV) * 2) / 3;
}
// -------------------------------------------------------------------------
// Timer for iso14443 commands. Uses ssp_clk from FPGA
// -------------------------------------------------------------------------
@ -246,6 +216,47 @@ uint32_t RAMFUNC GetCountSspClkDelta(uint32_t start) {
return (UINT32_MAX - start) + stop;
}
void WaitMS(uint32_t ms) {
WaitTicks((ms & 0x1FFFFF) * 1500);
}
#endif // #ifndef AS_BOOTROM
// -------------------------------------------------------------------------
// microseconds timer
// -------------------------------------------------------------------------
void StartCountUS(void) {
AT91C_BASE_PMC->PMC_PCER |= (1 << AT91C_ID_TC0) | (1 << AT91C_ID_TC1);
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;
// Assert a sync signal. This sets all timers to 0 on next active clock edge
AT91C_BASE_TCB->TCB_BCR = 1;
while (AT91C_BASE_TC1->TC_CV > 0);
}
uint32_t RAMFUNC GetCountUS(void) {
//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 ((uint32_t)AT91C_BASE_TC1->TC_CV) * 0x8000 + (((uint32_t)AT91C_BASE_TC0->TC_CV) * 2) / 3;
}
// -------------------------------------------------------------------------
// Timer for bitbanging, or LF stuff when you need a very precis timer
// 1us = 1.5ticks
@ -282,7 +293,6 @@ void StartTicks(void) {
AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG;
while (AT91C_BASE_TC0->TC_CV > 0);
}
uint32_t GetTicks(void) {
uint32_t hi, lo;
@ -307,9 +317,6 @@ void WaitTicks(uint32_t ticks) {
void WaitUS(uint32_t us) {
WaitTicks((us & 0x3FFFFFFF) * 3 / 2);
}
void WaitMS(uint32_t ms) {
WaitTicks((ms & 0x1FFFFF) * 1500);
}
// stop clock
void StopTicks(void) {

View file

@ -26,6 +26,19 @@
#define GET_TICKS GetTicks()
#endif
void StartTicks(void);
uint32_t GetTicks(void);
void WaitUS(uint32_t us);
void WaitTicks(uint32_t ticks);
void StartCountUS(void);
uint32_t RAMFUNC GetCountUS(void);
void StopTicks(void);
#ifndef AS_BOOTROM //////////////////////////////////////////////////////////////
// Bootrom does not require these functions.
// Wrap in #ifndef to avoid accidental bloat of bootrom
void SpinDelay(int ms);
void SpinDelayUs(int us);
void SpinDelayUsPrecision(int us); // precision 0.6us , running for 43ms before
@ -34,8 +47,6 @@ void StartTickCount(void);
uint32_t RAMFUNC GetTickCount(void);
uint32_t RAMFUNC GetTickCountDelta(uint32_t start_ticks);
void StartCountUS(void);
uint32_t RAMFUNC GetCountUS(void);
void ResetUSClock(void);
void SpinDelayCountUs(uint32_t us);
@ -44,12 +55,10 @@ void ResetSspClk(void);
uint32_t RAMFUNC GetCountSspClk(void);
uint32_t RAMFUNC GetCountSspClkDelta(uint32_t start);
void StartTicks(void);
uint32_t GetTicks(void);
void WaitTicks(uint32_t ticks);
void WaitUS(uint32_t us);
void WaitMS(uint32_t ms);
void StopTicks(void);
#endif // #ifndef AS_BOOTROM
#endif

View file

@ -382,7 +382,6 @@ static const char StrSerialNumber[] = {
// offset 18, length 32: 16x unicode chars (8-byte serial as hex characters)
// ============================
// total: 50 bytes
#define USB_STRING_DESCRIPTOR_SERIAL_NUMBER_LENGTH 50
char StrSerialNumber[] = {
14, // Length is initially identical to non-unique version ... The length updated at boot, if unique serial is available
@ -399,6 +398,7 @@ void usb_update_serial(uint64_t newSerialNumber) {
}
// run this only once per boot... even if it fails to find serial number
configured = true;
// reject serial number if all-zero or all-ones
if ((newSerialNumber == 0x0000000000000000) || (newSerialNumber == 0xFFFFFFFFFFFFFFFF)) {
return;
}
@ -407,10 +407,14 @@ void usb_update_serial(uint64_t newSerialNumber) {
// Convert uniqueID's eight bytes to 16 unicode characters in the
// descriptor and, finally, update the descriptor's length, which
// causes the serial number to become visible.
for (uint8_t i = 0; i < 16; i++) {
uint8_t nibble = (uint8_t)((newSerialNumber >> (60 - (4*i))) & 0xFu);
char c = nibble < 10 ? '0' + nibble : 'A' + (nibble-10);
StrSerialNumber[18+(2*i)] = c; // [ 18, 20, 22, .., 46, 48 ]
for (uint8_t i = 0; i < 8; i++) {
// order of nibbles chosen to match display order from `hw status`
uint8_t nibble1 = (newSerialNumber >> ((8*i) + 4)) & 0xFu; // bitmasks [0xF0, 0xF000, 0xF00000, ... 0xF000000000000000]
uint8_t nibble2 = (newSerialNumber >> ((8*i) + 0)) & 0xFu; // bitmasks [0x0F, 0x0F00, 0x0F0000, ... 0x0F00000000000000]
char c1 = nibble1 < 10 ? '0' + nibble1 : 'A' + (nibble1-10);
char c2 = nibble2 < 10 ? '0' + nibble2 : 'A' + (nibble2-10);
StrSerialNumber[46-(4*i)] = c1; // [ 46, 42, .., 22, 18 ]
StrSerialNumber[48-(4*i)] = c2; // [ 48, 44, .., 24, 20 ]
}
StrSerialNumber[0] = USB_STRING_DESCRIPTOR_SERIAL_NUMBER_LENGTH;
}