diff options
author | Aaron Durbin <adurbin@chromium.org> | 2015-03-26 14:39:07 -0500 |
---|---|---|
committer | Aaron Durbin <adurbin@chromium.org> | 2015-05-14 17:26:56 +0200 |
commit | 5d5f4b3c84677213d669d2218bc9a21e4177dcf7 (patch) | |
tree | 52c8ba0367f4200641900236f84374fa733562ab /src/lib | |
parent | d22206ac796b747ad1e790e2dc44cdf8832d66e8 (diff) |
coreboot: add region infrastructure
The region infrastructure provides a means of abstracting
access to different types of storage such as SPI flash, MMC,
or just plain memory. The regions are represented by
region devices which can be chained together forming subregions
of the larger region. This allows the call sites to be agnostic
about the implementations behind the regions. Additionally, this
prepares for a cleaner API for CBFS accesses.
Change-Id: I803f97567ef0505691a69975c282fde1215ea6da
Signed-off-by: Aaron Durbin <adurbin@chromium.org>
Reviewed-on: http://review.coreboot.org/9128
Tested-by: build bot (Jenkins)
Reviewed-by: Stefan Reinauer <stefan.reinauer@coreboot.org>
Diffstat (limited to 'src/lib')
-rw-r--r-- | src/lib/Makefile.inc | 4 | ||||
-rw-r--r-- | src/lib/region.c | 121 |
2 files changed, 125 insertions, 0 deletions
diff --git a/src/lib/Makefile.inc b/src/lib/Makefile.inc index d6d7b84190..c547c70ae4 100644 --- a/src/lib/Makefile.inc +++ b/src/lib/Makefile.inc @@ -29,6 +29,7 @@ bootblock-$(CONFIG_COLLECT_TIMESTAMPS) += timestamp.c bootblock-$(CONFIG_CONSOLE_CBMEM) += cbmem_console.c bootblock-y += memchr.c bootblock-y += memcmp.c +bootblock-y += region.c verstage-y += prog_ops.c verstage-y += delay.c @@ -37,6 +38,7 @@ verstage-y += cbfs_core.c verstage-y += halt.c verstage-y += memcmp.c verstage-$(CONFIG_COLLECT_TIMESTAMPS) += timestamp.c +verstage-y += region.c verstage-$(CONFIG_CONSOLE_CBMEM) += cbmem_console.c verstage-$(CONFIG_COMMON_CBFS_SPI_WRAPPER) += cbfs_spi.c @@ -132,6 +134,8 @@ ramstage-$(CONFIG_RELOCATABLE_RAMSTAGE) += cbmem_stage_cache.c romstage-$(CONFIG_RELOCATABLE_RAMSTAGE) += cbmem_stage_cache.c endif +romstage-y += region.c +ramstage-y += region.c smm-y += cbfs.c cbfs_core.c memcmp.c smm-$(CONFIG_COMPILER_GCC) += gcc.c diff --git a/src/lib/region.c b/src/lib/region.c new file mode 100644 index 0000000000..948addd2ca --- /dev/null +++ b/src/lib/region.c @@ -0,0 +1,121 @@ +/* + * This file is part of the coreboot project. + * + * Copyright 2015 Google Inc. + * + * 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; version 2 of the License. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc. + */ + +#include <region.h> +#include <string.h> + +static inline size_t region_offset(const struct region *r) +{ + return r->offset; +} + +static inline size_t region_end(const struct region *r) +{ + return region_sz(r) + region_offset(r); +} + +static int is_subregion(const struct region *p, const struct region *c) +{ + if (region_offset(c) < region_offset(p)) + return 0; + + if (region_sz(c) > region_sz(p)) + return 0; + + if (region_end(c) > region_end(p)) + return 0; + + return 1; +} + +static int normalize_and_ok(const struct region *outer, struct region *inner) +{ + inner->offset += region_offset(outer); + return is_subregion(outer, inner); +} + +static const struct region_device *rdev_root(const struct region_device *rdev) +{ + if (rdev->root == NULL) + return rdev; + return rdev->root; +} + +void *rdev_mmap(const struct region_device *rd, size_t offset, size_t size) +{ + const struct region_device *rdev; + struct region req = { + .offset = offset, + .size = size, + }; + + if (!normalize_and_ok(&rd->region, &req)) + return NULL; + + rdev = rdev_root(rd); + + return rdev->ops->mmap(rdev, req.offset, req.size); +} + +int rdev_munmap(const struct region_device *rd, void *mapping) +{ + const struct region_device *rdev; + + rdev = rdev_root(rd); + + return rdev->ops->munmap(rdev, mapping); +} + +ssize_t rdev_readat(const struct region_device *rd, void *b, size_t offset, + size_t size) +{ + const struct region_device *rdev; + struct region req = { + .offset = offset, + .size = size, + }; + + if (!normalize_and_ok(&rd->region, &req)) + return -1; + + rdev = rdev_root(rd); + + return rdev->ops->readat(rdev, b, req.offset, req.size); +} + +int rdev_chain(struct region_device *child, const struct region_device *parent, + size_t offset, size_t size) +{ + struct region req = { + .offset = offset, + .size = size, + }; + + if (!normalize_and_ok(&parent->region, &req)) + return -1; + + /* Keep track of root region device. Note the offsets are relative + * to the root device. */ + child->root = rdev_root(parent); + child->ops = NULL; + child->region.offset = req.offset; + child->region.size = req.size; + + return 0; +} |