diff options
author | Tom Wai-Hong Tam <waihong@chromium.org> | 2011-06-22 04:33:29 +0800 |
---|---|---|
committer | Simon Glass <sjg@chromium.org> | 2011-08-29 10:39:38 -0700 |
commit | 0aebc8a1b07658f00abcdbc6c1a2ee7e85090f7b (patch) | |
tree | 47849f3b0199126e1ecbaf7c1133a7d0a3106dbc | |
parent | 6cf6b0d7725ba0beb4e86e93adfebc5d26017335 (diff) |
CHROMIUM: Port firmware_storage related APIs from lib/chromeos to lib/vboot.
Directly copy firmware_storage related files from /lib/chromeos to /lib/vboot
and the include file from /include/chromeos to /include/vboot and change
the interfaces to proper vboot_wrapper ones.
Related tests will go to another CLs.
BUG=chromium-os:16543
TEST=compile without error
Change-Id: I8f101149fdc6e5d17d8c63b930b239746f39a376
Reviewed-on: http://gerrit.chromium.org/gerrit/2938
Reviewed-by: Tom Wai-Hong Tam <waihong@chromium.org>
Tested-by: Tom Wai-Hong Tam <waihong@chromium.org>
-rw-r--r-- | Makefile | 1 | ||||
-rw-r--r-- | include/vboot/firmware_storage.h | 64 | ||||
-rw-r--r-- | lib/vboot/Makefile | 31 | ||||
-rw-r--r-- | lib/vboot/firmware_storage.c | 87 | ||||
-rw-r--r-- | lib/vboot/firmware_storage_spi.c | 236 |
5 files changed, 419 insertions, 0 deletions
@@ -216,6 +216,7 @@ LIBS += lib/lzo/liblzo.o LIBS += lib/zlib/libz.o LIBS += lib/chromeos/libchromeos.a LIBS += lib/vbexport/libvbexport.a +LIBS += lib/vboot/libvboot.a LIBS += board/$(VENDOR)/chromeos/libchromeos_hardware_interface.a LIBS += $(shell if [ -f board/$(VENDOR)/common/Makefile ]; then echo \ "board/$(VENDOR)/common/lib$(VENDOR).o"; fi) diff --git a/include/vboot/firmware_storage.h b/include/vboot/firmware_storage.h new file mode 100644 index 0000000000..284853148c --- /dev/null +++ b/include/vboot/firmware_storage.h @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2011 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + */ + +/* Interface for access various storage device */ + +#ifndef VBOOT_FIRMWARE_STORAGE_H_ +#define VBOOT_FIRMWARE_STORAGE_H_ + +#include <linux/types.h> + +enum whence_t { SEEK_SET, SEEK_CUR, SEEK_END }; + +/* + * The semantic (argument and return value) is similar with system + * call lseek(2), read(2) and write(2), except that file descriptor + * is replaced by [context]. + */ +typedef struct { + off_t (*seek)(void *context, off_t offset, enum whence_t whence); + ssize_t (*read)(void *context, void *buf, size_t count); + ssize_t (*write)(void *context, const void *buf, size_t count); + int (*close)(void *context); + + /** + * This locks the storage device, i.e., enables write protect. + * + * @return 0 if it succeeds, non-zero if it fails + */ + int (*lock_device)(void *context); + + void *context; +} firmware_storage_t; + +/** + * This opens SPI flash device + * + * @param file - the opened SPI flash device + * @return 0 if it succeeds, non-zero if it fails + */ +int firmware_storage_open_spi(firmware_storage_t *file); + +/** + * These read or write [count] bytes starting from [offset] of storage into or + * from the [buf]. These are really wrappers of file->{seek,read,write}. + * + * @param file - storage device you access + * @param offset - where on the device you access + * @param count - the amount of data in byte you access + * @param buf - the data that these functions read from or write to + * @return 0 if it succeeds, non-zero if it fails + */ +int firmware_storage_read(firmware_storage_t *file, + const off_t offset, const size_t count, void *buf); +int firmware_storage_write(firmware_storage_t *file, + const off_t offset, const size_t count, const void *buf); + +#endif /* CHROMEOS_FIRMWARE_STORAGE_H_ */ diff --git a/lib/vboot/Makefile b/lib/vboot/Makefile new file mode 100644 index 0000000000..f557c3bcb0 --- /dev/null +++ b/lib/vboot/Makefile @@ -0,0 +1,31 @@ +# +# Copyright (c) 2011 The Chromium OS Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. +# +# Alternatively, this software may be distributed under the terms of the +# GNU General Public License ("GPL") version 2 as published by the Free +# Software Foundation. +# + +include $(TOPDIR)/config.mk + +LIB = $(obj)libvboot.a + +COBJS-$(CONFIG_VBOOT_WRAPPER) += firmware_storage.o +COBJS-$(CONFIG_VBOOT_WRAPPER) += firmware_storage_spi.o + +COBJS := $(COBJS-y) +OBJS := $(addprefix $(obj),$(COBJS)) + +$(LIB): $(obj).depend $(OBJS) + $(AR) $(ARFLAGS) $@ $(OBJS) + +######################################################################### + +# defines $(obj).depend target +include $(SRCTREE)/rules.mk + +sinclude $(obj).depend + +######################################################################### diff --git a/lib/vboot/firmware_storage.c b/lib/vboot/firmware_storage.c new file mode 100644 index 0000000000..a41cfe0ce4 --- /dev/null +++ b/lib/vboot/firmware_storage.c @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2011 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + */ + +#include <common.h> +#include <vboot/firmware_storage.h> + +/* Import the header files from vboot_reference. */ +#include <vboot_api.h> + +#define PREFIX "firmware_storage: " + +int firmware_storage_read(firmware_storage_t *file, + const off_t offset, const size_t count, void *buf) +{ + ssize_t size; + size_t remain; + + VbExDebug(PREFIX "read\n"); + + if (file->seek(file->context, offset, SEEK_SET) < 0) { + VbExDebug(PREFIX "seek to address 0x%08lx fail\n", offset); + return -1; + } + + size = 0; + remain = count; + while (remain > 0 && + (size = file->read(file->context, buf, remain)) > 0) { + remain -= size; + buf += size; + } + + if (size < 0) { + VbExDebug(PREFIX "an error occur when read firmware: %u\n", + size); + return -1; + } + + if (remain > 0) { + VbExDebug(PREFIX "cannot read all data: %u\n", remain); + return -1; + } + + return 0; +} + +int firmware_storage_write(firmware_storage_t *file, + const off_t offset, const size_t count, const void *buf) +{ + ssize_t size; + size_t remain; + + VbExDebug(PREFIX "write\n"); + + if (file->seek(file->context, offset, SEEK_SET) < 0) { + VbExDebug(PREFIX "seek to address 0x%08lx fail\n", offset); + return -1; + } + + size = 0; + remain = count; + while (remain > 0 && + (size = file->write(file->context, buf, remain)) > 0) { + remain -= size; + buf += size; + } + + if (size < 0) { + VbExDebug(PREFIX "an error occur when write firmware: %d\n", + size); + return -1; + } + + if (remain > 0) { + VbExDebug(PREFIX "cannot write all data: %u\n", remain); + return -1; + } + + return 0; +} diff --git a/lib/vboot/firmware_storage_spi.c b/lib/vboot/firmware_storage_spi.c new file mode 100644 index 0000000000..53ac56982d --- /dev/null +++ b/lib/vboot/firmware_storage_spi.c @@ -0,0 +1,236 @@ +/* + * Copyright (c) 2011 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + */ + +/* Implementation of firmware storage access interface for SPI */ + +#include <common.h> +#include <spi_flash.h> +#include <vboot/firmware_storage.h> + +/* Import the header files from vboot_reference. */ +#include <vboot_api.h> + +#define PREFIX "firmware_storage_spi: " + +#ifndef CONFIG_SF_DEFAULT_SPEED +# define CONFIG_SF_DEFAULT_SPEED 1000000 +#endif +#ifndef CONFIG_SF_DEFAULT_MODE +# define CONFIG_SF_DEFAULT_MODE SPI_MODE_3 +#endif + +struct context_t { + struct spi_flash *flash; + off_t offset; +}; + +static off_t seek_spi(void *context, off_t offset, enum whence_t whence) +{ + struct context_t *cxt = context; + off_t next_offset; + + if (whence == SEEK_SET) + next_offset = offset; + else if (whence == SEEK_CUR) + next_offset = cxt->offset + offset; + else if (whence == SEEK_END) + next_offset = cxt->flash->size + offset; + else { + VbExDebug(PREFIX "unknown whence value: %d\n", whence); + return -1; + } + + if (next_offset < 0) { + VbExDebug(PREFIX "negative offset: %d\n", next_offset); + return -1; + } + + if (next_offset > cxt->flash->size) { + VbExDebug(PREFIX "offset overflow: 0x%08x > 0x%08x\n", + next_offset, cxt->flash->size); + return -1; + } + + cxt->offset = next_offset; + return cxt->offset; +} + +/* + * Check the right-exclusive range [offset:offset+*count_ptr), and adjust + * value pointed by <count_ptr> to form a valid range when needed. + * + * Return 0 if it is possible to form a valid range. and non-zero if not. + */ +static int border_check(struct spi_flash *flash, off_t offset, + size_t *count_ptr) +{ + if (offset >= flash->size) { + VbExDebug(PREFIX "at EOF\n"); + return -1; + } + + if (offset + *count_ptr > flash->size) + *count_ptr = flash->size - offset; + + return 0; +} + +static ssize_t read_spi(void *context, void *buf, size_t count) +{ + struct context_t *cxt = context; + + if (border_check(cxt->flash, cxt->offset, &count)) + return -1; + + if (cxt->flash->read(cxt->flash, cxt->offset, count, buf)) { + VbExDebug(PREFIX "SPI read fail\n"); + return -1; + } + + cxt->offset += count; + return count; +} + +/* + * FIXME: It is a reasonable assumption that sector size = 4096 bytes. + * Nevertheless, comparing to coding this magic number here, there should be a + * better way (maybe rewrite driver interface?) to expose this parameter from + * eeprom driver. + */ +#define SECTOR_SIZE 0x1000 + +/* + * Align the right-exclusive range [*offset_ptr:*offset_ptr+*length_ptr) with + * SECTOR_SIZE. + * After alignment adjustment, both offset and length will be multiple of + * SECTOR_SIZE, and will be larger than or equal to the original range. + */ +static void align_to_sector(size_t *offset_ptr, size_t *length_ptr) +{ + VbExDebug(PREFIX "before adjustment\n"); + VbExDebug(PREFIX "offset: 0x%x\n", *offset_ptr); + VbExDebug(PREFIX "length: 0x%x\n", *length_ptr); + + /* Adjust if offset is not multiple of SECTOR_SIZE */ + if (*offset_ptr & (SECTOR_SIZE - 1ul)) { + *offset_ptr &= ~(SECTOR_SIZE - 1ul); + } + + /* Adjust if length is not multiple of SECTOR_SIZE */ + if (*length_ptr & (SECTOR_SIZE - 1ul)) { + *length_ptr &= ~(SECTOR_SIZE - 1ul); + *length_ptr += SECTOR_SIZE; + } + + VbExDebug(PREFIX "after adjustment\n"); + VbExDebug(PREFIX "offset: 0x%x\n", *offset_ptr); + VbExDebug(PREFIX "length: 0x%x\n", *length_ptr); +} + +static ssize_t write_spi(void *context, const void *buf, size_t count) +{ + struct context_t *cxt = context; + struct spi_flash *flash = cxt->flash; + uint8_t static_buf[SECTOR_SIZE]; + uint8_t *backup_buf; + ssize_t ret = -1; + size_t offset, length, tmp; + int status; + + /* We will erase <length> bytes starting from <offset> */ + offset = cxt->offset; + length = count; + align_to_sector(&offset, &length); + + tmp = length; + if (border_check(flash, offset, &tmp)) + return -1; + if (tmp != length) { + VbExDebug(PREFIX "cannot erase range [%08x:%08x]: %08x\n", + offset, offset + length, offset + tmp); + return -1; + } + + backup_buf = length > sizeof(static_buf) ? VbExMalloc(length) + : static_buf; + + if ((status = flash->read(flash, offset, length, backup_buf))) { + VbExDebug(PREFIX "cannot backup data: %d\n", status); + goto EXIT; + } + + if ((status = flash->erase(flash, offset, length))) { + VbExDebug(PREFIX "SPI erase fail: %d\n", status); + goto EXIT; + } + + VbExDebug(PREFIX "cxt->offset: 0x%08x\n", cxt->offset); + VbExDebug(PREFIX "offset: 0x%08x\n", offset); + + /* combine data we want to write and backup data */ + memcpy(backup_buf + (cxt->offset - offset), buf, count); + + if (flash->write(flash, offset, length, backup_buf)) { + VbExDebug(PREFIX "SPI write fail\n"); + goto EXIT; + } + + cxt->offset += count; + ret = count; + +EXIT: + if (backup_buf != static_buf) + VbExFree(backup_buf); + + return ret; +} + +static int close_spi(void *context) +{ + struct context_t *cxt = context; + + spi_flash_free(cxt->flash); + VbExFree(cxt); + + return 0; +} + +static int lock_spi(void *context) +{ + /* TODO Implement lock device */ + return 0; +} + +int firmware_storage_open_spi(firmware_storage_t *file) +{ + const unsigned int bus = 0; + const unsigned int cs = 0; + const unsigned int max_hz = CONFIG_SF_DEFAULT_SPEED; + const unsigned int spi_mode = CONFIG_SF_DEFAULT_MODE; + struct context_t *cxt; + + cxt = VbExMalloc(sizeof(*cxt)); + cxt->offset = 0; + cxt->flash = spi_flash_probe(bus, cs, max_hz, spi_mode); + if (!cxt->flash) { + VbExDebug(PREFIX "fail to init SPI flash at %u:%u\n", bus, cs); + VbExFree(cxt); + return -1; + } + + file->seek = seek_spi; + file->read = read_spi; + file->write = write_spi; + file->close = close_spi; + file->lock_device = lock_spi; + file->context = (void*) cxt; + + return 0; +} |