blob: fe55a017a2d35d13bb4a3f29e9593967e7abfd00 [file] [log] [blame]
/*
* Copyright 2012, Google Inc.
* All rights reserved.
*
* 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 Google Inc. 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.
*
* flashrom.c: flashrom wrappers
*/
#include <ctype.h>
#include <fcntl.h>
#include <inttypes.h>
#include <limits.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "mosys/alloc.h"
#include "mosys/big_lock.h"
#include "mosys/log.h"
#include "lib/flashrom.h"
#include "lib/string_builder.h"
/* returns pointer to string containing flashrom path if successful,
returns NULL otherwise */
static const char *flashrom_path(void)
{
FILE *fp;
static char path[PATH_MAX];
int c, i = 0;
if ((fp = popen("which flashrom 2>/dev/null", "r")) == NULL) {
lprintf(LOG_DEBUG, "Cannot find flashrom\n");
return NULL;
}
for (i = 0; i < PATH_MAX; i++) {
c = fgetc(fp);
if (c == EOF || c == '\n') {
path[i] = '\0';
break;
}
path[i] = c;
}
pclose(fp);
/* no characters were read from stream, or buffer overrun */
if ((c == EOF && i == 0) || (c != EOF && i == PATH_MAX))
return NULL;
return path;
}
static int do_flashrom(const char *cmd)
{
int rc = 0;
#if defined(CONFIG_USE_IPC_LOCK)
int re_acquire_lock = 1;
#endif
#if defined(CONFIG_USE_IPC_LOCK)
if (mosys_release_big_lock() < 0)
re_acquire_lock = 0;
#endif
if (system(cmd) != 0) {
lprintf(LOG_DEBUG, "%s: Failed to run %s\n", __func__, cmd);
rc = -1;
}
#if defined(CONFIG_USE_IPC_LOCK)
/* try to get lock */
if (re_acquire_lock && (mosys_acquire_big_lock(50000) < 0)) {
lprintf(LOG_DEBUG, "%s: could not re-acquire lock\n", __func__);
rc = -1;
}
#endif
return rc;
}
/* TODO: add arbitrary range support */
int flashrom_read(uint8_t *buf, size_t size,
enum target_bus target, const char *region)
{
int fd, rc = -1;
struct string_builder *sb = new_string_builder();
char *flashrom_cmd;
char filename[] = "/tmp/flashrom_XXXXXX";
struct stat s;
const char *path;
if ((path = flashrom_path()) == NULL)
goto flashrom_read_exit_1;
string_builder_sprintf(sb, path);
switch(target) {
case INTERNAL_BUS_SPI:
string_builder_strcat(sb, " -p internal:bus=spi");
break;
case INTERNAL_BUS_I2C:
string_builder_strcat(sb, " -p internal:bus=i2c");
break;
case INTERNAL_BUS_LPC:
string_builder_strcat(sb, " -p internal:bus=lpc");
break;
default:
lprintf(LOG_DEBUG, "Unsupported target: %d\n", target);
goto flashrom_read_exit_1;
}
if (!mkstemp(filename)) {
lperror(LOG_DEBUG, "Unable to make temporary file for flashrom");
goto flashrom_read_exit_1;
}
if (region) {
string_builder_strcat(sb, " -i ");
string_builder_strcat(sb, region);
}
string_builder_strcat(sb, " -r ");
string_builder_strcat(sb, filename);
string_builder_strcat(sb, " >/dev/null 2>&1");
flashrom_cmd = mosys_strdup(string_builder_get_string(sb));
lprintf(LOG_DEBUG, "Calling \"%s\"\n", flashrom_cmd);
if (do_flashrom(flashrom_cmd) < 0)
goto flashrom_read_exit_2;
fd = open(filename, O_RDONLY);
if (fstat(fd, &s) < 0) {
lprintf(LOG_DEBUG, "%s: Cannot stat %s\n", __func__, filename);
goto flashrom_read_exit_2;
}
if (s.st_size != size) {
lprintf(LOG_DEBUG, "%s: Size of image: %lu, expected %lu",
__func__, s.st_size, size);
goto flashrom_read_exit_2;
}
if (read(fd, buf, size) != size) {
lperror(LOG_DEBUG, "%s: Unable to read image");
goto flashrom_read_exit_2;
}
rc = 0;
flashrom_read_exit_2:
free(flashrom_cmd);
flashrom_read_exit_1:
unlink(filename);
free_string_builder(sb);
return rc;
}
int flashrom_read_by_name(uint8_t **buf,
enum target_bus target, const char *region)
{
int fd, rc = -1;
struct string_builder *sb = new_string_builder();
char *flashrom_cmd;
char filename[] = "/tmp/flashrom_XXXXXX";
struct stat s;
const char *path;
if (!region)
goto flashrom_read_exit_0;
if ((path = flashrom_path()) == NULL)
goto flashrom_read_exit_0;
string_builder_sprintf(sb, path);
switch(target) {
case INTERNAL_BUS_SPI:
string_builder_strcat(sb, " -p internal:bus=spi");
break;
case INTERNAL_BUS_I2C:
string_builder_strcat(sb, " -p internal:bus=i2c");
break;
case INTERNAL_BUS_LPC:
string_builder_strcat(sb, " -p internal:bus=lpc");
break;
default:
lprintf(LOG_DEBUG, "Unsupported target: %d\n", target);
goto flashrom_read_exit_1;
}
if (!mkstemp(filename)) {
lperror(LOG_DEBUG, "Unable to make temporary file for flashrom");
goto flashrom_read_exit_1;
}
string_builder_strcat(sb, " -i ");
string_builder_strcat(sb, region);
string_builder_strcat(sb, ":");
string_builder_strcat(sb, filename);
string_builder_strcat(sb, " -r /dev/null");
string_builder_strcat(sb, " >/dev/null 2>&1");
flashrom_cmd = mosys_strdup(string_builder_get_string(sb));
lprintf(LOG_DEBUG, "Calling \"%s\"\n", flashrom_cmd);
if (do_flashrom(flashrom_cmd) < 0) {
lprintf(LOG_DEBUG, "Unable to read region \"%s\"\n", region);
goto flashrom_read_exit_2;
}
fd = open(filename, O_RDONLY);
if (fstat(fd, &s) < 0) {
lprintf(LOG_DEBUG, "%s: Cannot stat %s\n", __func__, filename);
goto flashrom_read_exit_2;
}
*buf = mosys_malloc(s.st_size);
if (read(fd, *buf, s.st_size) < 0) {
lperror(LOG_DEBUG, "%s: Unable to read image");
free(*buf);
goto flashrom_read_exit_2;
}
rc = s.st_size;
flashrom_read_exit_2:
free(flashrom_cmd);
flashrom_read_exit_1:
unlink(filename);
flashrom_read_exit_0:
free_string_builder(sb);
return rc;
}