blob: 507e3e3b1d4f354b0e83cb03d64e02766aaba992 [file] [log] [blame]
/*
* Copyright 2013 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 <endian.h>
#include <stdlib.h>
#include <string.h>
#include <coreboot_tables.h>
#include <libpayload.h>
#include <sysinfo.h>
#include "base/device_tree.h"
#include "base/init_funcs.h"
#include "config.h"
#include "image/fmap.h"
#include "vboot/util/commonparams.h"
/* TODO move to common device tree code */
static void bin_prop(ListNode *props, ListNode *old_props,
char *name, void *data, int size)
{
DeviceTreeProperty *prop;
// Check to see if the kernel already had a property with this name.
// To avoid unnecessary overhead, only look through properties that
// were already there under the assumption we won't be trying to
// overwrite something we just added.
if (old_props) {
list_for_each(prop, *old_props, list_node) {
if (!strcmp(prop->prop.name, name)) {
prop->prop.data = data;
prop->prop.size = size;
return;
}
}
}
prop = dt_new_property();
list_insert_after(&prop->list_node, props);
prop->prop.name = name;
prop->prop.data = data;
prop->prop.size = size;
}
/* TODO move to common device tree code */
static void string_prop(ListNode *props, ListNode *old_props,
char *name, char *str)
{
bin_prop(props, old_props, name, str, strlen(str) + 1);
}
/* TODO move to common device tree code */
static void int_prop(ListNode *props, ListNode *old_props,
char *name, uint32_t val)
{
uint32_t *val_ptr = malloc(sizeof(val));
assert(val_ptr);
*val_ptr = htobel(val);
bin_prop(props, old_props, name, val_ptr, sizeof(*val_ptr));
}
static DeviceTreeNode *dt_find_coreboot_node(DeviceTree *tree)
{
DeviceTreeNode *node;
DeviceTreeNode *firmware = NULL;
DeviceTreeNode *coreboot = NULL;
// Find the /firmware node, if one exists.
list_for_each(node, tree->root->children, list_node) {
if (!strcmp(node->name, "firmware")) {
firmware = node;
break;
}
}
// Make one if it didn't.
if (!firmware) {
firmware = dt_new_node();
firmware->name = "firmware";
list_insert_after(&firmware->list_node, &tree->root->children);
}
// Find the /firmware/coreboot node, if one exists
list_for_each(node, firmware->children, list_node) {
if (!strcmp(node->name, "coreboot")) {
coreboot = node;
break;
}
}
// Make one if it didn't.
if (!coreboot) {
coreboot = dt_new_node();
coreboot->name = "coreboot";
list_insert_after(&coreboot->list_node, &firmware->children);
}
return coreboot;
}
static int install_coreboot_data(DeviceTreeFixup *fixup, DeviceTree *tree)
{
DeviceTreeNode *coreboot = dt_find_coreboot_node(tree);
ListNode *props = &coreboot->properties;
ListNode *old = coreboot->properties.next;
string_prop(props, old, "compatible", "coreboot");
void *blob;
int size, i;
if (find_common_params(&blob, &size))
return 1;
struct memrange *range = NULL;
for (i = lib_sysinfo.n_memranges - 1; i >= 0; i--) {
if (lib_sysinfo.memrange[i].type == CB_MEM_TABLE) {
range = &lib_sysinfo.memrange[i];
break;
}
}
if (!range)
return 1;
int_prop(props, old, "coreboot-memory", range->base);
int_prop(props, old, "coreboot-table", (unsigned long)lib_sysinfo.header);
return 0;
}
static DeviceTreeFixup coreboot_fixup = {
&install_coreboot_data
};
int coreboot_setup(void)
{
list_insert_after(&coreboot_fixup.list_node, &device_tree_fixups);
return 0;
}
INIT_FUNC(coreboot_setup);