Take Platform / SPI lock before doing anything, and disable BSM interrupts (and set both back at the end)
Some checks failed
continuous-integration/drone/push Build is failing

This commit is contained in:
DataHoarder 2021-01-06 08:50:15 +01:00
parent e8dcaa3af3
commit 6223ca323c
5 changed files with 138 additions and 1 deletions

View file

@ -76,9 +76,15 @@ int main(int argc, char **argv) {
return 1;
}
if(fm10k_mem_TakePlatformLock((uintptr_t) memmapAddr)){
printf("Error taking SPI Lock\n");
return 1;
}
SPI_COMMAND_READ_MANUFACTURER_RESULT manufacturerInfo = fm10k_mem_spi_ReadManufacturerData((uintptr_t) memmapAddr);
if (manufacturerInfo.value == 0) {
printf("Error getting manufacturer information\n");
fm10k_mem_ReleasePlatformLock((uintptr_t) memmapAddr);
return 1;
}
printf("Manufacturer Info 0x%08x :: JEDEC Manufacturer ID 0x%02x family 0x%02x density 0x%02x %02x:%02x\n",
@ -107,11 +113,13 @@ int main(int argc, char **argv) {
if (mbitsToRead > 1024) {
printf("Too many MBit: %u\n", mbitsToRead);
fm10k_mem_ReleasePlatformLock((uintptr_t) memmapAddr);
return 1;
}
if (mbitsToRead < 8) {
printf("Too few MBit: %u\n", mbitsToRead);
fm10k_mem_ReleasePlatformLock((uintptr_t) memmapAddr);
return 1;
}
@ -124,6 +132,7 @@ int main(int argc, char **argv) {
for (uint32_t addr = 0; addr < bootImageSize; addr += strideSize) {
printf("\rread @ 0x%08x / 0x%08x %d bytes", addr, bootImageSize, strideSize);
if (fm10k_mem_spi_ReadFlash((uintptr_t) memmapAddr, addr, value + addr, strideSize)) {
fm10k_mem_ReleasePlatformLock((uintptr_t) memmapAddr);
return 2;
}
}
@ -135,6 +144,8 @@ int main(int argc, char **argv) {
fclose(fdOutput);
fm10k_mem_ReleasePlatformLock((uintptr_t) memmapAddr);
printf("\nRead %u bytes\n", bootImageSize);
return 0;

View file

@ -98,9 +98,15 @@ int main(int argc, char **argv) {
return 1;
}
if(fm10k_mem_TakePlatformLock((uintptr_t) memmapAddr)){
printf("Error taking SPI Lock\n");
return 1;
}
SPI_COMMAND_READ_MANUFACTURER_RESULT manufacturerInfo = fm10k_mem_spi_ReadManufacturerData((uintptr_t) memmapAddr);
if (manufacturerInfo.value == 0) {
printf("Error getting manufacturer information\n");
fm10k_mem_ReleasePlatformLock((uintptr_t) memmapAddr);
return 1;
}
printf("Manufacturer Info 0x%08x :: JEDEC Manufacturer ID 0x%02x family 0x%02x density 0x%02x %02x:%02x\n",
@ -121,11 +127,13 @@ int main(int argc, char **argv) {
if (mbitsToReadMax > 1024) {
printf("Too many MBit: %u\n", mbitsToReadMax);
fm10k_mem_ReleasePlatformLock((uintptr_t) memmapAddr);
return 1;
}
if (mbitsToReadMax == 0) {
printf("Too few MBit: %u\n", mbitsToReadMax);
fm10k_mem_ReleasePlatformLock((uintptr_t) memmapAddr);
return 1;
}
@ -134,6 +142,7 @@ int main(int argc, char **argv) {
if (fileSize > bootImageSizeMax) {
printf("Image too large: have %d, can write max %d bytes.\n", fileSize, bootImageSizeMax);
fm10k_mem_ReleasePlatformLock((uintptr_t) memmapAddr);
return 1;
} else if (fileSize < bootImageSizeMax) {
do {
@ -147,11 +156,13 @@ int main(int argc, char **argv) {
if (fread(value, 1, bootImageSizeMax, fdInput) != bootImageSizeMax) {
printf("Error reading image file.\n");
fm10k_mem_ReleasePlatformLock((uintptr_t) memmapAddr);
return 1;
}
if (fread(valueBackup, 1, bootImageSizeMax, fdBackup) != bootImageSizeMax) {
printf("Error reading backup image file.\n");
fm10k_mem_ReleasePlatformLock((uintptr_t) memmapAddr);
return 1;
}
@ -163,6 +174,7 @@ int main(int argc, char **argv) {
for (uint32_t addr = 0; addr < bootImageSizeMax; addr += strideSize) {
printf("\rbackup check @ 0x%08x / 0x%08x %d bytes", addr, bootImageSizeMax, strideSize);
if (fm10k_mem_spi_ReadFlash((uintptr_t) memmapAddr, addr, valueCheck + addr, strideSize)) {
fm10k_mem_ReleasePlatformLock((uintptr_t) memmapAddr);
return 2;
}
}
@ -171,6 +183,7 @@ int main(int argc, char **argv) {
if (memcmp(valueBackup, valueCheck, bootImageSizeMax) != 0) {
printf("Backup image mismatch! Dump image again.\n");
fm10k_mem_ReleasePlatformLock((uintptr_t) memmapAddr);
return 1;
} else {
printf("Backup matches.\n");
@ -188,6 +201,7 @@ int main(int argc, char **argv) {
if (memcmp(valueBackup + addr, value + addr, strideSize) != 0) {
printf("write @ 0x%08x\n", addr);
if (fm10k_mem_spi_WriteFlash((uintptr_t) memmapAddr, addr, value + addr, strideSize)) {
fm10k_mem_ReleasePlatformLock((uintptr_t) memmapAddr);
return 2;
}
sleep(1);
@ -202,6 +216,7 @@ int main(int argc, char **argv) {
for (uint32_t addr = 0; addr < bootImageSizeMax; addr += strideSize) {
printf("\rverify check @ 0x%08x / 0x%08x %d bytes", addr, bootImageSizeMax, strideSize);
if (fm10k_mem_spi_ReadFlash((uintptr_t) memmapAddr, addr, valueCheck + addr, strideSize)) {
fm10k_mem_ReleasePlatformLock((uintptr_t) memmapAddr);
return 2;
}
}
@ -224,6 +239,7 @@ int main(int argc, char **argv) {
if (memcmp(valueBackup + addr, valueCheck + addr, strideSize) != 0) {
printf("write backup @ 0x%08x\n", addr);
if (fm10k_mem_spi_WriteFlash((uintptr_t) memmapAddr, addr, valueBackup + addr, strideSize)) {
fm10k_mem_ReleasePlatformLock((uintptr_t) memmapAddr);
return 2;
}
sleep(1);
@ -235,6 +251,8 @@ int main(int argc, char **argv) {
sleep(1);
fm10k_mem_ReleasePlatformLock((uintptr_t) memmapAddr);
free(value);
free(valueBackup);

View file

@ -35,6 +35,7 @@
#include <limits.h>
#include <unistd.h>
#include <stdlib.h>
#include <time.h>
KNOWN_FLASH_DEVICE KNOWN_FLASH_DEVICE_LIST[] = {
{{0x0101271f}, "Adesto AT45DB321E 32-Mbit", 32}, // Present on Silicom PE3100G2DQiRM-QX4
@ -427,6 +428,81 @@ const KNOWN_FLASH_DEVICE *getKnownFlashFromManufacturerData(SPI_COMMAND_READ_MAN
return NULL;
}
uint8_t fm10k_mem_spi_LockTake(uintptr_t mem){
uint32_t maxTries = 64;
API_SPI_LOCK_STATE spiLock;
do{
ReadRegister32(mem, FM10K_API_SPI_LOCK_STATE, &spiLock.value);
if(!spiLock.fields.LockTaken){
spiLock.fields.LockTaken = 1;
spiLock.fields.LockOwner = 0; //Switch API
WriteRegister32(mem, FM10K_API_SPI_LOCK_STATE, spiLock.value);
nanosleep(&(struct timespec){0, 50000}, NULL); //Delay to observe if lock was actually taken by us
ReadRegister32(mem, FM10K_API_SPI_LOCK_STATE, &spiLock.value);
if(spiLock.fields.LockTaken && spiLock.fields.LockOwner == 0){
printf("Taken SPI Lock\n");
return 0;
}
}else if(spiLock.fields.LockOwner == 0){ //Are we taking a lock again, with same owner?
printf("WARNING: SPI Lock was already taken by us, maybe other process was using it?\n");
return 0;
}
nanosleep(&(struct timespec){0, 1000}, NULL);
} while (--maxTries);
return 1;
}
void fm10k_mem_spi_LockRelease(uintptr_t mem){
API_SPI_LOCK_STATE spiLock;
ReadRegister32(mem, FM10K_API_SPI_LOCK_STATE, &spiLock.value);
if(!spiLock.fields.LockTaken) {
printf("WARNING: SPI Lock was already released\n");
return;
}
if(spiLock.fields.LockOwner != 0){
printf("WARNING: SPI Lock Owner unexpected: %u\n", spiLock.fields.LockOwner);
return;
}
spiLock.fields.LockTaken = 0;
WriteRegister32(mem, FM10K_API_SPI_LOCK_STATE, spiLock.value);
printf("Released SPI Lock\n");
}
uint32_t bsm_interruptMask[2] = {0, 0};
void fm10k_mem_bsm_DisableInterrupts(uintptr_t mem){
//Save old registers
ReadRegister32(mem, FM10K_REGISTER_INTERRUPT_MASK_BSM(0), bsm_interruptMask);
ReadRegister32(mem, FM10K_REGISTER_INTERRUPT_MASK_BSM(1), bsm_interruptMask + 1);
WriteRegister32(mem, FM10K_REGISTER_INTERRUPT_MASK_BSM(0), 0xFFFFFFFF);
WriteRegister32(mem, FM10K_REGISTER_INTERRUPT_MASK_BSM(1), 0xFFFFFFFF);
}
void fm10k_mem_bsm_RestoreInterrupts(uintptr_t mem){
WriteRegister32(mem, FM10K_REGISTER_INTERRUPT_MASK_BSM(0), bsm_interruptMask[0]);
WriteRegister32(mem, FM10K_REGISTER_INTERRUPT_MASK_BSM(1), bsm_interruptMask[1]);
}
uint8_t fm10k_mem_TakePlatformLock(uintptr_t mem){
if(fm10k_mem_spi_LockTake(mem)){
return 1;
}
fm10k_mem_bsm_DisableInterrupts(mem);
return 0;
}
void fm10k_mem_ReleasePlatformLock(uintptr_t mem){
fm10k_mem_spi_LockRelease(mem);
fm10k_mem_bsm_RestoreInterrupts(mem);
}
FM10K_PCI_DEVICE fm10k_pci_findDevice() {
DIR *folder;
char fileName[PATH_MAX];

View file

@ -41,6 +41,13 @@
//From Datasheet, 11.25.1 MGMT Map, Table 11-37
#define FM10K_REGISTER_BASE 0
#define FM10K_REGISTER_BSM_SCRATCH(r) ((0x800) + (FM10K_REGISTER_BASE) + (r))
#define FM10K_REGISTER_INTERRUPT_MASK_BSM(w) ((0x442) + (FM10K_REGISTER_BASE) + (w))
#define FM10K_API_SPI_LOCK_STATE FM10K_REGISTER_BSM_SCRATCH(0x000)
#define FM10K_API_EEPROM_IMAGE_VERSION FM10K_REGISTER_BSM_SCRATCH(0x191)
#define FM10K_REGISTER_SPI_TX_DATA ((0xC26) + (FM10K_REGISTER_BASE))
#define FM10K_REGISTER_SPI_RX_DATA ((0xC27) + (FM10K_REGISTER_BASE))
#define FM10K_REGISTER_SPI_HEADER ((0xC28) + (FM10K_REGISTER_BASE))
@ -56,6 +63,15 @@
/* Test for GCC >= 4.4.0, see https://gcc.gnu.org/gcc-4.4/changes.html : Packed bit-fields of type char were not properly bit-packed on many targets prior to GCC 4.4 */
#if __GNUC__ > 4 || (__GNUC__ == 4 && (__GNUC_MINOR__ >= 4)) || __clang__ || __TINYC__
typedef union {
uint32_t value;
struct {
uint8_t LockTaken : 1; //Whether lock is currently taken by anyone
uint8_t LockOwner : 2; //Who owns the lock. Switch API = 0, QV tools = 1, Board Manager = 2, RESERVED = 3
uint32_t Reserved : 29;
} __attribute__((packed)) fields;
} API_SPI_LOCK_STATE;
typedef union {
uint32_t value;
struct {
@ -83,7 +99,7 @@ typedef union {
uint8_t familyCode: 3;
uint8_t productVariant: 5;
uint8_t subCode: 3;
uint8_t RESERVED: 8;
uint8_t Reserved: 8;
} __attribute__((packed)) fields;
} SPI_COMMAND_READ_MANUFACTURER_RESULT;
@ -106,6 +122,18 @@ uint32_t get_interval_diff(struct timeval *begin, struct timeval *end);
uint32_t fm10k_mem_spi_SetCtrlReg(uintptr_t mem, SPI_CTRL value);
uint8_t fm10k_mem_spi_LockTake(uintptr_t mem);
void fm10k_mem_spi_LockRelease(uintptr_t mem);
void fm10k_mem_bsm_DisableInterrupts(uintptr_t mem);
void fm10k_mem_bsm_RestoreInterrupts(uintptr_t mem);
uint8_t fm10k_mem_TakePlatformLock(uintptr_t mem);
void fm10k_mem_ReleasePlatformLock(uintptr_t mem);
void fm10k_mem_spi_Enable(uintptr_t mem);
void fm10k_mem_spi_Disable(uintptr_t mem);

View file

@ -47,6 +47,10 @@ int main(int argc, char **argv) {
SPI_COMMAND_READ_MANUFACTURER_RESULT s;
TEST((uint32_t)sizeof(s.fields), (uint32_t)sizeof(s.value), "SPI_COMMAND_READ_MANUFACTURER_RESULT packed misalignment. size struct %u, size value %u");
}
{
API_SPI_LOCK_STATE s;
TEST((uint32_t)sizeof(s.fields), (uint32_t)sizeof(s.value), "API_SPI_LOCK_STATE packed misalignment. size struct %u, size value %u");
}
printf("\nTests run, failed %u/%u\n", testsFailed, tests);
return testsFailed > 0 ? 1 : 0;