blob: edf82c5ffd2ba46799f27ad7d091dd4a88ed6083 [file] [log] [blame]
/*
* Copyright 2016 Google Inc.
*
* See file CREDITS for list of people who contributed to this
* project.
*
* 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; either version 2 of
* the License, or (at your option) any later version.
*
* 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., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/
#include <assert.h>
#include <stdio.h>
#include "base/algorithm.h"
#include "base/coreboot/cbfs.h"
#include "base/die.h"
#include "base/xalloc.h"
#include "drivers/board/board_helpers.h"
#include "drivers/layout/coreboot.h"
#include "drivers/storage/cbfs.h"
#include "drivers/storage/fmap.h"
#include "drivers/storage/section_index.h"
#include "net/netboot/params.h"
#include "vboot/board.h"
PRIV_DYN(fmap_media, new_fmap_storage_media(board__coreboot_storage(),
CONFIG_FMAP_OFFSET))
PRIV_DYN(fw_main_a, &new_fmap_storage(get_fmap_media(), "FW_MAIN_A")->ops)
PRIV_DYN(main_a_index, new_section_index_storage(get_fw_main_a()))
PRIV_DYN(fw_main_b, &new_fmap_storage(get_fmap_media(), "FW_MAIN_B")->ops)
PRIV_DYN(main_b_index, new_section_index_storage(get_fw_main_b()))
PUB_DYN(storage_gbb, &new_fmap_storage(get_fmap_media(), "GBB")->ops)
PUB_DYN(storage_fwid_ro, &new_fmap_storage(get_fmap_media(), "RO_FRID")->ops)
PUB_DYN(storage_fwid_rwa, &new_fmap_storage(get_fmap_media(), "RW_FWID_A")->ops)
PUB_DYN(storage_fwid_rwb, &new_fmap_storage(get_fmap_media(), "RW_FWID_B")->ops)
PUB_DYN(storage_legacy, &new_fmap_storage(get_fmap_media(), "RW_LEGACY")->ops)
PUB_DYN(storage_main_fw_a,
&new_section_index_entry_storage(get_main_a_index(), 0)->ops)
PUB_DYN(storage_main_fw_b,
&new_section_index_entry_storage(get_main_b_index(), 0)->ops)
PUB_DYN(storage_nv_scratch, &new_fmap_storage(get_fmap_media(),
"SHARED_DATA")->ops)
PUB_DYN(storage_vblock_a, &new_fmap_storage(get_fmap_media(), "VBLOCK_A")->ops)
PUB_DYN(storage_vblock_b, &new_fmap_storage(get_fmap_media(), "VBLOCK_B")->ops)
PUB_DYN(storage_vboot_nvstorage, &new_fmap_storage(get_fmap_media(),
"RW_NVRAM")->ops)
PUB_DYN(storage_verified_a, &get_main_a_index()->ops)
PUB_DYN(storage_verified_b, &get_main_b_index()->ops)
StorageOps *netboot_params_storage(void)
{
return board_storage_nv_scratch();
}
typedef StorageOps *EcStorageCache[CONFIG_MAX_EC_DEV_IDX + 1];
static StorageOps *board_storage_ec_hash(EcStorageCache *cache,
SectionIndexStorage *index, int devidx)
{
die_if(devidx > ARRAY_SIZE(*cache),
"EC devidx %d is out of bounds.\n", devidx);
if (!(*cache)[devidx]) {
(*cache)[devidx] = &new_section_index_entry_storage(
index, devidx + 1)->ops;
}
return (*cache)[devidx];
}
StorageOps *board_storage_ec_hash_a(int devidx)
{
static EcStorageCache ec_hashes;
return board_storage_ec_hash(&ec_hashes, get_main_a_index(), devidx);
}
StorageOps *board_storage_ec_hash_b(int devidx)
{
static EcStorageCache ec_hashes;
return board_storage_ec_hash(&ec_hashes, get_main_b_index(), devidx);
}
static StorageOps *board_storage_ec(EcStorageCache *cache,
const char *name, int devidx)
{
die_if(devidx > ARRAY_SIZE(*cache),
"EC devidx %d is out of bounds.\n", devidx);
if (!(*cache)[devidx]) {
FmapStorage *fmap_area =
new_fmap_storage(get_fmap_media(), name);
SectionIndexStorage *index =
new_section_index_storage(&fmap_area->ops);
SectionIndexEntryStorage *entry =
new_section_index_entry_storage(index, 0);
(*cache)[devidx] = &entry->ops;
}
return (*cache)[devidx];
}
StorageOps *board_storage_ec_a(int devidx)
{
static EcStorageCache ecs;
const char *name = NULL;
if (devidx == 0)
name = "EC_MAIN_A";
else if (devidx == 1)
name = "PD_MAIN_A";
die_if(!name, "Unrecognized devidx %d.\n", devidx);
return board_storage_ec(&ecs, name, devidx);
}
StorageOps *board_storage_ec_b(int devidx)
{
static EcStorageCache ecs;
const char *name = NULL;
if (devidx == 0)
name = "EC_MAIN_B";
else if (devidx == 1)
name = "PD_MAIN_B";
die_if(!name, "Unrecognized devidx %d.\n", devidx);
return board_storage_ec(&ecs, name, devidx);
}
static const char *image_name[IMAGE_MAX_INDEX] = {
[IMAGE_ARROW_LEFT] = "arrow_left.bmp",
[IMAGE_ARROW_RIGHT] = "arrow_right.bmp",
[IMAGE_BAD_SD] = "BadSD.bmp",
[IMAGE_BAD_USB] = "BadUSB.bmp",
[IMAGE_CHROME_LOGO] = "chrome_logo.bmp",
[IMAGE_DEV_MODE] = "devmode.bmp",
[IMAGE_DIVIDER_TOP] = "divider_top.bmp",
[IMAGE_DIVIDER_BOTTOM] = "divider_btm.bmp",
[IMAGE_FOR_HELP_LEFT] = "for_help_left.bmp",
[IMAGE_ICON_VERIFICATION_OFF] = "VerificationOff.bmp",
[IMAGE_ICON_VERIFICATION_ON] = "VerificationOn.bmp",
[IMAGE_ICON_WARNING] = "Warning.bmp",
[IMAGE_INSERT] = "insert.bmp",
[IMAGE_LANGUAGE] = "language.bmp",
[IMAGE_MODEL] = "model.bmp",
[IMAGE_OS_BROKEN] = "os_broken.bmp",
[IMAGE_REBOOT_ERASE] = "reboot_erase.bmp",
[IMAGE_REMOVE] = "remove.bmp",
[IMAGE_REMOVE_DEVICES] = "RemoveDevices.bmp",
[IMAGE_TO_DEV] = "todev.bmp",
[IMAGE_TO_NORM] = "tonorm.bmp",
[IMAGE_UPDATE] = "update.bmp",
[IMAGE_URL] = "Url.bmp",
[IMAGE_VERIFICIATION_OFF] = "verif_off.bmp",
[IMAGE_VERIFICATION_ON] = "verif_on.bmp",
[IMAGE_YUCK] = "yuck.bmp",
};
typedef CbfsStorage *ImageStorageCache[IMAGE_MAX_INDEX];
static int get_locales(uint32_t *locale_count, char ***supported_locales)
{
static uint32_t count;
static char *supported[256];
if (!count) {
// Load locale list from cbfs.
size_t size;
char *locales = cbfs_get_file_content(
CBFS_DEFAULT_MEDIA, "locales", CBFS_TYPE_RAW, &size);
if (!locales || !size) {
printf("%s: Locale list not found.", __func__);
return 1;
}
// Copy the file and null-terminate it.
char *loc = xmalloc(size + 1);
memcpy(loc, locales, size);
loc[size] = '\0';
free(locales);
locales = loc;
// Parse the list.
printf("%s: Supported locales:", __func__);
while (loc - locales < size && count < ARRAY_SIZE(supported)) {
char *lang = strsep(&loc, "\n");
if (!lang || !strlen(lang))
break;
printf(" %s,", lang);
supported[count++] = lang;
}
printf(" (%d locales)\n", count);
}
*locale_count = count;
*supported_locales = supported;
return 0;
}
int board_storage_locale_count(uint32_t *count)
{
char **locales;
return get_locales(count, &locales);
}
static int check_image_index(BoardImageIdx idx)
{
if (idx >= IMAGE_MAX_INDEX) {
printf("Image index %d out of range.\n", idx);
return 1;
} else {
return 0;
}
}
StorageOps *board_storage_image(BoardImageIdx idx)
{
static ImageStorageCache cache;
assert(!check_image_index(idx));
if (!cache[idx]) {
const char *cbfs_name = image_name[idx];
cache[idx] = new_cbfs_storage(
CBFS_DEFAULT_MEDIA, cbfs_name, CBFS_TYPE_RAW);
}
return &cache[idx]->ops;
}
StorageOps *board_storage_image_locale(uint32_t locale, BoardImageIdx idx)
{
static ImageStorageCache **caches;
uint32_t count;
char **locales;
assert(!get_locales(&count, &locales));
assert(!check_image_index(idx));
die_if(locale >= count, "Locale %d out of bounds.\n", locale);
if (!caches) {
// Construct the cache of image caches, indexed by locale.
caches = xzalloc(sizeof(caches[0]) * count);
}
if (!caches[locale]) {
// If this locale's cache hasn't been allocated, do so now.
caches[locale] = xzalloc(sizeof(*caches[locale]));
}
ImageStorageCache *cache = caches[locale];
if (!(*cache)[idx]) {
// Set up this image's storage ops.
char *cbfs_name = xmalloc(256);
snprintf(cbfs_name, 256, "locale/%s/%s",
locales[locale], image_name[idx]);
(*cache)[idx] = new_cbfs_storage(
CBFS_DEFAULT_MEDIA, cbfs_name, CBFS_TYPE_RAW);
}
CbfsStorage *storage = (*cache)[idx];
return &storage->ops;
}
typedef CbfsStorage *GlyphStorageCache[sizeof(char) * (1 << 8)];
StorageOps *board_storage_glyph(char c)
{
static GlyphStorageCache cache;
int ch = c;
if (!cache[ch]) {
char *cbfs_name = xmalloc(256);
snprintf(cbfs_name, 256, "font/idx%03d_%02x.bmp", c, c);
cache[ch] = new_cbfs_storage(
CBFS_DEFAULT_MEDIA, cbfs_name, CBFS_TYPE_RAW);
}
return &cache[ch]->ops;
}