Merge pull request #1914 from henrygab/serial_from_flash_uniqueid

Use unique USB Serial using flash's uniqueID
This commit is contained in:
Iceman 2023-02-18 21:43:06 +01:00 committed by GitHub
commit 21ab53c7cf
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 618 additions and 493 deletions

View file

@ -3,6 +3,7 @@ All notable changes to this project will be documented in this file.
This project uses the changelog in accordance with [keepchangelog](http://keepachangelog.com/). Please use this to write notable changes, which is not the same as git commit log... This project uses the changelog in accordance with [keepchangelog](http://keepachangelog.com/). Please use this to write notable changes, which is not the same as git commit log...
## [unreleased][unreleased] ## [unreleased][unreleased]
- Enable unique USB serial numbers when built with `FLASH` -- **_UPDATES BOOTROM ALSO_**
- Changed the readline package to v8.2 in the CMAKE files for the client (@iceman1001) - Changed the readline package to v8.2 in the CMAKE files for the client (@iceman1001)
- Add ICECLASS standalone read/sim mode (@natesales) - Add ICECLASS standalone read/sim mode (@natesales)
- Added verbose flag to `hf iclass encode` (@natesales) - Added verbose flag to `hf iclass encode` (@natesales)

View file

@ -5,6 +5,8 @@ PLATFORM=PM3RDV4
#PLATFORM=PM3GENERIC #PLATFORM=PM3GENERIC
# If you want more than one PLATFORM_EXTRAS option, separate them by spaces: # If you want more than one PLATFORM_EXTRAS option, separate them by spaces:
#PLATFORM_EXTRAS=BTADDON #PLATFORM_EXTRAS=BTADDON
#PLATFORM_EXTRAS=FLASH
#PLATFORM_EXTRAS=BTADDON FLASH
#STANDALONE=LF_SAMYRUN #STANDALONE=LF_SAMYRUN
# Uncomment the lines below in order to make a 256KB image # Uncomment the lines below in order to make a 256KB image

View file

@ -2471,8 +2471,11 @@ static void PacketReceived(PacketCommandNG *packet) {
LED_B_OFF(); LED_B_OFF();
break; break;
} }
if (page < 3) if (page < 3) {
isok = Flash_WipeMemoryPage(page); isok = Flash_WipeMemoryPage(page);
// let spiffs check and update its info post flash erase
rdv40_spiffs_check();
}
reply_mix(CMD_ACK, isok, 0, 0, 0, 0); reply_mix(CMD_ACK, isok, 0, 0, 0, 0);
LED_B_OFF(); LED_B_OFF();
@ -2677,6 +2680,17 @@ void __attribute__((noreturn)) AppMain(void) {
I2C_init(false); I2C_init(false);
#endif #endif
#ifdef WITH_FLASH
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));
}
FlashStop();
usb_update_serial(flash_uniqueID);
}
#endif
#ifdef WITH_FPC_USART #ifdef WITH_FPC_USART
usart_init(USART_BAUD_RATE, USART_PARITY); usart_init(USART_BAUD_RATE, USART_PARITY);
#endif #endif

View file

@ -34,11 +34,17 @@ VERSIONSRC = version_pm3.c
# THUMBSRC := # THUMBSRC :=
# stdint.h provided locally until GCC 4.5 becomes C99 compliant # 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 # 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 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 # Do not move this inclusion before the definition of {THUMB,ASM,ARM}SRC
include ../common_arm/Makefile.common include ../common_arm/Makefile.common

View file

@ -20,6 +20,10 @@
#include "clocks.h" #include "clocks.h"
#include "usb_cdc.h" #include "usb_cdc.h"
#ifdef WITH_FLASH
#include "flashmem.h"
#endif
#include "proxmark3_arm.h" #include "proxmark3_arm.h"
#define DEBUG 0 #define DEBUG 0
@ -214,8 +218,18 @@ static void flash_mode(void) {
bootrom_unlocked = false; bootrom_unlocked = false;
uint8_t rx[sizeof(PacketCommandOLD)]; uint8_t rx[sizeof(PacketCommandOLD)];
g_common_area.command = COMMON_AREA_COMMAND_NONE; 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; 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(); usb_enable();

View file

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

View file

@ -1407,7 +1407,7 @@ static int CmdHFiClassDecrypt(const char *Cmd) {
case DES: case DES:
case RFU: case RFU:
case None: case None:
// Nothing to do for None anyway... // Nothing to do for None anyway...
default: default:
continue; continue;
} }

View file

@ -114,6 +114,10 @@ endif
# parsing additional PLATFORM_EXTRAS tokens # parsing additional PLATFORM_EXTRAS tokens
PLATFORM_EXTRAS_TMP:=$(PLATFORM_EXTRAS) PLATFORM_EXTRAS_TMP:=$(PLATFORM_EXTRAS)
ifneq (,$(findstring FLASH,$(PLATFORM_EXTRAS_TMP)))
PLATFORM_DEFS += -DWITH_FLASH
PLATFORM_EXTRAS_TMP := $(strip $(filter-out FLASH,$(PLATFORM_EXTRAS_TMP)))
endif
ifneq (,$(findstring BTADDON,$(PLATFORM_EXTRAS_TMP))) ifneq (,$(findstring BTADDON,$(PLATFORM_EXTRAS_TMP)))
PLATFORM_DEFS += -DWITH_FPC_USART_HOST PLATFORM_DEFS += -DWITH_FPC_USART_HOST
PLATFORM_EXTRAS_TMP := $(strip $(filter-out BTADDON,$(PLATFORM_EXTRAS_TMP))) PLATFORM_EXTRAS_TMP := $(strip $(filter-out BTADDON,$(PLATFORM_EXTRAS_TMP)))

View file

@ -20,9 +20,13 @@
#include "proxmark3_arm.h" #include "proxmark3_arm.h"
#include "ticks.h" #include "ticks.h"
#ifndef AS_BOOTROM
#include "dbprint.h" #include "dbprint.h"
#endif // AS_BOOTROM
#include "string.h" #include "string.h"
#include "spiffs.h" #include "usb_cdc.h"
/* here: use NCPS2 @ PA10: */ /* here: use NCPS2 @ PA10: */
#define SPI_CSR_NUM 2 #define SPI_CSR_NUM 2
@ -37,11 +41,378 @@
static uint32_t FLASHMEM_SPIBAUDRATE = FLASH_BAUD; static uint32_t FLASHMEM_SPIBAUDRATE = FLASH_BAUD;
#define FASTFLASH (FLASHMEM_SPIBAUDRATE > FLASH_MINFAST) #define FASTFLASH (FLASHMEM_SPIBAUDRATE > FLASH_MINFAST)
#ifndef AS_BOOTROM
void FlashmemSetSpiBaudrate(uint32_t baudrate) { void FlashmemSetSpiBaudrate(uint32_t baudrate) {
FLASHMEM_SPIBAUDRATE = baudrate; FLASHMEM_SPIBAUDRATE = baudrate;
Dbprintf("Spi Baudrate : %dMHz", FLASHMEM_SPIBAUDRATE / 1000000); Dbprintf("Spi Baudrate : %dMHz", FLASHMEM_SPIBAUDRATE / 1000000);
} }
// read ID out
bool Flash_ReadID_90(flash_device_type_90_t *result) {
if (Flash_CheckBusy(BUSY_TIMEOUT)) return false;
// Manufacture ID / device ID
FlashSendByte(ID);
FlashSendByte(0x00);
FlashSendByte(0x00);
FlashSendByte(0x00);
result->manufacturer_id = FlashSendByte(0xFF);
result->device_id = FlashSendLastByte(0xFF);
return true;
}
uint16_t Flash_ReadData(uint32_t address, uint8_t *out, uint16_t len) {
if (!FlashInit()) return 0;
// length should never be zero
if (!len || Flash_CheckBusy(BUSY_TIMEOUT)) return 0;
uint8_t cmd = (FASTFLASH) ? FASTREAD : READDATA;
FlashSendByte(cmd);
Flash_TransferAdresse(address);
if (FASTFLASH) {
FlashSendByte(DUMMYBYTE);
}
uint16_t i = 0;
for (; i < (len - 1); i++)
out[i] = FlashSendByte(0xFF);
out[i] = FlashSendLastByte(0xFF);
FlashStop();
return len;
}
void Flash_TransferAdresse(uint32_t address) {
FlashSendByte((address >> 16) & 0xFF);
FlashSendByte((address >> 8) & 0xFF);
FlashSendByte((address >> 0) & 0xFF);
}
/* This ensures we can ReadData without having to cycle through initialization every time */
uint16_t Flash_ReadDataCont(uint32_t address, uint8_t *out, uint16_t len) {
// length should never be zero
if (!len) return 0;
uint8_t cmd = (FASTFLASH) ? FASTREAD : READDATA;
FlashSendByte(cmd);
Flash_TransferAdresse(address);
if (FASTFLASH) {
FlashSendByte(DUMMYBYTE);
}
uint16_t i = 0;
for (; i < (len - 1); i++)
out[i] = FlashSendByte(0xFF);
out[i] = FlashSendLastByte(0xFF);
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.
uint16_t Flash_WriteData(uint32_t address, uint8_t *in, uint16_t len) {
// length should never be zero
if (!len)
return 0;
// Max 256 bytes write
if (((address & 0xFF) + len) > 256) {
Dbprintf("Flash_WriteData 256 fail [ 0x%02x ] [ %u ]", (address & 0xFF) + len, len);
return 0;
}
// out-of-range
if (((address >> 16) & 0xFF) > MAX_BLOCKS) {
Dbprintf("Flash_WriteData, block out-of-range");
return 0;
}
if (!FlashInit()) {
if (g_dbglevel > 3) Dbprintf("Flash_WriteData init fail");
return 0;
}
Flash_CheckBusy(BUSY_TIMEOUT);
Flash_WriteEnable();
FlashSendByte(PAGEPROG);
FlashSendByte((address >> 16) & 0xFF);
FlashSendByte((address >> 8) & 0xFF);
FlashSendByte((address >> 0) & 0xFF);
uint16_t i = 0;
for (; i < (len - 1); i++)
FlashSendByte(in[i]);
FlashSendLastByte(in[i]);
FlashStop();
return len;
}
// length should never be zero
// Max 256 bytes write
// out-of-range
uint16_t Flash_WriteDataCont(uint32_t address, uint8_t *in, uint16_t len) {
if (!len)
return 0;
if (((address & 0xFF) + len) > 256) {
Dbprintf("Flash_WriteDataCont 256 fail [ 0x%02x ] [ %u ]", (address & 0xFF) + len, len);
return 0;
}
if (((address >> 16) & 0xFF) > MAX_BLOCKS) {
Dbprintf("Flash_WriteDataCont, block out-of-range");
return 0;
}
FlashSendByte(PAGEPROG);
FlashSendByte((address >> 16) & 0xFF);
FlashSendByte((address >> 8) & 0xFF);
FlashSendByte((address >> 0) & 0xFF);
uint16_t i = 0;
for (; i < (len - 1); i++)
FlashSendByte(in[i]);
FlashSendLastByte(in[i]);
return len;
}
// assumes valid start 256 based 00 address
//
uint16_t Flash_Write(uint32_t address, uint8_t *in, uint16_t len) {
bool isok;
uint16_t res, bytes_sent = 0, bytes_remaining = len;
uint8_t buf[FLASH_MEM_BLOCK_SIZE];
while (bytes_remaining > 0) {
Flash_CheckBusy(BUSY_TIMEOUT);
Flash_WriteEnable();
uint32_t bytes_in_packet = MIN(FLASH_MEM_BLOCK_SIZE, bytes_remaining);
memcpy(buf, in + bytes_sent, bytes_in_packet);
res = Flash_WriteDataCont(address + bytes_sent, buf, bytes_in_packet);
bytes_remaining -= bytes_in_packet;
bytes_sent += bytes_in_packet;
isok = (res == bytes_in_packet);
if (!isok)
goto out;
}
out:
FlashStop();
return len;
}
// WARNING -- if callers are using a file system (such as SPIFFS),
// they should inform the file system of this change
// e.g., rdv40_spiffs_check()
bool Flash_WipeMemoryPage(uint8_t page) {
if (!FlashInit()) {
if (g_dbglevel > 3) Dbprintf("Flash_WriteData init fail");
return false;
}
Flash_ReadStat1();
// Each block is 64Kb. One block erase takes 1s ( 1000ms )
Flash_WriteEnable();
Flash_Erase64k(page);
Flash_CheckBusy(BUSY_TIMEOUT);
FlashStop();
return true;
}
// Wipes flash memory completely, fills with 0xFF
bool Flash_WipeMemory(void) {
if (!FlashInit()) {
if (g_dbglevel > 3) Dbprintf("Flash_WriteData init fail");
return false;
}
Flash_ReadStat1();
// Each block is 64Kb. Four blocks
// one block erase takes 1s ( 1000ms )
Flash_WriteEnable();
Flash_Erase64k(0);
Flash_CheckBusy(BUSY_TIMEOUT);
Flash_WriteEnable();
Flash_Erase64k(1);
Flash_CheckBusy(BUSY_TIMEOUT);
Flash_WriteEnable();
Flash_Erase64k(2);
Flash_CheckBusy(BUSY_TIMEOUT);
Flash_WriteEnable();
Flash_Erase64k(3);
Flash_CheckBusy(BUSY_TIMEOUT);
FlashStop();
return true;
}
// enable the flash write
void Flash_WriteEnable(void) {
FlashSendLastByte(WRITEENABLE);
if (g_dbglevel > 3) Dbprintf("Flash Write enabled");
}
// erase 4K at one time
// execution time: 0.8ms / 800us
bool Flash_Erase4k(uint8_t block, uint8_t sector) {
if (block > MAX_BLOCKS || sector > MAX_SECTORS) return false;
FlashSendByte(SECTORERASE);
FlashSendByte(block);
FlashSendByte(sector << 4);
FlashSendLastByte(00);
return true;
}
/*
// erase 32K at one time
// execution time: 0,3s / 300ms
bool Flash_Erase32k(uint32_t address) {
if (address & (32*1024 - 1)) {
if ( g_dbglevel > 1 ) Dbprintf("Flash_Erase32k : Address is not align at 4096");
return false;
}
FlashSendByte(BLOCK32ERASE);
FlashSendByte((address >> 16) & 0xFF);
FlashSendByte((address >> 8) & 0xFF);
FlashSendLastByte((address >> 0) & 0xFF);
return true;
}
*/
// erase 64k at one time
// since a block is 64kb, and there is four blocks.
// we only need block number, as MSB
// execution time: 1s / 1000ms
// 0x00 00 00 -- 0x 00 FF FF == block 0
// 0x01 00 00 -- 0x 01 FF FF == block 1
// 0x02 00 00 -- 0x 02 FF FF == block 2
// 0x03 00 00 -- 0x 03 FF FF == block 3
bool Flash_Erase64k(uint8_t block) {
if (block > MAX_BLOCKS) return false;
FlashSendByte(BLOCK64ERASE);
FlashSendByte(block);
FlashSendByte(0x00);
FlashSendLastByte(0x00);
return true;
}
/*
// Erase chip
void Flash_EraseChip(void) {
FlashSendLastByte(CHIPERASE);
}
*/
void Flashmem_print_status(void) {
DbpString(_CYAN_("Flash memory"));
Dbprintf(" Baudrate................ " _GREEN_("%d MHz"), FLASHMEM_SPIBAUDRATE / 1000000);
if (!FlashInit()) {
DbpString(" Init.................... " _RED_("FAILED"));
return;
}
DbpString(" Init.................... " _GREEN_("OK"));
// NOTE: It would likely be more useful to use JDEC ID command 9F,
// as it provides a third byte indicative of capacity.
flash_device_type_90_t device_type = {0};
if (!Flash_ReadID_90(&device_type)) {
DbpString(" Device ID............... " _RED_(" --> Not Found <--"));
} else {
if ((device_type.manufacturer_id == WINBOND_MANID) && (device_type.device_id == WINBOND_DEVID)) {
DbpString(" Memory size............. " _GREEN_("2 mbits / 256 kb"));
} else {
Dbprintf(" Device ID............... " _YELLOW_("%02X / %02X (unknown)"),
device_type.manufacturer_id, device_type.device_id);
}
}
uint8_t uid[8] = {0, 0, 0, 0, 0, 0, 0, 0};
Flash_UniqueID(uid);
Dbprintf(" Unique ID (be).......... " _YELLOW_("0x%02X%02X%02X%02X%02X%02X%02X%02X"),
uid[0], uid[1], uid[2], uid[3],
uid[4], uid[5], uid[6], uid[7]
);
if (g_dbglevel > 3) {
Dbprintf(" Unique ID (le).......... " _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]
);
}
FlashStop();
}
void Flashmem_print_info(void) {
if (!FlashInit()) return;
DbpString(_CYAN_("Flash memory dictionary loaded"));
// load dictionary offsets.
uint8_t keysum[2];
uint16_t num;
Flash_CheckBusy(BUSY_TIMEOUT);
uint16_t isok = Flash_ReadDataCont(DEFAULT_MF_KEYS_OFFSET, keysum, 2);
if (isok == 2) {
num = ((keysum[1] << 8) | keysum[0]);
if (num != 0xFFFF && num != 0x0)
Dbprintf(" Mifare.................. "_YELLOW_("%d")" / "_GREEN_("%d")" keys", num, DEFAULT_MF_KEYS_MAX);
}
Flash_CheckBusy(BUSY_TIMEOUT);
isok = Flash_ReadDataCont(DEFAULT_T55XX_KEYS_OFFSET, keysum, 2);
if (isok == 2) {
num = ((keysum[1] << 8) | keysum[0]);
if (num != 0xFFFF && num != 0x0)
Dbprintf(" T55x7................... "_YELLOW_("%d")" / "_GREEN_("%d")" keys", num, DEFAULT_T55XX_KEYS_MAX);
}
Flash_CheckBusy(BUSY_TIMEOUT);
isok = Flash_ReadDataCont(DEFAULT_ICLASS_KEYS_OFFSET, keysum, 2);
if (isok == 2) {
num = ((keysum[1] << 8) | keysum[0]);
if (num != 0xFFFF && num != 0x0)
Dbprintf(" iClass.................. "_YELLOW_("%d")" / "_GREEN_("%d")" keys", num, DEFAULT_ICLASS_KEYS_MAX);
}
FlashStop();
}
#endif // #ifndef AS_BOOTROM
// initialize // initialize
bool FlashInit(void) { bool FlashInit(void) {
FlashSetup(FLASHMEM_SPIBAUDRATE); FlashSetup(FLASHMEM_SPIBAUDRATE);
@ -56,6 +427,52 @@ bool FlashInit(void) {
return true; 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) { void FlashSetup(uint32_t baudrate) {
//WDT_DISABLE //WDT_DISABLE
AT91C_BASE_WDTC->WDTC_WDMR = AT91C_WDTC_WDDIS; AT91C_BASE_WDTC->WDTC_WDMR = AT91C_WDTC_WDDIS;
@ -156,26 +573,32 @@ void FlashSetup(uint32_t baudrate) {
if (AT91C_BASE_SPI->SPI_RDR == 0) {}; if (AT91C_BASE_SPI->SPI_RDR == 0) {};
} }
void FlashStop(void) { bool Flash_CheckBusy(uint32_t timeout) {
//Bof WaitUS(WINBOND_WRITE_DELAY);
//* Reset all the Chip Select register StartCountUS();
AT91C_BASE_SPI->SPI_CSR[0] = 0; uint32_t _time = GetCountUS();
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 #ifndef AS_BOOTROM
AT91C_BASE_SPI->SPI_MR = 0; if (g_dbglevel > 3) Dbprintf("Checkbusy in...");
#endif // AS_BOOTROM
// Disable all interrupts do {
AT91C_BASE_SPI->SPI_IDR = 0xFFFFFFFF; if (!(Flash_ReadStat1() & BUSY)) {
return false;
}
} while ((GetCountUS() - _time) < timeout);
// SPI disable if (timeout <= (GetCountUS() - _time)) {
AT91C_BASE_SPI->SPI_CR = AT91C_SPI_SPIDIS; return true;
}
if (g_dbglevel > 3) Dbprintf("FlashStop"); return false;
}
StopTicks(); // read state register 1
uint8_t Flash_ReadStat1(void) {
FlashSendByte(READSTAT1);
return FlashSendLastByte(0xFF);
} }
// send one byte over SPI // send one byte over SPI
@ -201,419 +624,3 @@ uint16_t FlashSendByte(uint32_t data) {
uint16_t FlashSendLastByte(uint32_t data) { uint16_t FlashSendLastByte(uint32_t data) {
return FlashSendByte(data | AT91C_SPI_LASTXFER); 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) {
if (Flash_CheckBusy(BUSY_TIMEOUT)) return 0;
// Manufacture ID / device ID
FlashSendByte(ID);
FlashSendByte(0x00);
FlashSendByte(0x00);
FlashSendByte(0x00);
uint8_t man_id = FlashSendByte(0xFF);
uint8_t dev_id = FlashSendLastByte(0xFF);
if (g_dbglevel > 3) Dbprintf("Flash ReadID | Man ID %02x | Device ID %02x", man_id, dev_id);
if ((man_id == WINBOND_MANID) && (dev_id == WINBOND_DEVID))
return dev_id;
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;
// length should never be zero
if (!len || Flash_CheckBusy(BUSY_TIMEOUT)) return 0;
uint8_t cmd = (FASTFLASH) ? FASTREAD : READDATA;
FlashSendByte(cmd);
Flash_TransferAdresse(address);
if (FASTFLASH) {
FlashSendByte(DUMMYBYTE);
}
uint16_t i = 0;
for (; i < (len - 1); i++)
out[i] = FlashSendByte(0xFF);
out[i] = FlashSendLastByte(0xFF);
FlashStop();
return len;
}
void Flash_TransferAdresse(uint32_t address) {
FlashSendByte((address >> 16) & 0xFF);
FlashSendByte((address >> 8) & 0xFF);
FlashSendByte((address >> 0) & 0xFF);
}
/* This ensures we can ReadData without having to cycle through initialization every time */
uint16_t Flash_ReadDataCont(uint32_t address, uint8_t *out, uint16_t len) {
// length should never be zero
if (!len) return 0;
uint8_t cmd = (FASTFLASH) ? FASTREAD : READDATA;
FlashSendByte(cmd);
Flash_TransferAdresse(address);
if (FASTFLASH) {
FlashSendByte(DUMMYBYTE);
}
uint16_t i = 0;
for (; i < (len - 1); i++)
out[i] = FlashSendByte(0xFF);
out[i] = FlashSendLastByte(0xFF);
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.
uint16_t Flash_WriteData(uint32_t address, uint8_t *in, uint16_t len) {
// length should never be zero
if (!len)
return 0;
// Max 256 bytes write
if (((address & 0xFF) + len) > 256) {
Dbprintf("Flash_WriteData 256 fail [ 0x%02x ] [ %u ]", (address & 0xFF) + len, len);
return 0;
}
// out-of-range
if (((address >> 16) & 0xFF) > MAX_BLOCKS) {
Dbprintf("Flash_WriteData, block out-of-range");
return 0;
}
if (!FlashInit()) {
if (g_dbglevel > 3) Dbprintf("Flash_WriteData init fail");
return 0;
}
Flash_CheckBusy(BUSY_TIMEOUT);
Flash_WriteEnable();
FlashSendByte(PAGEPROG);
FlashSendByte((address >> 16) & 0xFF);
FlashSendByte((address >> 8) & 0xFF);
FlashSendByte((address >> 0) & 0xFF);
uint16_t i = 0;
for (; i < (len - 1); i++)
FlashSendByte(in[i]);
FlashSendLastByte(in[i]);
FlashStop();
return len;
}
// length should never be zero
// Max 256 bytes write
// out-of-range
uint16_t Flash_WriteDataCont(uint32_t address, uint8_t *in, uint16_t len) {
if (!len)
return 0;
if (((address & 0xFF) + len) > 256) {
Dbprintf("Flash_WriteDataCont 256 fail [ 0x%02x ] [ %u ]", (address & 0xFF) + len, len);
return 0;
}
if (((address >> 16) & 0xFF) > MAX_BLOCKS) {
Dbprintf("Flash_WriteDataCont, block out-of-range");
return 0;
}
FlashSendByte(PAGEPROG);
FlashSendByte((address >> 16) & 0xFF);
FlashSendByte((address >> 8) & 0xFF);
FlashSendByte((address >> 0) & 0xFF);
uint16_t i = 0;
for (; i < (len - 1); i++)
FlashSendByte(in[i]);
FlashSendLastByte(in[i]);
return len;
}
// assumes valid start 256 based 00 address
//
uint16_t Flash_Write(uint32_t address, uint8_t *in, uint16_t len) {
bool isok;
uint16_t res, bytes_sent = 0, bytes_remaining = len;
uint8_t buf[FLASH_MEM_BLOCK_SIZE];
while (bytes_remaining > 0) {
Flash_CheckBusy(BUSY_TIMEOUT);
Flash_WriteEnable();
uint32_t bytes_in_packet = MIN(FLASH_MEM_BLOCK_SIZE, bytes_remaining);
memcpy(buf, in + bytes_sent, bytes_in_packet);
res = Flash_WriteDataCont(address + bytes_sent, buf, bytes_in_packet);
bytes_remaining -= bytes_in_packet;
bytes_sent += bytes_in_packet;
isok = (res == bytes_in_packet);
if (!isok)
goto out;
}
out:
FlashStop();
return len;
}
bool Flash_WipeMemoryPage(uint8_t page) {
if (!FlashInit()) {
if (g_dbglevel > 3) Dbprintf("Flash_WriteData init fail");
return false;
}
Flash_ReadStat1();
// Each block is 64Kb. One block erase takes 1s ( 1000ms )
Flash_WriteEnable();
Flash_Erase64k(page);
Flash_CheckBusy(BUSY_TIMEOUT);
FlashStop();
// let spiffs check and update its info post flash erase
rdv40_spiffs_check();
return true;
}
// Wipes flash memory completely, fills with 0xFF
bool Flash_WipeMemory(void) {
if (!FlashInit()) {
if (g_dbglevel > 3) Dbprintf("Flash_WriteData init fail");
return false;
}
Flash_ReadStat1();
// Each block is 64Kb. Four blocks
// one block erase takes 1s ( 1000ms )
Flash_WriteEnable();
Flash_Erase64k(0);
Flash_CheckBusy(BUSY_TIMEOUT);
Flash_WriteEnable();
Flash_Erase64k(1);
Flash_CheckBusy(BUSY_TIMEOUT);
Flash_WriteEnable();
Flash_Erase64k(2);
Flash_CheckBusy(BUSY_TIMEOUT);
Flash_WriteEnable();
Flash_Erase64k(3);
Flash_CheckBusy(BUSY_TIMEOUT);
FlashStop();
return true;
}
// enable the flash write
void Flash_WriteEnable(void) {
FlashSendLastByte(WRITEENABLE);
if (g_dbglevel > 3) Dbprintf("Flash Write enabled");
}
// erase 4K at one time
// execution time: 0.8ms / 800us
bool Flash_Erase4k(uint8_t block, uint8_t sector) {
if (block > MAX_BLOCKS || sector > MAX_SECTORS) return false;
FlashSendByte(SECTORERASE);
FlashSendByte(block);
FlashSendByte(sector << 4);
FlashSendLastByte(00);
return true;
}
/*
// erase 32K at one time
// execution time: 0,3s / 300ms
bool Flash_Erase32k(uint32_t address) {
if (address & (32*1024 - 1)) {
if ( g_dbglevel > 1 ) Dbprintf("Flash_Erase32k : Address is not align at 4096");
return false;
}
FlashSendByte(BLOCK32ERASE);
FlashSendByte((address >> 16) & 0xFF);
FlashSendByte((address >> 8) & 0xFF);
FlashSendLastByte((address >> 0) & 0xFF);
return true;
}
*/
// erase 64k at one time
// since a block is 64kb, and there is four blocks.
// we only need block number, as MSB
// execution time: 1s / 1000ms
// 0x00 00 00 -- 0x 00 FF FF == block 0
// 0x01 00 00 -- 0x 01 FF FF == block 1
// 0x02 00 00 -- 0x 02 FF FF == block 2
// 0x03 00 00 -- 0x 03 FF FF == block 3
bool Flash_Erase64k(uint8_t block) {
if (block > MAX_BLOCKS) return false;
FlashSendByte(BLOCK64ERASE);
FlashSendByte(block);
FlashSendByte(0x00);
FlashSendLastByte(0x00);
return true;
}
/*
// Erase chip
void Flash_EraseChip(void) {
FlashSendLastByte(CHIPERASE);
}
*/
void Flashmem_print_status(void) {
DbpString(_CYAN_("Flash memory"));
Dbprintf(" Baudrate................ " _GREEN_("%d MHz"), FLASHMEM_SPIBAUDRATE / 1000000);
if (!FlashInit()) {
DbpString(" Init.................... " _RED_("FAILED"));
return;
}
DbpString(" Init.................... " _GREEN_("OK"));
uint8_t dev_id = Flash_ReadID();
switch (dev_id) {
case 0x11 :
DbpString(" Memory size............. " _YELLOW_("2 mbits / 256 kb"));
break;
case 0x10 :
DbpString(" Memory size..... ....... " _YELLOW_("1 mbits / 128 kb"));
break;
case 0x05 :
DbpString(" Memory size............. " _YELLOW_("512 kbits / 64 kb"));
break;
default :
DbpString(" Device ID............... " _YELLOW_(" --> Unknown <--"));
break;
}
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",
uid[7], uid[6], uid[5], uid[4],
uid[3], uid[2], uid[1], uid[0]
);
FlashStop();
}
void Flashmem_print_info(void) {
if (!FlashInit()) return;
DbpString(_CYAN_("Flash memory dictionary loaded"));
// load dictionary offsets.
uint8_t keysum[2];
uint16_t num;
Flash_CheckBusy(BUSY_TIMEOUT);
uint16_t isok = Flash_ReadDataCont(DEFAULT_MF_KEYS_OFFSET, keysum, 2);
if (isok == 2) {
num = ((keysum[1] << 8) | keysum[0]);
if (num != 0xFFFF && num != 0x0)
Dbprintf(" Mifare.................. "_YELLOW_("%d")" / "_GREEN_("%d")" keys", num, DEFAULT_MF_KEYS_MAX);
}
Flash_CheckBusy(BUSY_TIMEOUT);
isok = Flash_ReadDataCont(DEFAULT_T55XX_KEYS_OFFSET, keysum, 2);
if (isok == 2) {
num = ((keysum[1] << 8) | keysum[0]);
if (num != 0xFFFF && num != 0x0)
Dbprintf(" T55x7................... "_YELLOW_("%d")" / "_GREEN_("%d")" keys", num, DEFAULT_T55XX_KEYS_MAX);
}
Flash_CheckBusy(BUSY_TIMEOUT);
isok = Flash_ReadDataCont(DEFAULT_ICLASS_KEYS_OFFSET, keysum, 2);
if (isok == 2) {
num = ((keysum[1] << 8) | keysum[0]);
if (num != 0xFFFF && num != 0x0)
Dbprintf(" iClass.................. "_YELLOW_("%d")" / "_GREEN_("%d")" keys", num, DEFAULT_ICLASS_KEYS_MAX);
}
FlashStop();
}

View file

@ -100,17 +100,21 @@
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
void FlashmemSetSpiBaudrate(uint32_t baudrate);
bool FlashInit(void); bool FlashInit(void);
void FlashSetup(uint32_t baudrate); void Flash_UniqueID(uint8_t *uid);
void FlashStop(void); void FlashStop(void);
bool Flash_WaitIdle(void);
uint8_t Flash_ReadStat1(void);
uint8_t Flash_ReadStat2(void);
uint16_t FlashSendByte(uint32_t data);
void Flash_TransferAdresse(uint32_t address);
void FlashSetup(uint32_t baudrate);
bool Flash_CheckBusy(uint32_t timeout); bool Flash_CheckBusy(uint32_t timeout);
uint8_t Flash_ReadStat1(void);
uint16_t FlashSendByte(uint32_t data);
uint16_t FlashSendLastByte(uint32_t data);
#ifndef AS_BOOTROM
void FlashmemSetSpiBaudrate(uint32_t baudrate);
bool Flash_WaitIdle(void);
void Flash_TransferAdresse(uint32_t address);
void Flash_WriteEnable(void); void Flash_WriteEnable(void);
bool Flash_WipeMemoryPage(uint8_t page); bool Flash_WipeMemoryPage(uint8_t page);
@ -119,8 +123,12 @@ bool Flash_Erase4k(uint8_t block, uint8_t sector);
//bool Flash_Erase32k(uint32_t address); //bool Flash_Erase32k(uint32_t address);
bool Flash_Erase64k(uint8_t block); bool Flash_Erase64k(uint8_t block);
void Flash_UniqueID(uint8_t *uid); typedef struct {
uint8_t Flash_ReadID(void); uint8_t manufacturer_id;
uint8_t device_id;
} flash_device_type_90_t; // to differentiate from JDEC ID via cmd 9F
bool Flash_ReadID_90(flash_device_type_90_t *result);
uint16_t Flash_ReadData(uint32_t address, uint8_t *out, uint16_t len); 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); uint16_t Flash_ReadDataCont(uint32_t address, uint8_t *out, uint16_t len);
uint16_t Flash_Write(uint32_t address, uint8_t *in, uint16_t len); uint16_t Flash_Write(uint32_t address, uint8_t *in, uint16_t len);
@ -128,6 +136,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); uint16_t Flash_WriteDataCont(uint32_t address, uint8_t *in, uint16_t len);
void Flashmem_print_status(void); void Flashmem_print_status(void);
void Flashmem_print_info(void); void Flashmem_print_info(void);
uint16_t FlashSendLastByte(uint32_t data);
#endif // #ifndef AS_BOOTROM
#endif #endif

View file

@ -19,9 +19,13 @@
#include "ticks.h" #include "ticks.h"
#include "proxmark3_arm.h" #include "proxmark3_arm.h"
#ifndef AS_BOOTROM
#include "dbprint.h" #include "dbprint.h"
#endif
#ifndef AS_BOOTROM
// timer counts in 666ns increments (32/48MHz), rounding applies // timer counts in 666ns increments (32/48MHz), rounding applies
// WARNING: timer can't measure more than 43ms (666ns * 0xFFFF) // WARNING: timer can't measure more than 43ms (666ns * 0xFFFF)
void SpinDelayUsPrecision(int us) { void SpinDelayUsPrecision(int us) {
@ -117,40 +121,6 @@ uint32_t RAMFUNC GetTickCountDelta(uint32_t start_ticks) {
return (UINT32_MAX - start_ticks) + stop_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 // 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; 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 // Timer for bitbanging, or LF stuff when you need a very precis timer
// 1us = 1.5ticks // 1us = 1.5ticks
@ -282,7 +293,6 @@ void StartTicks(void) {
AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG;
while (AT91C_BASE_TC0->TC_CV > 0); while (AT91C_BASE_TC0->TC_CV > 0);
} }
uint32_t GetTicks(void) { uint32_t GetTicks(void) {
uint32_t hi, lo; uint32_t hi, lo;
@ -307,9 +317,6 @@ void WaitTicks(uint32_t ticks) {
void WaitUS(uint32_t us) { void WaitUS(uint32_t us) {
WaitTicks((us & 0x3FFFFFFF) * 3 / 2); WaitTicks((us & 0x3FFFFFFF) * 3 / 2);
} }
void WaitMS(uint32_t ms) {
WaitTicks((ms & 0x1FFFFF) * 1500);
}
// stop clock // stop clock
void StopTicks(void) { void StopTicks(void) {

View file

@ -26,6 +26,19 @@
#define GET_TICKS GetTicks() #define GET_TICKS GetTicks()
#endif #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 SpinDelay(int ms);
void SpinDelayUs(int us); void SpinDelayUs(int us);
void SpinDelayUsPrecision(int us); // precision 0.6us , running for 43ms before 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 GetTickCount(void);
uint32_t RAMFUNC GetTickCountDelta(uint32_t start_ticks); uint32_t RAMFUNC GetTickCountDelta(uint32_t start_ticks);
void StartCountUS(void);
uint32_t RAMFUNC GetCountUS(void);
void ResetUSClock(void); void ResetUSClock(void);
void SpinDelayCountUs(uint32_t us); void SpinDelayCountUs(uint32_t us);
@ -44,12 +55,10 @@ void ResetSspClk(void);
uint32_t RAMFUNC GetCountSspClk(void); uint32_t RAMFUNC GetCountSspClk(void);
uint32_t RAMFUNC GetCountSspClkDelta(uint32_t start); 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 WaitMS(uint32_t ms);
void StopTicks(void); #endif // #ifndef AS_BOOTROM
#endif #endif

View file

@ -366,11 +366,60 @@ static const char StrProduct[] = {
'p', 0, 'r', 0, 'o', 0, 'x', 0, 'm', 0, 'a', 0, 'r', 0, 'k', 0, '3', 0 'p', 0, 'r', 0, 'o', 0, 'x', 0, 'm', 0, 'a', 0, 'r', 0, 'k', 0, '3', 0
}; };
#ifndef WITH_FLASH
static const char StrSerialNumber[] = { static const char StrSerialNumber[] = {
14, // Length 14, // Length
0x03, // Type is string 0x03, // Type is string
'i', 0, 'c', 0, 'e', 0, 'm', 0, 'a', 0, 'n', 0 'i', 0, 'c', 0, 'e', 0, 'm', 0, 'a', 0, 'n', 0
}; };
#else // WITH_FLASH is defined
// Manually calculated size of descriptor with unique ID:
// offset 0, lengt h 1: total length field
// offset 1, length 1: descriptor type field
// offset 2, length 12: 6x unicode chars (original string)
// offset 14, length 4: 2x unicode chars (underscores) [[ to avoid descriptor being (size % 8) == 0, OS bug workaround ]]
// 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
0x03, // Type is string
'i', 0, 'c', 0, 'e', 0, 'm', 0, 'a', 0, 'n', 0,
'_', 0, '_', 0,
'x', 0, 'x', 0, 'x', 0, 'x', 0, 'x', 0, 'x', 0, 'x', 0, 'x', 0,
'x', 0, 'x', 0, 'x', 0, 'x', 0, 'x', 0, 'x', 0, 'x', 0, 'x', 0,
};
void usb_update_serial(uint64_t newSerialNumber) {
static bool configured = false; // TODO: enable by setting to false here...
if (configured) {
return;
}
// 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;
}
// Descriptor is, effectively, initially identical to non-unique serial
// number because it reports the shorter length in the first byte.
// 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 < 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[18 + (4 * i) + 0] = c1; // [ 18, 22, .., 42, 46 ]
StrSerialNumber[18 + (4 * i) + 2] = c2; // [ 20, 24, .., 44, 48 ]
}
StrSerialNumber[0] = USB_STRING_DESCRIPTOR_SERIAL_NUMBER_LENGTH;
}
#endif
// size includes their own field. // size includes their own field.
static const char StrMS_OSDescriptor[] = { static const char StrMS_OSDescriptor[] = {

View file

@ -31,6 +31,7 @@ bool usb_poll_validate_length(void);
uint32_t usb_read(uint8_t *data, size_t len); uint32_t usb_read(uint8_t *data, size_t len);
int usb_write(const uint8_t *data, const size_t len); int usb_write(const uint8_t *data, const size_t len);
uint32_t usb_read_ng(uint8_t *data, size_t len); uint32_t usb_read_ng(uint8_t *data, size_t len);
void usb_update_serial(uint64_t newSerialNumber);
void SetUSBreconnect(int value); void SetUSBreconnect(int value);
int GetUSBreconnect(void); int GetUSBreconnect(void);

View file

@ -11507,7 +11507,7 @@
}, },
"script help": { "script help": {
"command": "script help", "command": "script help",
"description": "This is a feature to run Lua/Cmd scripts. You can place scripts within the luascripts/cmdscripts folders. --------------------------------------------------------------------------------------- script list available offline: yes", "description": "This is a feature to run Lua/Cmd/Python scripts. You can place scripts within the luascripts/cmdscripts/pyscripts folders. --------------------------------------------------------------------------------------- script list available offline: yes",
"notes": [], "notes": [],
"offline": true, "offline": true,
"options": [], "options": [],
@ -11904,6 +11904,6 @@
"metadata": { "metadata": {
"commands_extracted": 749, "commands_extracted": 749,
"extracted_by": "PM3Help2JSON v1.00", "extracted_by": "PM3Help2JSON v1.00",
"extracted_on": "2023-02-11T10:42:29" "extracted_on": "2023-02-18T20:20:19"
} }
} }