diff options
Diffstat (limited to 'src/vendorcode/google/chromeos/vboot_wrapper.c')
-rw-r--r-- | src/vendorcode/google/chromeos/vboot_wrapper.c | 268 |
1 files changed, 268 insertions, 0 deletions
diff --git a/src/vendorcode/google/chromeos/vboot_wrapper.c b/src/vendorcode/google/chromeos/vboot_wrapper.c new file mode 100644 index 0000000000..66b7cfb276 --- /dev/null +++ b/src/vendorcode/google/chromeos/vboot_wrapper.c @@ -0,0 +1,268 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2013 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +#include <console/vtxprintf.h> +#include <cpu/x86/tsc.h> +#include <rmodule.h> +#include <stdlib.h> +#include <string.h> +#include "vboot_context.h" +#include "vboot_handoff.h" + +static void vboot_wrapper(struct vboot_context *context); + +DEFINE_RMODULE_HEADER(vboot_wrapper_header, vboot_wrapper, RMODULE_TYPE_VBOOT); + +/* Keep a global context pointer around for the callbacks to use. */ +static struct vboot_context *gcontext; + +/* The FW areas consist of multiple components. At the beginning of + * each area is the number of total compoments as well as the size and + * offset for each component. One needs to caculate the total size of the + * signed firmware region based off of the embedded metadata. */ +#define MAX_NUM_COMPONENTS 20 + +struct component_entry { + uint32_t offset; + uint32_t size; +} __attribute__((packed)); + +struct components { + uint32_t num_components; + struct component_entry entries[0]; +} __attribute__((packed)); + + +static void parse_component(const struct components *components, int num, + struct firmware_component *fw) +{ + const char *base; + + if (num >= components->num_components) + return; + + /* Offsets are relative to the stat of the book keeping structure. */ + base = (void *)components; + + fw->address = (uint32_t)&base[components->entries[num].offset]; + fw->size = (uint32_t)components->entries[num].size; +} + +static void vboot_wrapper(struct vboot_context *context) +{ + int i; + VbError_t res; + const struct components *components; + + gcontext = context; + + VbExDebug("Calling VbInit()\n"); + res = VbInit(context->cparams, &context->handoff->init_params); + VbExDebug("VbInit() returned 0x%08x\n", res); + + if (res != VBERROR_SUCCESS) + return; + + VbExDebug("Calling VbSelectFirmware()\n"); + res = VbSelectFirmware(context->cparams, context->fparams); + VbExDebug("VbSelectFirmware() returned 0x%08x\n", res); + + if (res != VBERROR_SUCCESS) + return; + + /* Fix up the handoff structure. */ + context->handoff->selected_firmware = + context->fparams->selected_firmware; + + /* Parse out the components for downstream consumption. */ + if (context->handoff->selected_firmware == VB_SELECT_FIRMWARE_A) + components = (void *)context->fw_a; + else if (context->handoff->selected_firmware == VB_SELECT_FIRMWARE_B) + components = (void *)context->fw_b; + else + return; + + for (i = 0; i < MAX_PARSED_FW_COMPONENTS; i++) { + parse_component(components, i, + &context->handoff->components[i]); + } +} + +void VbExError(const char *format, ...) +{ + va_list args; + + va_start(args, format); + gcontext->log_msg(format, args); + va_end(args); + + gcontext->fatal_error(); +} + +void VbExDebug(const char *format, ...) +{ + va_list args; + + va_start(args, format); + gcontext->log_msg(format, args); + va_end(args); +} + +uint64_t VbExGetTimer(void) +{ + return rdtscll(); +} + +VbError_t VbExNvStorageRead(uint8_t *buf) +{ + gcontext->read_vbnv(buf); + return VBERROR_SUCCESS; +} + +VbError_t VbExNvStorageWrite(const uint8_t *buf) +{ + gcontext->save_vbnv(buf); + return VBERROR_SUCCESS; +} + +extern char _heap[]; +extern char _eheap[]; +static char *heap_current; +static int heap_size; + +void *VbExMalloc(size_t size) +{ + void *ptr; + + if (heap_current == NULL) { + heap_current = &_heap[0]; + heap_size = &_eheap[0] - &_heap[0]; + VbExDebug("vboot heap: %p 0x%08x bytes\n", + heap_current, heap_size); + } + + if (heap_size < size) { + VbExError("vboot heap request cannot be fulfilled. " + "0x%08x available, 0x%08x requested\n", + heap_size, size); + } + + ptr = heap_current; + heap_size -= size; + heap_current += size; + + return ptr; +} + +void VbExFree(void *ptr) +{ + /* Leak all memory. */ +} + +/* vboot doesn't expose these through the vboot_api.h, but they are needed. + * coreboot requires declarations so provide them to avoid compiler errors. */ +int Memcmp(const void *src1, const void *src2, size_t n); +void *Memcpy(void *dest, const void *src, uint64_t n); +void *Memset(void *dest, const uint8_t c, uint64_t n); + +int Memcmp(const void *src1, const void *src2, size_t n) +{ + return memcmp(src1, src2, n); +} + +void *Memcpy(void *dest, const void *src, uint64_t n) +{ + return memcpy(dest, src, n); +} + +void *Memset(void *dest, const uint8_t c, uint64_t n) +{ + return memset(dest, c, n); +} + +VbError_t VbExHashFirmwareBody(VbCommonParams *cparams, uint32_t firmware_index) +{ + uint8_t *data; + uint32_t size; + uint32_t data_size; + struct components *components; + uint32_t i; + + switch (firmware_index) { + case VB_SELECT_FIRMWARE_A: + data = gcontext->fw_a; + size = gcontext->fw_a_size; + break; + case VB_SELECT_FIRMWARE_B: + data = gcontext->fw_b; + size = gcontext->fw_b_size; + break; + default: + return VBERROR_UNKNOWN; + } + + components = (void *)data; + data_size = sizeof(struct components); + + if (components->num_components > MAX_NUM_COMPONENTS) + return VBERROR_UNKNOWN; + + data_size += + components->num_components * sizeof(struct component_entry); + + for (i = 0; i < components->num_components; i++) + data_size += ALIGN(components->entries[i].size, 4); + + if (size < data_size) + return VBERROR_UNKNOWN; + + VbUpdateFirmwareBodyHash(cparams, data, data_size); + + return VBERROR_SUCCESS; +} + +VbError_t VbExTpmInit(void) +{ + if (gcontext->tis_init()) + return VBERROR_UNKNOWN; + return VbExTpmOpen(); +} + +VbError_t VbExTpmClose(void) +{ + if (gcontext->tis_close()) + return VBERROR_UNKNOWN; + return VBERROR_SUCCESS; +} + +VbError_t VbExTpmOpen(void) +{ + if (gcontext->tis_open()) + return VBERROR_UNKNOWN; + return VBERROR_SUCCESS; +} + +VbError_t VbExTpmSendReceive(const uint8_t *request, uint32_t request_length, + uint8_t *response, uint32_t *response_length) +{ + if (gcontext->tis_sendrecv(request, request_length, + response, response_length)) + return VBERROR_UNKNOWN; + return VBERROR_SUCCESS; +} + |