Compare commits

...

24 commits
v0.3 ... master

Author SHA1 Message Date
DataHoarder 37b1644120 Apply consistent spaces and style across project
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/tag Build is passing
2021-12-19 15:32:37 +01:00
DataHoarder 702209cbe6 Update copyright year 2021-12-19 15:30:44 +01:00
DataHoarder 88646eb2bb Added device found string with path / vendor details.
Some checks failed
continuous-integration/drone/push Build is failing
2021-12-19 15:29:45 +01:00
DataHoarder f13923f5da Refactor device handling to allow finding multiple devices and select appropiate one.
All checks were successful
continuous-integration/drone/push Build is passing
2021-12-19 15:25:56 +01:00
DataHoarder ab1bffe446 Mark values as volatile
All checks were successful
continuous-integration/drone/push Build is passing
2021-10-28 07:27:22 +02:00
DataHoarder 3a434aa9c6 Build Debian bullseye
All checks were successful
continuous-integration/drone/push Build is passing
2021-08-04 07:24:59 +02:00
DataHoarder a361926b62 Remove old UIO comment on documentation header for flash/dump
All checks were successful
continuous-integration/drone/push Build is passing
2021-02-07 22:27:51 +01:00
DataHoarder 9a2fc07ad8 Add extra newlines on SPI lock end
All checks were successful
continuous-integration/drone/push Build is passing
2021-01-06 12:39:08 +01:00
DataHoarder 975f7df4d8 Remove TCC from debian jessie and fedora, fix alpine, fix void
All checks were successful
continuous-integration/drone/push Build is passing
2021-01-06 11:17:07 +01:00
DataHoarder 60963aa01a Fix TCC on some architectures, -pedantic build, replaced binary literals with hex numbers
Some checks failed
continuous-integration/drone/push Build is failing
2021-01-06 09:36:51 +01:00
DataHoarder f018396b1d Add specific #pragma pack(1) for TCC, fixes packed alignment issues
Some checks failed
continuous-integration/drone/push Build is failing
2021-01-06 08:53:51 +01:00
DataHoarder 6223ca323c 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
2021-01-06 08:50:15 +01:00
DataHoarder e8dcaa3af3 Support TCC building, added two packed struct alignment tests 2021-01-06 08:01:35 +01:00
DataHoarder 32123658e9 Compacted pipelines to build gcc & clang tests in two steps
All checks were successful
continuous-integration/drone/push Build is passing
2020-12-31 05:15:50 +01:00
DataHoarder cf88d445e3 Test arm64 platform build
All checks were successful
continuous-integration/drone/push Build is passing
2020-12-31 04:52:06 +01:00
DataHoarder 9e8623be7c Force drone to build on linux-amd64
All checks were successful
continuous-integration/drone/push Build is passing
2020-12-31 01:24:49 +01:00
DataHoarder 233cdfcaa3 Some libraries on clang come from gcc, and it does not depend on it
All checks were successful
continuous-integration/drone/push Build is passing
2020-12-29 21:20:27 +01:00
DataHoarder 070e3f3368 Added Void Linux test for XBPS
Some checks failed
continuous-integration/drone/push Build is failing
2020-12-29 21:06:10 +01:00
DataHoarder fe20d93634 Added binutils to alpine
Some checks reported errors
continuous-integration/drone/push Build was killed
2020-12-29 21:02:47 +01:00
DataHoarder 1b57ca3f78 Added Fedora test, fixed alpine test
Some checks failed
continuous-integration/drone/push Build is failing
2020-12-29 20:49:12 +01:00
DataHoarder 6ca1dd96c9 Added alpine linux test
Some checks failed
continuous-integration/drone/push Build is failing
2020-12-29 20:38:53 +01:00
DataHoarder a68b1312f3 Added -Wno-unknown-pragmas to Makefile 2020-12-29 18:53:50 +01:00
DataHoarder 929f438a35 Change .drone.yml in favor of more compact .drone.jsonnet
All checks were successful
continuous-integration/drone/push Build is passing
Include debian & archlinux in tests
2020-12-29 18:20:12 +01:00
DataHoarder e9ad8ad656 General reformat commit to make Sora happy again
All checks were successful
continuous-integration/drone/push Build is passing
2020-12-23 02:24:04 +01:00
11 changed files with 626 additions and 290 deletions

83
.drone.jsonnet Normal file
View file

@ -0,0 +1,83 @@
local Pipeline(image, version, arch, depinstall, extra, gccExtra, clangExtra, tccExtra) = {
kind: "pipeline",
type: "docker",
name: image+"-"+version+"-"+arch,
platform: {
os: "linux",
arch: arch
},
steps: [
{
name: "build-gcc",
image: image+":"+version,
commands: [
depinstall+" make "+extra+" "+gccExtra,
"make clean",
"make CC=gcc all"
]
},
{
name: "build-clang",
image: image+":"+version,
commands: [
depinstall+" make "+extra+" "+clangExtra,
"make clean",
"make CC=clang all"
]
}
] + (if tccExtra != "" then [
{
name: "build-tcc",
image: image+":"+version,
commands: [
depinstall+" make "+extra+" "+tccExtra,
"make clean",
"make CC=tcc all"
]
}
] else []
)
};
local AptPipeline(image, version, arch, extra="", gccExtra="gcc", clangExtra="clang", tccExtra="tcc") = Pipeline(image, version, arch, "apt update && DEBIAN_FRONTEND=noninteractive apt install -y", extra, gccExtra, clangExtra, tccExtra);
local PacManPipeline(image, version, arch, extra="", gccExtra="gcc", clangExtra="clang", tccExtra="tcc") = Pipeline(image, version, arch, "pacman -Syy && pacman --noconfirm -S", extra, gccExtra, clangExtra, tccExtra);
local ApkPipeline(image, version, arch, extra="musl-dev linux-headers", gccExtra="gcc", clangExtra="gcc clang", tccExtra="") = Pipeline(image, version, arch, "apk add --update", extra, gccExtra, clangExtra, tccExtra);
local YumPipeline(image, version, arch, extra="", gccExtra="gcc", clangExtra="clang", tccExtra="") = Pipeline(image, version, arch, "yum install -y", extra, gccExtra, clangExtra, tccExtra);
local XbpsPipeline(image, version, arch, extra="", gccExtra="gcc", clangExtra="clang", tccExtra="tcc glibc-devel") = Pipeline(image, version, arch, "xbps-install -Sy", extra, gccExtra, clangExtra, tccExtra);
#
[
AptPipeline("ubuntu", "20.04", "amd64"),
AptPipeline("ubuntu", "20.04", "arm64"),
AptPipeline("ubuntu", "18.04", "amd64"),
AptPipeline("debian", "bullseye", "amd64"),
AptPipeline("debian", "bullseye", "arm64"),
AptPipeline("debian", "buster", "amd64"),
AptPipeline("debian", "stretch", "amd64"),
AptPipeline("debian", "jessie", "amd64", "", "gcc", "clang", ""),
YumPipeline("fedora", "latest", "amd64", "", "gcc", "clang", ""),
YumPipeline("fedora", "latest", "arm64"),
PacManPipeline("archlinux", "latest", "amd64"),
ApkPipeline("alpine", "latest", "amd64"),
ApkPipeline("alpine", "latest", "arm64"),
XbpsPipeline("voidlinux/voidlinux", "latest", "amd64"),
]

View file

@ -1,27 +0,0 @@
---
kind: pipeline
type: docker
name: build-gcc
steps:
- name: build
image: ubuntu:20.04
commands:
- apt update
- DEBIAN_FRONTEND=noninteractive apt install -y gcc make
- make clean
- make CC=gcc CFLAGS="-Wall -Werror -Wno-unknown-warning-option -Wno-packed-bitfield-compat"
---
kind: pipeline
type: docker
name: build-clang
steps:
- name: build
image: ubuntu:20.04
commands:
- apt update
- DEBIAN_FRONTEND=noninteractive apt install -y clang make
- make clean
- make CC=clang CFLAGS="-Wall -Werror -Wno-unknown-warning-option -Wno-packed-bitfield-compat"
...

1
.gitignore vendored
View file

@ -1,4 +1,5 @@
/fm10k-dump
/fm10k-flash
/test-runner
*.o
/.idea

View file

@ -1,5 +1,5 @@
Copyright (c) 2014 - 2015, Intel Corporation
Copyright (c) 2020, FM10K-Documentation Contributors
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:

View file

@ -1,25 +1,41 @@
CC=cc
CFLAGS=-ggdb -Og -Wall -Wno-unknown-warning-option -Wno-packed-bitfield-compat
CFLAGS=-ggdb -Wall -Werror -pedantic -Wno-unknown-pragmas -Wno-packed-bitfield-compat
default: all
ifeq ($(shell $(CC) -v 2>&1 | grep -c "clang version"), 1)
CFLAGS += -O0 -std=gnu99 -Wno-unknown-warning-option
else ifeq ($(shell $(CC) -v 2>&1 | grep -c "tcc version"), 1)
CFLAGS += -std=c99 -Wno-macro-redefined
else
CFLAGS += -Og -std=gnu99
endif
all: fm10k-dump fm10k-flash
default: fm10k-dump fm10k-flash
fm10k.o: src/fm10k.c
$(CC) -c src/fm10k.c -o src/fm10k.o $(CFLAGS)
all: fm10k-dump fm10k-flash test
fm10k-dump.o: src/fm10k-dump.c
$(CC) -c src/fm10k-dump.c -o src/fm10k-dump.o $(CFLAGS)
test: run_test
fm10k-dump: fm10k-dump.o fm10k.o
src/%.o: src/%.c
@$(CC) $(CFLAGS) -c $< $(INC) -o $@
fm10k-dump: src/fm10k-dump.o src/fm10k.o
$(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
fm10k-flash: src/fm10k-flash.o src/fm10k.o
$(CC) src/fm10k-flash.o src/fm10k.o -o fm10k-flash $(CFLAGS)
test-runner: src/test.o src/fm10k.o
$(CC) src/test.o src/fm10k.o -o test-runner $(CFLAGS)
run_test: test-runner
./test-runner
clean:
-rm -f fm10k-dump
-rm -f fm10k-flash
-rm -f test-runner
-rm -f src/*.o

View file

@ -3,7 +3,7 @@
Utility that allows dumping/flashing the SPI Flash Non-Volatile Memory of the FM10000 family of cards.
## Requirements
* GCC >= 4.4.0 or clang
* GCC >= 4.4.0, TCC, or clang
* make
* Only one FM10K device installed on hardware.
* A management resource (BAR4) must be exposed, check bifurcation settings if needed.
@ -11,7 +11,7 @@ Utility that allows dumping/flashing the SPI Flash Non-Volatile Memory of the FM
## Compilation
* `$ make clean && make`
* You can specify whether to use gcc or clang this way: `$ make CC=gcc` / `$ make CC=clang`
* You can specify whether to use gcc/clang/tcc this way: `$ make CC=gcc` / `$ make CC=clang` / `$ make CC=tcc`
* Two executables named `./fm10k-dump` and `./fm10k-flash` should now exist.
## fm10k-dump usage example

View file

@ -3,10 +3,10 @@
* 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: make fm10k-dump
* Usage: ./fm10k-dump </dev/uio0> <output.bin> [readSizeInMegabits=8]
* Usage: ./fm10k-dump <output.bin> [readSizeInMegabits=8]
*
* Copyright (c) 2014 - 2015, Intel Corporation
* Copyright (c) 2020, FM10K-Documentation Contributors
* 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:
@ -35,92 +35,85 @@
#include "fm10k.h"
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <unistd.h>
#include <fcntl.h>
int main(int argc, char** argv){
int fdBAR4;
FILE* fdOutput;
int main(int argc, char **argv) {
FILE *fdOutput;
if(argc < 2){
if (argc < 2) {
printf("Usage: %s <output.bin> [forceSizeInMegabits, default 8]\n", argv[0]);
return 1;
}
fdOutput = fopen(argv[1], "wb");
if(fdOutput == NULL){
if (fdOutput == NULL) {
printf("Could not create %s\n", argv[1]);
return 1;
}
FM10K_PCI_DEVICE device = fm10k_pci_findDevice();
FM10K_PCI_MAPPED_DEVICE map;
FM10K_PCI_DEVICES devices = fm10k_pci_findDevices();
if(device.vendor == 0){
printf("Unable to find FM10K device with BAR4 port access. Check bifurcation settings?\n");
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;
}
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;
}
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) memmapAddr);
if(manufacturerInfo.value == 0){
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);
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 mbitsToRead = 8;
const KNOWN_FLASH_DEVICE* knownFlashDevice = getKnownFlashFromManufacturerData(manufacturerInfo);
const KNOWN_FLASH_DEVICE *knownFlashDevice = getKnownFlashFromManufacturerData(manufacturerInfo);
if(knownFlashDevice != NULL){
printf("Device: %s\n", knownFlashDevice->name);
if (knownFlashDevice != NULL) {
printf("SPI Device: %s\n", knownFlashDevice->name);
mbitsToRead = knownFlashDevice->sizeInMbit;
}else{
printf("Device: Unknown, defaulting %uMbit size\n", mbitsToRead);
} else {
printf("SPI Device: Unknown, defaulting %uMbit size\n", mbitsToRead);
}
if(argc > 2){
if(mbitsToRead != 8){
if (argc > 2) {
if (mbitsToRead != 8) {
printf("WARNING: %uMbit size was already auto-detected\n", mbitsToRead);
}
mbitsToRead = strtoul(argv[2], NULL, 10);
printf("Forcing %uMbit size\n", mbitsToRead);
}
if(mbitsToRead > 1024){
if (mbitsToRead > 1024) {
printf("Too many MBit: %u\n", mbitsToRead);
fm10k_mem_ReleasePlatformLock((uintptr_t) map.map);
return 1;
}
if(mbitsToRead < 8){
if (mbitsToRead < 8) {
printf("Too few MBit: %u\n", mbitsToRead);
fm10k_mem_ReleasePlatformLock((uintptr_t) map.map);
return 1;
}
uint32_t bootImageSize = (mbitsToRead * 1024 * 1024) / 8;
uint8_t* value = malloc(bootImageSize);
uint8_t *value = malloc(bootImageSize);
uint32_t strideSize = 512;
for(uint32_t addr = 0; addr < bootImageSize; addr += strideSize){
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)){
if (fm10k_mem_spi_ReadFlash((uintptr_t) map.map, addr, value + addr, strideSize)) {
fm10k_mem_ReleasePlatformLock((uintptr_t) map.map);
return 2;
}
}
@ -132,7 +125,13 @@ int main(int argc, char** argv){
fclose(fdOutput);
printf("\nRead %u bytes\n", bootImageSize);
printf("\n");
fm10k_mem_ReleasePlatformLock((uintptr_t) map.map);
fm10k_pci_unmapDevice(&map);
printf("Read %u bytes\n", bootImageSize);
return 0;
}
}

View file

@ -3,10 +3,10 @@
* 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>
* Usage: ./fm10k-flash <input.bin> <backup.bin>
*
* Copyright (c) 2014 - 2015, Intel Corporation
* Copyright (c) 2020, FM10K-Documentation Contributors
* 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:
@ -36,156 +36,154 @@
#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;
int main(int argc, char **argv) {
FILE *fdBackup;
FILE *fdInput;
if(argc < 3){
if (argc < 3) {
printf("Usage: %s <input.bin> <backup.bin>\n", argv[0]);
return 1;
}
fdInput = fopen(argv[1], "rb");
if(fdInput == NULL){
if (fdInput == NULL) {
printf("Could not open %s\n", argv[1]);
return 1;
}
fdBackup = fopen(argv[2], "rb");
if(fdBackup == NULL){
if (fdBackup == NULL) {
printf("Could not open existing backup %s\n", argv[2]);
return 1;
}
fseek(fdInput , 0, SEEK_END);
fseek(fdInput, 0, SEEK_END);
uint32_t fileSize = ftell(fdInput);
rewind(fdInput);
fseek(fdBackup , 0, SEEK_END);
fseek(fdBackup, 0, SEEK_END);
uint32_t backupFileSize = ftell(fdBackup);
rewind(fdBackup);
if(backupFileSize < fileSize){
if (backupFileSize < fileSize) {
printf("Backup %d is smaller than new image %d\n", backupFileSize, fileSize);
return 1;
}
FM10K_PCI_DEVICE device = fm10k_pci_findDevice();
FM10K_PCI_MAPPED_DEVICE map;
FM10K_PCI_DEVICES devices = fm10k_pci_findDevices();
if(device.vendor == 0){
printf("Unable to find FM10K device with BAR4 port access. Check bifurcation settings?\n");
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;
}
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;
}
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) memmapAddr);
if(manufacturerInfo.value == 0){
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);
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);
const KNOWN_FLASH_DEVICE *knownFlashDevice = getKnownFlashFromManufacturerData(manufacturerInfo);
if(knownFlashDevice != NULL){
printf("Device: %s\n", knownFlashDevice->name);
if (knownFlashDevice != NULL) {
printf("SPI Device: %s\n", knownFlashDevice->name);
mbitsToReadMax = knownFlashDevice->sizeInMbit;
}else{
printf("Device: Unknown, defaulting max %uMbit size\n", mbitsToReadMax);
} else {
printf("SPI Device: Unknown, defaulting max %uMbit size\n", mbitsToReadMax);
}
if(mbitsToReadMax > 1024){
if (mbitsToReadMax > 1024) {
printf("Too many MBit: %u\n", mbitsToReadMax);
fm10k_mem_ReleasePlatformLock((uintptr_t) map.map);
return 1;
}
if(mbitsToReadMax == 0){
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){
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{
} 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));
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){
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){
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){
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){
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)){
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){
if (memcmp(valueBackup, valueCheck, bootImageSizeMax) != 0) {
printf("Backup image mismatch! Dump image again.\n");
fm10k_mem_ReleasePlatformLock((uintptr_t) map.map);
return 1;
}else{
} else {
printf("Backup matches.\n");
}
sleep(1);
printf("Disabling sector protection.\n");
fm10k_mem_spi_DisableSectorProtection((uintptr_t) memmapAddr);
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){
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)){
if (fm10k_mem_spi_WriteFlash((uintptr_t) map.map, addr, value + addr, strideSize)) {
fm10k_mem_ReleasePlatformLock((uintptr_t) map.map);
return 2;
}
sleep(1);
@ -197,42 +195,49 @@ int main(int argc, char** argv){
sleep(1);
for(uint32_t addr = 0; addr < bootImageSizeMax; addr += strideSize){
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)){
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));
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){
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){
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)){
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{
} else {
printf("Data written verified.\n");
}
sleep(1);
printf("\n");
fm10k_mem_ReleasePlatformLock((uintptr_t) map.map);
fm10k_pci_unmapDevice(&map);
free(value);
@ -245,4 +250,4 @@ int main(int argc, char** argv){
printf("\nWritten %u bytes\n", bootImageSizeMax);
return 0;
}
}

View file

@ -3,7 +3,7 @@
* Creation Date: December 20, 2020
*
* Copyright (c) 2014 - 2015, Intel Corporation
* Copyright (c) 2020, FM10K-Documentation Contributors
* 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:
@ -31,30 +31,32 @@
#include "fm10k.h"
#include <stdio.h>
#include <time.h>
#include <dirent.h>
#include <limits.h>
#include <unistd.h>
#include <stdlib.h>
#include <time.h>
#include <sys/mman.h>
#include <fcntl.h>
KNOWN_FLASH_DEVICE KNOWN_FLASH_DEVICE_LIST[] = {
{{0x0101271f}, "Adesto AT45DB321E 32-Mbit", 32}, // Present on Silicom PE3100G2DQiRM-QX4
{{0x001540ef}, "Winbond W25Q16JV 16-Mbit", 16}, // Present on Intel FM10420-100GbE-QDA2
{{0}, "", 0}
{{0x001540ef}, "Winbond W25Q16JV 16-Mbit", 16}, // Present on Intel FM10420-100GbE-QDA2
{{0}, "", 0}
};
void ReadRegister32(uintptr_t mem, uint32_t addr, uint32_t* value) {
*value = *(((uint32_t*)mem) + addr);
void ReadRegister32(uintptr_t mem, uint32_t addr, uint32_t *value) {
*value = *(((volatile uint32_t *) mem) + addr);
}
void WriteRegister32(uintptr_t mem, uint32_t addr, uint32_t value) {
*(uint32_t volatile*)(((uint32_t*)mem) + addr) = value;
*(((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){
for (uint32_t i = 0; i < 100; ++i) {
dummy = i;
}
#pragma GCC diagnostic pop
@ -71,13 +73,13 @@ uint32_t get_interval_diff(struct timeval *begin, struct timeval *end) {
endT.tv_usec = end->tv_usec;
}
diff.tv_sec = endT.tv_sec - begin->tv_sec;
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_mem_spi_SetCtrlReg(uintptr_t mem, SPI_CTRL value){
uint32_t fm10k_mem_spi_SetCtrlReg(uintptr_t mem, SPI_CTRL value) {
struct timeval startTime;
uint8_t isTimeout = 0;
SPI_CTRL spiCtrl = {0};
@ -85,13 +87,13 @@ uint32_t fm10k_mem_spi_SetCtrlReg(uintptr_t mem, SPI_CTRL value){
WriteRegister32(mem, FM10K_REGISTER_SPI_CTRL, value.value);
gettimeofday(&startTime, NULL);
do{
if(isTimeout){
do {
if (isTimeout) {
printf("Timeout waiting for SPI_CTRL.Busy 0x%02x\n", spiCtrl.value);
return 1;
}
if(get_interval_diff(&startTime, NULL) > 50){
if (get_interval_diff(&startTime, NULL) > 50) {
isTimeout = 1;
}
@ -106,7 +108,7 @@ uint32_t fm10k_mem_spi_SetCtrlReg(uintptr_t mem, SPI_CTRL value){
return 0;
}
void fm10k_mem_spi_Enable(uintptr_t mem){
void fm10k_mem_spi_Enable(uintptr_t mem) {
//ENABLE SPI
SPI_CTRL spiCtrl;
ReadRegister32(mem, FM10K_REGISTER_SPI_CTRL, &spiCtrl.value);
@ -118,7 +120,7 @@ void fm10k_mem_spi_Enable(uintptr_t mem){
WriteRegister32(mem, FM10K_REGISTER_SPI_CTRL, newSpiCtrl.value);
}
void fm10k_mem_spi_Disable(uintptr_t mem){
void fm10k_mem_spi_Disable(uintptr_t mem) {
//DISABLE SPI
SPI_CTRL spiCtrl;
ReadRegister32(mem, FM10K_REGISTER_SPI_CTRL, &spiCtrl.value);
@ -131,7 +133,7 @@ void fm10k_mem_spi_Disable(uintptr_t mem){
//Error if result.value is 0x00
SPI_COMMAND_READ_MANUFACTURER_RESULT fm10k_mem_spi_ReadManufacturerData(uintptr_t mem){
SPI_COMMAND_READ_MANUFACTURER_RESULT fm10k_mem_spi_ReadManufacturerData(uintptr_t mem) {
SPI_COMMAND_READ_MANUFACTURER_RESULT result = {0};
SPI_CTRL currentSpiCtrl;
@ -145,9 +147,9 @@ SPI_COMMAND_READ_MANUFACTURER_RESULT fm10k_mem_spi_ReadManufacturerData(uintptr_
ReadRegister32(mem, FM10K_REGISTER_SPI_CTRL, &currentSpiCtrl.value);
if(FM10K_SPI_FREQ_KHZ > 0){
freq = ((100000 / (int)FM10K_SPI_FREQ_KHZ) / 2) - 1;
if (freq < 0){
if (FM10K_SPI_FREQ_KHZ > 0) {
freq = ((100000 / (int) FM10K_SPI_FREQ_KHZ) / 2) - 1;
if (freq < 0) {
freq = 0;
}
spiCtrl.fields.Freq = freq;
@ -160,12 +162,12 @@ SPI_COMMAND_READ_MANUFACTURER_RESULT fm10k_mem_spi_ReadManufacturerData(uintptr_
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.Command |= 0x1;
spiCtrl.fields.Command |= 0x4;
spiCtrl.fields.HeaderSize = 1;
spiCtrl.fields.DataSize = 4 & 0b11;
spiCtrl.fields.DataSize = 0x4 & 3;
if(fm10k_mem_spi_SetCtrlReg(mem, spiCtrl)){
if (fm10k_mem_spi_SetCtrlReg(mem, spiCtrl)) {
return result;
}
@ -173,12 +175,13 @@ SPI_COMMAND_READ_MANUFACTURER_RESULT fm10k_mem_spi_ReadManufacturerData(uintptr_
/* get data */
ReadRegister32(mem, FM10K_REGISTER_SPI_RX_DATA, &rxData);
result.value = ((rxData>>24)&0xff) | ((rxData<<8)&0xff0000) | ((rxData>>8)&0xff00) | ((rxData<<24)&0xff000000);
result.value = ((rxData >> 24) & 0xff) | ((rxData << 8) & 0xff0000) | ((rxData >> 8) & 0xff00) |
((rxData << 24) & 0xff000000);
/* release CS */
spiCtrl.fields.Command = 0b1000;
if(fm10k_mem_spi_SetCtrlReg(mem, spiCtrl)){
spiCtrl.fields.Command = 0x8;
if (fm10k_mem_spi_SetCtrlReg(mem, spiCtrl)) {
result.value = 0;
return result;
}
@ -189,7 +192,7 @@ SPI_COMMAND_READ_MANUFACTURER_RESULT fm10k_mem_spi_ReadManufacturerData(uintptr_
return result;
}
uint32_t fm10k_mem_spi_ReadFlash(uintptr_t mem, uint32_t address, uint8_t* data, uint32_t len){
uint32_t fm10k_mem_spi_ReadFlash(uintptr_t mem, uint32_t address, uint8_t *data, uint32_t len) {
SPI_CTRL currentSpiCtrl;
SPI_CTRL spiCtrl = {0};
@ -205,9 +208,9 @@ uint32_t fm10k_mem_spi_ReadFlash(uintptr_t mem, uint32_t address, uint8_t* data,
ReadRegister32(mem, FM10K_REGISTER_SPI_CTRL, &currentSpiCtrl.value);
if(FM10K_SPI_FREQ_KHZ > 0){
freq = ((100000 / (int)FM10K_SPI_FREQ_KHZ) / 2) - 1;
if (freq < 0){
if (FM10K_SPI_FREQ_KHZ > 0) {
freq = ((100000 / (int) FM10K_SPI_FREQ_KHZ) / 2) - 1;
if (freq < 0) {
freq = 0;
}
spiCtrl.fields.Freq = freq;
@ -220,17 +223,17 @@ uint32_t fm10k_mem_spi_ReadFlash(uintptr_t mem, uint32_t address, uint8_t* data,
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 |= 0x1;
cnt = 0;
while (cnt < len){
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;
spiCtrl.fields.Command |= 0x4;
spiCtrl.fields.DataSize = numRead & 3;
if(fm10k_mem_spi_SetCtrlReg(mem, spiCtrl)){
if (fm10k_mem_spi_SetCtrlReg(mem, spiCtrl)) {
return 1;
}
@ -243,13 +246,13 @@ uint32_t fm10k_mem_spi_ReadFlash(uintptr_t mem, uint32_t address, uint8_t* data,
data[cnt++] = (rxData >> (numRead * 8)) & 0xff;
}
spiCtrl.fields.Command = 0b0000;
spiCtrl.fields.DataSize = 0b0000;
spiCtrl.fields.Command = 0;
spiCtrl.fields.DataSize = 0;
}
/* release CS */
spiCtrl.fields.Command = 0b1000;
if(fm10k_mem_spi_SetCtrlReg(mem, spiCtrl)){
spiCtrl.fields.Command = 0x8;
if (fm10k_mem_spi_SetCtrlReg(mem, spiCtrl)) {
return 1;
}
@ -259,7 +262,7 @@ uint32_t fm10k_mem_spi_ReadFlash(uintptr_t mem, uint32_t address, uint8_t* data,
return 0;
}
uint32_t fm10k_mem_spi_EnableSectorProtection(uintptr_t mem){
uint32_t fm10k_mem_spi_EnableSectorProtection(uintptr_t mem) {
SPI_CTRL currentSpiCtrl;
SPI_CTRL spiCtrl = {0};
@ -271,9 +274,9 @@ uint32_t fm10k_mem_spi_EnableSectorProtection(uintptr_t mem){
ReadRegister32(mem, FM10K_REGISTER_SPI_CTRL, &currentSpiCtrl.value);
if(FM10K_SPI_FREQ_KHZ > 0){
freq = ((100000 / (int)FM10K_SPI_FREQ_KHZ) / 2) - 1;
if (freq < 0){
if (FM10K_SPI_FREQ_KHZ > 0) {
freq = ((100000 / (int) FM10K_SPI_FREQ_KHZ) / 2) - 1;
if (freq < 0) {
freq = 0;
}
spiCtrl.fields.Freq = freq;
@ -285,16 +288,16 @@ uint32_t fm10k_mem_spi_EnableSectorProtection(uintptr_t mem){
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 |= 0x1;
/* send command to the flash */
if(fm10k_mem_spi_SetCtrlReg(mem, spiCtrl)){
if (fm10k_mem_spi_SetCtrlReg(mem, spiCtrl)) {
return 1;
}
/* release CS */
spiCtrl.fields.Command = 0b1000;
if(fm10k_mem_spi_SetCtrlReg(mem, spiCtrl)){
spiCtrl.fields.Command = 0x8;
if (fm10k_mem_spi_SetCtrlReg(mem, spiCtrl)) {
return 1;
}
@ -303,7 +306,7 @@ uint32_t fm10k_mem_spi_EnableSectorProtection(uintptr_t mem){
return 0;
}
uint32_t fm10k_mem_spi_DisableSectorProtection(uintptr_t mem){
uint32_t fm10k_mem_spi_DisableSectorProtection(uintptr_t mem) {
SPI_CTRL currentSpiCtrl;
SPI_CTRL spiCtrl = {0};
@ -315,9 +318,9 @@ uint32_t fm10k_mem_spi_DisableSectorProtection(uintptr_t mem){
ReadRegister32(mem, FM10K_REGISTER_SPI_CTRL, &currentSpiCtrl.value);
if(FM10K_SPI_FREQ_KHZ > 0){
freq = ((100000 / (int)FM10K_SPI_FREQ_KHZ) / 2) - 1;
if (freq < 0){
if (FM10K_SPI_FREQ_KHZ > 0) {
freq = ((100000 / (int) FM10K_SPI_FREQ_KHZ) / 2) - 1;
if (freq < 0) {
freq = 0;
}
spiCtrl.fields.Freq = freq;
@ -329,16 +332,16 @@ uint32_t fm10k_mem_spi_DisableSectorProtection(uintptr_t mem){
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 |= 0x1;
/* send command to the flash */
if(fm10k_mem_spi_SetCtrlReg(mem, spiCtrl)){
if (fm10k_mem_spi_SetCtrlReg(mem, spiCtrl)) {
return 1;
}
/* release CS */
spiCtrl.fields.Command = 0b1000;
if(fm10k_mem_spi_SetCtrlReg(mem, spiCtrl)){
spiCtrl.fields.Command = 0x8;
if (fm10k_mem_spi_SetCtrlReg(mem, spiCtrl)) {
return 1;
}
@ -347,7 +350,7 @@ uint32_t fm10k_mem_spi_DisableSectorProtection(uintptr_t mem){
return 0;
}
uint32_t fm10k_mem_spi_WriteFlash(uintptr_t mem, uint32_t address, const uint8_t* data, uint32_t len){
uint32_t fm10k_mem_spi_WriteFlash(uintptr_t mem, uint32_t address, const uint8_t *data, uint32_t len) {
SPI_CTRL currentSpiCtrl;
SPI_CTRL spiCtrl = {0};
@ -363,9 +366,9 @@ uint32_t fm10k_mem_spi_WriteFlash(uintptr_t mem, uint32_t address, const uint8_t
ReadRegister32(mem, FM10K_REGISTER_SPI_CTRL, &currentSpiCtrl.value);
if(FM10K_SPI_FREQ_KHZ > 0){
freq = ((100000 / (int)FM10K_SPI_FREQ_KHZ) / 2) - 1;
if (freq < 0){
if (FM10K_SPI_FREQ_KHZ > 0) {
freq = ((100000 / (int) FM10K_SPI_FREQ_KHZ) / 2) - 1;
if (freq < 0) {
freq = 0;
}
spiCtrl.fields.Freq = freq;
@ -378,15 +381,15 @@ uint32_t fm10k_mem_spi_WriteFlash(uintptr_t mem, uint32_t address, const uint8_t
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 |= 0x1;
cnt = 0;
while (cnt < len){
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;
spiCtrl.fields.Command |= 0x4;
spiCtrl.fields.DataSize = numWrite & 3;
txData = 0;
while (numWrite--) {
@ -396,17 +399,17 @@ uint32_t fm10k_mem_spi_WriteFlash(uintptr_t mem, uint32_t address, const uint8_t
WriteRegister32(mem, FM10K_REGISTER_SPI_TX_DATA, txData);
/* send command to the flash */
if(fm10k_mem_spi_SetCtrlReg(mem, spiCtrl)){
if (fm10k_mem_spi_SetCtrlReg(mem, spiCtrl)) {
return 1;
}
spiCtrl.fields.Command = 0b0000;
spiCtrl.fields.DataSize = 0b0000;
spiCtrl.fields.Command = 0;
spiCtrl.fields.DataSize = 0;
}
/* release CS */
spiCtrl.fields.Command = 0b1000;
if(fm10k_mem_spi_SetCtrlReg(mem, spiCtrl)){
spiCtrl.fields.Command = 0x8;
if (fm10k_mem_spi_SetCtrlReg(mem, spiCtrl)) {
return 1;
}
@ -416,10 +419,10 @@ uint32_t fm10k_mem_spi_WriteFlash(uintptr_t mem, uint32_t address, const uint8_t
return 0;
}
const KNOWN_FLASH_DEVICE* getKnownFlashFromManufacturerData(SPI_COMMAND_READ_MANUFACTURER_RESULT data){
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){
for (uint32_t i = 0; i < deviceCount; ++i) {
if (KNOWN_FLASH_DEVICE_LIST[i].data.value == data.value) {
return &KNOWN_FLASH_DEVICE_LIST[i];
}
}
@ -427,52 +430,192 @@ const KNOWN_FLASH_DEVICE* getKnownFlashFromManufacturerData(SPI_COMMAND_READ_MAN
return NULL;
}
FM10K_PCI_DEVICE fm10k_pci_findDevice(){
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);
}
int fm10k_pci_unmapDevice(FM10K_PCI_MAPPED_DEVICE *map) {
if (map->map != NULL && map->map != MAP_FAILED) {
if (munmap(map->map, FM10K_BAR4_SIZE) != 0) {
return 1;
}
map->map = NULL;
}
if (map->fd > 0) {
if (close(map->fd) != 0) {
return 1;
}
map->fd = 0;
}
return 0;
}
int fm10k_pci_mapDevice(const FM10K_PCI_DEVICE *device, FM10K_PCI_MAPPED_DEVICE *map) {
int fdBAR4;
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;
}
map->device = device;
map->fd = fdBAR4;
map->map = memmapAddr;
if (fm10k_mem_TakePlatformLock((uintptr_t) map->map)) {
//Error taking lock
fm10k_pci_unmapDevice(map);
return 1;
}
return 0;
}
int fm10k_pci_findDevice(const FM10K_PCI_DEVICES *devices, FM10K_PCI_MAPPED_DEVICE *map) {
if (devices->count == 0) {
return 1;
}
for (uint32_t i = 0; i < devices->count; ++i) {
if (fm10k_pci_mapDevice(&devices->devices[i], map) == 0) {
return 0;
}
}
return 1;
}
FM10K_PCI_DEVICES fm10k_pci_findDevices() {
DIR *folder;
char fileName[PATH_MAX];
FM10K_PCI_DEVICE device = {0, 0, ""};
FM10K_PCI_DEVICES devices;
devices.count = 0;
folder = opendir("/sys/bus/pci/devices");
if(folder == NULL){
return device;
if (folder == NULL) {
return devices;
}
struct dirent *entry;
while((entry = readdir(folder))){
if(entry->d_type == DT_DIR || entry->d_type == DT_LNK){
while ((entry = readdir(folder))) {
if (entry->d_type == DT_DIR || entry->d_type == DT_LNK) {
sprintf(fileName, "/sys/bus/pci/devices/%s/vendor", entry->d_name);
FILE* vendorBytesPointer = fopen(fileName, "rb");
if(vendorBytesPointer != NULL){
char* vendorBytesBuffer = NULL;
FILE *vendorBytesPointer = fopen(fileName, "rb");
if (vendorBytesPointer != NULL) {
char *vendorBytesBuffer = NULL;
size_t vendorBytesLen;
size_t vendorBytesRead = getdelim(&vendorBytesBuffer, &vendorBytesLen, '\0', vendorBytesPointer);
if(vendorBytesRead != -1){
int vendor = (int)strtol(vendorBytesBuffer, NULL, 0);
if (vendorBytesRead != -1) {
unsigned int vendor = (unsigned int) strtoul(vendorBytesBuffer, NULL, 0);
if(vendor == 0x8086){ //Intel Corporation
if (vendor == 0x8086) { //Intel Corporation
sprintf(fileName, "/sys/bus/pci/devices/%s/device", entry->d_name);
FILE* classBytesPointer = fopen(fileName, "rb");
if(classBytesPointer != NULL){
char* classBytesBuffer = NULL;
FILE *classBytesPointer = fopen(fileName, "rb");
if (classBytesPointer != NULL) {
char *classBytesBuffer = NULL;
size_t classBytesLen;
size_t classBytesRead = getdelim(&classBytesBuffer, &classBytesLen, '\0', classBytesPointer);
if(classBytesRead != -1){
int class = (int)strtol(classBytesBuffer, NULL, 0);
size_t classBytesRead = getdelim(&classBytesBuffer, &classBytesLen, '\0',
classBytesPointer);
if (classBytesRead != -1) {
unsigned int class = (unsigned int) strtoul(classBytesBuffer, NULL, 0);
if(class == 0x15a4 || class == 0x15d0 || class == 0x15d5){ //FM10000 devices
if (class == 0x15a4 || class == 0x15d0 || class == 0x15d5) { //FM10000 devices
sprintf(fileName, "/sys/bus/pci/devices/%s/resource4", entry->d_name);
if(access(fileName, F_OK ) == 0 ) {
device.vendor = vendor;
device.class = class;
if (access(fileName, F_OK) == 0) {
devices.devices[devices.count].vendor = vendor;
devices.devices[devices.count].class = class;
sprintf(device.bar4Path, "/sys/bus/pci/devices/%s/resource4", entry->d_name);
sprintf(devices.devices[devices.count].bar4Path, "/sys/bus/pci/devices/%s/resource4",
entry->d_name);
++devices.count;
}
}
}
if(classBytesBuffer != NULL){
if (classBytesBuffer != NULL) {
free(classBytesBuffer);
}
fclose(classBytesPointer);
@ -480,13 +623,13 @@ FM10K_PCI_DEVICE fm10k_pci_findDevice(){
}
}
if(vendorBytesBuffer != NULL){
if (vendorBytesBuffer != NULL) {
free(vendorBytesBuffer);
}
fclose(vendorBytesPointer);
}
if(device.vendor != 0){
if (devices.count >= FM10K_PCI_DEVICE_MAX) {
break;
}
@ -495,5 +638,5 @@ FM10K_PCI_DEVICE fm10k_pci_findDevice(){
closedir(folder);
return device;
}
return devices;
}

View file

@ -3,7 +3,7 @@
* Creation Date: December 20, 2020
*
* Copyright (c) 2014 - 2015, Intel Corporation
* Copyright (c) 2020, FM10K-Documentation Contributors
* 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:
@ -33,7 +33,7 @@
#include <inttypes.h>
#include <sys/time.h>
#include <limits.h>
#include <linux/limits.h>
#define FM10K_BAR4_SIZE 0x0000000004000000
#define FM10K_BAR4_OFFSET 0
@ -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))
@ -54,79 +61,129 @@
#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__
#if __GNUC__ > 4 || (__GNUC__ == 4 && (__GNUC_MINOR__ >= 4)) || __clang__ || __TINYC__
#if defined(__TINYC__)
#pragma pack(1)
#endif
typedef union {
uint32_t value;
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;
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 {
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;
} SPI_CTRL;
typedef union {
uint32_t value;
struct {
uint8_t manufacturerId : 8;
uint8_t densityCode : 5;
uint8_t familyCode : 3;
uint8_t productVariant : 5;
uint8_t subCode : 3;
uint8_t RESERVED : 8;
} __attribute__((packed)) fields;
uint32_t value;
struct {
uint8_t manufacturerId: 8;
uint8_t densityCode: 5;
uint8_t familyCode: 3;
uint8_t productVariant: 5;
uint8_t subCode: 3;
uint8_t Reserved: 8;
} __attribute__((packed)) fields;
} SPI_COMMAND_READ_MANUFACTURER_RESULT;
typedef struct {
SPI_COMMAND_READ_MANUFACTURER_RESULT data;
char name[64];
uint32_t sizeInMbit;
SPI_COMMAND_READ_MANUFACTURER_RESULT data;
char name[64];
uint32_t sizeInMbit;
} KNOWN_FLASH_DEVICE;
#if defined(__TINYC__)
#pragma pack(1)
#endif
#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 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_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);
//Error if result.value is 0x00
SPI_COMMAND_READ_MANUFACTURER_RESULT fm10k_mem_spi_ReadManufacturerData(uintptr_t mem);
const KNOWN_FLASH_DEVICE* getKnownFlashFromManufacturerData(SPI_COMMAND_READ_MANUFACTURER_RESULT data);
const KNOWN_FLASH_DEVICE *getKnownFlashFromManufacturerData(SPI_COMMAND_READ_MANUFACTURER_RESULT data);
uint32_t fm10k_mem_spi_EnableSectorProtection(uintptr_t mem);
uint32_t fm10k_mem_spi_DisableSectorProtection(uintptr_t mem);
uint32_t fm10k_mem_spi_ReadFlash(uintptr_t mem, uint32_t address, uint8_t* data, uint32_t len);
uint32_t fm10k_mem_spi_WriteFlash(uintptr_t mem, uint32_t address, const uint8_t* data, uint32_t len);
uint32_t fm10k_mem_spi_ReadFlash(uintptr_t mem, uint32_t address, uint8_t *data, uint32_t len);
typedef struct{
uint16_t vendor;
uint16_t class;
char bar4Path[PATH_MAX];
uint32_t fm10k_mem_spi_WriteFlash(uintptr_t mem, uint32_t address, const uint8_t *data, uint32_t len);
#define FM10K_PCI_DEVICE_MAX 16
typedef struct {
uint16_t vendor;
uint16_t class;
char bar4Path[PATH_MAX];
} FM10K_PCI_DEVICE;
FM10K_PCI_DEVICE fm10k_pci_findDevice();
typedef struct {
const FM10K_PCI_DEVICE *device;
void *map;
int fd;
} FM10K_PCI_MAPPED_DEVICE;
typedef struct {
uint32_t count;
FM10K_PCI_DEVICE devices[FM10K_PCI_DEVICE_MAX];
} FM10K_PCI_DEVICES;
FM10K_PCI_DEVICES fm10k_pci_findDevices();
int fm10k_pci_findDevice(const FM10K_PCI_DEVICES *devices, FM10K_PCI_MAPPED_DEVICE *map);
int fm10k_pci_mapDevice(const FM10K_PCI_DEVICE *device, FM10K_PCI_MAPPED_DEVICE *map);
int fm10k_pci_unmapDevice(FM10K_PCI_MAPPED_DEVICE *map);

59
src/test.c Normal file
View file

@ -0,0 +1,59 @@
/*****************************************************************************
* File: test.c
* Creation Date: January 06, 2021
* Description: Runs several platform alignment tests
* Compile: make test-bin
* Usage: ./test
*
* 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>
#define TEST(have, expected, i) if(have != expected){ printf("[TEST %u] FAIL: " i "\n", ++tests, have, expected); ++testsFailed; }else { printf("[TEST %u] PASS: " i "\n", ++tests, have, expected);}
int main(int argc, char **argv) {
uint32_t tests = 0;
uint32_t testsFailed = 0;
{
SPI_CTRL s;
TEST((uint32_t) sizeof(s.fields), (uint32_t) sizeof(s.value), "SPI_CTRL packed misalignment. size struct %u, size value %u");
}
{
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;
}