255 lines
8.8 KiB
C
255 lines
8.8 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 <input.bin> <backup.bin>
|
|
*
|
|
* Copyright (c) 2014 - 2015, Intel Corporation
|
|
* Copyright (c) 2021, 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 <unistd.h>
|
|
|
|
|
|
|
|
int main(int argc, char **argv) {
|
|
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_MAPPED_DEVICE map;
|
|
FM10K_PCI_DEVICES devices = fm10k_pci_findDevices();
|
|
|
|
if(fm10k_pci_findDevice(&devices, &map)){
|
|
printf("Unable to find FM10K device with BAR4 port access, or could not take SPI lock. Check bifurcation settings?\n");
|
|
return 1;
|
|
}
|
|
|
|
printf("FM10K device found at %s :: Vendor 0x%04x :: Class 0x%04x\n", map.device->bar4Path, map.device->vendor, map.device->class);
|
|
|
|
SPI_COMMAND_READ_MANUFACTURER_RESULT manufacturerInfo = fm10k_mem_spi_ReadManufacturerData((uintptr_t) map.map);
|
|
if (manufacturerInfo.value == 0) {
|
|
printf("Error getting manufacturer information\n");
|
|
fm10k_mem_ReleasePlatformLock((uintptr_t) map.map);
|
|
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("SPI Device: %s\n", knownFlashDevice->name);
|
|
mbitsToReadMax = knownFlashDevice->sizeInMbit;
|
|
} else {
|
|
printf("SPI Device: Unknown, defaulting max %uMbit size\n", mbitsToReadMax);
|
|
}
|
|
|
|
if (mbitsToReadMax > 1024) {
|
|
printf("Too many MBit: %u\n", mbitsToReadMax);
|
|
fm10k_mem_ReleasePlatformLock((uintptr_t) map.map);
|
|
return 1;
|
|
}
|
|
|
|
if (mbitsToReadMax == 0) {
|
|
printf("Too few MBit: %u\n", mbitsToReadMax);
|
|
fm10k_mem_ReleasePlatformLock((uintptr_t) map.map);
|
|
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);
|
|
fm10k_mem_ReleasePlatformLock((uintptr_t) map.map);
|
|
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");
|
|
fm10k_mem_ReleasePlatformLock((uintptr_t) map.map);
|
|
return 1;
|
|
}
|
|
|
|
if (fread(valueBackup, 1, bootImageSizeMax, fdBackup) != bootImageSizeMax) {
|
|
printf("Error reading backup image file.\n");
|
|
fm10k_mem_ReleasePlatformLock((uintptr_t) map.map);
|
|
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) map.map, addr, valueCheck + addr, strideSize)) {
|
|
fm10k_mem_ReleasePlatformLock((uintptr_t) map.map);
|
|
return 2;
|
|
}
|
|
}
|
|
|
|
printf("\n");
|
|
|
|
if (memcmp(valueBackup, valueCheck, bootImageSizeMax) != 0) {
|
|
printf("Backup image mismatch! Dump image again.\n");
|
|
fm10k_mem_ReleasePlatformLock((uintptr_t) map.map);
|
|
return 1;
|
|
} else {
|
|
printf("Backup matches.\n");
|
|
}
|
|
|
|
sleep(1);
|
|
|
|
printf("Disabling sector protection.\n");
|
|
fm10k_mem_spi_DisableSectorProtection((uintptr_t) map.map);
|
|
|
|
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) map.map, addr, value + addr, strideSize)) {
|
|
fm10k_mem_ReleasePlatformLock((uintptr_t) map.map);
|
|
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) map.map, addr, valueCheck + addr, strideSize)) {
|
|
fm10k_mem_ReleasePlatformLock((uintptr_t) map.map);
|
|
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) map.map, addr, valueBackup + addr, strideSize)) {
|
|
fm10k_mem_ReleasePlatformLock((uintptr_t) map.map);
|
|
return 2;
|
|
}
|
|
sleep(1);
|
|
}
|
|
}
|
|
} else {
|
|
printf("Data written verified.\n");
|
|
}
|
|
|
|
sleep(1);
|
|
|
|
printf("\n");
|
|
|
|
fm10k_mem_ReleasePlatformLock((uintptr_t) map.map);
|
|
|
|
fm10k_pci_unmapDevice(&map);
|
|
|
|
|
|
free(value);
|
|
free(valueBackup);
|
|
free(valueCheck);
|
|
|
|
fclose(fdInput);
|
|
fclose(fdBackup);
|
|
|
|
printf("\nWritten %u bytes\n", bootImageSizeMax);
|
|
|
|
return 0;
|
|
}
|