mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-08-20 13:23:51 -07:00
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:
parent
5784c8de77
commit
44676bde72
9 changed files with 373 additions and 272 deletions
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -53,6 +53,7 @@ SECTIONS
|
|||
*(.rodata.*)
|
||||
*(.data)
|
||||
*(.data.*)
|
||||
*(.ramfunc)
|
||||
. = ALIGN(4);
|
||||
} >ram AT>bootphase2 :phase2
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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
|
|
@ -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) {
|
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue