From 63e54275f684da6f6db8289561726adab5254b39 Mon Sep 17 00:00:00 2001 From: Jakub Czapiga Date: Mon, 15 Nov 2021 08:36:07 +0000 Subject: libpayload: Implement new CBFS access API This commit adds new CBFS API, which is based on the one available in the main coreboot source tree. Libpayload implementation supports RO/RW file lookups and file contents verification. Change-Id: I00da0658dbac0cddf92ad55611def947932d23c7 Signed-off-by: Jakub Czapiga Reviewed-on: https://review.coreboot.org/c/coreboot/+/59497 Tested-by: build bot (Jenkins) Reviewed-by: Julius Werner --- payloads/libpayload/libcbfs/Kconfig | 31 +++ payloads/libpayload/libcbfs/Makefile.inc | 6 + payloads/libpayload/libcbfs/cbfs.c | 363 +++++++++++++----------------- payloads/libpayload/libcbfs/cbfs_core.c | 1 - payloads/libpayload/libcbfs/cbfs_legacy.c | 223 ++++++++++++++++++ 5 files changed, 419 insertions(+), 205 deletions(-) create mode 100644 payloads/libpayload/libcbfs/Kconfig create mode 100644 payloads/libpayload/libcbfs/cbfs_legacy.c (limited to 'payloads/libpayload/libcbfs') diff --git a/payloads/libpayload/libcbfs/Kconfig b/payloads/libpayload/libcbfs/Kconfig new file mode 100644 index 0000000000..634d77f3e5 --- /dev/null +++ b/payloads/libpayload/libcbfs/Kconfig @@ -0,0 +1,31 @@ +## SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0-or-later + +config CBFS + bool "CBFS support" + default y + help + CBFS is the archive format of coreboot + +if CBFS + +config DEBUG_CBFS + bool "Output verbose CBFS debug messages" + default n + help + This option enables additional CBFS related debug messages. + +config ENABLE_CBFS_FALLBACK + bool "Fallback to RO (COREBOOT) region" + default n + help + When this option is enabled, the CBFS code will look for a file in the + RO (COREBOOT) region, if it isn't available in the active RW region. + This option makes sense only if CONFIG_VBOOT was enabled in the coreboot. + +config CBFS_VERIFICATION + bool "Enable CBFS verification" + depends on VBOOT + help + This option enables hash verification of CBFS files in RO (COREBOOT) and RW regions. + +endif diff --git a/payloads/libpayload/libcbfs/Makefile.inc b/payloads/libpayload/libcbfs/Makefile.inc index 85ef485822..53e6f7fa43 100644 --- a/payloads/libpayload/libcbfs/Makefile.inc +++ b/payloads/libpayload/libcbfs/Makefile.inc @@ -28,3 +28,9 @@ libcbfs-$(CONFIG_LP_CBFS) += cbfs.c libcbfs-$(CONFIG_LP_CBFS) += ram_media.c +libcbfs-$(CONFIG_LP_CBFS) += cbfs_legacy.c + +ifeq ($(CONFIG_LP_CBFS),y) +libcbfs-srcs += $(coreboottop)/src/commonlib/bsd/cbfs_private.c +libcbfs-srcs += $(coreboottop)/src/commonlib/bsd/cbfs_mcache.c +endif diff --git a/payloads/libpayload/libcbfs/cbfs.c b/payloads/libpayload/libcbfs/cbfs.c index d24b528ded..530f9e292d 100644 --- a/payloads/libpayload/libcbfs/cbfs.c +++ b/payloads/libpayload/libcbfs/cbfs.c @@ -1,243 +1,198 @@ -/* - * - * Copyright (C) 2011 secunet Security Networks AG - * Copyright (C) 2013 Google, Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ -#define LIBPAYLOAD - -#ifdef LIBPAYLOAD -# include -# if CONFIG(LP_LZMA) -# include -# define CBFS_CORE_WITH_LZMA -# endif -# if CONFIG(LP_LZ4) -# include -# define CBFS_CORE_WITH_LZ4 -# endif -# define CBFS_MINI_BUILD -#elif defined(__SMM__) -# define CBFS_MINI_BUILD -#else -# define CBFS_CORE_WITH_LZMA -# define CBFS_CORE_WITH_LZ4 -# include -#endif +/* SPDX-License-Identifier: BSD-3-Clause */ +#include +#include +#include #include +#include +#include +#include +#include +#include #include +#include -#ifdef LIBPAYLOAD -# include -# define DEBUG(x...) -# define LOG(x...) -# define ERROR(x...) printf(x) -#else -# include -# define ERROR(x...) printk(BIOS_ERR, "CBFS: " x) -# define LOG(x...) printk(BIOS_INFO, "CBFS: " x) -# if CONFIG_LP_DEBUG_CBFS -# define DEBUG(x...) printk(BIOS_SPEW, "CBFS: " x) -# else -# define DEBUG(x...) -# endif -#endif - -#include "cbfs_core.c" - -#ifndef __SMM__ -static inline int tohex4(unsigned int c) -{ - return (c <= 9) ? (c + '0') : (c - 10 + 'a'); -} -static void tohex16(unsigned int val, char* dest) +static const struct cbfs_boot_device *cbfs_get_boot_device(bool force_ro) { - dest[0] = tohex4(val>>12); - dest[1] = tohex4((val>>8) & 0xf); - dest[2] = tohex4((val>>4) & 0xf); - dest[3] = tohex4(val & 0xf); -} + static struct cbfs_boot_device ro; + static struct cbfs_boot_device rw; + + if (!force_ro) { + if (!rw.dev.size) { + rw.dev.offset = lib_sysinfo.cbfs_offset; + rw.dev.size = lib_sysinfo.cbfs_size; + rw.mcache = phys_to_virt(lib_sysinfo.cbfs_rw_mcache_offset); + rw.mcache_size = lib_sysinfo.cbfs_rw_mcache_size; + } + return &rw; + } -void *cbfs_load_optionrom(struct cbfs_media *media, uint16_t vendor, - uint16_t device) -{ - char name[17] = "pciXXXX,XXXX.rom"; + if (ro.dev.size) + return &ro; - tohex16(vendor, name+3); - tohex16(device, name+8); + if (fmap_locate_area("COREBOOT", &ro.dev.offset, &ro.dev.size)) + return NULL; + + ro.mcache = phys_to_virt(lib_sysinfo.cbfs_ro_mcache_offset); + ro.mcache_size = lib_sysinfo.cbfs_ro_mcache_size; - return cbfs_get_file_content(media, name, CBFS_TYPE_OPTIONROM, NULL); + return &ro; } -void * cbfs_load_stage(struct cbfs_media *media, const char *name) +ssize_t _cbfs_boot_lookup(const char *name, bool force_ro, union cbfs_mdata *mdata) { - struct cbfs_stage *stage = (struct cbfs_stage *) - cbfs_get_file_content(media, name, CBFS_TYPE_STAGE, NULL); - /* this is a mess. There is no ntohll. */ - /* for now, assume compatible byte order until we solve this. */ - uintptr_t entry; - uint32_t final_size; - - if (stage == NULL) - return (void *) -1; - - LOG("loading stage %s @ %p (%d bytes), entry @ 0x%llx\n", - name, - (void*)(uintptr_t) stage->load, stage->memlen, - stage->entry); - - final_size = cbfs_decompress(stage->compression, - ((unsigned char *) stage) + - sizeof(struct cbfs_stage), - stage->len, - (void *) (uintptr_t) stage->load, - stage->memlen); - if (!final_size) { - entry = -1; - goto out; + const struct cbfs_boot_device *cbd = cbfs_get_boot_device(force_ro); + if (!cbd) + return CB_ERR; + + size_t data_offset; + cb_err_t err = CB_CBFS_CACHE_FULL; + if (cbd->mcache_size) + err = cbfs_mcache_lookup(cbd->mcache, cbd->mcache_size, name, mdata, + &data_offset); + + if (err == CB_CBFS_CACHE_FULL) + err = cbfs_lookup(&cbd->dev, name, mdata, &data_offset, NULL); + + /* Fallback to RO if possible. */ + if (CONFIG(LP_ENABLE_CBFS_FALLBACK) && !force_ro && err == CB_CBFS_NOT_FOUND) { + LOG("Fall back to RO region for '%s'\n", name); + return _cbfs_boot_lookup(name, true, mdata); } - memset((void *)((uintptr_t)stage->load + final_size), 0, - stage->memlen - final_size); - - DEBUG("stage loaded.\n"); - - entry = stage->entry; - // entry = ntohll(stage->entry); + if (err) { + if (err == CB_CBFS_NOT_FOUND) + LOG("'%s' not found.\n", name); + else + ERROR("Error %d when looking up '%s'\n", err, name); + return err; + } -out: - free(stage); - return (void *) entry; + return cbd->dev.offset + data_offset; } -int cbfs_execute_stage(struct cbfs_media *media, const char *name) +void cbfs_unmap(void *mapping) { - struct cbfs_stage *stage = (struct cbfs_stage *) - cbfs_get_file_content(media, name, CBFS_TYPE_STAGE, NULL); + free(mapping); +} - if (stage == NULL) - return 1; +static bool cbfs_file_hash_mismatch(const void *buffer, size_t size, + const union cbfs_mdata *mdata) +{ + if (!CONFIG(LP_CBFS_VERIFICATION)) + return false; - if (ntohl(stage->compression) != CBFS_COMPRESS_NONE) { - LOG("Unable to run %s: Compressed file" - "Not supported for in-place execution\n", name); - free(stage); - return 1; + const struct vb2_hash *hash = cbfs_file_hash(mdata); + if (!hash) { + ERROR("'%s' does not have a file hash!\n", mdata->h.filename); + return true; + } + if (vb2_hash_verify(buffer, size, hash) != VB2_SUCCESS) { + ERROR("'%s' file hash mismatch!\n", mdata->h.filename); + return true; } - LOG("run @ %p\n", (void *) (uintptr_t)ntohll(stage->entry)); - int result = run_address((void *)(uintptr_t)ntohll(stage->entry)); - free(stage); - return result; + return false; } -void *cbfs_load_payload(struct cbfs_media *media, const char *name) +static size_t cbfs_load_and_decompress(size_t offset, size_t in_size, void *buffer, + size_t buffer_size, uint32_t compression, + const union cbfs_mdata *mdata) { - return (struct cbfs_payload *)cbfs_get_file_content( - media, name, CBFS_TYPE_SELF, NULL); -} + void *load = buffer; + size_t out_size = 0; + + DEBUG("Decompressing %zu bytes from '%s' to %p with algo %d\n", in_size, + mdata->h.filename, buffer, compression); + + if (compression != CBFS_COMPRESS_NONE) { + load = malloc(in_size); + if (!load) { + ERROR("'%s' buffer allocation failed\n", mdata->h.filename); + return 0; + } + } -struct cbfs_file *cbfs_find(const char *name) { - struct cbfs_handle *handle = cbfs_get_handle(CBFS_DEFAULT_MEDIA, name); - struct cbfs_media *m = &handle->media; - void *ret; + if (boot_device_read(load, offset, in_size) != in_size) { + ERROR("'%s' failed to read contents of file\n", mdata->h.filename); + goto out; + } - if (!handle) - return NULL; + if (cbfs_file_hash_mismatch(buffer, in_size, mdata)) + goto out; - ret = m->map(m, handle->media_offset, - handle->content_offset + handle->content_size); - if (ret == CBFS_MEDIA_INVALID_MAP_ADDRESS) { - free(handle); - return NULL; + switch (compression) { + case CBFS_COMPRESS_NONE: + out_size = in_size; + break; + case CBFS_COMPRESS_LZ4: + if (!CONFIG(LP_LZ4)) + goto out; + out_size = ulz4fn(load, in_size, buffer, buffer_size); + break; + case CBFS_COMPRESS_LZMA: + if (!CONFIG(LP_LZMA)) + goto out; + out_size = ulzman(load, in_size, buffer, buffer_size); + break; + default: + ERROR("'%s' decompression algo %d not supported\n", mdata->h.filename, + compression); } - - free(handle); - return ret; +out: + if (load != buffer) + free(load); + return out_size; } -void *cbfs_find_file(const char *name, int type) { - return cbfs_get_file_content(CBFS_DEFAULT_MEDIA, name, type, NULL); -} +void *_cbfs_load(const char *name, void *buf, size_t *size_inout, bool force_ro) +{ + ssize_t offset; + size_t out_size; + union cbfs_mdata mdata; + bool malloced = false; -const struct cbfs_header *get_cbfs_header(void) { - return cbfs_get_header(CBFS_DEFAULT_MEDIA); -} + DEBUG("%s(name='%s', buf=%p, force_ro=%s)\n", __func__, name, buf, + force_ro ? "true" : "false"); -/* Simple buffer */ - -void *cbfs_simple_buffer_map(struct cbfs_simple_buffer *buffer, - struct cbfs_media *media, - size_t offset, size_t count) { - void *address = buffer->buffer + buffer->allocated; - DEBUG("simple_buffer_map(offset=%zu, count=%zu): " - "allocated=%zu, size=%zu, last_allocate=%zu\n", - offset, count, buffer->allocated, buffer->size, - buffer->last_allocate); - if (buffer->allocated + count >= buffer->size) - return CBFS_MEDIA_INVALID_MAP_ADDRESS; - if (media->read(media, address, offset, count) != count) { - ERROR("simple_buffer: fail to read %zd bytes from 0x%zx\n", - count, offset); - return CBFS_MEDIA_INVALID_MAP_ADDRESS; + offset = _cbfs_boot_lookup(name, force_ro, &mdata); + if (offset < 0) + return NULL; + + uint32_t compression = CBFS_COMPRESS_NONE; + const struct cbfs_file_attr_compression *cattr = + cbfs_find_attr(&mdata, CBFS_FILE_ATTR_TAG_COMPRESSION, sizeof(*cattr)); + if (cattr) { + compression = be32toh(cattr->compression); + out_size = be32toh(cattr->decompressed_size); + } else { + out_size = be32toh(mdata.h.len); } - buffer->allocated += count; - buffer->last_allocate = count; - return address; -} -void *cbfs_simple_buffer_unmap(struct cbfs_simple_buffer *buffer, - const void *address) { - // TODO Add simple buffer management so we can free more than last - // allocated one. - DEBUG("simple_buffer_unmap(address=%p): " - "allocated=%zu, size=%zu, last_allocate=%zu\n", - address, buffer->allocated, buffer->size, - buffer->last_allocate); - if ((buffer->buffer + buffer->allocated - buffer->last_allocate) == - address) { - buffer->allocated -= buffer->last_allocate; - buffer->last_allocate = 0; + if (buf) { + if (!size_inout || *size_inout < out_size) { + ERROR("'%s' buffer too small", mdata.h.filename); + return NULL; + } + } else { + buf = malloc(out_size); + if (!buf) { + ERROR("'%s' allocation failure", mdata.h.filename); + return NULL; + } + malloced = true; } - return NULL; -} -/** - * run_address is passed the address of a function taking no parameters and - * jumps to it, returning the result. - * @param f the address to call as a function. - * @return value returned by the function. - */ + if (cbfs_load_and_decompress(offset, be32toh(mdata.h.len), buf, out_size, compression, + &mdata) + != out_size) { + if (malloced) + free(buf); + return NULL; + } + if (size_inout) + *size_inout = out_size; -int run_address(void *f) -{ - int (*v) (void); - v = f; - return v(); + return buf; } - -#endif diff --git a/payloads/libpayload/libcbfs/cbfs_core.c b/payloads/libpayload/libcbfs/cbfs_core.c index 82c2846054..bc513682c9 100644 --- a/payloads/libpayload/libcbfs/cbfs_core.c +++ b/payloads/libpayload/libcbfs/cbfs_core.c @@ -242,7 +242,6 @@ void *cbfs_get_contents(struct cbfs_handle *handle, size_t *size, size_t limit) cbfs_get_attr(handle, CBFS_FILE_ATTR_TAG_COMPRESSION); if (comp) { algo = ntohl(comp->compression); - DEBUG("File '%s' is compressed (alg=%d)\n", name, algo); *size = ntohl(comp->decompressed_size); /* TODO: Implement partial decompression with |limit| */ } diff --git a/payloads/libpayload/libcbfs/cbfs_legacy.c b/payloads/libpayload/libcbfs/cbfs_legacy.c new file mode 100644 index 0000000000..8249196d9a --- /dev/null +++ b/payloads/libpayload/libcbfs/cbfs_legacy.c @@ -0,0 +1,223 @@ +/* + * + * Copyright (C) 2011 secunet Security Networks AG + * Copyright (C) 2013 Google, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#if CONFIG(LP_LZMA) +# include +# define CB_CBFS_CORE_WITH_LZMA +#endif +#if CONFIG(LP_LZ4) +# include +# define CB_CBFS_CORE_WITH_LZ4 +#endif + +#include +#include + +#define DEBUG(x...) +#define LOG(x...) +#define ERROR(x...) printf(x) + +#ifndef __SMM__ + +#include "cbfs_core.c" + +static inline int tohex4(unsigned int c) +{ + return (c <= 9) ? (c + '0') : (c - 10 + 'a'); +} + +static void tohex16(unsigned int val, char *dest) +{ + dest[0] = tohex4(val>>12); + dest[1] = tohex4((val>>8) & 0xf); + dest[2] = tohex4((val>>4) & 0xf); + dest[3] = tohex4(val & 0xf); +} + +void *cbfs_load_optionrom(struct cbfs_media *media, uint16_t vendor, + uint16_t device) +{ + char name[17] = "pciXXXX,XXXX.rom"; + + tohex16(vendor, name+3); + tohex16(device, name+8); + + return cbfs_get_file_content(media, name, CBFS_TYPE_OPTIONROM, NULL); +} + +void *cbfs_load_stage(struct cbfs_media *media, const char *name) +{ + struct cbfs_stage *stage = (struct cbfs_stage *) + cbfs_get_file_content(media, name, CBFS_TYPE_STAGE, NULL); + /* this is a mess. There is no ntohll. */ + /* for now, assume compatible byte order until we solve this. */ + uintptr_t entry; + uint32_t final_size; + + if (stage == NULL) + return (void *) -1; + + LOG("loading stage %s @ %p (%d bytes), entry @ 0x%llx\n", name, + (void *)(uintptr_t)stage->load, stage->memlen, stage->entry); + + final_size = cbfs_decompress(stage->compression, + ((unsigned char *) stage) + + sizeof(struct cbfs_stage), + stage->len, + (void *) (uintptr_t) stage->load, + stage->memlen); + if (!final_size) { + entry = -1; + goto out; + } + + memset((void *)((uintptr_t)stage->load + final_size), 0, + stage->memlen - final_size); + + DEBUG("stage loaded.\n"); + + entry = stage->entry; + // entry = ntohll(stage->entry); + +out: + free(stage); + return (void *) entry; +} + +int cbfs_execute_stage(struct cbfs_media *media, const char *name) +{ + struct cbfs_stage *stage = (struct cbfs_stage *) + cbfs_get_file_content(media, name, CBFS_TYPE_STAGE, NULL); + + if (stage == NULL) + return 1; + + if (ntohl(stage->compression) != CBFS_COMPRESS_NONE) { + LOG("Unable to run %s: Compressed file" + "Not supported for in-place execution\n", name); + free(stage); + return 1; + } + + LOG("run @ %p\n", (void *) (uintptr_t)ntohll(stage->entry)); + int result = run_address((void *)(uintptr_t)ntohll(stage->entry)); + free(stage); + return result; +} + +void *cbfs_load_payload(struct cbfs_media *media, const char *name) +{ + return (struct cbfs_payload *)cbfs_get_file_content( + media, name, CBFS_TYPE_SELF, NULL); +} + +struct cbfs_file *cbfs_find(const char *name) +{ + struct cbfs_handle *handle = cbfs_get_handle(CBFS_DEFAULT_MEDIA, name); + struct cbfs_media *m = &handle->media; + void *ret; + + if (!handle) + return NULL; + + ret = m->map(m, handle->media_offset, + handle->content_offset + handle->content_size); + if (ret == CBFS_MEDIA_INVALID_MAP_ADDRESS) { + free(handle); + return NULL; + } + + free(handle); + return ret; +} + +void *cbfs_find_file(const char *name, int type) +{ + return cbfs_get_file_content(CBFS_DEFAULT_MEDIA, name, type, NULL); +} + +const struct cbfs_header *get_cbfs_header(void) +{ + return cbfs_get_header(CBFS_DEFAULT_MEDIA); +} + +/* Simple buffer */ + +void *cbfs_simple_buffer_map(struct cbfs_simple_buffer *buffer, struct cbfs_media *media, + size_t offset, size_t count) +{ + void *address = buffer->buffer + buffer->allocated; + DEBUG("simple_buffer_map(offset=%zu, count=%zu): " + "allocated=%zu, size=%zu, last_allocate=%zu\n", + offset, count, buffer->allocated, buffer->size, + buffer->last_allocate); + if (buffer->allocated + count >= buffer->size) + return CBFS_MEDIA_INVALID_MAP_ADDRESS; + if (media->read(media, address, offset, count) != count) { + ERROR("simple_buffer: fail to read %zd bytes from 0x%zx\n", + count, offset); + return CBFS_MEDIA_INVALID_MAP_ADDRESS; + } + buffer->allocated += count; + buffer->last_allocate = count; + return address; +} + +void *cbfs_simple_buffer_unmap(struct cbfs_simple_buffer *buffer, const void *address) +{ + // TODO Add simple buffer management so we can free more than last + // allocated one. + DEBUG("simple_buffer_unmap(address=%p): " + "allocated=%zu, size=%zu, last_allocate=%zu\n", + address, buffer->allocated, buffer->size, + buffer->last_allocate); + if ((buffer->buffer + buffer->allocated - buffer->last_allocate) == + address) { + buffer->allocated -= buffer->last_allocate; + buffer->last_allocate = 0; + } + return NULL; +} + +/** + * run_address is passed the address of a function taking no parameters and + * jumps to it, returning the result. + * @param f the address to call as a function. + * @return value returned by the function. + */ + +int run_address(void *f) +{ + int (*v)(void); + v = f; + return v(); +} + +#endif /* __SMM__ */ -- cgit v1.2.3