21 changes: 21 additions & 0 deletions include/flash_access.h
@@ -0,0 +1,21 @@
#ifndef FLASH_ACCESS_H
#define FLASH_ACCESS_H

#include <stdint.h>

#define MAX_DEVICES 64
#define MAX_LENGTH 64
#define NEWLINE 0x0A
#define NUL 0x00

int init_flash(void);
int is_flash_locked(void);
int lock_flash(void);
int unlock_flash(void);
int read_sec_status(void);
int read_sec(u8 reg, u8 addr, void *buf, size_t len);
int prog_sec(u8 reg, u8 addr, const void *buf, size_t len);
int lock_sec(u8 reg);
void save_flash(int flash_address, char buffer[MAX_DEVICES][MAX_LENGTH], u8 max_lines, u8 spi_wp_toggle);

#endif
6 changes: 6 additions & 0 deletions include/sec_reg_menu.h
@@ -0,0 +1,6 @@
#ifndef SEC_REG_MENU_H
#define SEC_REG_MENU_H

void handle_reg_sec_menu(void);

#endif
14 changes: 0 additions & 14 deletions spi.h → include/spi/spi.h
Expand Up @@ -52,20 +52,6 @@
#define SPI_READ_FLAG 0x01
#define SPI_WRITE_FLAG 0x02

struct spi_flash {
struct spi_slave *spi;
const char *name;
u32 size;
u32 sector_size;
int (*read)(struct spi_flash *flash, u32 offset, size_t len, void *buf);
int (*write)(struct spi_flash *flash, u32 offset, size_t len,
const void *buf);
int (*spi_erase)(struct spi_flash *flash, u32 offset, size_t len);
int (*lock)(struct spi_flash *flash);
int (*unlock)(struct spi_flash *flash);
int (*is_locked)(struct spi_flash *flash);
};

struct spi_slave {
unsigned int bus;
unsigned int cs;
Expand Down
44 changes: 43 additions & 1 deletion spi_flash.h → include/spi/spi_flash.h
Expand Up @@ -23,7 +23,7 @@

#include <stdint.h>
#include <stddef.h>
#include "spi.h"
#include <spi/spi.h>

/**
* container_of - cast a member of a structure out to the containing structure
Expand All @@ -37,6 +37,7 @@
(type *)( (char *)__mptr - offsetof(type,member) );})

#define min(a, b) ((a)<(b)?(a):(b))
#define sec_addr(offset, address) ((((uint32_t)offset) << 12) | (address))

#define CONFIG_ICH_SPI
#ifdef CONFIG_ICH_SPI
Expand All @@ -46,6 +47,25 @@
#define CONTROLLER_PAGE_LIMIT ((int)(~0U>>1))
#endif

struct spi_flash {
struct spi_slave *spi;
const char *name;
u32 size;
u32 sector_size;
int (*read)(struct spi_flash *flash, u32 offset, size_t len, void *buf);
int (*write)(struct spi_flash *flash, u32 offset, size_t len,
const void *buf);
int (*spi_erase)(struct spi_flash *flash, u32 offset, size_t len);
int (*lock)(struct spi_flash *flash);
int (*unlock)(struct spi_flash *flash);
int (*is_locked)(struct spi_flash *flash);
int (*sec_sts)(struct spi_flash *flash);
int (*sec_read)(struct spi_flash *flash, u32 offset, size_t len, void *buf);
int (*sec_prog)(struct spi_flash *flash, u32 offset, size_t len,
const void *buf);
int (*sec_lock)(struct spi_flash *flash, u8 reg);
};

struct spi_flash *spi_flash_probe(unsigned int bus, unsigned int cs,
unsigned int max_hz, unsigned int spi_mode);

Expand Down Expand Up @@ -81,4 +101,26 @@ static inline int spi_flash_is_locked(struct spi_flash *flash)
return flash->is_locked(flash);
}

static inline int spi_flash_sec_sts(struct spi_flash *flash)
{
return flash->sec_sts(flash);
}

static inline int spi_flash_sec_read(struct spi_flash *flash, u32 offset, size_t len,
void *buf)
{
return flash->sec_read(flash, offset, len, buf);
}

static inline int spi_flash_sec_prog(struct spi_flash *flash, u32 offset, size_t len,
const void *buf)
{
return flash->sec_prog(flash, offset, len, buf);
}

static inline int spi_flash_sec_lock(struct spi_flash *flash, u8 reg)
{
return flash->sec_lock(flash, reg);
}

#endif /* _SPI_FLASH_H_ */
221 changes: 82 additions & 139 deletions sortbootorder.c
Expand Up @@ -19,19 +19,14 @@
#include <libpayload.h>
#include <cbfs.h>
#include <curses.h>
#include "spi_flash.h"
#include <flash_access.h>
#include <sec_reg_menu.h>
#include "version.h"

/*** defines ***/
#define CONFIG_SPI_FLASH_NO_FAST_READ
#define BOOTORDER_FILE "bootorder"
#define BOOTORDER_DEF "bootorder_def"
#define BOOTORDER_MAP "bootorder_map"
#define MAX_DEVICES 64
#define MAX_LENGTH 64
#define NEWLINE 0x0A
#define NUL 0x00
#define FLASH_SIZE_CHUNK 0x1000 //4k

// These names come from bootorder_map file
// indexes depend on device order in this file
Expand All @@ -55,32 +50,26 @@ static void copy_list_line( char *src, char *dest );
static int fetch_file_from_cbfs( char *filename, char destination[MAX_DEVICES][MAX_LENGTH], u8 *line_count);
static int get_line_number(u8 line_start, u8 line_end, char key );
static void int_ids( char buffer[MAX_DEVICES][MAX_LENGTH], u8 line_cnt, u8 lineDef_cnt );
static inline int init_flash(void);
static inline int is_flash_locked(void);
static inline int lock_flash(void);
static inline int unlock_flash(void);
static void save_flash(char buffer[MAX_DEVICES][MAX_LENGTH], u8 max_lines);
static void update_tag_value(char buffer[MAX_DEVICES][MAX_LENGTH], u8 *max_lines, const char * tag, char value);
static void refresh_tag_values(u8 max_lines);

/*** local variables ***/
static int flash_address;

static u8 ipxe_toggle;
static u8 usb_toggle;
static u8 sga_toggle;
static u8 spi_wp_toggle;

#ifdef COREBOOT_LEGACY
static u8 console_toggle;
static u8 ehci0_toggle;
static u8 uartc_toggle;
static u8 uartd_toggle;
static u8 mpcie2_clk_toggle;
#endif

static char bootlist_def[MAX_DEVICES][MAX_LENGTH];
static char bootlist_map[MAX_DEVICES][MAX_LENGTH];
static char id[MAX_DEVICES] = {0};
static struct spi_flash *flash_device;
static int flash_address;

static u8 device_toggle[MAX_DEVICES];

/* sortbootorder payload:
Expand Down Expand Up @@ -152,11 +141,6 @@ int main(void) {
token += strlen("usben");
usb_toggle = token ? strtoul(token, NULL, 10) : 1;

token = cbfs_find_string("sgaen", BOOTORDER_FILE);
token += strlen("sgaen");
sga_toggle = token ? strtoul(token, NULL, 10) : 0;

#ifdef COREBOOT_LEGACY
token = cbfs_find_string("scon", BOOTORDER_FILE);
token += strlen("scon");
console_toggle = token ? strtoul(token, NULL, 10) : 1;
Expand All @@ -176,7 +160,7 @@ int main(void) {
token = cbfs_find_string("mpcie2_clk", BOOTORDER_FILE);
token += strlen("mpcie2_clk");
mpcie2_clk_toggle = token ? strtoul(token, NULL, 10) : 0;
#endif


spi_wp_toggle = is_flash_locked();

Expand All @@ -193,6 +177,7 @@ int main(void) {
for (i = 0; i < max_lines && i < bootlist_def_ln; i++ )
copy_list_line(&(bootlist_def[i][0]), &(bootlist[i][0]));
int_ids( bootlist, max_lines, bootlist_def_ln );
refresh_tag_values(bootlist_def_ln);
break;
case 'n':
case 'N':
Expand All @@ -202,10 +187,6 @@ int main(void) {
case 'U':
usb_toggle ^= 0x1;
break;
case 'l':
case 'L':
sga_toggle ^= 0x1;
break;
case 'w':
case 'W':
if (spi_wp_toggle) {
Expand All @@ -215,7 +196,6 @@ int main(void) {
}
spi_wp_toggle = is_flash_locked();
break;
#ifdef COREBOOT_LEGACY
case 't':
case 'T':
console_toggle ^= 0x1;
Expand All @@ -236,20 +216,19 @@ int main(void) {
case 'H':
ehci0_toggle ^= 0x1;
break;
#endif
case 'Z':
handle_reg_sec_menu();
break;
case 's':
case 'S':
update_tag_value(bootlist, &max_lines, "pxen", ipxe_toggle + '0');
update_tag_value(bootlist, &max_lines, "usben", usb_toggle + '0');
update_tag_value(bootlist, &max_lines, "sgaen", sga_toggle + '0');
#ifdef COREBOOT_LEGACY
update_tag_value(bootlist, &max_lines, "scon", console_toggle + '0');
update_tag_value(bootlist, &max_lines, "uartc", uartc_toggle + '0');
update_tag_value(bootlist, &max_lines, "uartd", uartd_toggle + '0');
update_tag_value(bootlist, &max_lines, "mpcie2_clk", mpcie2_clk_toggle + '0');
update_tag_value(bootlist, &max_lines, "ehcien", ehci0_toggle + '0');
#endif
save_flash( bootlist, max_lines );
save_flash(flash_address, bootlist, max_lines, spi_wp_toggle);
// fall through to exit ...
case 'x':
case 'X':
Expand Down Expand Up @@ -320,17 +299,19 @@ static void show_boot_device_list( char buffer[MAX_DEVICES][MAX_LENGTH], u8 line
printf("Boot order - type letter to move device to top.\n\n");
for (i = 0; i < line_cnt; i++ ) {
for (y = 0; y < lineDef_cnt; y++) {
if (strcmp_printable_char(&(buffer[i][0]), &(bootlist_def[y][0])) == 0) {
unique = 1;
for (j = 0; j < y; j++) {
if (strcmp_printable_char(&bootlist_map[y][0], &bootlist_map[j][0]) == 0)
unique = 0;
}
if (unique) {
strcpy(print_device, &bootlist_map[y][0]);
print_device[strlen(print_device)-1] = '\0';
printf(" %s %s\n", print_device, (device_toggle[y]) ? "" : "(disabled)");
break;
if(bootlist_def[y][0] == '/') {
if (strcmp_printable_char(&(buffer[i][0]), &(bootlist_def[y][0])) == 0) {
unique = 1;
for (j = 0; j < y; j++) {
if (strcmp_printable_char(&bootlist_map[y][0], &bootlist_map[j][0]) == 0)
unique = 0;
}
if (unique) {
strcpy(print_device, &bootlist_map[y][0]);
print_device[strlen(print_device)-1] = '\0';
printf(" %s %s\n", print_device, (device_toggle[y]) ? "" : "(disabled)");
break;
}
}
}
}
Expand All @@ -339,14 +320,11 @@ static void show_boot_device_list( char buffer[MAX_DEVICES][MAX_LENGTH], u8 line
printf(" r Restore boot order defaults\n");
printf(" n Network/PXE boot - Currently %s\n", (ipxe_toggle) ? "Enabled" : "Disabled");
printf(" u USB boot - Currently %s\n", (usb_toggle) ? "Enabled" : "Disabled");
printf(" l Legacy console redirection - Currently %s\n", (sga_toggle) ? "Enabled" : "Disabled");
#ifdef COREBOOT_LEGACY
printf(" t Serial console - Currently %s\n", (console_toggle) ? "Enabled" : "Disabled");
printf(" o UART C - Currently %s\n", (uartc_toggle) ? "Enabled" : "Disabled");
printf(" p UART D - Currently %s\n", (uartd_toggle) ? "Enabled" : "Disabled");
printf(" m Force mPCIe2 slot CLK (GPP3 PCIe) - Currently %s\n", (mpcie2_clk_toggle) ? "Enabled" : "Disabled");
printf(" h EHCI0 controller - Currently %s\n", (ehci0_toggle) ? "Enabled" : "Disabled");
#endif
printf(" w Enable BIOS write protect - Currently %s\n", (spi_wp_toggle) ? "Enabled" : "Disabled");
printf(" x Exit setup without save\n");
printf(" s Save configuration and exit\n");
Expand All @@ -356,10 +334,12 @@ static void show_boot_device_list( char buffer[MAX_DEVICES][MAX_LENGTH], u8 line
static void int_ids( char buffer[MAX_DEVICES][MAX_LENGTH], u8 line_cnt, u8 lineDef_cnt ) {
int i,y;
for (i = 0; i < line_cnt; i++ ) {
for (y = 0; y < lineDef_cnt; y++) {
if (strcmp_printable_char(&(buffer[i][0]), &(bootlist_def[y][0])) == 0) {
strncpy(&id[i], &(bootlist_map[y][0]), 1);
break;
if (buffer[i][0] == '/') {
for (y = 0; y < lineDef_cnt; y++) {
if (strcmp_printable_char(&(buffer[i][0]), &(bootlist_def[y][0])) == 0) {
strncpy(&id[i], &(bootlist_map[y][0]), 1);
break;
}
}
}
}
Expand Down Expand Up @@ -432,94 +412,6 @@ static void move_boot_list( char buffer[MAX_DEVICES][MAX_LENGTH], u8 line, u8 ma
id[0] = ln;
}

/*******************************************************************************/
static inline int init_flash(void)
{
flash_device = spi_flash_probe(0, 0, 0, 0);

if (!flash_device)
return -1;

return 0;
}

/*******************************************************************************/
static inline int is_flash_locked(void)
{
return spi_flash_is_locked(flash_device);
}

/*******************************************************************************/
static inline int lock_flash(void)
{
return spi_flash_lock(flash_device);
}

/*******************************************************************************/
static inline int unlock_flash(void)
{
return spi_flash_unlock(flash_device);
}

/*******************************************************************************/
static void save_flash(char buffer[MAX_DEVICES][MAX_LENGTH], u8 max_lines) {
int i = 0;
int k = 0;
int j, ret;
char cbfs_formatted_list[MAX_DEVICES * MAX_LENGTH];
u32 nvram_pos;

// compact the table into the expected packed list
for (j = 0; j < max_lines; j++) {
k = 0;
while (1) {
cbfs_formatted_list[i++] = buffer[j][k];
if (buffer[j][k] == NEWLINE )
break;
k++;
}
}
cbfs_formatted_list[i++] = NUL;

// try to unlock the flash if it is locked
if (spi_flash_is_locked(flash_device)) {
spi_flash_unlock(flash_device);
if (spi_flash_is_locked(flash_device)) {
printf("Flash is write protected. Exiting...\n");
return;
}
}

printf("Erasing Flash size 0x%x @ 0x%x\n", FLASH_SIZE_CHUNK, flash_address);
ret = spi_flash_erase(flash_device, flash_address, FLASH_SIZE_CHUNK);
if (ret) {
printf("Erase failed, ret: %d\n", ret);
}

printf("Writing %d bytes @ 0x%x\n", i, flash_address);
// write first 512 bytes
for (nvram_pos = 0; nvram_pos < (i & 0xFFFC); nvram_pos += 4) {
ret = spi_flash_write(flash_device, nvram_pos + flash_address, sizeof(u32), (u32 *)(cbfs_formatted_list + nvram_pos));
if (ret) {
printf("Write failed, ret: %d\n", ret);
}
}
// write remaining filler characters in one run
ret = spi_flash_write(flash_device, nvram_pos + flash_address, sizeof(i % 4), (u32 *)(cbfs_formatted_list + nvram_pos));
if (ret) {
printf("Write failed, ret: %d\n", ret);
}

if (spi_wp_toggle) {
printf("Enabling flash write protect...\n");
spi_flash_lock(flash_device);
}

spi_wp_toggle = spi_flash_is_locked(flash_device);

printf("Done\n");
}

/*******************************************************************************/
static void update_tag_value(char buffer[MAX_DEVICES][MAX_LENGTH], u8 *max_lines, const char * tag, char value)
{
Expand All @@ -546,3 +438,54 @@ static void update_tag_value(char buffer[MAX_DEVICES][MAX_LENGTH], u8 *max_lines
(*max_lines)++;
}
}

/*******************************************************************************/
static void refresh_tag_values(u8 max_lines)
{
int i;
char *token;

for ( i = 0; i < max_lines; i++) {
token = strstr(&(bootlist_def[i][0]), "pxen");
if(token) {
token += strlen("pxen");
ipxe_toggle = strtoul(token, NULL, 10);
}

token = strstr(&(bootlist_def[i][0]), "usben");
if(token) {
token += strlen("usben");
usb_toggle = strtoul(token, NULL, 10);
}

token = strstr(&(bootlist_def[i][0]), "scon");
if(token) {
token += strlen("scon");
console_toggle = strtoul(token, NULL, 10);
}

token = strstr(&(bootlist_def[i][0]), "ehcien");
if(token) {
token += strlen("ehcien");
ehci0_toggle = strtoul(token, NULL, 10);
}

token = strstr(&(bootlist_def[i][0]), "uartc");
if(token) {
token += strlen("uartc");
uartc_toggle = strtoul(token, NULL, 10);
}

token = strstr(&(bootlist_def[i][0]), "uartd");
if(token) {
token += strlen("uartd");
uartd_toggle = strtoul(token, NULL, 10);
}

token = strstr(&(bootlist_def[i][0]), "mpcie2_clk");
if(token) {
token += strlen("mpcie2_clk");
mpcie2_clk_toggle = strtoul(token, NULL, 10);
}
}
}
5 changes: 3 additions & 2 deletions eon.c → spi/eon.c
Expand Up @@ -9,9 +9,10 @@
//#define SPI_DEBUG

#include <stdlib.h>
#include "spi_flash.h"
#include <spi/spi_flash.h>
#include <spi/spi.h>
#include "spi_flash_internal.h"
#include "spi.h"


/* EN25Q128-specific commands */
#define CMD_EN25Q128_WREN 0x06 /* Write Enable */
Expand Down
4 changes: 2 additions & 2 deletions gigadevice.c → spi/gigadevice.c
Expand Up @@ -26,9 +26,9 @@
//#define SPI_DEBUG

#include <stdlib.h>
#include "spi_flash.h"
#include <spi/spi_flash.h>
#include <spi/spi.h>
#include "spi_flash_internal.h"
#include "spi.h"

/* GD25Pxx-specific commands */
#define CMD_GD25_WREN 0x06 /* Write Enable */
Expand Down
4 changes: 2 additions & 2 deletions macronix.c → spi/macronix.c
Expand Up @@ -31,9 +31,9 @@
//#define SPI_DEBUG

#include <stdlib.h>
#include "spi_flash.h"
#include <spi/spi_flash.h>
#include <spi/spi.h>
#include "spi_flash_internal.h"
#include "spi.h"

/* MX25xx-specific commands */
#define CMD_MX25XX_WREN 0x06 /* Write Enable */
Expand Down
4 changes: 2 additions & 2 deletions spansion.c → spi/spansion.c
Expand Up @@ -27,9 +27,9 @@
//#define SPI_DEBUG

#include <stdlib.h>
#include "spi_flash.h"
#include <spi/spi_flash.h>
#include <spi/spi.h>
#include "spi_flash_internal.h"
#include "spi.h"

/* S25FLxx-specific commands */
#define CMD_S25FLXX_READ 0x03 /* Read Data Bytes */
Expand Down
2 changes: 1 addition & 1 deletion spi.c → spi/spi.c
Expand Up @@ -22,7 +22,7 @@
#include <stdlib.h>
#include <string.h>
#include <arch/io.h>
#include "spi.h"
#include <spi/spi.h>
#include <pci.h>

#if defined (CONFIG_SB800_IMC_FWM)
Expand Down
4 changes: 2 additions & 2 deletions spi_flash.c → spi/spi_flash.c
Expand Up @@ -13,9 +13,9 @@
#include <libpayload-config.h>
#include <stdlib.h>
#include <string.h>
#include "spi_flash.h"
#include <spi/spi_flash.h>
#include <spi/spi.h>
#include "spi_flash_internal.h"
#include "spi.h"

static void spi_flash_addr(u32 addr, u8 *cmd)
{
Expand Down
File renamed without changes.
4 changes: 2 additions & 2 deletions sst.c → spi/sst.c
Expand Up @@ -16,9 +16,9 @@
//#define SPI_DEBUG

#include <stdlib.h>
#include "spi_flash.h"
#include <spi/spi_flash.h>
#include <spi/spi.h>
#include "spi_flash_internal.h"
#include "spi.h"

#define CMD_SST_WREN 0x06 /* Write Enable */
#define CMD_SST_WRDI 0x04 /* Write Disable */
Expand Down
4 changes: 2 additions & 2 deletions stmicro.c → spi/stmicro.c
Expand Up @@ -29,9 +29,9 @@
//#define SPI_DEBUG

#include <stdlib.h>
#include "spi_flash.h"
#include <spi/spi_flash.h>
#include <spi/spi.h>
#include "spi_flash_internal.h"
#include "spi.h"

/* M25Pxx-specific commands */
#define CMD_M25PXX_WREN 0x06 /* Write Enable */
Expand Down
177 changes: 175 additions & 2 deletions winbond.c → spi/winbond.c
Expand Up @@ -10,9 +10,9 @@
//#define SPI_DEBUG

#include <stdlib.h>
#include "spi_flash.h"
#include <spi/spi_flash.h>
#include <spi/spi.h>
#include "spi_flash_internal.h"
#include "spi.h"

/* M25Pxx-specific commands */
#define CMD_W25_WREN 0x06 /* Write Enable */
Expand All @@ -31,6 +31,9 @@
#define CMD_W25_CE 0xc7 /* Chip Erase */
#define CMD_W25_DP 0xb9 /* Deep Power-down */
#define CMD_W25_RES 0xab /* Release from DP, and Read Signature */
#define CMD_W25_ER_SEC 0x44 /* Erase security registers */
#define CMD_W25_WR_SEC 0x42 /* Write security registers */
#define CMD_W25_RD_SEC 0x48 /* Read security registers */

#define REG_W25_BP0 (1 << 2)
#define REG_W25_BP1 (1 << 3)
Expand All @@ -41,6 +44,13 @@
#define REG_W25_SRP1 (1 << 0)
#define REG_W25_CMP (1 << 6)
#define REG_W25_WPS (1 << 2)
#define REG_W25_LB1 (1 << 3)
#define REG_W25_LB2 (1 << 4)
#define REG_W25_LB3 (1 << 5)

#define ADDR_W25_SEC1 0x10
#define ADDR_W25_SEC2 0x20
#define ADDR_W25_SEC3 0x30

struct winbond_spi_flash_params {
uint16_t id;
Expand Down Expand Up @@ -285,6 +295,165 @@ static int winbond_is_locked(struct spi_flash *flash)
return 0;
}

static int winbond_sec_read(struct spi_flash *flash, u32 offset, size_t len, void *buf)
{
int ret = 1;
u8 cmd[5];
u8 reg = (offset >> 8) & 0xFF;
u8 addr = offset & 0xFF;

if (reg != ADDR_W25_SEC1 && reg != ADDR_W25_SEC2 && reg != ADDR_W25_SEC3) {
spi_debug("SF: Wrong security register\n");
return 1;
}

cmd[0] = CMD_W25_RD_SEC;
cmd[1] = 0x0;
cmd[2] = reg;
cmd[3] = addr;
cmd[4] = 0x0; // dummy byte needed for this instruction

flash->spi->rw = SPI_READ_FLAG;
ret = spi_claim_bus(flash->spi);
if (ret) {
spi_debug("SF: Unable to claim SPI bus\n");
return ret;
}

ret = spi_flash_cmd_read(flash->spi, cmd, sizeof(cmd), buf, len);
if (ret) {
spi_debug("SF: Can't read sec register %d\n", reg >> 4);
goto out;
}

out:
spi_release_bus(flash->spi);
return ret;
}

static int winbond_sec_program(struct spi_flash *flash, u32 offset, size_t len, const void *buf)
{
int ret = 1;
u8 cmd[4];
u8 reg = (offset >> 8) & 0xFF;
u8 addr = offset & 0xFF;
u32 tmp_sect_size = flash->sector_size;

if (reg != ADDR_W25_SEC1 && reg != ADDR_W25_SEC2 && reg != ADDR_W25_SEC3) {
spi_debug("SF: Wrong security register\n");
return 1;
}

flash->sector_size = 1;
ret = spi_flash_cmd_erase(flash, CMD_W25_ER_SEC, offset & (0xFF << 8), 1);
flash->sector_size = tmp_sect_size;
if (ret) {
spi_debug("SF: Can't erase sec reg\n");
return ret;
}

flash->spi->rw = SPI_WRITE_FLAG;
ret = spi_claim_bus(flash->spi);
if (ret) {
spi_debug("SF: Unable to claim SPI bus\n");
return ret;
}

ret = spi_flash_cmd(flash->spi, CMD_W25_WREN, NULL, 0);
if (ret) {
spi_debug("SF: Enabling Write failed\n");
goto out;
}

cmd[0] = CMD_W25_WR_SEC;
cmd[1] = 0x0;
cmd[2] = reg;
cmd[3] = addr;
ret = spi_flash_cmd_write(flash->spi, cmd, sizeof(cmd), buf, len);
if (ret) {
spi_debug("SF: Can't write to sec register %d\n", reg >> 4);
goto out;
}

ret = spi_flash_cmd_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT);
if (ret) {
spi_debug("SF: Programming sec register failed - timeout\n");
goto out;
}

out:
spi_release_bus(flash->spi);
return ret;
}

static int winbond_sec_sts(struct spi_flash *flash)
{
u8 status = 0;
int ret;

ret = spi_flash_cmd(flash->spi, CMD_W25_RDSR2, &status, 1);
if (ret) {
return -1;
}

status = status & ((REG_W25_LB1 | REG_W25_LB2 | REG_W25_LB3) >> 3);

return status;
}

static int winbond_sec_lock(struct spi_flash *flash, u8 reg)
{
int ret;
u8 status = 0;
u8 cmd;

flash->spi->rw = SPI_WRITE_FLAG;
ret = spi_claim_bus(flash->spi);
if (ret) {
spi_debug("SF: Unable to claim SPI bus\n");
return ret;
}

ret = spi_flash_cmd(flash->spi, CMD_W25_RDSR2, &status, sizeof(status));
if (ret) {
spi_debug("SF: problem reading the status register\n");
goto out;
}

switch (reg) {
case 1:
status |= REG_W25_LB1;
break;
case 2:
status |= REG_W25_LB2;
break;
case 3:
status |= REG_W25_LB3;
break;
default:
spi_debug("SF: can't lock sec register, wrong index given\n");
goto out;
}

ret = spi_flash_cmd(flash->spi, CMD_W25_WREN, NULL, 0);
if (ret) {
spi_debug("SF: Enabling Write failed\n");
goto out;
}

cmd = CMD_W25_WRSR2;
ret = spi_flash_cmd_write(flash->spi, &cmd, sizeof(cmd),
&status, sizeof(status));
if (ret) {
spi_debug("SF: Status register write failed\n");
goto out;
}

out:
spi_release_bus(flash->spi);
return ret;
}

struct spi_flash *spi_flash_probe_winbond(struct spi_slave *spi, u8 *idcode)
{
const struct winbond_spi_flash_params *params;
Expand Down Expand Up @@ -322,6 +491,10 @@ struct spi_flash *spi_flash_probe_winbond(struct spi_slave *spi, u8 *idcode)
stm->flash.lock = winbond_lock;
stm->flash.unlock = winbond_unlock;
stm->flash.is_locked = winbond_is_locked;
stm->flash.sec_sts = winbond_sec_sts;
stm->flash.sec_read = winbond_sec_read;
stm->flash.sec_prog = winbond_sec_program;
stm->flash.sec_lock = winbond_sec_lock;
#if CONFIG_SPI_FLASH_NO_FAST_READ
stm->flash.read = spi_flash_cmd_read_slow;
#else
Expand Down
123 changes: 123 additions & 0 deletions utils/flash_access.c
@@ -0,0 +1,123 @@
#define CONFIG_SPI_FLASH_NO_FAST_READ

#include <spi/spi_flash.h>
#include <flash_access.h>

#define FLASH_SIZE_CHUNK 0x1000 //4k

static struct spi_flash *flash_device;

/*******************************************************************************/
inline int init_flash(void)
{
flash_device = spi_flash_probe(0, 0, 0, 0);

if (!flash_device)
return -1;

return 0;
}

/*******************************************************************************/
inline int is_flash_locked(void)
{
return spi_flash_is_locked(flash_device);
}

/*******************************************************************************/
inline int lock_flash(void)
{
return spi_flash_lock(flash_device);
}

/*******************************************************************************/
inline int unlock_flash(void)
{
return spi_flash_unlock(flash_device);
}

inline int read_sec_status(void)
{
return spi_flash_sec_sts(flash_device);
}

inline int read_sec(u8 reg, u8 addr, void *buf, size_t len)
{
return spi_flash_sec_read(flash_device, sec_addr(reg, addr), len, buf);
}

inline int prog_sec(u8 reg, u8 addr, const void *buf, size_t len)
{
return spi_flash_sec_prog(flash_device, sec_addr(reg, addr), len, buf);
}

inline int lock_sec(u8 reg)
{
return spi_flash_sec_lock(flash_device, reg);
}

/*******************************************************************************/
void save_flash(int flash_address, char buffer[MAX_DEVICES][MAX_LENGTH],
u8 max_lines, u8 spi_wp_toggle) {
int i = 0;
int k = 0;
int j, ret;
char cbfs_formatted_list[MAX_DEVICES * MAX_LENGTH];
u32 nvram_pos;

// compact the table into the expected packed list
for (j = 0; j < max_lines; j++) {
for (k = 0; k < MAX_LENGTH; k++) {
cbfs_formatted_list[i++] = buffer[j][k];
if (buffer[j][k] == NEWLINE )
break;
}
}
cbfs_formatted_list[i++] = NUL;

// try to unlock the flash if it is locked
if (spi_flash_is_locked(flash_device)) {
spi_flash_unlock(flash_device);
if (spi_flash_is_locked(flash_device)) {
printf("Flash is write protected. Exiting...\n");
return;
}
}

printf("Erasing Flash size 0x%x @ 0x%x\n",
FLASH_SIZE_CHUNK, flash_address);
ret = spi_flash_erase(flash_device, flash_address, FLASH_SIZE_CHUNK);
if (ret) {
printf("Erase failed, ret: %d\n", ret);
return;
}

printf("Writing %d bytes @ 0x%x\n", i, flash_address);
// write first 512 bytes
for (nvram_pos = 0; nvram_pos < (i & 0xFFFC); nvram_pos += 4) {
ret = spi_flash_write(flash_device, nvram_pos + flash_address,
sizeof(u32),
(u32 *)(cbfs_formatted_list + nvram_pos));
if (ret) {
printf("Write failed, ret: %d\n", ret);
return;
}
}
// write remaining filler characters in one run
ret = spi_flash_write(flash_device, nvram_pos + flash_address,
sizeof(i % 4),
(u32 *)(cbfs_formatted_list + nvram_pos));
if (ret) {
printf("Write failed, ret: %d\n", ret);
return;
}

if (spi_wp_toggle) {
printf("Enabling flash write protect...\n");
spi_flash_lock(flash_device);
}

spi_wp_toggle = spi_flash_is_locked(flash_device);

printf("Done\n");
}
129 changes: 129 additions & 0 deletions utils/sec_reg_menu.c
@@ -0,0 +1,129 @@
#include <libpayload.h>
#include <curses.h>
#include <flash_access.h>
#include <sec_reg_menu.h>

#define SERIAL_REG_NO 1
#define SERIAL_OFFSET 0
#define MAX_SERIAL_LEN 10

/* Locking functionality n/a due to not working hardware lock procedure */

static void print_reg_sec_menu(void) {
printf("\n\n--- Security registers menu ---\n\n");
printf(" r - read serial from security register 1\n");
printf(" w serial - write serial to security register 1\n");
printf(" s - get security registers OTP status\n");
/* printf(" l reg - lock security register reg\n"); */
printf(" q - exit menu\n");
printf("\n");
}

static void cmd_read_serial(void)
{
u8 reg = SERIAL_REG_NO;
u8 offset = SERIAL_OFFSET;
u8 buf[MAX_SERIAL_LEN] = { 0 };
int ret;

ret = read_sec(reg, offset, buf, sizeof(buf));
if (ret) {
printf("can't read register\n");
return;
}

printf("serial: %s\n", buf);
}

static void cmd_write_serial(char *cmd)
{
u8 reg = SERIAL_REG_NO;
u8 offset = SERIAL_OFFSET;
u8 buf[MAX_SERIAL_LEN] = { 0 };
int ret;

strncpy((char *)buf, cmd+2, sizeof(buf)-1);

ret = prog_sec(reg, offset, buf, sizeof(buf));
if (ret) {
printf("can't write to register\n");
return;
}

printf("serial written\n");
}

static void cmd_read_sec_sts(void)
{
int status = read_sec_status();

printf("Security registers status:\n");
printf(" reg 1 = %s\n", (status & 0x1) ? "locked" : "writeable");
printf(" reg 2 = %s\n", (status & 0x2) ? "locked" : "writeable");
printf(" reg 3 = %s\n", (status & 0x4) ? "locked" : "writeable");
}

static void cmd_lock_sec(char *cmd)
{
u8 reg;
int ret;

reg = strtoul(cmd+2, NULL, 10);

if (reg < 1 || reg > 3) {
printf("Wrong register number!\n");
return;
}

printf("Warning! This will permamently lock the security register %d."
" Are you sure? (yes/no)\n", reg);

cmd[0] = '\0';
cmd = readline("> ");

if (strcmp(cmd, "yes") != 0) {
return;
}

ret = lock_sec(reg);
printf("%s\n", ret ? "Can't lock!" : "Locked!");

return;
}

void handle_reg_sec_menu(void) {
bool end = FALSE;
char *command;

print_reg_sec_menu();

while(1) {
command = readline("> ");

switch(command[0]) {
case 'r':
cmd_read_serial();
break;
case 'w':
cmd_write_serial(command);
break;
case 's':
cmd_read_sec_sts();
break;
case 'l':
cmd_lock_sec(command);
break;
case 'q':
end = TRUE;
break;
default:
printf("wrong command: '%s'\n", command);
break;
}

command[0] = '\0';

if (end)
break;
}
}
2 changes: 1 addition & 1 deletion version.h → version.h.in
Expand Up @@ -18,6 +18,6 @@
#ifndef _VERSION_H_
#define _VERSION_H_

#define SORTBOOTORDER_VER "v4.5.7"
#define SORTBOOTORDER_VER @version@

#endif /* _VERSION_H_ */