[Skiboot] [PATCH 2/2] libflash/file: add file abstraction for libflash
Daniel Axtens
dja at axtens.net
Thu Apr 2 08:48:35 AEDT 2015
Hi Cyril,
Looks good. Stewart, I assume you're dealing with the appropriate
copyright boilerplate at the top of each new file?
Reviewed-by: Daniel Axtens <dja at axtens.net>
Regards,
Daniel
On Wed, 2015-04-01 at 16:51 +1100, Cyril Bur wrote:
> The functionality provided by libflash and libffs are useful and it would be
> good to use them on dumps of flash or even access flash from userland through
> MTD devices which are presented as files.
>
> Signed-off-by: Cyril Bur <cyril.bur at au1.ibm.com>
> ---
> libflash/file_flash.c | 223 +++++++++++++++++++++++++++++++++++++++++++++++
> libflash/file_flash.h | 11 +++
> libflash/libflash-priv.h | 2 +
> libflash/libflash.c | 1 +
> 4 files changed, 237 insertions(+)
> create mode 100644 libflash/file_flash.c
> create mode 100644 libflash/file_flash.h
>
> diff --git a/libflash/file_flash.c b/libflash/file_flash.c
> new file mode 100644
> index 0000000..0fe46c4
> --- /dev/null
> +++ b/libflash/file_flash.c
> @@ -0,0 +1,223 @@
> +#include <unistd.h>
> +#include <sys/types.h>
> +#include <sys/stat.h>
> +#include <stdbool.h>
> +#include <stdlib.h>
> +#include <sys/ioctl.h>
> +#include <sys/mman.h>
> +#include <string.h>
> +
> +#include <mtd/mtd-abi.h>
> +
> +#include "file_flash.h"
> +
> +struct file_flash_priv {
> + int fd;
> +};
> +
> +/*
> + * Unfortunately not all file descriptors are created equal...
> + * Here we check to see if the file descriptor is to an MTD device, in which
> + * case we have to get the size of it differently.
> + */
> +int file_setup(struct spi_flash_ctrl *ctrl, uint32_t *tsize)
> +{
> + struct mtd_info_user mtd_info;
> + struct file_flash_priv *file_flash_data;
> + struct stat sbuf;
> +
> + if (!ctrl || !ctrl->priv)
> + return -1;
> +
> + file_flash_data = (struct file_flash_priv *)ctrl->priv;
> +
> + if (fstat(file_flash_data->fd, &sbuf) == -1)
> + return -1;
> +
> + if (S_ISCHR(sbuf.st_mode)) {
> + if (ioctl(file_flash_data->fd, MEMGETINFO, &mtd_info) == -1)
> + return -1;
> +
> + ctrl->finfo->size = mtd_info.size;
> +
> + } else if (S_ISREG(sbuf.st_mode)) {
> + ctrl->finfo->size = sbuf.st_size;
> +
> + } else {
> + /* Not going to be able to work with anything else */
> + return -1;
> + }
> +
> + if (tsize)
> + *tsize = ctrl->finfo->size;
> +
> + return 0;
> +}
> +
> +int file_set4b(struct spi_flash_ctrl *ctrl, bool enable)
> +{
> + /* Always report success no matter what, this isn't relevent for files */
> + return 0;
> +}
> +
> +int file_chipid(struct spi_flash_ctrl *ctrl, uint8_t *id_buf,
> + uint32_t *id_size)
> +{
> + if (!ctrl || !ctrl->priv || !id_size || *id_size < 3)
> + return -1;
> +
> + id_buf[0] = 'M';
> + id_buf[1] = 'T';
> + id_buf[2] = 'D';
> +
> + *id_size = 3;
> + return 0;
> +}
> +
> +int file_read(struct spi_flash_ctrl *ctrl, uint32_t addr, void *buf,
> + uint32_t size)
> +{
> + int rc;
> + struct file_flash_priv *file_flash_data;
> +
> + if (!ctrl || !ctrl->priv)
> + return -1;
> +
> + file_flash_data = (struct file_flash_priv *)ctrl->priv;
> +
> + rc = lseek(file_flash_data->fd, addr, SEEK_SET);
> + if ((off_t )rc == (off_t )-1)
> + return -1;
> +
> + rc = read(file_flash_data->fd, buf, size);
> + if (rc == -1)
> + return -1;
> + /* TODO Perhaps deal with short reads */
> +
> + return 0;
> +}
> +
> +int file_write(struct spi_flash_ctrl *ctrl, uint32_t addr,
> + const void *buf, uint32_t size)
> +{
> + size_t rc;
> + struct file_flash_priv *file_flash_data;
> +
> + if (!ctrl || !ctrl->priv)
> + return -1;
> +
> + file_flash_data = (struct file_flash_priv *)ctrl->priv;
> +
> + rc = lseek(file_flash_data->fd, addr, SEEK_SET);
> + if ((off_t )rc == (off_t )-1)
> + return -1;
> +
> + rc = write(file_flash_data->fd, buf, size);
> + if (rc != size)
> + return -1;
> + /* TODO Perhaps deal with short writes */
> +
> + return 0;
> +}
> +
> +int file_erase(struct spi_flash_ctrl *ctrl, uint32_t addr,
> + uint32_t size)
> +{
> + struct stat sbuf;
> + struct file_flash_priv *file_flash_data;
> + uint32_t esize;
> +
> + if (!ctrl || !ctrl->priv)
> + return -1;
> +
> + /*
> + * Input params addr = 0 and size = 0xffffffff mean libflash is telling us
> + * to erase the entire thing.
> + */
> + file_flash_data = (struct file_flash_priv *)ctrl->priv;
> +
> + esize = (size == 0xffffffff && addr == 0) ? ctrl->finfo->size : size;
> + if (esize > ctrl->finfo->size)
> + return -1;
> +
> + if (fstat(file_flash_data->fd, &sbuf) == -1)
> + return -1;
> +
> + /*
> + * If we're dealing with an MTD device then its possible that there is a
> + * real flash device somewhere (as opposed to a regular file where the
> + * assumption is that there is not).
> + * In that case lets try to represerve that idea and use the erase ioctl.
> + */
> + if (S_ISCHR(sbuf.st_mode)) {
> + struct erase_info_user erase_info = {
> + .start = addr,
> + .length = esize
> + };
> +
> + if (ioctl(file_flash_data->fd, MEMERASE, erase_info) == -1)
> + return -1;
> +
> + } else if (S_ISREG(sbuf.st_mode)) {
> + /* Regular file, erase is just write zeros */
> + char *section;
> +
> + section = mmap(NULL, sbuf.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, file_flash_data->fd, 0);
> + if (section == (void *)-1)
> + return -1;
> + bzero(section + addr, esize);
> + if (munmap(section, sbuf.st_size) == -1)
> + return -1;
> +
> + } else {
> + return -1;
> + }
> +
> + return 0;
> +}
> +
> +/* To be called by tools wanting to use the libflash/libffs APIs */
> +struct spi_flash_ctrl *build_flash_ctrl(int fd)
> +{
> + struct spi_flash_ctrl *ctrl;
> + struct file_flash_priv *data;
> +
> + ctrl = calloc(1, sizeof(struct spi_flash_ctrl));
> + if (!ctrl)
> + return NULL;
> +
> + data = calloc(1, sizeof(struct file_flash_priv));
> + if (!data) {
> + free(ctrl);
> + return NULL;
> + }
> +
> + data->fd = fd;
> +
> + /*
> + * Don't implement the low level interfaces because we aren't flash. This
> + * will also force libflash to only call us with the high level interface.
> + */
> + ctrl->cmd_rd = NULL;
> + ctrl->cmd_wr = NULL;
> +
> + /*
> + * Do implement everything else.
> + */
> + ctrl->erase = &file_erase;
> + ctrl->write = &file_write;
> + ctrl->read = &file_read;
> + ctrl->chip_id = &file_chipid;
> + ctrl->set_4b = &file_set4b;
> + ctrl->setup = &file_setup;
> +
> + ctrl->priv = data;
> +
> + return ctrl;
> +}
> +
> +void free_flash_ctrl(struct spi_flash_ctrl *flash_ctrl)
> +{
> + free(flash_ctrl->priv);
> + free(flash_ctrl);
> +}
> diff --git a/libflash/file_flash.h b/libflash/file_flash.h
> new file mode 100644
> index 0000000..dc6b5d7
> --- /dev/null
> +++ b/libflash/file_flash.h
> @@ -0,0 +1,11 @@
> +#ifndef __FILE_FLASH_H
> +#define __FILE_FLASH_H
> +
> +#include <libflash/libflash.h>
> +#include <libflash/libflash-priv.h>
> +
> +struct spi_flash_ctrl *build_flash_ctrl(int fd);
> +
> +void free_flash_ctrl(struct spi_flash_ctrl *flash_ctrl);
> +
> +#endif /* __FILE_FLASH_H */
> diff --git a/libflash/libflash-priv.h b/libflash/libflash-priv.h
> index ba6da66..e59d829 100644
> --- a/libflash/libflash-priv.h
> +++ b/libflash/libflash-priv.h
> @@ -223,6 +223,8 @@ struct spi_flash_ctrl {
> * been probed
> */
> struct flash_info *finfo;
> +
> + void *priv;
> };
>
> extern int fl_wren(struct spi_flash_ctrl *ct);
> diff --git a/libflash/libflash.c b/libflash/libflash.c
> index bb6f097..e43be4f 100644
> --- a/libflash/libflash.c
> +++ b/libflash/libflash.c
> @@ -32,6 +32,7 @@ static const struct flash_info flash_info[] = {
> { 0x20ba20, 0x04000000, FL_ERASE_4K | FL_ERASE_64K | FL_CAN_4B |
> FL_ERASE_BULK | FL_MICRON_BUGS,
> "Micron N25Qx512Ax" },
> + { 0x4d5444, 0x02000000, FL_ERASE_ALL | FL_CAN_4B, "File Abstraction"},
> { 0x55aa55, 0x00100000, FL_ERASE_ALL | FL_CAN_4B, "TEST_FLASH" },
> { 0xaa55aa, 0x02000000, FL_ERASE_ALL | FL_CAN_4B, "EMULATED_FLASH"},
> };
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 860 bytes
Desc: This is a digitally signed message part
URL: <http://lists.ozlabs.org/pipermail/skiboot/attachments/20150402/4da87ae8/attachment-0001.sig>
More information about the Skiboot
mailing list