From 11aa411875f4b46851106140433595fdb9fa5f69 Mon Sep 17 00:00:00 2001 From: WeebDataHoarder <57538841+weebdatahoarder@users.noreply.github.com> Date: Sun, 20 Dec 2020 23:07:01 +0100 Subject: [PATCH 1/5] Moved FM10K SPI functions to its own files --- Makefile | 12 +- fm10k-dump.c | 269 +------------------------------------------ fm10k.c | 319 +++++++++++++++++++++++++++++++++++++++++++++++++++ fm10k.h | 111 ++++++++++++++++++ 4 files changed, 440 insertions(+), 271 deletions(-) create mode 100644 fm10k.c create mode 100644 fm10k.h diff --git a/Makefile b/Makefile index 4666864..aa6dc11 100644 --- a/Makefile +++ b/Makefile @@ -1,14 +1,20 @@ CC=cc CFLAGS=-Wall -Wno-unknown-warning-option -Wno-packed-bitfield-compat -default: fm10k-dump +default: all + +all: fm10k-dump + +fm10k.o: fm10k.c + $(CC) -c fm10k.c -o fm10k.o $(CFLAGS) fm10k-dump.o: fm10k-dump.c $(CC) -c fm10k-dump.c -o fm10k-dump.o $(CFLAGS) -fm10k-dump: fm10k-dump.o - $(CC) fm10k-dump.o -o fm10k-dump $(CFLAGS) +fm10k-dump: fm10k-dump.o fm10k.o + $(CC) fm10k-dump.o fm10k.o -o fm10k-dump $(CFLAGS) clean: -rm -f fm10k-dump -rm -f fm10k-dump.o + -rm -f fm10k.o diff --git a/fm10k-dump.c b/fm10k-dump.c index 5fb2651..ef8d835 100644 --- a/fm10k-dump.c +++ b/fm10k-dump.c @@ -32,280 +32,13 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -#include +#include "fm10k.h" #include #include -#include #include #include #include -#define FM10K_UIO_SIZE 0x0000000004000000 -#define FM10K_UIO_OFFSET 0 - -//From Datasheet, 11.25.1 MGMT Map, Table 11-37 -#define FM10K_REGISTER_BASE 0 - -#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)) -#define FM10K_REGISTER_SPI_CTRL ((0xC29) + (FM10K_REGISTER_BASE)) - -#define FM10K_SPI_FREQ_KHZ 50000 - -#define FM10K_SPI_HEADER_COMMAND_READ_BYTES 0x3 -#define FM10K_SPI_HEADER_COMMAND_READ_MANUFACTURER_INFORMATION 0x9F - -/* 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__ - -typedef union { - struct { - uint16_t Freq : 10; // Actual speed is PCIE_REFCLK/(2*(1+Freq)) - uint8_t Enable : 1; - uint8_t Command : 4; // 0b00 = reset - uint8_t HeaderSize : 2; // 0b00 = 4 bytes - uint8_t DataSize : 2; // 0b00 = 4 bytes - uint8_t DataShiftMethod : 2; // 0b00 = SINGLE, 0b01 = DUAL, 0b10 = QUAD, 0b11 = Reserved - uint8_t Busy : 1; // volatile ReadOnly - uint8_t Selected : 1; // volatile ReadOnly - uint8_t DirIO2 : 1; // 0b0 = Input, 0b1 = Output - uint8_t DirIO3 : 1; // 0b0 = Input, 0b1 = Output - uint8_t PinIO2 : 1; // volatile ReadWrite - uint8_t PinIO3 : 1; // volatile ReadWrite - uint8_t Reserved : 5; - } __attribute__((packed)) fields; - uint32_t value; -} SPI_CTRL; - -typedef union { - struct { - uint8_t RESERVED : 8; - uint8_t productVariant : 5; - uint8_t subCode : 3; - uint8_t densityCode : 5; - uint8_t familyCode : 3; - uint8_t manufacturerId : 8; - } __attribute__((packed)) fields; - uint32_t value; -} SPI_COMMAND_READ_MANUFACTURER_RESULT; - -#else -#error "Packed bit-fields of type char were not properly bit-packed on many targets prior to GCC 4.4, upgrade to GCC >= 4.4." -#endif - -void ReadRegister32(uintptr_t mem, uint32_t addr, uint32_t* value) { - *value = *(((uint32_t*)mem) + addr); -} - -void WriteRegister32(uintptr_t mem, uint32_t addr, uint32_t value) { - *(uint32_t volatile*)(((uint32_t*)mem) + addr) = value; - - //If returning instantly this will caused missed writes. nanosleep wait of 1 nsec was too much. Busy wait works -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wunused-but-set-variable" - volatile uint32_t dummy; - for(uint32_t i = 0; i < 100; ++i){ - dummy = i; - } -#pragma GCC diagnostic pop -} - -uint32_t get_interval_diff(struct timeval *begin, struct timeval *end) { - struct timeval endT; - struct timeval diff; - - if (end == NULL) { - gettimeofday(&endT, NULL); - } else { - endT.tv_sec = end->tv_sec; - endT.tv_usec = end->tv_usec; - } - - diff.tv_sec = endT.tv_sec - begin->tv_sec; - diff.tv_usec = endT.tv_usec - begin->tv_usec; - - return (diff.tv_sec * 1000 + diff.tv_usec / 1000); -} - -uint32_t fm10k_uio_spi_SetCtrlReg(uintptr_t mem, SPI_CTRL value){ - struct timeval startTime; - uint8_t isTimeout = 0; - SPI_CTRL spiCtrl = {0}; - - WriteRegister32(mem, FM10K_REGISTER_SPI_CTRL, value.value); - - gettimeofday(&startTime, NULL); - do{ - if(isTimeout){ - printf("Timeout waiting for SPI_CTRL.Busy 0x%02x\n", spiCtrl.value); - return 1; - } - - if(get_interval_diff(&startTime, NULL) > 50){ - isTimeout = 1; - } - - ReadRegister32(mem, FM10K_REGISTER_SPI_CTRL, &spiCtrl.value); - - } while (spiCtrl.fields.Busy); - - /* write back SPI_CTRL with command = 0 */ - spiCtrl.fields.Command = 0; - WriteRegister32(mem, FM10K_REGISTER_SPI_CTRL, spiCtrl.value); - - return 0; -} - -void fm10k_uio_spi_Enable(uintptr_t mem){ - //ENABLE SPI - SPI_CTRL spiCtrl; - ReadRegister32(mem, FM10K_REGISTER_SPI_CTRL, &spiCtrl.value); - /* keep current freq setting and set SPI Enable */ - SPI_CTRL newSpiCtrl; - newSpiCtrl.value = 0; - newSpiCtrl.fields.Freq = spiCtrl.fields.Freq; - newSpiCtrl.fields.Enable = 1; - WriteRegister32(mem, FM10K_REGISTER_SPI_CTRL, newSpiCtrl.value); -} - -void fm10k_uio_spi_Disable(uintptr_t mem){ - //DISABLE SPI - SPI_CTRL spiCtrl; - ReadRegister32(mem, FM10K_REGISTER_SPI_CTRL, &spiCtrl.value); - /* keep current freq setting and set SPI Enable = 0 */ - SPI_CTRL newSpiCtrl; - newSpiCtrl.value = 0; - newSpiCtrl.fields.Freq = spiCtrl.fields.Freq; - WriteRegister32(mem, FM10K_REGISTER_SPI_CTRL, newSpiCtrl.value); -} - - -//Error if result.value is 0x00 -SPI_COMMAND_READ_MANUFACTURER_RESULT fm10k_uio_spi_ReadManufacturerData(uintptr_t mem){ - - SPI_COMMAND_READ_MANUFACTURER_RESULT result = {0}; - SPI_CTRL currentSpiCtrl; - SPI_CTRL spiCtrl = {0}; - - uint32_t header; - int32_t freq; - - fm10k_uio_spi_Enable(mem); - - - ReadRegister32(mem, FM10K_REGISTER_SPI_CTRL, ¤tSpiCtrl.value); - - if(FM10K_SPI_FREQ_KHZ > 0){ - freq = ((100000 / (int)FM10K_SPI_FREQ_KHZ) / 2) - 1; - if (freq < 0){ - freq = 0; - } - spiCtrl.fields.Freq = freq; - } - - spiCtrl.fields.Enable = currentSpiCtrl.fields.Enable; - - /* header: command (1 byte: READ_BYTES) */ - header = FM10K_SPI_HEADER_COMMAND_READ_MANUFACTURER_INFORMATION; - WriteRegister32(mem, FM10K_REGISTER_SPI_HEADER, header); - - /* first loop only: set send header flag. Following loops: shift only data. */ - spiCtrl.fields.Command |= 0b0001; - spiCtrl.fields.Command |= 0b0100; - spiCtrl.fields.HeaderSize = 1; - spiCtrl.fields.DataSize = 4 & 0b11; - - if(fm10k_uio_spi_SetCtrlReg(mem, spiCtrl)){ - return result; - } - - /* get data */ - ReadRegister32(mem, FM10K_REGISTER_SPI_RX_DATA, &result.value); - - /* release CS */ - spiCtrl.fields.Command = 0b1000; - if(fm10k_uio_spi_SetCtrlReg(mem, spiCtrl)){ - result.value = 0; - return result; - } - - - fm10k_uio_spi_Disable(mem); - - return result; -} - - -uint32_t fm10k_uio_spi_ReadFlash(uintptr_t mem, uint32_t address, uint8_t* data, int32_t len){ - - SPI_CTRL currentSpiCtrl; - SPI_CTRL spiCtrl = {0}; - - uint32_t rxData; - uint32_t header; - int32_t freq; - int32_t cnt; - int32_t numRead; - - fm10k_uio_spi_Enable(mem); - - - ReadRegister32(mem, FM10K_REGISTER_SPI_CTRL, ¤tSpiCtrl.value); - - if(FM10K_SPI_FREQ_KHZ > 0){ - freq = ((100000 / (int)FM10K_SPI_FREQ_KHZ) / 2) - 1; - if (freq < 0){ - freq = 0; - } - spiCtrl.fields.Freq = freq; - } - - spiCtrl.fields.Enable = currentSpiCtrl.fields.Enable; - - /* header: command (1 byte: READ_BYTES) + address (3 bytes) */ - header = (FM10K_SPI_HEADER_COMMAND_READ_BYTES << 24) | (address & 0xffffff); - WriteRegister32(mem, FM10K_REGISTER_SPI_HEADER, header); - - /* first loop only: set send header flag. Following loops: shift only data. */ - spiCtrl.fields.Command |= 0b0001; - - cnt = 0; - while (cnt < len){ - /* determine the number of data bytes to read [1..4] */ - numRead = (len - cnt) > 3 ? 4 : (len - cnt); - /* set 'shift data' flag and number of data bytes */ - spiCtrl.fields.Command |= 0b0100; - spiCtrl.fields.DataSize = numRead & 0b11; - - if(fm10k_uio_spi_SetCtrlReg(mem, spiCtrl)){ - return 1; - } - - /* get data */ - ReadRegister32(mem, FM10K_REGISTER_SPI_RX_DATA, &rxData); - - /* push the read data into the array */ - while (numRead) { - numRead--; - data[cnt++] = (rxData >> (numRead * 8)) & 0xff; - } - - spiCtrl.fields.Command = 0b0000; - spiCtrl.fields.DataSize = 0b0000; - } - - /* release CS */ - spiCtrl.fields.Command = 0b1000; - if(fm10k_uio_spi_SetCtrlReg(mem, spiCtrl)){ - return 1; - } - - - fm10k_uio_spi_Disable(mem); - - return 0; -} int main(int argc, char** argv){ int fdUIO; diff --git a/fm10k.c b/fm10k.c new file mode 100644 index 0000000..b27b235 --- /dev/null +++ b/fm10k.c @@ -0,0 +1,319 @@ +/***************************************************************************** + * File: fm10k.c + * Creation Date: December 20, 2020 + * + * Copyright (c) 2014 - 2015, Intel Corporation + * Copyright (c) 2020, FM10K-Documentation Contributors + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the copyright holders nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *****************************************************************************/ + +#include "fm10k.h" +#include + +void ReadRegister32(uintptr_t mem, uint32_t addr, uint32_t* value) { + *value = *(((uint32_t*)mem) + addr); +} + +void WriteRegister32(uintptr_t mem, uint32_t addr, uint32_t value) { + *(uint32_t volatile*)(((uint32_t*)mem) + addr) = value; + + //If returning instantly this will caused missed writes. nanosleep wait of 1 nsec was too much. Busy wait works +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-but-set-variable" + volatile uint32_t dummy; + for(uint32_t i = 0; i < 100; ++i){ + dummy = i; + } +#pragma GCC diagnostic pop +} + +uint32_t get_interval_diff(struct timeval *begin, struct timeval *end) { + struct timeval endT; + struct timeval diff; + + if (end == NULL) { + gettimeofday(&endT, NULL); + } else { + endT.tv_sec = end->tv_sec; + endT.tv_usec = end->tv_usec; + } + + diff.tv_sec = endT.tv_sec - begin->tv_sec; + diff.tv_usec = endT.tv_usec - begin->tv_usec; + + return (diff.tv_sec * 1000 + diff.tv_usec / 1000); +} + +uint32_t fm10k_uio_spi_SetCtrlReg(uintptr_t mem, SPI_CTRL value){ + struct timeval startTime; + uint8_t isTimeout = 0; + SPI_CTRL spiCtrl = {0}; + + WriteRegister32(mem, FM10K_REGISTER_SPI_CTRL, value.value); + + gettimeofday(&startTime, NULL); + do{ + if(isTimeout){ + printf("Timeout waiting for SPI_CTRL.Busy 0x%02x\n", spiCtrl.value); + return 1; + } + + if(get_interval_diff(&startTime, NULL) > 50){ + isTimeout = 1; + } + + ReadRegister32(mem, FM10K_REGISTER_SPI_CTRL, &spiCtrl.value); + + } while (spiCtrl.fields.Busy); + + /* write back SPI_CTRL with command = 0 */ + spiCtrl.fields.Command = 0; + WriteRegister32(mem, FM10K_REGISTER_SPI_CTRL, spiCtrl.value); + + return 0; +} + +void fm10k_uio_spi_Enable(uintptr_t mem){ + //ENABLE SPI + SPI_CTRL spiCtrl; + ReadRegister32(mem, FM10K_REGISTER_SPI_CTRL, &spiCtrl.value); + /* keep current freq setting and set SPI Enable */ + SPI_CTRL newSpiCtrl; + newSpiCtrl.value = 0; + newSpiCtrl.fields.Freq = spiCtrl.fields.Freq; + newSpiCtrl.fields.Enable = 1; + WriteRegister32(mem, FM10K_REGISTER_SPI_CTRL, newSpiCtrl.value); +} + +void fm10k_uio_spi_Disable(uintptr_t mem){ + //DISABLE SPI + SPI_CTRL spiCtrl; + ReadRegister32(mem, FM10K_REGISTER_SPI_CTRL, &spiCtrl.value); + /* keep current freq setting and set SPI Enable = 0 */ + SPI_CTRL newSpiCtrl; + newSpiCtrl.value = 0; + newSpiCtrl.fields.Freq = spiCtrl.fields.Freq; + WriteRegister32(mem, FM10K_REGISTER_SPI_CTRL, newSpiCtrl.value); +} + + +//Error if result.value is 0x00 +SPI_COMMAND_READ_MANUFACTURER_RESULT fm10k_uio_spi_ReadManufacturerData(uintptr_t mem){ + + SPI_COMMAND_READ_MANUFACTURER_RESULT result = {0}; + SPI_CTRL currentSpiCtrl; + SPI_CTRL spiCtrl = {0}; + + uint32_t header; + int32_t freq; + + fm10k_uio_spi_Enable(mem); + + + ReadRegister32(mem, FM10K_REGISTER_SPI_CTRL, ¤tSpiCtrl.value); + + if(FM10K_SPI_FREQ_KHZ > 0){ + freq = ((100000 / (int)FM10K_SPI_FREQ_KHZ) / 2) - 1; + if (freq < 0){ + freq = 0; + } + spiCtrl.fields.Freq = freq; + } + + spiCtrl.fields.Enable = currentSpiCtrl.fields.Enable; + + /* header: command (1 byte: READ_BYTES) */ + header = FM10K_SPI_HEADER_COMMAND_READ_MANUFACTURER_INFORMATION; + WriteRegister32(mem, FM10K_REGISTER_SPI_HEADER, header); + + /* first loop only: set send header flag. Following loops: shift only data. */ + spiCtrl.fields.Command |= 0b0001; + spiCtrl.fields.Command |= 0b0100; + spiCtrl.fields.HeaderSize = 1; + spiCtrl.fields.DataSize = 4 & 0b11; + + if(fm10k_uio_spi_SetCtrlReg(mem, spiCtrl)){ + return result; + } + + uint32_t rxData; + /* get data */ + ReadRegister32(mem, FM10K_REGISTER_SPI_RX_DATA, &rxData); + + result.value = ((rxData>>24)&0xff) | ((rxData<<8)&0xff0000) | ((rxData>>8)&0xff00) | ((rxData<<24)&0xff000000); + + + /* release CS */ + spiCtrl.fields.Command = 0b1000; + if(fm10k_uio_spi_SetCtrlReg(mem, spiCtrl)){ + result.value = 0; + return result; + } + + + fm10k_uio_spi_Disable(mem); + + return result; +} + +uint32_t fm10k_uio_spi_ReadFlash(uintptr_t mem, uint32_t address, uint8_t* data, uint32_t len){ + + SPI_CTRL currentSpiCtrl; + SPI_CTRL spiCtrl = {0}; + + uint32_t rxData; + uint32_t header; + int32_t freq; + uint32_t cnt; + uint32_t numRead; + + fm10k_uio_spi_Enable(mem); + + + ReadRegister32(mem, FM10K_REGISTER_SPI_CTRL, ¤tSpiCtrl.value); + + if(FM10K_SPI_FREQ_KHZ > 0){ + freq = ((100000 / (int)FM10K_SPI_FREQ_KHZ) / 2) - 1; + if (freq < 0){ + freq = 0; + } + spiCtrl.fields.Freq = freq; + } + + spiCtrl.fields.Enable = currentSpiCtrl.fields.Enable; + + /* header: command (1 byte: READ_BYTES) + address (3 bytes) */ + header = (FM10K_SPI_HEADER_COMMAND_READ_BYTES << 24) | (address & 0xffffff); + WriteRegister32(mem, FM10K_REGISTER_SPI_HEADER, header); + + /* first loop only: set send header flag. Following loops: shift only data. */ + spiCtrl.fields.Command |= 0b0001; + + cnt = 0; + while (cnt < len){ + /* determine the number of data bytes to read [1..4] */ + numRead = (len - cnt) > 3 ? 4 : (len - cnt); + /* set 'shift data' flag and number of data bytes */ + spiCtrl.fields.Command |= 0b0100; + spiCtrl.fields.DataSize = numRead & 0b11; + + if(fm10k_uio_spi_SetCtrlReg(mem, spiCtrl)){ + return 1; + } + + /* get data */ + ReadRegister32(mem, FM10K_REGISTER_SPI_RX_DATA, &rxData); + + /* push the read data into the array */ + while (numRead) { + numRead--; + data[cnt++] = (rxData >> (numRead * 8)) & 0xff; + } + + spiCtrl.fields.Command = 0b0000; + spiCtrl.fields.DataSize = 0b0000; + } + + /* release CS */ + spiCtrl.fields.Command = 0b1000; + if(fm10k_uio_spi_SetCtrlReg(mem, spiCtrl)){ + return 1; + } + + + fm10k_uio_spi_Disable(mem); + + return 0; +} + + +uint32_t fm10k_uio_spi_WriteFlash(uintptr_t mem, uint32_t address, const uint8_t* data, uint32_t len){ + + SPI_CTRL currentSpiCtrl; + SPI_CTRL spiCtrl = {0}; + + uint32_t txData; + uint32_t header; + int32_t freq; + uint32_t cnt; + uint32_t numWrite; + + fm10k_uio_spi_Enable(mem); + + + ReadRegister32(mem, FM10K_REGISTER_SPI_CTRL, ¤tSpiCtrl.value); + + if(FM10K_SPI_FREQ_KHZ > 0){ + freq = ((100000 / (int)FM10K_SPI_FREQ_KHZ) / 2) - 1; + if (freq < 0){ + freq = 0; + } + spiCtrl.fields.Freq = freq; + } + + spiCtrl.fields.Enable = 1; + + /* header: command (1 byte: PAGE_PROGRAM) + address (3 bytes) */ + header = (FM10K_SPI_HEADER_COMMAND_PAGE_PROGRAM << 24) | (address & 0xffffff); + WriteRegister32(mem, FM10K_REGISTER_SPI_HEADER, header); + + /* first loop only: set send header flag. Following loops: shift only data. */ + spiCtrl.fields.Command |= 0b0001; + + cnt = 0; + while (cnt < len){ + /* determine the number of data bytes to read [1..4] */ + numWrite = (len - cnt) > 3 ? 4 : (len - cnt); + /* set 'shift data' flag and number of data bytes */ + spiCtrl.fields.Command |= 0b0100; + spiCtrl.fields.DataSize = numWrite & 0b11; + + txData = 0; + while (numWrite--) { + txData = (txData << 8) | data[cnt++]; + } + /* set data to be written */ + WriteRegister32(mem, FM10K_REGISTER_SPI_TX_DATA, txData); + + /* send command to the flash */ + if(fm10k_uio_spi_SetCtrlReg(mem, spiCtrl)){ + return 1; + } + + spiCtrl.fields.Command = 0b0000; + spiCtrl.fields.DataSize = 0b0000; + } + + /* release CS */ + spiCtrl.fields.Command = 0b1000; + if(fm10k_uio_spi_SetCtrlReg(mem, spiCtrl)){ + return 1; + } + + + fm10k_uio_spi_Disable(mem); + + return 0; +} \ No newline at end of file diff --git a/fm10k.h b/fm10k.h new file mode 100644 index 0000000..a729330 --- /dev/null +++ b/fm10k.h @@ -0,0 +1,111 @@ +/***************************************************************************** + * File: fm10k.h + * Creation Date: December 20, 2020 + * + * Copyright (c) 2014 - 2015, Intel Corporation + * Copyright (c) 2020, FM10K-Documentation Contributors + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the copyright holders nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *****************************************************************************/ + +#pragma once + +#include +#include + +#define FM10K_UIO_SIZE 0x0000000004000000 +#define FM10K_UIO_OFFSET 0 + +//From Datasheet, 11.25.1 MGMT Map, Table 11-37 +#define FM10K_REGISTER_BASE 0 + +#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)) +#define FM10K_REGISTER_SPI_CTRL ((0xC29) + (FM10K_REGISTER_BASE)) + +#define FM10K_SPI_FREQ_KHZ 50000 + +#define FM10K_SPI_HEADER_COMMAND_PAGE_PROGRAM 0x02 +#define FM10K_SPI_HEADER_COMMAND_READ_BYTES 0x03 +#define FM10K_SPI_HEADER_COMMAND_READ_MANUFACTURER_INFORMATION 0x9F + +/* 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__ + +typedef union { + struct { + uint16_t Freq : 10; // Actual speed is PCIE_REFCLK/(2*(1+Freq)) + uint8_t Enable : 1; + uint8_t Command : 4; // 0b00 = reset + uint8_t HeaderSize : 2; // 0b00 = 4 bytes + uint8_t DataSize : 2; // 0b00 = 4 bytes + uint8_t DataShiftMethod : 2; // 0b00 = SINGLE, 0b01 = DUAL, 0b10 = QUAD, 0b11 = Reserved + uint8_t Busy : 1; // volatile ReadOnly + uint8_t Selected : 1; // volatile ReadOnly + uint8_t DirIO2 : 1; // 0b0 = Input, 0b1 = Output + uint8_t DirIO3 : 1; // 0b0 = Input, 0b1 = Output + uint8_t PinIO2 : 1; // volatile ReadWrite + uint8_t PinIO3 : 1; // volatile ReadWrite + uint8_t Reserved : 5; + } __attribute__((packed)) fields; + uint32_t value; +} SPI_CTRL; + +typedef union { + struct { + uint8_t manufacturerId : 8; + uint8_t familyCode : 3; + uint8_t densityCode : 5; + uint8_t subCode : 3; + uint8_t productVariant : 5; + uint8_t RESERVED : 8; + } __attribute__((packed)) fields; + uint32_t value; +} SPI_COMMAND_READ_MANUFACTURER_RESULT; + +#else +#error "Packed bit-fields of type char were not properly bit-packed on many targets prior to GCC 4.4, upgrade to GCC >= 4.4." +#endif + +void ReadRegister32(uintptr_t mem, uint32_t addr, uint32_t* value); + +void WriteRegister32(uintptr_t mem, uint32_t addr, uint32_t value); + + + +uint32_t get_interval_diff(struct timeval *begin, struct timeval *end); + +uint32_t fm10k_uio_spi_SetCtrlReg(uintptr_t mem, SPI_CTRL value); + +void fm10k_uio_spi_Enable(uintptr_t mem); + +void fm10k_uio_spi_Disable(uintptr_t mem); + + +//Error if result.value is 0x00 +SPI_COMMAND_READ_MANUFACTURER_RESULT fm10k_uio_spi_ReadManufacturerData(uintptr_t mem); + +uint32_t fm10k_uio_spi_ReadFlash(uintptr_t mem, uint32_t address, uint8_t* data, uint32_t len); +uint32_t fm10k_uio_spi_WriteFlash(uintptr_t mem, uint32_t address, const uint8_t* data, uint32_t len); \ No newline at end of file -- 2.45.2 From 43bfaa7a53991244dd389898e7628844128c60dd Mon Sep 17 00:00:00 2001 From: WeebDataHoarder <57538841+weebdatahoarder@users.noreply.github.com> Date: Sun, 20 Dec 2020 23:34:34 +0100 Subject: [PATCH 2/5] Added register of known devices --- fm10k-dump.c | 14 ++++++-------- fm10k.c | 16 ++++++++++++++++ fm10k.h | 15 +++++++++++---- 3 files changed, 33 insertions(+), 12 deletions(-) diff --git a/fm10k-dump.c b/fm10k-dump.c index ef8d835..c31c496 100644 --- a/fm10k-dump.c +++ b/fm10k-dump.c @@ -78,15 +78,13 @@ int main(int argc, char** argv){ unsigned int mbitsToRead = 8; + const KNOWN_FLASH_DEVICE* knownFlashDevice = getKnownFlashFromManufacturerData(manufacturerInfo); - switch (manufacturerInfo.value >> 8) { - case 0x1f2701: - printf("Device: Adesto AT45Dxxx Standard:1 32Mbit\n"); - mbitsToRead = 32; - break; - default: - printf("Device: Unknown, defaulting %uMbit size\n", mbitsToRead); - break; + if(knownFlashDevice != NULL){ + printf("Device: %s\n", knownFlashDevice->name); + mbitsToRead = knownFlashDevice->sizeInMbit; + }else{ + printf("Device: Unknown, defaulting %uMbit size\n", mbitsToRead); } if(argc > 3){ diff --git a/fm10k.c b/fm10k.c index b27b235..0adb3ac 100644 --- a/fm10k.c +++ b/fm10k.c @@ -32,6 +32,11 @@ #include "fm10k.h" #include +KNOWN_FLASH_DEVICE KNOWN_FLASH_DEVICE_LIST[] = { + {{0x0101271f}, "Adesto AT45DB321E 32-Mbit", 32}, + {{0}, "", 0} +}; + void ReadRegister32(uintptr_t mem, uint32_t addr, uint32_t* value) { *value = *(((uint32_t*)mem) + addr); } @@ -316,4 +321,15 @@ uint32_t fm10k_uio_spi_WriteFlash(uintptr_t mem, uint32_t address, const uint8_t fm10k_uio_spi_Disable(mem); return 0; +} + +const KNOWN_FLASH_DEVICE* getKnownFlashFromManufacturerData(SPI_COMMAND_READ_MANUFACTURER_RESULT data){ + uint32_t deviceCount = (sizeof(KNOWN_FLASH_DEVICE_LIST) / sizeof(KNOWN_FLASH_DEVICE)) - 1; + for(uint32_t i = 0; i < deviceCount; ++i){ + if(KNOWN_FLASH_DEVICE_LIST[i].data.value == data.value){ + return &KNOWN_FLASH_DEVICE_LIST[i]; + } + } + + return NULL; } \ No newline at end of file diff --git a/fm10k.h b/fm10k.h index a729330..70160c6 100644 --- a/fm10k.h +++ b/fm10k.h @@ -55,6 +55,7 @@ #if __GNUC__ > 4 || (__GNUC__ == 4 && (__GNUC_MINOR__ >= 4)) || __clang__ typedef union { + uint32_t value; struct { uint16_t Freq : 10; // Actual speed is PCIE_REFCLK/(2*(1+Freq)) uint8_t Enable : 1; @@ -70,21 +71,26 @@ typedef union { uint8_t PinIO3 : 1; // volatile ReadWrite uint8_t Reserved : 5; } __attribute__((packed)) fields; - uint32_t value; } SPI_CTRL; typedef union { + uint32_t value; struct { uint8_t manufacturerId : 8; - uint8_t familyCode : 3; uint8_t densityCode : 5; - uint8_t subCode : 3; + uint8_t familyCode : 3; uint8_t productVariant : 5; + uint8_t subCode : 3; uint8_t RESERVED : 8; } __attribute__((packed)) fields; - uint32_t value; } SPI_COMMAND_READ_MANUFACTURER_RESULT; +typedef struct { + SPI_COMMAND_READ_MANUFACTURER_RESULT data; + char name[64]; + uint32_t sizeInMbit; +} KNOWN_FLASH_DEVICE; + #else #error "Packed bit-fields of type char were not properly bit-packed on many targets prior to GCC 4.4, upgrade to GCC >= 4.4." #endif @@ -106,6 +112,7 @@ void fm10k_uio_spi_Disable(uintptr_t mem); //Error if result.value is 0x00 SPI_COMMAND_READ_MANUFACTURER_RESULT fm10k_uio_spi_ReadManufacturerData(uintptr_t mem); +const KNOWN_FLASH_DEVICE* getKnownFlashFromManufacturerData(SPI_COMMAND_READ_MANUFACTURER_RESULT data); uint32_t fm10k_uio_spi_ReadFlash(uintptr_t mem, uint32_t address, uint8_t* data, uint32_t len); uint32_t fm10k_uio_spi_WriteFlash(uintptr_t mem, uint32_t address, const uint8_t* data, uint32_t len); \ No newline at end of file -- 2.45.2 From 60f74b671e1bcba95534079df0e6259c864a42eb Mon Sep 17 00:00:00 2001 From: WeebDataHoarder <57538841+weebdatahoarder@users.noreply.github.com> Date: Mon, 21 Dec 2020 02:41:14 +0100 Subject: [PATCH 3/5] - New tool: fm10k-flash - Added COPYING file - Moved code under src/ --- .gitignore | 3 +- COPYING | 25 ++++ Makefile | 23 +-- README.md | 15 +- fm10k-dump.c => src/fm10k-dump.c | 4 +- src/fm10k-flash.c | 232 +++++++++++++++++++++++++++++++ fm10k.c => src/fm10k.c | 4 +- fm10k.h => src/fm10k.h | 1 + 8 files changed, 288 insertions(+), 19 deletions(-) create mode 100644 COPYING rename fm10k-dump.c => src/fm10k-dump.c (98%) create mode 100644 src/fm10k-flash.c rename fm10k.c => src/fm10k.c (98%) rename fm10k.h => src/fm10k.h (98%) diff --git a/.gitignore b/.gitignore index d51bdbd..fe9a6d0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ /fm10k-dump -/*.o +/fm10k-flash +*.o /.idea \ No newline at end of file diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..789114f --- /dev/null +++ b/COPYING @@ -0,0 +1,25 @@ +Copyright (c) 2014 - 2015, Intel Corporation +Copyright (c) 2020, FM10K-Documentation Contributors + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the copyright holders nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/Makefile b/Makefile index aa6dc11..7610e5f 100644 --- a/Makefile +++ b/Makefile @@ -1,20 +1,25 @@ CC=cc -CFLAGS=-Wall -Wno-unknown-warning-option -Wno-packed-bitfield-compat +CFLAGS=-ggdb -Og -Wall -Wno-unknown-warning-option -Wno-packed-bitfield-compat default: all -all: fm10k-dump +all: fm10k-dump fm10k-flash -fm10k.o: fm10k.c - $(CC) -c fm10k.c -o fm10k.o $(CFLAGS) +fm10k.o: src/fm10k.c + $(CC) -c src/fm10k.c -o src/fm10k.o $(CFLAGS) -fm10k-dump.o: fm10k-dump.c - $(CC) -c fm10k-dump.c -o fm10k-dump.o $(CFLAGS) +fm10k-dump.o: src/fm10k-dump.c + $(CC) -c src/fm10k-dump.c -o src/fm10k-dump.o $(CFLAGS) fm10k-dump: fm10k-dump.o fm10k.o - $(CC) fm10k-dump.o fm10k.o -o fm10k-dump $(CFLAGS) + $(CC) src/fm10k-dump.o src/fm10k.o -o fm10k-dump $(CFLAGS) +fm10k-flash.o: src/fm10k-flash.c + $(CC) -c src/fm10k-flash.c -o src/fm10k-flash.o $(CFLAGS) + +fm10k-flash: fm10k-flash.o fm10k.o + $(CC) src/fm10k-flash.o src/fm10k.o -o fm10k-flash $(CFLAGS) clean: -rm -f fm10k-dump - -rm -f fm10k-dump.o - -rm -f fm10k.o + -rm -f fm10k-flash + -rm -f src/*.o diff --git a/README.md b/README.md index d37eb03..9c50db5 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -# fm10k-dump +# fm10k-dump & fm10k-flash -Utility that allows dumping the SPI Flash Non-Volatile Memory of the FM10000 family of cards. +Utility that allows dumping/flashing the SPI Flash Non-Volatile Memory of the FM10000 family of cards. ## Requirements * GCC >= 4.4.0 or clang @@ -13,13 +13,18 @@ Utility that allows dumping the SPI Flash Non-Volatile Memory of the FM10000 fam ## Compilation * `$ make clean && make` * You can specify whether to use gcc or clang this way: `$ make CC=gcc` / `$ make CC=clang` -* An executable named `./fm10k-dump` should now exist. +* Two executables named `./fm10k-dump` and `./fm10k-flash` should now exist. -## Usage example +## fm10k-dump usage example * If the chip on the card is known to the tool, it'll set the image size to match. Alternatively it will use the platform minimum of 8Mbit. * `# ./fm10k-dump /dev/uio0 outputImage.bin` * You can also force the image/chip size: `# ./fm10k-dump /dev/uio0 outputImage.bin 32` +## fm10k-flash usage example +* _fm10k-flash_ requires a backup of the existing image before flashing a new one, for safety measures. Use _fm10k-dump_ to take a backup copy of the current state before flashing. +* `# ./fm10k-dump /dev/uio0 backupImage.bin` +* `# ./fm10k-flash /dev/uio0 inputImage.bin backupImage.bin` + ## License * BSD-3-Clause -* See [fm10k-dump.c](fm10k-dump.c) header for more information. \ No newline at end of file +* See [COPYING](COPYING) for the full license. \ No newline at end of file diff --git a/fm10k-dump.c b/src/fm10k-dump.c similarity index 98% rename from fm10k-dump.c rename to src/fm10k-dump.c index c31c496..5b739a4 100644 --- a/fm10k-dump.c +++ b/src/fm10k-dump.c @@ -2,7 +2,7 @@ * File: fm10k-dump.c * Creation Date: December 16, 2020 * Description: Utility to dump Non Volatile Memory on SPI for FM10K devices. Requires FM10K kernel module running with UIO enabled. - * Compile: gcc -o fm10k-dump fm10k-dump.c + * Compile: make fm10k-dump * Usage: ./fm10k-dump [readSizeInMegabits=8] * * Copyright (c) 2014 - 2015, Intel Corporation @@ -109,7 +109,7 @@ int main(int argc, char** argv){ uint8_t* value = malloc(bootImageSize); - uint32_t strideSize = 1024; + uint32_t strideSize = 512; for(uint32_t addr = 0; addr < bootImageSize; addr += strideSize){ printf("\rread @ 0x%08x / 0x%08x %d bytes", addr, bootImageSize, strideSize); diff --git a/src/fm10k-flash.c b/src/fm10k-flash.c new file mode 100644 index 0000000..f79e509 --- /dev/null +++ b/src/fm10k-flash.c @@ -0,0 +1,232 @@ +/***************************************************************************** + * File: fm10k-flash.c + * Creation Date: December 20, 2020 + * Description: Utility to flash Non Volatile Memory on SPI for FM10K devices. Requires FM10K kernel module running with UIO enabled. + * Compile: make fm10k-flash + * Usage: ./fm10k-flash + * + * Copyright (c) 2014 - 2015, Intel Corporation + * Copyright (c) 2020, FM10K-Documentation Contributors + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the copyright holders nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *****************************************************************************/ + +#include "fm10k.h" +#include +#include +#include +#include +#include +#include + + +int main(int argc, char** argv){ + int fdUIO; + FILE* fdBackup; + FILE* fdInput; + + + + if(argc < 4){ + printf("Usage: %s \n", argv[0]); + return 1; + } + + fdInput = fopen(argv[2], "rb"); + + if(fdInput == NULL){ + printf("Could not open %s\n", argv[2]); + return 1; + } + + fdBackup = fopen(argv[3], "rb"); + if(fdBackup == NULL){ + printf("Could not open existing backup %s\n", argv[3]); + return 1; + } + + fseek(fdInput , 0, SEEK_END); + uint32_t fileSize = ftell(fdInput); + rewind(fdInput); + + fseek(fdBackup , 0, SEEK_END); + uint32_t backupFileSize = ftell(fdBackup); + rewind(fdBackup); + + if(backupFileSize < fileSize){ + printf("Backup %d is smaller than new image %d\n", backupFileSize, fileSize); + return 1; + } + + fdUIO = open(argv[1], O_RDWR); + if(fdUIO <= 0){ + printf("Unable to open uio device %s to write NVM\n", argv[1]); + return 1; + } + void* memmapAddr; + memmapAddr = mmap(NULL, FM10K_UIO_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fdUIO, 0); + if (memmapAddr == MAP_FAILED) { + printf("Unable to map uio device %s to write NVM\n", argv[1]); + close(fdUIO); + return 1; + } + + SPI_COMMAND_READ_MANUFACTURER_RESULT manufacturerInfo = fm10k_uio_spi_ReadManufacturerData((uintptr_t)memmapAddr); + if(manufacturerInfo.value == 0){ + printf("Error getting manufacturer information\n"); + return 1; + } + printf("Manufacturer Info 0x%08x :: JEDEC Manufacturer ID 0x%02x family 0x%02x density 0x%02x %02x:%02x\n", manufacturerInfo.value, manufacturerInfo.fields.manufacturerId, manufacturerInfo.fields.familyCode, manufacturerInfo.fields.densityCode, manufacturerInfo.fields.subCode, manufacturerInfo.fields.productVariant); + + unsigned int mbitsToReadMax = 8; + + const KNOWN_FLASH_DEVICE* knownFlashDevice = getKnownFlashFromManufacturerData(manufacturerInfo); + + if(knownFlashDevice != NULL){ + printf("Device: %s\n", knownFlashDevice->name); + mbitsToReadMax = knownFlashDevice->sizeInMbit; + }else{ + printf("Device: Unknown, defaulting max %uMbit size\n", mbitsToReadMax); + } + + if(mbitsToReadMax > 1024){ + printf("Too many MBit: %u\n", mbitsToReadMax); + return 1; + } + + if(mbitsToReadMax == 0){ + printf("Too few MBit: %u\n", mbitsToReadMax); + return 1; + } + + uint32_t strideSize = 512; + uint32_t bootImageSizeMax = (mbitsToReadMax * 1024 * 1024) / 8; + + if(fileSize > bootImageSizeMax){ + printf("Image too large: have %d, can write max %d bytes.\n", fileSize, bootImageSizeMax); + return 1; + }else if(fileSize < bootImageSizeMax){ + do{ + bootImageSizeMax -= strideSize; + } while (fileSize < bootImageSizeMax); + } + + uint8_t* value = calloc(bootImageSizeMax, sizeof(uint8_t)); + uint8_t* valueBackup = calloc(bootImageSizeMax, sizeof(uint8_t)); + uint8_t* valueCheck = calloc(bootImageSizeMax, sizeof(uint8_t)); + + if(fread(value, 1, bootImageSizeMax, fdInput) != bootImageSizeMax){ + printf("Error reading image file.\n"); + return 1; + } + + if(fread(valueBackup, 1, bootImageSizeMax, fdBackup) != bootImageSizeMax){ + printf("Error reading backup image file.\n"); + return 1; + } + + if(memcmp(value, valueBackup, bootImageSizeMax) == 0){ + printf("NOTE: %s and %s have the same bytes.\n", argv[2], argv[3]); + } + + + for(uint32_t addr = 0; addr < bootImageSizeMax; addr += strideSize){ + printf("\rbackup check @ 0x%08x / 0x%08x %d bytes", addr, bootImageSizeMax, strideSize); + if(fm10k_uio_spi_ReadFlash((uintptr_t)memmapAddr, addr, valueCheck + addr, strideSize)){ + return 2; + } + } + + printf("\n"); + + if(memcmp(valueBackup, valueCheck, bootImageSizeMax) != 0){ + printf("Backup image mismatch! Dump image again.\n"); + return 1; + }else{ + printf("Backup matches.\n"); + } + + sleep(1); + + + for(uint32_t addr = 0; addr < bootImageSizeMax; addr += 4){ + if(memcmp(valueBackup + addr, value + addr, 4) != 0){ + printf("write @ 0x%08x: 0x%08x => 0x%08x\n", addr, *(uint32_t*)(valueBackup + addr), *(uint32_t*)(value + addr)); + if(fm10k_uio_spi_WriteFlash((uintptr_t)memmapAddr, addr, value + addr, 4)){ + return 2; + } + } + } + + printf("\n"); + + sleep(1); + + + for(uint32_t addr = 0; addr < bootImageSizeMax; addr += strideSize){ + printf("\rverify check @ 0x%08x / 0x%08x %d bytes", addr, bootImageSizeMax, strideSize); + if(fm10k_uio_spi_ReadFlash((uintptr_t)memmapAddr, addr, valueCheck + addr, strideSize)){ + return 2; + } + } + + printf("\n"); + + for(uint32_t addr = 0; addr < bootImageSizeMax; addr += 4){ + if(*(uint32_t*)(value + addr) != *(uint32_t*)(valueCheck + addr)){ + printf("@0x%08x: 0x%08x != 0x%08x\n", addr, *(uint32_t*)(value + addr), *(uint32_t*)(valueCheck + addr)); + } + } + + sleep(1); + + if(memcmp(value, valueCheck, bootImageSizeMax) != 0){ + printf("Data written mismatch! Replacing with backup.\n"); + + for(uint32_t addr = 0; addr < bootImageSizeMax; addr += strideSize){ + printf("\rwrite backup @ 0x%08x / 0x%08x %d bytes", addr, bootImageSizeMax, strideSize); + if(fm10k_uio_spi_WriteFlash((uintptr_t)memmapAddr, addr, valueBackup + addr, strideSize)){ + return 2; + } + } + }else{ + printf("Data written verified.\n"); + } + + sleep(1); + + + + + free(value); + free(valueBackup); + free(valueCheck); + + fclose(fdInput); + fclose(fdBackup); + + printf("\nWritten %u bytes\n", bootImageSizeMax); + + return 0; +} \ No newline at end of file diff --git a/fm10k.c b/src/fm10k.c similarity index 98% rename from fm10k.c rename to src/fm10k.c index 0adb3ac..1bf5627 100644 --- a/fm10k.c +++ b/src/fm10k.c @@ -280,8 +280,8 @@ uint32_t fm10k_uio_spi_WriteFlash(uintptr_t mem, uint32_t address, const uint8_t spiCtrl.fields.Enable = 1; - /* header: command (1 byte: PAGE_PROGRAM) + address (3 bytes) */ - header = (FM10K_SPI_HEADER_COMMAND_PAGE_PROGRAM << 24) | (address & 0xffffff); + /* header: command (1 byte: READ_MODIFY_WRITE) + address (3 bytes) */ + header = (FM10K_SPI_HEADER_COMMAND_READ_MODIFY_WRITE_512 << 24) | (address & 0xffffff); WriteRegister32(mem, FM10K_REGISTER_SPI_HEADER, header); /* first loop only: set send header flag. Following loops: shift only data. */ diff --git a/fm10k.h b/src/fm10k.h similarity index 98% rename from fm10k.h rename to src/fm10k.h index 70160c6..c216705 100644 --- a/fm10k.h +++ b/src/fm10k.h @@ -49,6 +49,7 @@ #define FM10K_SPI_HEADER_COMMAND_PAGE_PROGRAM 0x02 #define FM10K_SPI_HEADER_COMMAND_READ_BYTES 0x03 +#define FM10K_SPI_HEADER_COMMAND_READ_MODIFY_WRITE_512 0x58 #define FM10K_SPI_HEADER_COMMAND_READ_MANUFACTURER_INFORMATION 0x9F /* 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 */ -- 2.45.2 From 20a04186d2aa93f62d8b127511cf64a63dc6ee4b Mon Sep 17 00:00:00 2001 From: WeebDataHoarder <57538841+weebdatahoarder@users.noreply.github.com> Date: Mon, 21 Dec 2020 04:49:59 +0100 Subject: [PATCH 4/5] Add functions to enable/disable sector protection on flash --- src/fm10k-flash.c | 5 ++++ src/fm10k.c | 75 +++++++++++++++++++++++++++++++++++++++++++++++ src/fm10k.h | 3 ++ 3 files changed, 83 insertions(+) diff --git a/src/fm10k-flash.c b/src/fm10k-flash.c index f79e509..3ddc2ec 100644 --- a/src/fm10k-flash.c +++ b/src/fm10k-flash.c @@ -169,6 +169,11 @@ int main(int argc, char** argv){ sleep(1); + printf("Disabling sector protection.\n"); + fm10k_uio_spi_DisableSectorProtection((uintptr_t)memmapAddr); + + sleep(1); + for(uint32_t addr = 0; addr < bootImageSizeMax; addr += 4){ if(memcmp(valueBackup + addr, value + addr, 4) != 0){ diff --git a/src/fm10k.c b/src/fm10k.c index 1bf5627..46eed86 100644 --- a/src/fm10k.c +++ b/src/fm10k.c @@ -253,6 +253,81 @@ uint32_t fm10k_uio_spi_ReadFlash(uintptr_t mem, uint32_t address, uint8_t* data, return 0; } +uint32_t fm10k_uio_spi_EnableSectorProtection(uintptr_t mem){ + SPI_CTRL currentSpiCtrl; + SPI_CTRL spiCtrl = {0}; + + uint32_t header; + int32_t freq; + + fm10k_uio_spi_Enable(mem); + + + ReadRegister32(mem, FM10K_REGISTER_SPI_CTRL, ¤tSpiCtrl.value); + + if(FM10K_SPI_FREQ_KHZ > 0){ + freq = ((100000 / (int)FM10K_SPI_FREQ_KHZ) / 2) - 1; + if (freq < 0){ + freq = 0; + } + spiCtrl.fields.Freq = freq; + } + + spiCtrl.fields.Enable = 1; + + header = (0x3D << 24) | (0x2A << 16) | (0x7F) | (0xA9); + WriteRegister32(mem, FM10K_REGISTER_SPI_HEADER, header); + + /* first loop only: set send header flag. Following loops: shift only data. */ + spiCtrl.fields.Command |= 0b0001; + + /* send command to the flash */ + if(fm10k_uio_spi_SetCtrlReg(mem, spiCtrl)){ + return 1; + } + + fm10k_uio_spi_Disable(mem); + + return 0; +} + +uint32_t fm10k_uio_spi_DisableSectorProtection(uintptr_t mem){ + SPI_CTRL currentSpiCtrl; + SPI_CTRL spiCtrl = {0}; + + uint32_t header; + int32_t freq; + + fm10k_uio_spi_Enable(mem); + + + ReadRegister32(mem, FM10K_REGISTER_SPI_CTRL, ¤tSpiCtrl.value); + + if(FM10K_SPI_FREQ_KHZ > 0){ + freq = ((100000 / (int)FM10K_SPI_FREQ_KHZ) / 2) - 1; + if (freq < 0){ + freq = 0; + } + spiCtrl.fields.Freq = freq; + } + + spiCtrl.fields.Enable = 1; + + header = (0x3D << 24) | (0x2A << 16) | (0x7F) | (0x9A); + WriteRegister32(mem, FM10K_REGISTER_SPI_HEADER, header); + + /* first loop only: set send header flag. Following loops: shift only data. */ + spiCtrl.fields.Command |= 0b0001; + + /* send command to the flash */ + if(fm10k_uio_spi_SetCtrlReg(mem, spiCtrl)){ + return 1; + } + + fm10k_uio_spi_Disable(mem); + + return 0; +} uint32_t fm10k_uio_spi_WriteFlash(uintptr_t mem, uint32_t address, const uint8_t* data, uint32_t len){ diff --git a/src/fm10k.h b/src/fm10k.h index c216705..6a49df1 100644 --- a/src/fm10k.h +++ b/src/fm10k.h @@ -115,5 +115,8 @@ void fm10k_uio_spi_Disable(uintptr_t mem); SPI_COMMAND_READ_MANUFACTURER_RESULT fm10k_uio_spi_ReadManufacturerData(uintptr_t mem); const KNOWN_FLASH_DEVICE* getKnownFlashFromManufacturerData(SPI_COMMAND_READ_MANUFACTURER_RESULT data); +uint32_t fm10k_uio_spi_EnableSectorProtection(uintptr_t mem); +uint32_t fm10k_uio_spi_DisableSectorProtection(uintptr_t mem); + uint32_t fm10k_uio_spi_ReadFlash(uintptr_t mem, uint32_t address, uint8_t* data, uint32_t len); uint32_t fm10k_uio_spi_WriteFlash(uintptr_t mem, uint32_t address, const uint8_t* data, uint32_t len); \ No newline at end of file -- 2.45.2 From c1ec526eb852af8449acab2e60ef9fb7e3f1f71b Mon Sep 17 00:00:00 2001 From: WeebDataHoarder <57538841+weebdatahoarder@users.noreply.github.com> Date: Mon, 21 Dec 2020 06:07:39 +0100 Subject: [PATCH 5/5] Add CS release and sleep to finish write(?) --- src/fm10k-flash.c | 18 +++++++++++------- src/fm10k.c | 13 +++++++++++++ 2 files changed, 24 insertions(+), 7 deletions(-) diff --git a/src/fm10k-flash.c b/src/fm10k-flash.c index 3ddc2ec..c72d35b 100644 --- a/src/fm10k-flash.c +++ b/src/fm10k-flash.c @@ -175,12 +175,13 @@ int main(int argc, char** argv){ sleep(1); - for(uint32_t addr = 0; addr < bootImageSizeMax; addr += 4){ - if(memcmp(valueBackup + addr, value + addr, 4) != 0){ - printf("write @ 0x%08x: 0x%08x => 0x%08x\n", addr, *(uint32_t*)(valueBackup + addr), *(uint32_t*)(value + addr)); - if(fm10k_uio_spi_WriteFlash((uintptr_t)memmapAddr, addr, value + addr, 4)){ + for(uint32_t addr = 0; addr < bootImageSizeMax; addr += strideSize){ + if(memcmp(valueBackup + addr, value + addr, strideSize) != 0){ + printf("write @ 0x%08x\n", addr); + if(fm10k_uio_spi_WriteFlash((uintptr_t)memmapAddr, addr, value + addr, strideSize)){ return 2; } + sleep(1); } } @@ -210,9 +211,12 @@ int main(int argc, char** argv){ printf("Data written mismatch! Replacing with backup.\n"); for(uint32_t addr = 0; addr < bootImageSizeMax; addr += strideSize){ - printf("\rwrite backup @ 0x%08x / 0x%08x %d bytes", addr, bootImageSizeMax, strideSize); - if(fm10k_uio_spi_WriteFlash((uintptr_t)memmapAddr, addr, valueBackup + addr, strideSize)){ - return 2; + if(memcmp(valueBackup + addr, valueCheck + addr, strideSize) != 0){ + printf("write backup @ 0x%08x\n", addr); + if(fm10k_uio_spi_WriteFlash((uintptr_t)memmapAddr, addr, valueBackup + addr, strideSize)){ + return 2; + } + sleep(1); } } }else{ diff --git a/src/fm10k.c b/src/fm10k.c index 46eed86..98ba27a 100644 --- a/src/fm10k.c +++ b/src/fm10k.c @@ -31,6 +31,7 @@ #include "fm10k.h" #include +#include KNOWN_FLASH_DEVICE KNOWN_FLASH_DEVICE_LIST[] = { {{0x0101271f}, "Adesto AT45DB321E 32-Mbit", 32}, @@ -286,6 +287,12 @@ uint32_t fm10k_uio_spi_EnableSectorProtection(uintptr_t mem){ return 1; } + /* release CS */ + spiCtrl.fields.Command = 0b1000; + if(fm10k_uio_spi_SetCtrlReg(mem, spiCtrl)){ + return 1; + } + fm10k_uio_spi_Disable(mem); return 0; @@ -324,6 +331,12 @@ uint32_t fm10k_uio_spi_DisableSectorProtection(uintptr_t mem){ return 1; } + /* release CS */ + spiCtrl.fields.Command = 0b1000; + if(fm10k_uio_spi_SetCtrlReg(mem, spiCtrl)){ + return 1; + } + fm10k_uio_spi_Disable(mem); return 0; -- 2.45.2