mirror of
https://github.com/Telecominfraproject/OpenCellular.git
synced 2026-01-09 00:51:29 +00:00
BUG=chrome-os-partner:7459 TEST=manual In the chroot: cd src/platform/ec make BOARD=link The firmware image (build/link/ec.bin) is signed with dev-keys. Reflash the EC and try it, and it should verify and reboot into RW A. Additional tests (setting USE_RO_NORMAL, poking random values into VBLOCK_A or FW_MAIN_A to force RW B to run, etc.) are left as an exercise for the reader. I've done them and they work, though. Change-Id: I29a23ea69aef02a11aebd4af3b043f6864723523 Signed-off-by: Bill Richardson <wfrichar@chromium.org>
169 lines
4.0 KiB
C
169 lines
4.0 KiB
C
/* Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
|
|
* Use of this source code is governed by a BSD-style license that can be
|
|
* found in the LICENSE file.
|
|
*/
|
|
|
|
/* Functions needed by vboot library */
|
|
|
|
#define _STUB_IMPLEMENTATION_
|
|
#include "console.h"
|
|
#include "shared_mem.h"
|
|
#include "util.h"
|
|
#include "utility.h"
|
|
|
|
/* Console output macros */
|
|
#define CPUTS(outstr) cputs(CC_VBOOT, outstr)
|
|
#define CPRINTF(format, args...) cprintf(CC_VBOOT, format, ## args)
|
|
|
|
#if 0 /* change this to debug memory usage */
|
|
#define DPRINTF CPRINTF
|
|
#else
|
|
#define DPRINTF(...)
|
|
#endif
|
|
|
|
|
|
/****************************************************************************/
|
|
|
|
void *Memcpy(void *dest, const void *src, uint64_t n)
|
|
{
|
|
return memcpy(dest, src, (size_t)n);
|
|
}
|
|
|
|
void *Memset(void *d, const uint8_t c, uint64_t n)
|
|
{
|
|
return memset(d, c, n);
|
|
}
|
|
|
|
int Memcmp(const void *src1, const void *src2, size_t n)
|
|
{
|
|
size_t i;
|
|
const uint8_t *a = src1;
|
|
const uint8_t *b = src2;
|
|
for (i = 0; i < n; i++) {
|
|
if (*a != *b)
|
|
return (*a < *b) ? -1 : 1;
|
|
a++;
|
|
b++;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/****************************************************************************/
|
|
/* The vboot_api library requires some dynamic memory, but we don't have
|
|
* malloc/free. Instead we have one chunk of shared RAM that we can gain
|
|
* exclusive access to for a time. We'll have to experiment with various
|
|
* algorithms to see what works best. This algorithm allocates and
|
|
* reuses blocks, but never actually frees anything until all memory has been
|
|
* reclaimed. */
|
|
|
|
/* Since we only need this stuff to boot, don't waste run-time .bss */
|
|
static struct {
|
|
int bucket_size; /* total RAM available */
|
|
uint8_t *out_base; /* malloc from here */
|
|
int out_count; /* number of active mallocs */
|
|
int out_size; /* high-water mark */
|
|
|
|
/* We have a limited number of active mallocs. We never free, but we
|
|
* do reuse slots. */
|
|
#define MAX_SLOTS 8
|
|
struct {
|
|
int in_use; /* is this slot active? */
|
|
void *ptr; /* starts here */
|
|
size_t size; /* how big */
|
|
} slots[MAX_SLOTS];
|
|
} *bucket;
|
|
|
|
|
|
void *VbExMalloc(size_t size)
|
|
{
|
|
int i, j;
|
|
void *ptr = 0;
|
|
|
|
if (!bucket) {
|
|
i = shared_mem_size();
|
|
if (EC_SUCCESS != shared_mem_acquire(i, 1, (char **)&bucket)) {
|
|
CPRINTF("FAILED at %s:%d\n", __FILE__, __LINE__);
|
|
ASSERT(0);
|
|
}
|
|
Memset(bucket, 0, sizeof(*bucket));
|
|
bucket->bucket_size = i;
|
|
bucket->out_base = (uint8_t *)(bucket + 1);
|
|
bucket->out_size = sizeof(*bucket);
|
|
DPRINTF("grab the bucket: at 0x%x, size 0x%x\n",
|
|
bucket, bucket->bucket_size);
|
|
}
|
|
|
|
if (size % 8) {
|
|
int tmp = (size + 8) & ~0x7ULL;
|
|
DPRINTF(" %d -> %d\n", size, tmp);
|
|
size = tmp;
|
|
}
|
|
|
|
for (i = 0; i < MAX_SLOTS; i++) {
|
|
if (!bucket->slots[i].in_use) {
|
|
|
|
/* Found an empty one, but reuse the same size if one
|
|
* already exists. */
|
|
for (j = i; j < MAX_SLOTS; j++) {
|
|
if (!bucket->slots[j].in_use &&
|
|
size == bucket->slots[j].size) {
|
|
/* empty AND same size */
|
|
bucket->slots[j].in_use = 1;
|
|
ptr = bucket->slots[j].ptr;
|
|
DPRINTF(" = %d (%d)\n", j, size);
|
|
goto out;
|
|
}
|
|
}
|
|
|
|
/* no exact matches, must allocate a new chunk */
|
|
ptr = bucket->out_base + bucket->out_size;
|
|
bucket->out_size += size;
|
|
|
|
bucket->slots[i].in_use = 1;
|
|
bucket->slots[i].ptr = ptr;
|
|
bucket->slots[i].size = size;
|
|
DPRINTF(" + %d (%d)\n", i, size);
|
|
goto out;
|
|
}
|
|
}
|
|
|
|
CPRINTF("FAILED: no empty slots (%d/%d)\n", i, MAX_SLOTS);
|
|
ASSERT(0);
|
|
|
|
out:
|
|
bucket->out_count++;
|
|
if (bucket->out_size >= bucket->bucket_size) {
|
|
CPRINTF("FAILED: out of memory (%d/%d)\n",
|
|
bucket->out_size, bucket->bucket_size);
|
|
ASSERT(0);
|
|
}
|
|
|
|
return ptr;
|
|
}
|
|
|
|
|
|
void VbExFree(void *ptr)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < MAX_SLOTS; i++) {
|
|
if (ptr == bucket->slots[i].ptr) {
|
|
bucket->slots[i].in_use = 0;
|
|
DPRINTF(" - %d (%d)\n", i, bucket->slots[i].size);
|
|
break;
|
|
}
|
|
}
|
|
if (MAX_SLOTS == i) {
|
|
CPRINTF("FAILED: can't find ptr %x!\n", ptr);
|
|
ASSERT(0);
|
|
}
|
|
|
|
bucket->out_count--;
|
|
if (!bucket->out_count) {
|
|
DPRINTF("dump the bucket: max used = %d\n", bucket->out_size);
|
|
shared_mem_release(bucket);
|
|
bucket = 0;
|
|
}
|
|
}
|