fm10k-dump/src/fm10k-flash.c
DataHoarder a351389c1e
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
Direct PCIe resource access without depending on fm10k driver
2020-12-23 02:01:57 +01:00

248 lines
8.3 KiB
C

/*****************************************************************************
* 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 </dev/uio0> <input.bin> <backup.bin>
*
* 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 <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <unistd.h>
#include <fcntl.h>
int main(int argc, char** argv){
int fdBAR4;
FILE* fdBackup;
FILE* fdInput;
if(argc < 3){
printf("Usage: %s <input.bin> <backup.bin>\n", argv[0]);
return 1;
}
fdInput = fopen(argv[1], "rb");
if(fdInput == NULL){
printf("Could not open %s\n", argv[1]);
return 1;
}
fdBackup = fopen(argv[2], "rb");
if(fdBackup == NULL){
printf("Could not open existing backup %s\n", argv[2]);
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;
}
FM10K_PCI_DEVICE device = fm10k_pci_findDevice();
if(device.vendor == 0){
printf("Unable to find FM10K device with BAR4 port access. Check bifurcation settings?\n");
return 1;
}
fdBAR4 = open(device.bar4Path, O_RDWR);
if(fdBAR4 <= 0){
printf("Unable to open BAR4 resource %s to read NVM\n", device.bar4Path);
return 1;
}
void* memmapAddr;
memmapAddr = mmap(NULL, FM10K_BAR4_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fdBAR4, 0);
if (memmapAddr == MAP_FAILED) {
printf("Unable to map BAR4 resource %s to read NVM\n", device.bar4Path);
close(fdBAR4);
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");
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_mem_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);
printf("Disabling sector protection.\n");
fm10k_mem_spi_DisableSectorProtection((uintptr_t) memmapAddr);
sleep(1);
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_mem_spi_WriteFlash((uintptr_t) memmapAddr, addr, value + addr, strideSize)){
return 2;
}
sleep(1);
}
}
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_mem_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){
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)){
return 2;
}
sleep(1);
}
}
}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;
}