diff --git a/Makefile.inc b/Makefile.inc index b4855d0b68..857ad1642b 100644 --- a/Makefile.inc +++ b/Makefile.inc @@ -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 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); }