aboutsummaryrefslogtreecommitdiff
path: root/src/soc/intel/common/mma.c
diff options
context:
space:
mode:
authorPratik Prajapati <pratikkumar.v.prajapati@intel.com>2015-09-11 13:51:38 -0700
committerPatrick Georgi <pgeorgi@google.com>2015-11-20 18:21:25 +0100
commitb90b94d3efbbe969c019ab8bb8316e2c08ac4968 (patch)
tree66b36427232d4408f6706d00295837ec57bb3767 /src/soc/intel/common/mma.c
parentfb128734ec45b9ca7d3ed1a59ea05a81fa6ae360 (diff)
intel: Add MMA feature in coreboot
This patch implements Memory Margin Analysis feature in coreboot. Few things to note (1) the feature is enabled by setting CONFIG_MMA=y in the config file (2) coreboot reads mma_test_metadata.bin from cbfs during romstage and gets the name of MMA test name and test config name. Then coreboot finds these files in CBFS. If found, coreboot passes location and size of these files to FSP via UPD params. Sets MrcFastBoot to 0 so that MRC happens and then MMA test would be executed during memory init. (3) FSP passes MMA results data in HOB and coreboot saves it in cbmem (4) when system boots to OS after test is executed cbmem tool is used to grab the MMA results data. BRANCH=none BUG=chrome-os-partner:43731 TEST=Build and Boot kunimitsu (FAB3) and executed MMA tests Not tested on Glados CQ-DEPEND=CL:299476,CL:299475,CL:299474,CL:299473,CL:299509,CL:299508,CL:299507,CL:*230478,CL:*230479 Change-Id: I0b4524abcf57db4d2440a06a79b5a0f4b60fa0ea Signed-off-by: Patrick Georgi <pgeorgi@chromium.org> Original-Commit-Id: 4aba9b728c263b9d5da5746ede3807927c9cc2a7 Original-Change-Id: Ie2728154b49eac8695f707127334b12e345398dc Original-Signed-off-by: Pratik Prajapati <pratikkumar.v.prajapati@intel.com> Original-Reviewed-on: https://chromium-review.googlesource.com/299476 Original-Commit-Ready: Pratikkumar V Prajapati <pratikkumar.v.prajapati@intel.com> Original-Tested-by: Pratikkumar V Prajapati <pratikkumar.v.prajapati@intel.com> Original-Reviewed-by: Aaron Durbin <adurbin@chromium.org> Original-Reviewed-by: Pratikkumar V Prajapati <pratikkumar.v.prajapati@intel.com> Reviewed-on: http://review.coreboot.org/12481 Tested-by: build bot (Jenkins) Reviewed-by: Stefan Reinauer <stefan.reinauer@coreboot.org>
Diffstat (limited to 'src/soc/intel/common/mma.c')
-rw-r--r--src/soc/intel/common/mma.c244
1 files changed, 244 insertions, 0 deletions
diff --git a/src/soc/intel/common/mma.c b/src/soc/intel/common/mma.c
new file mode 100644
index 0000000000..3ac47e8d69
--- /dev/null
+++ b/src/soc/intel/common/mma.c
@@ -0,0 +1,244 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2015 Intel Corporation.
+ *
+ * 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.
+ */
+
+#include <boot/coreboot_tables.h>
+#include <bootstate.h>
+#include <cbfs.h>
+#include <cbmem.h>
+#include <console/console.h>
+#include <lib.h>
+#include "mma.h"
+#include <soc/romstage.h>
+#include <string.h>
+
+#define MMA_TEST_METADATA_FILENAME "mma_test_metadata.bin"
+#define MMA_TEST_NAME_TAG "MMA_TEST_NAME"
+#define MMA_TEST_PARAM_TAG "MMA_TEST_PARAM"
+#define TEST_NAME_MAX_SIZE 30
+#define TEST_PARAM_MAX_SIZE 100
+#define FSP_MMA_RESULTS_GUID { 0x8f4e928, 0xf5f, 0x46d4, \
+ { 0x84, 0x10, 0x47, 0x9f, 0xda, 0x27, 0x9d, 0xb6 } }
+#define MMA_DATA_SIGNATURE (('M'<<0)|('M'<<8)|('A'<<16)|('D'<<24))
+
+struct mma_data_container {
+ u32 mma_signature; // "MMAD"
+ u8 mma_data[0]; // Variable size, platform/run time dependent.
+} __attribute__ ((packed));
+
+/*
+Format of the MMA test metadata file, stored under CBFS
+MMA_TEST_NAME=xxxxxx.efi;MMA_TEST_PARAM=xxxxxx.bin;
+*/
+
+/* Returns index in haystack after 'LABEL=' string is found, < 0 on error. */
+static int find_label(const char *haystack, size_t haystack_sz,
+ const char *label)
+{
+ size_t label_sz;
+ size_t i;
+ size_t search_sz;
+
+ label_sz = strlen(label);
+
+ if (label_sz + 1 >= haystack_sz)
+ return -1;
+
+ /* Handle '=' follow label. i.e. LABEL= */
+ search_sz = haystack_sz - label_sz - 1;
+ for (i = 0; i < search_sz; i++) {
+ if (!strncmp(&haystack[i], label, label_sz))
+ break;
+ }
+
+ if (i == search_sz)
+ return -1;
+
+ if (haystack[i + label_sz] != '=')
+ return -1;
+
+ return i + label_sz + 1;
+}
+/*
+ * Fill in value in dest field located by LABEL=.
+ * Returns 0 on success, < 0 on error.
+ */
+static int label_value(const char *haystack, size_t haystack_sz,
+ const char *label, char *dest, size_t dest_sz)
+{
+ size_t val_begin;
+ size_t val_end;
+ size_t val_sz;
+ int val_index;
+
+ memset(dest, 0, dest_sz);
+
+ /* Allow for NULL termination. */
+ dest_sz--;
+ val_index = find_label(haystack, haystack_sz, label);
+ if (val_index < 0)
+ return -1;
+
+ val_begin = val_index;
+ val_end = val_begin;
+ val_sz = 0;
+
+ for (val_end = val_begin; val_end < haystack_sz; val_end++) {
+ if (haystack[val_end] == ';') {
+ val_sz = val_end - val_begin;
+ break;
+ }
+ }
+
+ if (val_end == haystack_sz)
+ return -1;
+
+ if (dest_sz < val_sz)
+ return -1;
+
+ memcpy(dest, &haystack[val_begin], val_sz);
+
+ return 0;
+}
+
+void setup_mma(MEMORY_INIT_UPD *memory_params)
+{
+ void *mma_test_metadata, *mma_test_content, *mma_test_param;
+ size_t mma_test_metadata_file_len, mma_test_content_file_len,
+ mma_test_param_file_len;
+ char test_filename[TEST_NAME_MAX_SIZE],
+ test_param_filename[TEST_PARAM_MAX_SIZE];
+
+ printk(BIOS_DEBUG, "Entry setup_mma\n");
+
+ memory_params->MmaTestContentPtr = 0;
+ memory_params->MmaTestContentSize = 0;
+ memory_params->MmaTestConfigPtr = 0;
+ memory_params->MmaTestConfigSize = 0;
+
+ mma_test_metadata = cbfs_boot_map_with_leak(MMA_TEST_METADATA_FILENAME,
+ CBFS_TYPE_MMA , &mma_test_metadata_file_len);
+
+ if (!mma_test_metadata) {
+ printk(BIOS_DEBUG, "MMA setup failed: Failed to read %s\n",
+ MMA_TEST_METADATA_FILENAME);
+ return;
+ }
+
+ if (label_value(mma_test_metadata, mma_test_metadata_file_len,
+ MMA_TEST_NAME_TAG, test_filename, TEST_NAME_MAX_SIZE)) {
+ printk(BIOS_DEBUG, "MMA setup failed : Failed to get %s",
+ MMA_TEST_NAME_TAG);
+ return;
+ }
+
+ if (label_value(mma_test_metadata, mma_test_metadata_file_len,
+ MMA_TEST_PARAM_TAG, test_param_filename,
+ TEST_PARAM_MAX_SIZE)) {
+ printk(BIOS_DEBUG, "MMA setup failed : Failed to get %s",
+ MMA_TEST_PARAM_TAG);
+ return;
+ }
+
+ printk(BIOS_DEBUG, "Got MMA_TEST_NAME=%s MMA_TEST_PARAM=%s\n",
+ test_filename, test_param_filename);
+
+ mma_test_content = cbfs_boot_map_with_leak(test_filename,
+ CBFS_TYPE_EFI , &mma_test_content_file_len);
+ if (!mma_test_content) {
+ printk(BIOS_DEBUG, "MMA setup failed: Failed to read %s.\n",
+ test_filename);
+ return;
+ }
+
+ mma_test_param = cbfs_boot_map_with_leak(test_param_filename,
+ CBFS_TYPE_MMA , &mma_test_param_file_len);
+ if (!mma_test_param) {
+ printk(BIOS_DEBUG, "MMA setup failed: Failed to read %s.\n",
+ test_param_filename);
+ return;
+ }
+
+ memory_params->MmaTestContentPtr = (uintptr_t) mma_test_content;
+ memory_params->MmaTestContentSize = mma_test_content_file_len;
+ memory_params->MmaTestConfigPtr = (uintptr_t) mma_test_param;
+ memory_params->MmaTestConfigSize = mma_test_param_file_len;
+ memory_params->MrcFastBoot = 0x00;
+
+ printk(BIOS_DEBUG, "MMA Test name %s\n", test_filename);
+ printk(BIOS_DEBUG, "MMA Test Config name %s\n", test_param_filename);
+ printk(BIOS_DEBUG, "MMA passing following memory_params\n");
+ printk(BIOS_DEBUG, "memory_params->MmaTestContentPtr = %0x\n",
+ memory_params->MmaTestContentPtr);
+ printk(BIOS_DEBUG, "memory_params->MmaTestContentSize = %d\n",
+ memory_params->MmaTestContentSize);
+ printk(BIOS_DEBUG, "memory_params->MmaTestConfigPtr = %0x\n",
+ memory_params->MmaTestConfigPtr);
+ printk(BIOS_DEBUG, "memory_params->MmaTestConfigSize = %d\n",
+ memory_params->MmaTestConfigSize);
+ printk(BIOS_DEBUG, "memory_params->MrcFastBoot = %d\n",
+ memory_params->MrcFastBoot);
+ printk(BIOS_DEBUG, "MMA setup successfully\n");
+}
+
+static void save_mma_results_data(void *unused)
+{
+ void *mma_results_hob;
+ u32 mma_hob_size;
+ u32 *mma_hob_data;
+ struct mma_data_container *mma_data;
+ int cbmem_size;
+
+ const EFI_GUID mma_results_guid = FSP_MMA_RESULTS_GUID;
+
+ printk(BIOS_DEBUG, "Entry save_mma_results_data MMA save data.\n");
+
+ mma_results_hob = get_first_guid_hob(&mma_results_guid);
+ if (mma_results_hob == NULL) {
+ printk(BIOS_DEBUG,
+ "MMA results data Hob not present\n");
+ return;
+ }
+
+ mma_hob_data = GET_GUID_HOB_DATA(mma_results_hob);
+ mma_hob_size = GET_HOB_LENGTH(mma_results_hob);
+ cbmem_size = ALIGN(mma_hob_size, 16) +
+ sizeof(struct mma_data_container);
+ mma_data = cbmem_add(CBMEM_ID_MMA_DATA, cbmem_size);
+
+ if (mma_data == NULL) {
+ printk(BIOS_DEBUG,
+ "CBMEM was not available to save the MMA data.\n");
+ return;
+ }
+
+ /*clear the mma_data before coping the actual data */
+ memset(mma_data, 0, cbmem_size);
+
+ printk(BIOS_DEBUG,
+ "Copy MMA DATA to HOB(src addr %p, dest addr %p, %u bytes)\n",
+ mma_hob_data, mma_data, mma_hob_size);
+
+ mma_data->mma_signature = MMA_DATA_SIGNATURE;
+ memcpy(mma_data->mma_data, mma_hob_data, mma_hob_size);
+
+ printk(BIOS_DEBUG, "write MMA results data to cbmem success\n");
+}
+
+BOOT_STATE_INIT_ENTRY(BS_WRITE_TABLES, BS_ON_ENTRY,
+ save_mma_results_data, NULL);