Add Google ChromeOS vendor support

Google's ChromeOS can be booted super fast and safely
using coreboot. This adds the ChromeOS specific code that
is required by all ChromeBooks to do this.

Change-Id: Ic03ff090a569a27acbd798ce1e5f89a34897a2f2
Signed-off-by: Stefan Reinauer <reinauer@google.com>
Reviewed-on: http://review.coreboot.org/817
Tested-by: build bot (Jenkins)
Reviewed-by: Ronald G. Minnich <rminnich@gmail.com>
This commit is contained in:
Stefan Reinauer 2012-03-30 12:01:06 -07:00 committed by Stefan Reinauer
parent c302d20ed3
commit 9aea04aa89
12 changed files with 504 additions and 16 deletions

View File

@ -43,6 +43,7 @@ subdirs-y += src/northbridge src/superio src/drivers src/cpu src/vendorcode
subdirs-y += util/cbfstool util/sconfig
subdirs-y += src/arch/$(ARCHDIR-y)
subdirs-y += src/mainboard/$(MAINBOARDDIR)
subdirs-y += src/vendorcode
subdirs-$(CONFIG_ARCH_X86) += src/pc80

View File

@ -1,2 +1,2 @@
subdirs-y += amd
subdirs-y += google

View File

@ -0,0 +1,20 @@
##
## This file is part of the coreboot project.
##
## Copyright (C) 2011 The ChromiumOS Authors. All rights reserved.
##
## 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
##
subdirs-$(CONFIG_CHROMEOS) += chromeos

View File

@ -22,7 +22,34 @@ config CHROMEOS
select TPM
select CACHE_ROM
help
Enable ChromeOS specific features
Enable ChromeOS specific features like the GPIO sub table in
the coreboot table. NOTE: Enabling this option on an unsupported
board will most likely break your build.
config VBNV_OFFSET
hex
default 0x26
help
CMOS offset for VbNv data. This value must match cmos.layout
in the mainboard directory, minus 14 bytes for the RTC.
config VBNV_SIZE
hex
default 0x10
help
CMOS storage size for VbNv data. This value must match cmos.layout
in the mainboard directory.
config CHROMEOS_RAMOOPS
bool "Reserve space for Chrome OS ramoops"
default y
config CHROMEOS_RAMOOPS_RAM_START
hex "Physical address of preserved RAM"
default 0x00f00000
depends on CHROMEOS_RAMOOPS
config CHROMEOS_RAMOOPS_RAM_SIZE
hex "Size of preserved RAM"
default 0x00100000
depends on CHROMEOS_RAMOOPS

View File

@ -0,0 +1,25 @@
##
## This file is part of the coreboot project.
##
## Copyright (C) 2011 The ChromiumOS Authors. All rights reserved.
##
## 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
##
romstage-y += chromeos.c
ramstage-y += chromeos.c
romstage-y += vbnv.c
ramstage-y += vbnv.c
romstage-y += vboot.c
ramstage-y += gnvs.c

View File

@ -0,0 +1,37 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2011 The ChromiumOS Authors. All rights reserved.
*
* 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
*/
/* This is the ChromeOS specific ACPI information needed by
* the mainboard's chromeos.asl
*/
VBT0, 32, // 0x000 - Boot Reason
VBT1, 32, // 0x004 - Active Main Firmware
VBT2, 32, // 0x008 - Active EC Firmware
VBT3, 16, // 0x00c - CHSW
VBT4, 2048, // 0x00e - HWID
VBT5, 512, // 0x10e - FWID
VBT6, 512, // 0x14e - FRID
VBT7, 32, // 0x18e - active main firmware type
VBT8, 32, // 0x192 - Recovery Reason
VBT9, 32, // 0x196 - FMAP base address
CHVD, 24576, // 0x19a - VDAT space filled by verified boot
VBTA, 32, // 0xd9a - pointer to smbios FWID
MEHH, 256, // 0xd9e - Management Engine Hash
// 0xdbe

View File

@ -0,0 +1,37 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2011 The ChromiumOS Authors. All rights reserved.
*
* 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 "chromeos.h"
#include <arch/coreboot_tables.h>
#include <console/console.h>
int developer_mode_enabled(void)
{
return get_developer_mode_switch();
}
int recovery_mode_enabled(void)
{
/* TODO(reinauer): get information from VbInit.
* the recovery mode switch is not the only reason to go
* to recovery mode.
*/
return get_recovery_mode_switch() || get_recovery_mode_from_vbnv();
}

View File

@ -0,0 +1,40 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2011 The ChromiumOS Authors. All rights reserved.
*
* 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
*/
#ifndef __CHROMEOS_H__
#define __CHROMEOS_H__
/* functions implemented per mainboard: */
int get_developer_mode_switch(void);
int get_recovery_mode_switch(void);
#ifdef __PRE_RAM__
void save_chromeos_gpios(void);
#endif
/* functions implemented in vbnv.c: */
int get_recovery_mode_from_vbnv(void);
/* functions implemented in chromeos.c: */
int developer_mode_enabled(void);
int recovery_mode_enabled(void);
/* functions implemented in vboot.c */
void init_chromeos(int bootmode);
#endif

View File

@ -0,0 +1,88 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2011 The ChromiumOS Authors. All rights reserved.
*
* 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 <types.h>
#include <cbfs.h>
#include <console/console.h>
#include "gnvs.h"
chromeos_acpi_t *vboot_data;
static u32 me_hash_saved[8];
void chromeos_init_vboot(chromeos_acpi_t *chromeos)
{
vboot_data = chromeos;
/* Copy saved ME hash into NVS */
memcpy(vboot_data->mehh, me_hash_saved, sizeof(vboot_data->mehh));
}
void chromeos_set_vboot_data_ptr(void *blob)
{
/* This code has to be rewritten to pass the vboot table
* pointer through the coreboot table instead of the
* FDT, since FDT support was rejected upstream. For now
* just make the code available for reference.
*/
#if 0 // CONFIG_ADD_FDT
int node_offset, addr_cell_len;
const u32 *cell;
uintptr_t table_addr = (uintptr_t)vboot_data;
u32 table_addr32;
u64 table_addr64;
void *table_ptr;
cell = fdt_getprop(blob, 0, "#address-cells", NULL);
if (cell && *cell == 2) {
addr_cell_len = 8;
table_addr64 = cpu_to_fdt64(table_addr);
table_ptr = &table_addr64;
} else {
addr_cell_len = 4;
table_addr32 = cpu_to_fdt32(table_addr);
table_ptr = &table_addr32;
}
node_offset = fdt_path_offset(blob, "/chromeos-config");
if (node_offset < 0) {
printk(BIOS_ERR,
"Couldn't find /chromeos-config in the fdt.\n");
return;
}
if (fdt_setprop(blob, node_offset, "gnvs-vboot-table",
table_ptr, addr_cell_len) < 0) {
printk(BIOS_ERR, "Couldn't set gnvs-vboot-table.\n");
}
#else
printk(BIOS_ERR, "Can't set gnvs-vboot-table.\n");
#endif
}
void chromeos_set_me_hash(u32 *hash, int len)
{
if ((len*sizeof(u32)) > sizeof(vboot_data->mehh))
return;
/* Copy to NVS or save until it is ready */
if (vboot_data)
memcpy(vboot_data->mehh, hash, len*sizeof(u32));
else
memcpy(me_hash_saved, hash, len*sizeof(u32));
}

View File

@ -0,0 +1,69 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2011 The ChromiumOS Authors. All rights reserved.
*
* 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
*/
#ifndef __VENDORCODE_GOOGLE_CHROMEOS_GNVS_H
#define __VENDORCODE_GOOGLE_CHROMEOS_GNVS_H
#define BOOT_REASON_OTHER 0
#define BOOT_REASON_S3DIAG 9
#define CHSW_RECOVERY_X86 (1 << 1)
#define CHSW_RECOVERY_EC (1 << 2)
#define CHSW_DEVELOPER_SWITCH (1 << 5)
#define CHSW_FIRMWARE_WP_DIS (1 << 9)
#define ACTIVE_MAINFW_RECOVERY 0
#define ACTIVE_MAINFW_RW_A 1
#define ACTIVE_MAINFW_RW_B 2
#define ACTIVE_MAINFW_TYPE_RECOVERY 0
#define ACTIVE_MAINFW_TYPE_NORMAL 1
#define ACTIVE_MAINFW_TYPE_DEVELOPER 2
#define RECOVERY_REASON_NONE 0
#define RECOVERY_REASON_ME 1
// TODO(reinauer) other recovery reasons?
#define ACTIVE_ECFW_RO 0
#define ACTIVE_ECFW_RW 1
typedef struct {
/* ChromeOS specific */
u32 vbt0; // 00 boot reason
u32 vbt1; // 04 active main firmware
u32 vbt2; // 08 active ec firmware
u16 vbt3; // 0c CHSW
u8 vbt4[256]; // 0e HWID
u8 vbt5[64]; // 10e FWID
u8 vbt6[64]; // 14e FRID - 275
u32 vbt7; // 18e active main firmware type
u32 vbt8; // 192 recovery reason
u32 vbt9; // 196 fmap base address
u8 vdat[3072]; // 19a
u32 vbt10; // d9a smbios bios version
u32 mehh[8]; // d9e management engine hash
// dbe
} __attribute__((packed)) chromeos_acpi_t;
extern chromeos_acpi_t *vboot_data;
void chromeos_init_vboot(chromeos_acpi_t *chromeos);
void chromeos_set_vboot_data_ptr(void *);
void chromeos_set_me_hash(u32*, int);
#endif

View File

@ -0,0 +1,109 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2011 The ChromiumOS Authors. All rights reserved.
*
* 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 <types.h>
#include <string.h>
#include <console/console.h>
#include <pc80/mc146818rtc.h>
#include <cpu/x86/car.h>
#include "chromeos.h"
#define VBNV_BLOCK_SIZE 16 /* Size of NV storage block in bytes */
/* Constants for NV storage. We use this rather than structs and
* bitfields so the data format is consistent across platforms and
* compilers.
*/
#define HEADER_OFFSET 0
#define HEADER_MASK 0xC0
#define HEADER_SIGNATURE 0x40
#define HEADER_FIRMWARE_SETTINGS_RESET 0x20
#define HEADER_KERNEL_SETTINGS_RESET 0x10
#define BOOT_OFFSET 1
#define BOOT_DEBUG_RESET_MODE 0x80
#define BOOT_TRY_B_COUNT_MASK 0x0F
#define RECOVERY_OFFSET 2
#define LOCALIZATION_OFFSET 3
#define DEV_FLAGS_OFFSET 4
#define DEV_BOOT_USB_MASK 0x01
#define FIRMWARE_FLAGS_OFFSET 5
#define FIRMWARE_TEST_ERR_FUNC_MASK 0x38
#define FIRMWARE_TEST_ERR_FUNC_SHIFT 3
#define FIRMWARE_TEST_ERR_NUM_MASK 0x07
#define KERNEL_FIELD_OFFSET 11
#define CRC_OFFSET 15
static int vbnv_initialized CAR_GLOBAL;
uint8_t vbnv[CONFIG_VBNV_SIZE] CAR_GLOBAL;
/* Return CRC-8 of the data, using x^8 + x^2 + x + 1 polynomial. A
* table-based algorithm would be faster, but for only 15 bytes isn't
* worth the code size.
*/
static uint8_t crc8(const uint8_t * data, int len)
{
unsigned crc = 0;
int i, j;
for (j = len; j; j--, data++) {
crc ^= (*data << 8);
for (i = 8; i; i--) {
if (crc & 0x8000)
crc ^= (0x1070 << 3);
crc <<= 1;
}
}
return (uint8_t) (crc >> 8);
}
static void vbnv_setup(void)
{
int i;
for (i = 0; i < CONFIG_VBNV_SIZE; i++)
vbnv[i] = cmos_read(CONFIG_VBNV_OFFSET + 14 + i);
/* Check data for consistency */
if ((HEADER_SIGNATURE != (vbnv[HEADER_OFFSET] & HEADER_MASK))
|| (crc8(vbnv, CRC_OFFSET) != vbnv[CRC_OFFSET])) {
/* Data is inconsistent (bad CRC or header),
* so reset to defaults
*/
memset(vbnv, 0, VBNV_BLOCK_SIZE);
vbnv[HEADER_OFFSET] =
(HEADER_SIGNATURE | HEADER_FIRMWARE_SETTINGS_RESET |
HEADER_KERNEL_SETTINGS_RESET);
}
vbnv_initialized = 1;
}
int get_recovery_mode_from_vbnv(void)
{
if (!vbnv_initialized)
vbnv_setup();
return vbnv[RECOVERY_OFFSET];
}

View File

@ -21,9 +21,11 @@
#include <console/console.h>
#include <arch/acpi.h>
#include <pc80/tpm.h>
#include <reset.h>
#include "chromeos.h"
//#define EXTRA_LOGGING
#define UBOOT_DOES_TPM_STARTUP
#define TPM_LARGE_ENOUGH_COMMAND_SIZE 256 /* saves space in the firmware */
@ -43,6 +45,12 @@ static const struct {
{ 0x0, 0xc1, 0x0, 0x0, 0x0, 0xc, 0x0, 0x0, 0x0, 0x99, 0x0, 0x2 }
};
static const struct {
u8 buffer[12];
} tpm_startup_cmd = {
{0x0, 0xc1, 0x0, 0x0, 0x0, 0xc, 0x0, 0x0, 0x0, 0x99, 0x0, 0x1 }
};
static const struct {
u8 buffer[10];
} tpm_continueselftest_cmd = {
@ -169,33 +177,60 @@ static u32 TlclSendReceive(const u8 * request, u8 * response, int max_length)
return result;
}
void init_vboot(void)
static void init_vboot(int bootmode)
{
u32 result;
u8 response[TPM_LARGE_ENOUGH_COMMAND_SIZE];
printk(BIOS_DEBUG, "TPM: Init\n");
#ifdef UBOOT_DOES_TPM_STARTUP
/* Doing TPM startup when we're not coming in on the S3 resume path
* saves us roughly 20ms in boot time only. This does not seem to
* be worth an API change to vboot_reference-firmware right now, so
* let's keep the code around, but just bail out early:
*/
if (bootmode != 2)
return;
#endif
printk(BIOS_DEBUG, "Verified boot TPM initialization.\n");
printk(BIOS_SPEW, "TPM: Init\n");
if (tis_init())
return;
printk(BIOS_DEBUG, "TPM: Open\n");
printk(BIOS_SPEW, "TPM: Open\n");
if (tis_open())
return;
printk(BIOS_DEBUG, "TPM: Resume\n");
result =
TlclSendReceive(tpm_resume_cmd.buffer, response, sizeof(response));
if (result == TPM_E_INVALID_POSTINIT) {
/* We're on a platform where the TPM maintains power in S3, so
* it's already initialized. */
printk(BIOS_DEBUG, "TPM: Already initialized.\n");
return;
if (bootmode == 2) {
/* S3 Resume */
printk(BIOS_SPEW, "TPM: Resume\n");
result = TlclSendReceive(tpm_resume_cmd.buffer,
response, sizeof(response));
if (result == TPM_E_INVALID_POSTINIT) {
/* We're on a platform where the TPM maintains power
* in S3, so it's already initialized.
*/
printk(BIOS_DEBUG, "TPM: Already initialized.\n");
return;
}
} else {
printk(BIOS_SPEW, "TPM: Startup\n");
result = TlclSendReceive(tpm_startup_cmd.buffer,
response, sizeof(response));
}
if (result == TPM_SUCCESS) {
printk(BIOS_DEBUG, "TPM: OK.\n");
printk(BIOS_SPEW, "TPM: OK.\n");
return;
}
// TODO(reinauer) hard reboot?
printk(BIOS_ERR, "TPM: Error code 0x%x. Hard reset!\n", result);
hard_reset();
}
void init_chromeos(int bootmode)
{
init_vboot(bootmode);
}