Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(294)

Unified Diff: arch/arm/cpu/arm_cortexa9/tegra2/warmboot.c

Issue 4841001: Tegra2: implement Warmboot code and lp0_vec (Closed) Base URL: http://git.chromium.org/git/u-boot-next.git@chromeos-v2010.09
Patch Set: Add CONFIG_TEGRA2_LP0 to support LP0 conditionally Created 10 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: arch/arm/cpu/arm_cortexa9/tegra2/warmboot.c
diff --git a/arch/arm/cpu/arm_cortexa9/tegra2/warmboot.c b/arch/arm/cpu/arm_cortexa9/tegra2/warmboot.c
new file mode 100755
index 0000000000000000000000000000000000000000..36213170c9137b5fe59a09d3e1bce495f70d1f18
--- /dev/null
+++ b/arch/arm/cpu/arm_cortexa9/tegra2/warmboot.c
@@ -0,0 +1,321 @@
+/*
+ * (C) Copyright 2010
+ * NVIDIA Corporation <www.nvidia.com>
+ *
+ * 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 <common.h>
+#include <asm/arch/nv_drf.h>
+#include <asm/arch/nvboot_error.h>
+#include <asm/arch/nvcommon.h>
+#include <asm/arch/nverror.h>
+#include <asm/arch/tegra2.h>
+#include <asm/arch/nv_hardware_access.h>
+#include <asm/arch/warmboot.h>
+
+NvBootError sign_data_block(NvU8 *source,
+ NvU32 length,
+ NvU8 *hash);
+
+/* -------------------------------------
+ * Configuration parameters
+ * -------------------------------------
+ */
+
+/* -------------------------------------
+ * Definitions
+ * -------------------------------------
+ */
+
+/* NOTE: If more than one of the following is enabled, only one of them will
+ * actually be used. RANDOM takes precedence over PATTERN and ZERO, and
+ * PATTERN takes precedence overy ZERO.
+ */
+#define RANDOM_AES_BLOCK_IS_RANDOM 1 /* Set nonzero to randomize the header */
+#define RANDOM_AES_BLOCK_IS_PATTERN 1 /* Set nonzero to patternize the header */
+#define RANDOM_AES_BLOCK_IS_ZERO 1 /* Set nonzero to clear the header */
+
+/* Address at which AP20 WB0 code runs */
+/* The address must not overlap the bootrom's IRAM usage */
+#define AP20_WB0_RUN_ADDRESS 0x40020000
+#define AP20_IRAM_BASE 0x40000000
+
+/* -------------------------------------
+ * Global External Labels
+ * -------------------------------------
+ */
+
+void wb_start(void); /* Start of WB assembly code */
+void wb_end(void); /* End of WB assembly code */
+
+#define NV_ADDRESS_MAP_FUSE_BASE 0x7000F800UL
+#define FUSE_PRODUCTION_MODE_0 _MK_ADDR_CONST(0x100)
+#define FUSE_FA_0 _MK_ADDR_CONST(0x148)
+#define FUSE_SECURITY_MODE_0 _MK_ADDR_CONST(0x1a0)
+
+/* -------------------------------------
+ * Local Functions
+ * -------------------------------------
+ */
+static NvU32 get_major_version(void)
+{
+ NvU32 reg = 0;
+ NvU32 major_id = 0;
+
+ reg = NV_READ32( NV_ADDRESS_MAP_APB_MISC_BASE + APB_MISC_GP_HIDREV_0) ;
+ major_id = NV_DRF_VAL(APB_MISC, GP_HIDREV, MAJORREV, reg);
+ return major_id;
+}
+
+static NvBool is_production_mode_fuse_set(void)
+{
+ NvU32 reg;
+
+ reg = NV_READ32(NV_ADDRESS_MAP_FUSE_BASE + FUSE_PRODUCTION_MODE_0);
+ if (reg)
+ return NV_TRUE;
+ else
+ return NV_FALSE;
+}
+
+static NvBool is_odm_production_mode_fuse_set(void)
+{
+ NvU32 reg;
+
+ reg = NV_READ32(NV_ADDRESS_MAP_FUSE_BASE + FUSE_SECURITY_MODE_0);
+ if (reg)
+ return NV_TRUE;
+ else
+ return NV_FALSE;
+}
+
+static NvBool ap20_is_failure_analysis_mode(void)
+{
+ volatile NvU32 reg;
+
+ reg = NV_READ32(NV_ADDRESS_MAP_FUSE_BASE + FUSE_FA_0);
+ if (reg)
+ return NV_TRUE;
+ else
+ return NV_FALSE;
+}
+
+static NvBool ap20_is_odm_production_mode(void)
+{
+ if (!ap20_is_failure_analysis_mode() &&
+ is_odm_production_mode_fuse_set())
+ return NV_TRUE;
+ else
+ return NV_FALSE;
+}
+
+static NvBool ap20_is_production_mode(void)
+{
+ if (get_major_version() == 0)
+ return NV_TRUE;
+
+ if (!ap20_is_failure_analysis_mode() &&
+ is_production_mode_fuse_set() &&
+ !is_odm_production_mode_fuse_set())
+ return NV_TRUE;
+ else
+ return NV_FALSE;
+}
+
+static NvBool fuse_get_ap20_hal(nv_fuse_hal *hal)
+{
+ NvU32 reg;
+
+ reg = NV_READ32(NV_ADDRESS_MAP_APB_MISC_BASE + APB_MISC_GP_HIDREV_0);
+ if (NV_DRF_VAL(APB_MISC_GP, HIDREV, CHIPID, reg) == 0x20) {
+ hal->is_odm_production_mode = ap20_is_odm_production_mode;
+ hal->is_nv_production_mode = ap20_is_production_mode;
+ return NV_TRUE;
+ }
+ return NV_FALSE;
+}
+
+static nvbl_operating_mode nv_fuse_get_operation_mode(void)
+{
+ nv_fuse_hal hal;
+ if (fuse_get_ap20_hal(&hal)) {
+ if (hal.is_odm_production_mode()) {
+ printf("!!! OdmProductionMode is not supported !!!\n");
+ return nvbl_mode_undefined;
+ } else {
+ if (hal.is_nv_production_mode())
+ return nvbl_mode_production;
+ else
+ return nvbl_mode_undefined;
+ }
+ }
+ return nvbl_mode_undefined;
+}
+
+static NvU64 query_random_seed(void)
+{
+ return 0;
+}
+
+static void determine_crypto_options(NvBool* is_encrypted, NvBool* is_signed, NvBool* use_zero_key)
+{
+ switch (nv_fuse_get_operation_mode()) {
+ case nvbl_mode_production:
+ *is_encrypted = NV_FALSE;
+ *is_signed = NV_TRUE;
+ *use_zero_key = NV_TRUE;
+ break;
+
+ case nvbl_mode_undefined:
+ default:
+ *is_encrypted = NV_FALSE;
+ *is_signed = NV_FALSE;
+ *use_zero_key = NV_FALSE;
+ break;
+ }
+}
+
+static NvBootError sign_wb_code(NvU32 start, NvU32 length, NvBool use_zero_key)
+{
+ NvBootError e;
+ NvU8 *source; /* Pointer to source */
+ NvU8 *hash;
+
+ /* Calculate AES block parameters. */
+ source = (NvU8 *)(start + offsetof(nvboot_wb_header, random_aes_block));
+ length -= offsetof(nvboot_wb_header, random_aes_block);
+ hash = (NvU8 *)(start + offsetof(nvboot_wb_header, hash));
+ e = sign_data_block(source, length, hash);
+ return e;
+}
+
+/* -------------------------------------
+ * Global Functions
+ * -------------------------------------
+ */
+
+NvBootError prepare_wb_code(NvU32 seg_address, NvU32 seg_length)
+{
+ NvBootError e = NvBootError_NotInitialized; /* Error code */
+
+ NvU32 start; /* start of the actual code */
+ NvU32 end; /* end of the actual code */
+ NvU32 actual_length; /* length of the actual code */
+ NvU32 length; /* length of the signed/encrypted code */
+ nvboot_wb_header *src_header; /* Pointer to source WB0 header */
+ nvboot_wb_header *dst_header; /* Pointer to destination WB0 header */
+ NvBool is_encrypted; /* Segment is encrypted */
+ NvBool is_signed; /* Segment is signed */
+ NvBool use_zero_key; /* Use key of all zeros */
+
+ /* Determine crypto options. */
+ determine_crypto_options(&is_encrypted, &is_signed, &use_zero_key);
+
+ /* Get the actual code limits. */
+ start = (NvU32)wb_start;
+ end = (NvU32)wb_end;
+ actual_length = end - start;
+ length = ((actual_length + 15) >> 4) << 4;
+
+ /* The region specified by seg_address must be in SDRAM and must be
+ * nonzero in length.
+ */
+ if ((seg_length == 0) ||(seg_address == 0) ||
+ (seg_address >= AP20_IRAM_BASE)) {
+ goto fail;
+ }
+
+ /* Things must be 16-byte aligned. */
+ if ((seg_length & 0xF) || (seg_address & 0xF)) {
+ goto fail;
+ }
+
+ /* Will the code fit? */
+ if (seg_length < length) {
+ goto fail;
+ }
+
+ /* Get a pointers to the source and destination region header. */
+ src_header = (nvboot_wb_header*)start;
+ dst_header = (nvboot_wb_header*)seg_address;
+
+ /* Populate the random_aes_block as requested. */
+#if RANDOM_AES_BLOCK_IS_RANDOM
+ {
+ NvU64 *pRandomAesBlock = (NvU64*)&(src_header->random_aes_block);
+ NvU64 *pEnd = (NvU64*)(((NvU32)pRandomAesBlock) +
+ sizeof(src_header->random_aes_block));
+ do {
+ *pRandomAesBlock++ = query_random_seed();
+ } while (pRandomAesBlock < pEnd);
+ }
+#elif RANDOM_AES_BLOCK_IS_PATTERN
+ {
+ NvU32 *pRandomAesBlock = (NvU32*)&(src_header->random_aes_block);
+ NvU32 *pEnd = (NvU32*)(((NvU32)pRandomAesBlock) +
+ sizeof(src_header->random_aes_block));
+
+ do {
+ *pRandomAesBlock++ = RANDOM_AES_BLOCK_IS_PATTERN;
+ } while (pRandomAesBlock < pEnd);
+ }
+#elif RANDOM_AES_BLOCK_IS_ZERO
+ {
+ NvU32 *pRandomAesBlock = (NvU32*)&(src_header->random_aes_block);
+ NvU32 *pEnd = (NvU32*)(((NvU32)pRandomAesBlock) +
+ sizeof(src_header->random_aes_block));
+
+ do {
+ *pRandomAesBlock++ = 0;
+ } while (pRandomAesBlock < pEnd);
+ }
+#endif
+
+ /* Populate the header. */
+ src_header->length_in_secure = length;
+ src_header->length_secure = length;
+ src_header->destination = AP20_WB0_RUN_ADDRESS;
+ src_header->entry_point = AP20_WB0_RUN_ADDRESS;
+ src_header->code_length = length - sizeof(nvboot_wb_header);
+
+ if (is_encrypted) {
+ /* Encryption is not supported */
+ printf("!!!! No Encrypion implemented!!!!\n");
+ dst_header->length_in_secure = 0;
+ e = NvBootError_Unimplemented;
+ goto fail;
+ } else {
+ /* No, just copy the code directly. */
+ memcpy(dst_header, src_header, length);
+ }
+
+ /* Clear the signature in the destination code segment. */
+ memset(&(dst_header->hash), 0, sizeof(dst_header->hash));
+
+ if (is_signed) {
+ NV_CHECK_ERROR_CLEANUP(sign_wb_code(seg_address, length, use_zero_key));
+ }
+
+fail:
+ if (e != NvBootError_Success)
+ printf("WB0 code is not copied to LP0 location !!! (error=0x%x)\n", e);
+
+ return e;
+}

Powered by Google App Engine
This is Rietveld 408576698