Nico Huber has uploaded this change for review. ( https://review.coreboot.org/c/flashrom/+/33372
Change subject: [WIP] Add data source/sink abstraction `flashrom_data` ......................................................................
[WIP] Add data source/sink abstraction `flashrom_data`
A first sketch. API will change when I see how it works out.
Change-Id: Ie550914eca2cffb4c14cfdd76289334a2f0636b9 Signed-off-by: Nico Huber nico.h@gmx.de --- M Makefile M flash.h A flashrom_data.c A flashrom_data_file.c M libflashrom.h A libflashrom_file.h 6 files changed, 373 insertions(+), 1 deletion(-)
git pull ssh://review.coreboot.org:29418/flashrom refs/changes/72/33372/1
diff --git a/Makefile b/Makefile index e08a3f6..744344a 100644 --- a/Makefile +++ b/Makefile @@ -547,7 +547,10 @@ ############################################################################### # Library code.
-LIB_OBJS = libflashrom.o layout.o flashrom.o udelay.o programmer.o helpers.o ich_descriptors.o fmap.o +LIB_OBJS = libflashrom.o flashrom_data.o layout.o flashrom.o udelay.o programmer.o helpers.o ich_descriptors.o fmap.o +ifneq ($(TARGET_OS), libpayload) +LIB_OBJS += flashrom_data_file.o +endif
############################################################################### # Frontend related stuff. diff --git a/flash.h b/flash.h index 911214c..af01479 100644 --- a/flash.h +++ b/flash.h @@ -55,6 +55,8 @@
#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+#define container_of(ptr, type, member) ((type *)((char *)ptr - offsetof(type, member))) + enum chipbustype { BUS_NONE = 0, BUS_PARALLEL = 1 << 0, @@ -267,6 +269,10 @@ bool in_4ba_mode; };
+static inline size_t total_size(const struct flashrom_flashctx *flash) { + return flash ? flash->chip ? flash->chip->total_size * 1024 : 0 : 0; +}; + /* Timing used in probe routines. ZERO is -2 to differentiate between an unset * field and zero delay. * diff --git a/flashrom_data.c b/flashrom_data.c new file mode 100644 index 0000000..5e541a9 --- /dev/null +++ b/flashrom_data.c @@ -0,0 +1,220 @@ +/* + * This file is part of the flashrom project. + * + * Copyright (C) 2019 Nico Huber nico.h@gmx.de + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "flash.h" +#include "libflashrom.h" + +/** + * @defgroup flashrom-data Data sources/sinks + * @{ + */ + +struct flash_data { + struct flashrom_data data; + struct flashrom_flashctx *flash; +}; +#define FLASH_DATA(d) container_of(d, struct flash_data, data) + +static ssize_t flash_readat( + void *const buf, const struct flashrom_data *const data, + const off_t offset, const size_t count) +{ + const struct flash_data *const fdata = FLASH_DATA(data); + + if (!data || !fdata->flash || !fdata->flash->chip || !fdata->flash->chip->read) + return -1; + + return fdata->flash->chip->read(fdata->flash, buf, offset, count); +} + +static void flash_release(struct flashrom_data *const data) +{ + free(FLASH_DATA(data)); +} + +int flashrom_data_from_flash( + struct flashrom_data **const data, struct flashrom_flashctx *const flash) +{ + struct flash_data *const fdata = malloc(sizeof(*fdata)); + + if (!fdata) + return -1; + + memset(fdata, 0x00, sizeof(*fdata)); + fdata->flash = flash; + fdata->data.size = total_size(flash); + fdata->data.readat = flash_readat; + fdata->data.release = flash_release; + + *data = &fdata->data; + return 0; +} + +struct buffer_data { + struct flashrom_data data; + void *buf; +}; +#define BUFFER_DATA(d) container_of(d, struct buffer_data, data) + +static ssize_t buffer_readat( + void *const buf, const struct flashrom_data *const data, + const off_t offset, const size_t count) +{ + const struct buffer_data *const bdata = BUFFER_DATA(data); + + if (!data || !bdata->buf || offset + count > data->size) + return -1; + + memcpy(buf, (char *)bdata->buf + offset, count); + return count; +} + +static ssize_t buffer_writeat( + const struct flashrom_data *const data, const off_t offset, + const void *const buf, const size_t count) +{ + const struct buffer_data *const bdata = BUFFER_DATA(data); + + if (!data || !bdata->buf || offset + count > data->size) + return -1; + + memcpy((char *)bdata->buf + offset, buf, count); + return count; +} + +static void buffer_release(struct flashrom_data *const data) +{ + free(BUFFER_DATA(data)); +} + +int flashrom_data_from_buf( + struct flashrom_data **const data, void *const buf, const size_t size) +{ + struct buffer_data *const bdata = malloc(sizeof(*bdata)); + + if (!bdata) + return -1; + + memset(bdata, 0x00, sizeof(*bdata)); + bdata->buf = buf; + bdata->data.size = size; + bdata->data.readat = buffer_readat; + bdata->data.writeat = buffer_writeat; + bdata->data.release = buffer_release; + + *data = &bdata->data; + return 0; +} + +struct sub_data { + struct flashrom_data data; + const struct flashrom_data *parent; + off_t offset; +}; +#define SUB_DATA(d) container_of(d, struct sub_data, data) + +static ssize_t sub_readat( + void *const buf, const struct flashrom_data *const data, + const off_t offset, const size_t count) +{ + const struct sub_data *const sdata = SUB_DATA(data); + + if (!data || !sdata->parent || !sdata->parent->readat || + offset + count > data->size) + return -1; + + return sdata->parent->readat(buf, sdata->parent, sdata->offset + offset, count); +} + +static ssize_t sub_writeat( + const struct flashrom_data *const data, const off_t offset, + const void *const buf, const size_t count) +{ + const struct sub_data *const sdata = SUB_DATA(data); + + if (!data || !sdata->parent || !sdata->parent->writeat || + offset + count > data->size) + return -1; + + return sdata->parent->writeat(sdata->parent, sdata->offset + offset, buf, count); +} + +static void sub_release(struct flashrom_data *const data) +{ + free(SUB_DATA(data)); +} + +int flashrom_data_subregion( + struct flashrom_data **const data, + const struct flashrom_data *const parent, + const off_t offset, const size_t size) +{ + if (!parent || offset + size > parent.size) + return -1; + + struct sub_data *const sdata = malloc(sizeof(*sdata)); + + if (!sdata) + return -1; + + memset(sdata, 0x00, sizeof(*sdata)); + sdata->parent = parent; + sdata->offset = offset; + sdata->data.size = size; + sdata->data.readat = parent->readat ? sub_readat : NULL; + sdata->data.writeat = parent->writeat ? sub_writeat : NULL; + sdata->data.release = sub_release; + + *data = &sdata->data; + return 0; +} + +ssize_t flashrom_data_copy( + const struct flashrom_data *const dst, + const struct flashrom_data *const src) +{ + ssize_t ret = -1; + + if (!dst || !dst->writeat || !src || !src->readat) + return ret; + if (dst->size != src->size) + return ret; + + void *const buf = malloc(dst->size); + if (!buf) + return ret; + + if (src->readat(buf, src, 0, dst->size) != dst->size) + goto _free_ret; + + ret = dst->writeat(dst, 0, buf, dst->size); + +_free_ret: + free(buf); + return ret; +} + +void flashrom_data_release(struct flashrom_data *const data) +{ + if (data->release) + data->release(data); +} + +/** @} */ /* end flashrom-data */ diff --git a/flashrom_data_file.c b/flashrom_data_file.c new file mode 100644 index 0000000..d7e1c66 --- /dev/null +++ b/flashrom_data_file.c @@ -0,0 +1,95 @@ +/* + * This file is part of the flashrom project. + * + * Copyright (C) 2019 Nico Huber nico.h@gmx.de + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "flash.h" +#include "libflashrom.h" +#include "libflashrom_file.h" + +/** @ingroup flashrom-data */ + +struct file_data { + struct flashrom_data data; + FILE *file; +}; +#define FILE_DATA(d) container_of(d, struct file_data, data) + +static ssize_t file_readat( + void *const buf, const struct flashrom_data *const data, + const off_t offset, const size_t count) +{ + const struct file_data *const fdata = FILE_DATA(data); + + if (!data || !fdata->file) + return -1; + + if (fseek(fdata->file, offset, SEEK_SET) != 0) + return -1; + if (fread(buf, count, 1, fdata->file) != 1) + return -1; + + return count; +} + +static ssize_t file_writeat( + const struct flashrom_data *const data, const off_t offset, + const void *const buf, const size_t count) +{ + const struct file_data *const fdata = FILE_DATA(data); + + if (!data || !fdata->file) + return -1; + + if (fseek(fdata->file, offset, SEEK_SET) != 0) + return -1; + if (fwrite(buf, count, 1, fdata->file) != 1) + return -1; + + return count; +} + +static void file_release(struct flashrom_data *const data) +{ + free(FILE_DATA(data)); +} + +int flashrom_data_from_file(struct flashrom_data **const data, FILE *const file) +{ + struct file_data *const fdata = malloc(sizeof(*fdata)); + + if (!fdata || !file) + return -1; + + if (fseek(file, 0, SEEK_END) != 0) + return -1; + + const long pos = ftell(file); + if (pos < 0 || pos > SIZE_MAX) + return -1; + + memset(fdata, 0x00, sizeof(*fdata)); + fdata->file = file; + fdata->data.size = (size_t)pos; + fdata->data.readat = file_readat; + fdata->data.writeat = file_writeat; + fdata->data.release = file_release; + + *data = &fdata->data; + return 0; +} diff --git a/libflashrom.h b/libflashrom.h index 38c95d2..01ecd3f 100644 --- a/libflashrom.h +++ b/libflashrom.h @@ -3,6 +3,7 @@ * * Copyright (C) 2012 secunet Security Networks AG * (Written by Nico Huber nico.huber@secunet.com for secunet) + * Copyright (C) 2019 Nico Huber nico.h@gmx.de * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -47,6 +48,26 @@ int flashrom_flash_erase(struct flashrom_flashctx *); void flashrom_flash_release(struct flashrom_flashctx *);
+/** @ingroup flashrom-data */ +/** Representation of a data source/sink (can be flash, a file, memory buffer, ...) */ +struct flashrom_data { + size_t size; + + /* Offsets are relative to the `flashrom_data` instance, not the `buf`. */ + ssize_t (*readat)(void *buf, const struct flashrom_data *, off_t offset, size_t count); + ssize_t (*writeat)(const struct flashrom_data *, off_t offset, const void *buf, size_t count); + + void (*release)(struct flashrom_data *); +}; + +int flashrom_data_from_flash(struct flashrom_data **, struct flashrom_flashctx *); +int flashrom_data_from_buf(struct flashrom_data **, void *, size_t); +int flashrom_data_subregion(struct flashrom_data **, const struct flashrom_data *parent, off_t, size_t); + +ssize_t flashrom_data_copy(const struct flashrom_data *dst, const struct flashrom_data *src); + +void flashrom_data_release(struct flashrom_data *); + /** @ingroup flashrom-flash */ enum flashrom_flag { FLASHROM_FLAG_FORCE, diff --git a/libflashrom_file.h b/libflashrom_file.h new file mode 100644 index 0000000..54de515 --- /dev/null +++ b/libflashrom_file.h @@ -0,0 +1,27 @@ +/* + * This file is part of the flashrom project. + * + * Copyright (C) 2019 Nico Huber nico.h@gmx.de + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __LIBFLASHROM_FILE_H__ +#define __LIBFLASHROM_FILE_H__ 1 + +#include <stdio.h> + +#include "libflashrom.h" + +/** @ingroup flashrom-data */ +int flashrom_data_from_file(struct flashrom_data **, FILE *); + +#endif /* !__LIBFLASHROM_FILE_H__ */