From 9aea04aa892903009e487ada7f7b911691e68630 Mon Sep 17 00:00:00 2001 From: Stefan Reinauer Date: Fri, 30 Mar 2012 12:01:06 -0700 Subject: 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 Reviewed-on: http://review.coreboot.org/817 Tested-by: build bot (Jenkins) Reviewed-by: Ronald G. Minnich --- src/vendorcode/Makefile.inc | 2 +- src/vendorcode/google/Makefile.inc | 20 +++++ src/vendorcode/google/chromeos/Kconfig | 29 ++++++- src/vendorcode/google/chromeos/Makefile.inc | 25 ++++++ src/vendorcode/google/chromeos/acpi/gnvs.asl | 37 +++++++++ src/vendorcode/google/chromeos/chromeos.c | 37 +++++++++ src/vendorcode/google/chromeos/chromeos.h | 40 ++++++++++ src/vendorcode/google/chromeos/gnvs.c | 88 +++++++++++++++++++++ src/vendorcode/google/chromeos/gnvs.h | 69 +++++++++++++++++ src/vendorcode/google/chromeos/vbnv.c | 109 +++++++++++++++++++++++++++ src/vendorcode/google/chromeos/vboot.c | 63 ++++++++++++---- 11 files changed, 503 insertions(+), 16 deletions(-) create mode 100644 src/vendorcode/google/Makefile.inc create mode 100644 src/vendorcode/google/chromeos/Makefile.inc create mode 100644 src/vendorcode/google/chromeos/acpi/gnvs.asl create mode 100644 src/vendorcode/google/chromeos/chromeos.c create mode 100644 src/vendorcode/google/chromeos/chromeos.h create mode 100644 src/vendorcode/google/chromeos/gnvs.c create mode 100644 src/vendorcode/google/chromeos/gnvs.h create mode 100644 src/vendorcode/google/chromeos/vbnv.c (limited to 'src/vendorcode') diff --git a/src/vendorcode/Makefile.inc b/src/vendorcode/Makefile.inc index 16c0d68497..e6d6bb13a0 100644 --- a/src/vendorcode/Makefile.inc +++ b/src/vendorcode/Makefile.inc @@ -1,2 +1,2 @@ subdirs-y += amd - +subdirs-y += google diff --git a/src/vendorcode/google/Makefile.inc b/src/vendorcode/google/Makefile.inc new file mode 100644 index 0000000000..20d40a8b17 --- /dev/null +++ b/src/vendorcode/google/Makefile.inc @@ -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 diff --git a/src/vendorcode/google/chromeos/Kconfig b/src/vendorcode/google/chromeos/Kconfig index f838b74804..207431d0ec 100644 --- a/src/vendorcode/google/chromeos/Kconfig +++ b/src/vendorcode/google/chromeos/Kconfig @@ -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 diff --git a/src/vendorcode/google/chromeos/Makefile.inc b/src/vendorcode/google/chromeos/Makefile.inc new file mode 100644 index 0000000000..c1b1ccef3e --- /dev/null +++ b/src/vendorcode/google/chromeos/Makefile.inc @@ -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 diff --git a/src/vendorcode/google/chromeos/acpi/gnvs.asl b/src/vendorcode/google/chromeos/acpi/gnvs.asl new file mode 100644 index 0000000000..dc4a0bfbe8 --- /dev/null +++ b/src/vendorcode/google/chromeos/acpi/gnvs.asl @@ -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 diff --git a/src/vendorcode/google/chromeos/chromeos.c b/src/vendorcode/google/chromeos/chromeos.c new file mode 100644 index 0000000000..c1c3b3834c --- /dev/null +++ b/src/vendorcode/google/chromeos/chromeos.c @@ -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 +#include + +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(); +} + diff --git a/src/vendorcode/google/chromeos/chromeos.h b/src/vendorcode/google/chromeos/chromeos.h new file mode 100644 index 0000000000..ec0f3b733a --- /dev/null +++ b/src/vendorcode/google/chromeos/chromeos.h @@ -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 diff --git a/src/vendorcode/google/chromeos/gnvs.c b/src/vendorcode/google/chromeos/gnvs.c new file mode 100644 index 0000000000..8d0f9bb222 --- /dev/null +++ b/src/vendorcode/google/chromeos/gnvs.c @@ -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 +#include +#include +#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)); +} diff --git a/src/vendorcode/google/chromeos/gnvs.h b/src/vendorcode/google/chromeos/gnvs.h new file mode 100644 index 0000000000..36922baac8 --- /dev/null +++ b/src/vendorcode/google/chromeos/gnvs.h @@ -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 diff --git a/src/vendorcode/google/chromeos/vbnv.c b/src/vendorcode/google/chromeos/vbnv.c new file mode 100644 index 0000000000..2129461fc1 --- /dev/null +++ b/src/vendorcode/google/chromeos/vbnv.c @@ -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 +#include +#include +#include +#include +#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]; +} diff --git a/src/vendorcode/google/chromeos/vboot.c b/src/vendorcode/google/chromeos/vboot.c index e0a8c9b336..5bdb7a2b7a 100644 --- a/src/vendorcode/google/chromeos/vboot.c +++ b/src/vendorcode/google/chromeos/vboot.c @@ -21,9 +21,11 @@ #include #include #include +#include #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); } -- cgit v1.2.3