[Skiboot] [PATCH 1/2] blocklevel_info: Refactor the passing of output data
William A. Kennington III
wak at google.com
Sat Apr 8 09:11:46 AEST 2017
Signed-off-by: William A. Kennington III <wak at google.com>
Change-Id: Iae339e75d72a5131a35d30dde52ed72629c4308e
---
core/flash.c | 15 ++++++------
external/common/arch_flash_arm.c | 6 ++---
external/common/arch_flash_common.c | 5 ++--
external/gard/gard.c | 10 ++++----
external/opal-prd/pnor.c | 12 +++++-----
external/opal-prd/pnor.h | 3 +--
external/opal-prd/test/test_pnor_ops.c | 7 ++++--
external/pflash/pflash.c | 19 +++++++--------
libflash/blocklevel.c | 33 +++++++++++++-------------
libflash/blocklevel.h | 13 ++++++----
libflash/file.c | 43 ++++++++++++++--------------------
libflash/libffs.c | 8 +++----
libflash/libflash.c | 15 ++++++------
libflash/mbox-flash.c | 19 ++++-----------
platforms/mambo/mambo.c | 15 ++++--------
15 files changed, 101 insertions(+), 122 deletions(-)
diff --git a/core/flash.c b/core/flash.c
index 793401c9..10cf8b4d 100644
--- a/core/flash.c
+++ b/core/flash.c
@@ -254,21 +254,20 @@ static int num_flashes(void)
int flash_register(struct blocklevel_device *bl)
{
- uint64_t size;
- uint32_t block_size;
+ struct blocklevel_info bl_info;
struct ffs_handle *ffs;
struct dt_node *node;
struct flash *flash;
- const char *name;
int rc;
- rc = blocklevel_get_info(bl, &name, &size, &block_size);
+ rc = blocklevel_get_info(bl, &bl_info);
if (rc)
return rc;
prlog(PR_INFO, "FLASH: registering flash device %s "
"(size 0x%llx, blocksize 0x%x)\n",
- name ?: "(unnamed)", size, block_size);
+ bl_info.name ?: "(unnamed)", bl_info.size,
+ bl_info.erase_granule);
lock(&flash_lock);
@@ -281,8 +280,8 @@ int flash_register(struct blocklevel_device *bl)
flash->busy = false;
flash->bl = bl;
- flash->size = size;
- flash->block_size = block_size;
+ flash->size = bl_info.size;
+ flash->block_size = bl_info.erase_granule;
flash->id = num_flashes();
list_add(&flashes, &flash->list);
@@ -302,7 +301,7 @@ int flash_register(struct blocklevel_device *bl)
node = flash_add_dt_node(flash, flash->id);
- setup_system_flash(flash, node, name, ffs);
+ setup_system_flash(flash, node, bl_info.name, ffs);
if (ffs)
ffs_close(ffs);
diff --git a/external/common/arch_flash_arm.c b/external/common/arch_flash_arm.c
index 3cdd41de..ac43de0c 100644
--- a/external/common/arch_flash_arm.c
+++ b/external/common/arch_flash_arm.c
@@ -303,13 +303,13 @@ int arch_flash_erase_chip(struct blocklevel_device *bl)
if (!arch_data.flash_chip) {
/* Just assume its a regular erase */
int rc;
- uint64_t total_size;
+ struct blocklevel_info bl_info;
- rc = blocklevel_get_info(bl, NULL, &total_size, NULL);
+ rc = blocklevel_get_info(bl, &bl_info);
if (rc)
return rc;
- return blocklevel_erase(bl, 0, total_size);
+ return blocklevel_erase(bl, 0, bl_info.size);
}
return flash_erase_chip(arch_data.flash_chip);
diff --git a/external/common/arch_flash_common.c b/external/common/arch_flash_common.c
index 5b7f9ea0..e4ab432d 100644
--- a/external/common/arch_flash_common.c
+++ b/external/common/arch_flash_common.c
@@ -31,13 +31,14 @@
int __attribute__((weak)) arch_flash_erase_chip(struct blocklevel_device *bl)
{
int rc;
+ struct blocklevel_info bl_info;
uint64_t total_size;
- rc = blocklevel_get_info(bl, NULL, &total_size, NULL);
+ rc = blocklevel_get_info(bl, &bl_info);
if (rc)
return rc;
- return blocklevel_erase(bl, 0, total_size);
+ return blocklevel_erase(bl, 0, bl_info.size);
}
int __attribute__((weak)) arch_flash_4b_mode(struct blocklevel_device *bl, int set_4b)
diff --git a/external/gard/gard.c b/external/gard/gard.c
index 32a0003f..0abf7c73 100644
--- a/external/gard/gard.c
+++ b/external/gard/gard.c
@@ -576,7 +576,7 @@ int main(int argc, char **argv)
const char *action, *progname;
char *filename = NULL;
struct gard_ctx _ctx, *ctx;
- uint64_t bl_size;
+ struct blocklevel_info bl_info;
int rc, i = 0;
bool part = 0;
bool ecc = 0;
@@ -645,17 +645,17 @@ int main(int argc, char **argv)
goto out_free;
}
- rc = blocklevel_get_info(ctx->bl, NULL, &bl_size, NULL);
+ rc = blocklevel_get_info(ctx->bl, &bl_info);
if (rc)
goto out;
- if (bl_size > UINT_MAX) {
+ if (bl_info.size > UINT_MAX) {
fprintf(stderr, "MTD device bigger than %i: size: %" PRIu64 "\n",
- UINT_MAX, bl_size);
+ UINT_MAX, bl_info.size);
rc = EXIT_FAILURE;
goto out;
}
- ctx->f_size = bl_size;
+ ctx->f_size = bl_info.size;
if (!part) {
rc = ffs_init(0, ctx->f_size, ctx->bl, &ctx->ffs, 1);
diff --git a/external/opal-prd/pnor.c b/external/opal-prd/pnor.c
index 0e7e5c04..2156f70d 100644
--- a/external/opal-prd/pnor.c
+++ b/external/opal-prd/pnor.c
@@ -45,13 +45,13 @@ int pnor_init(struct pnor *pnor)
return -1;
}
- rc = blocklevel_get_info(pnor->bl, NULL, &(pnor->size), &(pnor->erasesize));
+ rc = blocklevel_get_info(pnor->bl, &pnor->bl_info);
if (rc) {
pr_log(LOG_ERR, "PNOR: blocklevel_get_info() failed. Can't use PNOR");
goto out;
}
- rc = ffs_init(0, pnor->size, pnor->bl, &pnor->ffsh, 0);
+ rc = ffs_init(0, pnor->bl_info.size, pnor->bl, &pnor->ffsh, 0);
if (rc) {
pr_log(LOG_ERR, "PNOR: Failed to open pnor partition table");
goto out;
@@ -102,8 +102,8 @@ static int mtd_write(struct pnor *pnor, void *data, uint64_t offset,
{
int rc;
- if (len > pnor->size || offset > pnor->size ||
- len + offset > pnor->size)
+ if (len > pnor->bl_info.size || offset > pnor->bl_info.size ||
+ len + offset > pnor->bl_info.size)
return -ERANGE;
rc = blocklevel_smart_write(pnor->bl, offset, data, len);
@@ -118,8 +118,8 @@ static int mtd_read(struct pnor *pnor, void *data, uint64_t offset,
{
int rc;
- if (len > pnor->size || offset > pnor->size ||
- len + offset > pnor->size)
+ if (len > pnor->bl_info.size || offset > pnor->bl_info.size ||
+ len + offset > pnor->bl_info.size)
return -ERANGE;
rc = blocklevel_read(pnor->bl, offset, data, len);
diff --git a/external/opal-prd/pnor.h b/external/opal-prd/pnor.h
index 4ff449c8..93759ef4 100644
--- a/external/opal-prd/pnor.h
+++ b/external/opal-prd/pnor.h
@@ -7,8 +7,7 @@
struct pnor {
char *path;
struct ffs_handle *ffsh;
- uint64_t size;
- uint32_t erasesize;
+ struct blocklevel_info bl_info;
struct blocklevel_device *bl;
};
diff --git a/external/opal-prd/test/test_pnor_ops.c b/external/opal-prd/test/test_pnor_ops.c
index fd5e2c22..3743362e 100644
--- a/external/opal-prd/test/test_pnor_ops.c
+++ b/external/opal-prd/test/test_pnor_ops.c
@@ -130,11 +130,14 @@ int main(int argc, char **argv)
for (i = 0; i < 2; i++)
write(fd, data, 16);
+ /* Unused */
+ pnor.bl_info.name = NULL;
+
/* Adjust this if making the file smaller */
- pnor.size = 32;
+ pnor.bl_info.size = 32;
/* This is fake. Make it smaller than the size */
- pnor.erasesize = 4;
+ pnor.bl_info.erase_granule = 4;
printf("Write: ");
memset(data, 'A', sizeof(data));
diff --git a/external/pflash/pflash.c b/external/pflash/pflash.c
index a344987e..b4b7e34f 100644
--- a/external/pflash/pflash.c
+++ b/external/pflash/pflash.c
@@ -55,9 +55,7 @@ static uint8_t file_buf[FILE_BUF_SIZE] __aligned(0x1000);
static struct blocklevel_device *bl;
static struct ffs_handle *ffsh;
-static uint64_t fl_total_size;
-static uint32_t fl_erase_granule;
-static const char *fl_name;
+static struct blocklevel_info bl_info;
static int32_t ffs_index = -1;
static void check_confirm(void)
@@ -97,7 +95,7 @@ static void print_ffs_info(uint32_t toc_offset)
printf("TOC at 0x%08x Partitions:\n", toc_offset);
printf("-----------\n");
- rc = ffs_init(toc_offset, fl_total_size, bl, &ffs_handle, 0);
+ rc = ffs_init(toc_offset, bl_info.size, bl, &ffs_handle, 0);
if (rc) {
fprintf(stderr, "Error %d opening ffs !\n", rc);
return;
@@ -136,9 +134,9 @@ static void print_flash_info(uint32_t toc)
{
printf("Flash info:\n");
printf("-----------\n");
- printf("Name = %s\n", fl_name);
- printf("Total size = %"PRIu64"MB \n", fl_total_size >> 20);
- printf("Erase granule = %dKB \n", fl_erase_granule >> 10);
+ printf("Name = %s\n", bl_info.name);
+ printf("Total size = %"PRIu64"MB \n", bl_info.size >> 20);
+ printf("Erase granule = %dKB \n", bl_info.erase_granule >> 10);
if (bmc_flash)
return;
@@ -153,7 +151,7 @@ static int open_partition(const char *name)
/* Open libffs if needed */
if (!ffsh) {
- rc = ffs_init(ffs_toc, fl_total_size, bl, &ffsh, 0);
+ rc = ffs_init(ffs_toc, bl_info.size, bl, &ffsh, 0);
if (rc) {
fprintf(stderr, "Error %d opening ffs !\n", rc);
if (ffs_toc)
@@ -768,8 +766,7 @@ int main(int argc, char *argv[])
atexit(exiting);
- rc = blocklevel_get_info(bl, &fl_name,
- &fl_total_size, &fl_erase_granule);
+ rc = blocklevel_get_info(bl, &bl_info);
if (rc) {
fprintf(stderr, "Error %d getting flash info\n", rc);
exit(1);
@@ -781,7 +778,7 @@ int main(int argc, char *argv[])
/* If read specified and no read_size, use flash size */
if (do_read && !read_size && !part_name)
- read_size = fl_total_size;
+ read_size = bl_info.size;
/* We have a partition specified, grab the details */
if (part_name)
diff --git a/libflash/blocklevel.c b/libflash/blocklevel.c
index 9802ad0f..6272f8fd 100644
--- a/libflash/blocklevel.c
+++ b/libflash/blocklevel.c
@@ -220,12 +220,11 @@ int blocklevel_erase(struct blocklevel_device *bl, uint64_t pos, uint64_t len)
return rc;
}
-int blocklevel_get_info(struct blocklevel_device *bl, const char **name, uint64_t *total_size,
- uint32_t *erase_granule)
+int blocklevel_get_info(struct blocklevel_device *bl, struct blocklevel_info *bl_info)
{
int rc;
- if (!bl || !bl->get_info) {
+ if (!bl || !bl->get_info || !bl_info) {
errno = EINVAL;
return FLASH_ERR_PARM_ERROR;
}
@@ -234,12 +233,12 @@ int blocklevel_get_info(struct blocklevel_device *bl, const char **name, uint64_
if (rc)
return rc;
- rc = bl->get_info(bl, name, total_size, erase_granule);
+ rc = bl->get_info(bl, bl_info);
/* Check the validity of what we are being told */
- if (erase_granule && *erase_granule != bl->erase_mask + 1)
+ if (bl_info->erase_granule != bl->erase_mask + 1)
fprintf(stderr, "blocklevel_get_info: WARNING: erase_granule (0x%08x) and erase_mask"
- " (0x%08x) don't match\n", *erase_granule, bl->erase_mask + 1);
+ " (0x%08x) don't match\n", bl_info->erase_granule, bl->erase_mask + 1);
release(bl);
@@ -392,7 +391,7 @@ out:
int blocklevel_smart_write(struct blocklevel_device *bl, uint64_t pos, const void *buf, uint64_t len)
{
- uint32_t erase_size;
+ struct blocklevel_info bl_info;
const void *write_buf = buf;
void *write_buf_start = NULL;
void *erase_buf;
@@ -406,7 +405,7 @@ int blocklevel_smart_write(struct blocklevel_device *bl, uint64_t pos, const voi
if (!(bl->flags & WRITE_NEED_ERASE))
return blocklevel_write(bl, pos, buf, len);
- rc = blocklevel_get_info(bl, NULL, NULL, &erase_size);
+ rc = blocklevel_get_info(bl, &bl_info);
if (rc)
return rc;
@@ -427,7 +426,7 @@ int blocklevel_smart_write(struct blocklevel_device *bl, uint64_t pos, const voi
write_buf = write_buf_start;
}
- erase_buf = malloc(erase_size);
+ erase_buf = malloc(bl_info.erase_granule);
if (!erase_buf) {
errno = ENOMEM;
rc = FLASH_ERR_MALLOC_FAILED;
@@ -439,26 +438,26 @@ int blocklevel_smart_write(struct blocklevel_device *bl, uint64_t pos, const voi
goto out_free;
while (len > 0) {
- uint32_t erase_block = pos & ~(erase_size - 1);
- uint32_t block_offset = pos & (erase_size - 1);
- uint32_t size = erase_size > len ? len : erase_size;
+ uint32_t erase_block = pos & ~(bl_info.erase_granule - 1);
+ uint32_t block_offset = pos & (bl_info.erase_granule - 1);
+ uint32_t size = bl_info.erase_granule > len ? len : bl_info.erase_granule;
int cmp;
/* Write crosses an erase boundary, shrink the write to the boundary */
- if (erase_size < block_offset + size) {
- size = erase_size - block_offset;
+ if (bl_info.erase_granule < block_offset + size) {
+ size = bl_info.erase_granule - block_offset;
}
- rc = bl->read(bl, erase_block, erase_buf, erase_size);
+ rc = bl->read(bl, erase_block, erase_buf, bl_info.erase_granule);
if (rc)
goto out;
cmp = blocklevel_flashcmp(erase_buf + block_offset, write_buf, size);
if (cmp != 0) {
if (cmp == -1)
- bl->erase(bl, erase_block, erase_size);
+ bl->erase(bl, erase_block, bl_info.erase_granule);
memcpy(erase_buf + block_offset, write_buf, size);
- rc = bl->write(bl, erase_block, erase_buf, erase_size);
+ rc = bl->write(bl, erase_block, erase_buf, bl_info.erase_granule);
if (rc)
goto out;
}
diff --git a/libflash/blocklevel.h b/libflash/blocklevel.h
index ba42c83d..7e4a7e8d 100644
--- a/libflash/blocklevel.h
+++ b/libflash/blocklevel.h
@@ -34,6 +34,12 @@ enum blocklevel_flags {
WRITE_NEED_ERASE = 1,
};
+struct blocklevel_info {
+ const char *name;
+ uint64_t size;
+ uint32_t erase_granule;
+};
+
/*
* libffs may be used with different backends, all should provide these for
* libflash to get the information it needs
@@ -45,8 +51,7 @@ struct blocklevel_device {
int (*read)(struct blocklevel_device *bl, uint64_t pos, void *buf, uint64_t len);
int (*write)(struct blocklevel_device *bl, uint64_t pos, const void *buf, uint64_t len);
int (*erase)(struct blocklevel_device *bl, uint64_t pos, uint64_t len);
- int (*get_info)(struct blocklevel_device *bl, const char **name, uint64_t *total_size,
- uint32_t *erase_granule);
+ int (*get_info)(struct blocklevel_device *bl, struct blocklevel_info *bl_info);
/*
* Keep the erase mask so that blocklevel_erase() can do sanity checking
@@ -62,8 +67,8 @@ int blocklevel_read(struct blocklevel_device *bl, uint64_t pos, void *buf, uint6
int blocklevel_raw_write(struct blocklevel_device *bl, uint64_t pos, const void *buf, uint64_t len);
int blocklevel_write(struct blocklevel_device *bl, uint64_t pos, const void *buf, uint64_t len);
int blocklevel_erase(struct blocklevel_device *bl, uint64_t pos, uint64_t len);
-int blocklevel_get_info(struct blocklevel_device *bl, const char **name, uint64_t *total_size,
- uint32_t *erase_granule);
+
+int blocklevel_get_info(struct blocklevel_device *bl, struct blocklevel_info *bl_info);
/*
* blocklevel_smart_write() performs reads on the data to see if it
diff --git a/libflash/file.c b/libflash/file.c
index 5f074cf2..b8ceedb5 100644
--- a/libflash/file.c
+++ b/libflash/file.c
@@ -169,6 +169,7 @@ static int get_info_name(struct file_data *file_data, char **name)
}
lpath[len] = '\0';
+ free(*name);
*name = lpath;
free(path);
@@ -176,8 +177,8 @@ static int get_info_name(struct file_data *file_data, char **name)
}
-static int mtd_get_info(struct blocklevel_device *bl, const char **name,
- uint64_t *total_size, uint32_t *erase_granule)
+static int mtd_get_info(struct blocklevel_device *bl,
+ struct blocklevel_info *bl_info)
{
struct file_data *file_data = container_of(bl, struct file_data, bl);
struct mtd_info_user mtd_info;
@@ -187,24 +188,19 @@ static int mtd_get_info(struct blocklevel_device *bl, const char **name,
if (rc == -1)
return FLASH_ERR_BAD_READ;
- if (total_size)
- *total_size = mtd_info.size;
-
- if (erase_granule)
- *erase_granule = mtd_info.erasesize;
+ rc = get_info_name(file_data, &(file_data->name));
+ if (rc)
+ return rc;
- if (name) {
- rc = get_info_name(file_data, &(file_data->name));
- if (rc)
- return rc;
- *name = file_data->name;
- }
+ bl_info->name = file_data->name;
+ bl_info->total_size = mtd_info.size;
+ bl_info->erase_granule = mtd_info.erasesize;
return 0;
}
-static int file_get_info(struct blocklevel_device *bl, const char **name,
- uint64_t *total_size, uint32_t *erase_granule)
+static int file_get_info(struct blocklevel_device *bl,
+ struct blocklevel_info *bl_info)
{
struct file_data *file_data = container_of(bl, struct file_data, bl);
struct stat st;
@@ -213,18 +209,13 @@ static int file_get_info(struct blocklevel_device *bl, const char **name,
if (fstat(file_data->fd, &st))
return FLASH_ERR_PARM_ERROR;
- if (total_size)
- *total_size = st.st_size;
-
- if (erase_granule)
- *erase_granule = 1;
+ rc = get_info_name(file_data, &(file_data->name));
+ if (rc)
+ return rc;
- if (name) {
- rc = get_info_name(file_data, &(file_data->name));
- if (rc)
- return rc;
- *name = file_data->name;
- }
+ bl_info->name = file_data->name;
+ bl_info->size = st.st_size;
+ bl_info->erase_granule = 1;
return 0;
}
diff --git a/libflash/libffs.c b/libflash/libffs.c
index dca40188..9360966a 100644
--- a/libflash/libffs.c
+++ b/libflash/libffs.c
@@ -203,25 +203,25 @@ int ffs_init(uint32_t offset, uint32_t max_size, struct blocklevel_device *bl,
{
struct __ffs_hdr blank_hdr;
struct __ffs_hdr raw_hdr;
+ struct blocklevel_info bl_info;
struct ffs_handle *f;
- uint64_t total_size;
int rc, i;
if (!ffs || !bl)
return FLASH_ERR_PARM_ERROR;
*ffs = NULL;
- rc = blocklevel_get_info(bl, NULL, &total_size, NULL);
+ rc = blocklevel_get_info(bl, &bl_info);
if (rc) {
FL_ERR("FFS: Error %d retrieving flash info\n", rc);
return rc;
}
- if (total_size > UINT_MAX)
+ if (bl_info.size > UINT_MAX)
return FLASH_ERR_VERIFY_FAILURE;
if ((offset + max_size) < offset)
return FLASH_ERR_PARM_ERROR;
- if ((max_size > total_size))
+ if ((max_size > bl_info.size))
return FLASH_ERR_PARM_ERROR;
/* Read flash header */
diff --git a/libflash/libflash.c b/libflash/libflash.c
index 9bdc7d6f..9765c43e 100644
--- a/libflash/libflash.c
+++ b/libflash/libflash.c
@@ -794,16 +794,15 @@ static int flash_configure(struct flash_chip *c)
return 0;
}
-static int flash_get_info(struct blocklevel_device *bl, const char **name,
- uint64_t *total_size, uint32_t *erase_granule)
+static int flash_get_info(struct blocklevel_device *bl,
+ struct blocklevel_info *bl_info)
{
struct flash_chip *c = container_of(bl, struct flash_chip, bl);
- if (name)
- *name = c->info.name;
- if (total_size)
- *total_size = c->tsize;
- if (erase_granule)
- *erase_granule = c->min_erase_mask + 1;
+
+ bl_info->name = c->info.name;
+ bl_info->size = c->tsize;
+ bl_info->erase_granule = c->min_erase_mask + 1;
+
return 0;
}
diff --git a/libflash/mbox-flash.c b/libflash/mbox-flash.c
index 7bf731d0..75e03005 100644
--- a/libflash/mbox-flash.c
+++ b/libflash/mbox-flash.c
@@ -388,8 +388,8 @@ static int mbox_flash_read(struct blocklevel_device *bl, uint64_t pos,
return rc;
}
-static int mbox_flash_get_info(struct blocklevel_device *bl, const char **name,
- uint64_t *total_size, uint32_t *erase_granule)
+static int mbox_flash_get_info(struct blocklevel_device *bl,
+ struct blocklevel_info *bl_info)
{
struct mbox_flash_data *mbox_flash;
struct bmc_mbox_msg *msg;
@@ -400,14 +400,7 @@ static int mbox_flash_get_info(struct blocklevel_device *bl, const char **name,
if (!msg)
return FLASH_ERR_MALLOC_FAILED;
- /*
- * We want to avoid runtime mallocs in skiboot. The expected
- * behavour to uses of libflash is that one can free() the memory
- * returned.
- * NULL will do for now.
- */
- if (name)
- *name = NULL;
+ bl_info->name = "pnor_mbox";
mbox_flash->busy = true;
rc = msg_send(mbox_flash, msg);
@@ -423,10 +416,8 @@ static int mbox_flash_get_info(struct blocklevel_device *bl, const char **name,
mbox_flash->bl.erase_mask = mbox_flash->erase_granule - 1;
- if (total_size)
- *total_size = mbox_flash->total_size;
- if (erase_granule)
- *erase_granule = mbox_flash->erase_granule;
+ bl_info->size = mbox_flash->total_size;
+ bl_info->erase_granule = mbox_flash->erase_granule;
out:
msg_free_memory(msg);
diff --git a/platforms/mambo/mambo.c b/platforms/mambo/mambo.c
index cb6e103c..dd7872a8 100644
--- a/platforms/mambo/mambo.c
+++ b/platforms/mambo/mambo.c
@@ -125,19 +125,14 @@ static int bogus_disk_erase(struct blocklevel_device *bl __unused,
return 0; /* NOP */
}
-static int bogus_disk_get_info(struct blocklevel_device *bl, const char **name,
- uint64_t *total_size, uint32_t *erase_granule)
+static int bogus_disk_get_info(struct blocklevel_device *bl,
+ struct blocklevel_info *bl_info)
{
struct bogus_disk_info *bdi = bl->priv;
- if (total_size)
- *total_size = bdi->size;
-
- if (erase_granule)
- *erase_granule = BD_SECT_SZ;
-
- if (name)
- *name = "mambobogus";
+ bl_info->name = "mambobogus";
+ bl_info->size = bdi->size;
+ bl_info->erase_granule = BD_SECT_SZ;
return 0;
}
--
2.12.2
More information about the Skiboot
mailing list