coreboot: Add a VMX feature lock check and reset if VMX is disabled

Starting with M80, OS requires VMX to be enabled. However, since the
previous version of the OS had the feature disabled and locked, the
system needs to go through a cold reset to allow VMX to be enabled.

BUG=b:150215069, crbug:1072877
TEST=Update/reset between M79 and M84 versions; confirm that the
issue is resolved and /dev/kvm comes up.

Change-Id: Ifa2f370b1212b13a2eeb8d95c738068d5109d423
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/third_party/coreboot/+/2319413
Tested-by: Dossym Nurmukhanov <dossym@chromium.org>
Auto-Submit: Dossym Nurmukhanov <dossym@chromium.org>
Commit-Queue: Furquan Shaikh <furquan@chromium.org>
Reviewed-by: Furquan Shaikh <furquan@chromium.org>
diff --git a/src/soc/intel/broadwell/cpu.c b/src/soc/intel/broadwell/cpu.c
index 4c47a3a..fb9037b 100644
--- a/src/soc/intel/broadwell/cpu.c
+++ b/src/soc/intel/broadwell/cpu.c
@@ -44,7 +44,12 @@
 #include <soc/rcba.h>
 #include <soc/smm.h>
 #include <soc/systemagent.h>
+#include <soc/reset.h>
 #include <soc/intel/broadwell/chip.h>
+#if CONFIG_EC_GOOGLE_CHROMEEC
+#include <ec/google/chromeec/ec.h>
+#include <ec/google/chromeec/ec_commands.h>
+#endif
 
 /* Convert time in seconds to POWER_LIMIT_1_TIME MSR value */
 static const u8 power_limit_time_sec_to_msr[] = {
@@ -683,6 +688,30 @@
 	.id_table = cpu_table,
 };
 
+static void validate_vmx_lock_status(void)
+{
+#if CONFIG_EC_GOOGLE_CHROMEEC
+	msr_t msr;
+
+	msr = rdmsr(IA32_FEATURE_CONTROL);
+	printk(BIOS_DEBUG, "IA32 Feature Control hi = %u, lo = %u.\n",
+			msr.hi, msr.lo);
+
+	if ((msr.lo & FEATURE_CONTROL_LOCK_BIT) &&
+	    !(msr.lo & (FEATURE_ENABLE_VMX_INSIDE_SMX |
+	                FEATURE_ENABLE_VMX_OUTSIDE_SMX))) {
+		printk(BIOS_INFO, "Feature control MSR locked. Rebooting.\n");
+		if (!google_chromeec_gsv_set(EC_CMD_GSV_PAUSE_IN_S5, 1))
+			cold_reset_system();
+		else
+			google_chromeec_reboot();
+	}
+
+	google_chromeec_gsv_set(EC_CMD_GSV_PAUSE_IN_S5, 0);
+#endif
+
+}
+
 void broadwell_init_cpus(device_t dev)
 {
 	struct bus *cpu_bus = dev->link_list;
@@ -692,6 +721,8 @@
 	struct mp_params mp_params;
 	void *smm_save_area;
 
+	validate_vmx_lock_status();
+
 	msr = rdmsr(CORE_THREAD_COUNT_MSR);
 	num_threads = (msr.lo >> 0) & 0xffff;
 	num_cores = (msr.lo >> 16) & 0xffff;
diff --git a/src/soc/intel/broadwell/include/soc/msr.h b/src/soc/intel/broadwell/include/soc/msr.h
index 707041a..d723757 100644
--- a/src/soc/intel/broadwell/include/soc/msr.h
+++ b/src/soc/intel/broadwell/include/soc/msr.h
@@ -23,6 +23,9 @@
 #define MSR_PIC_MSG_CONTROL		0x2e
 #define CORE_THREAD_COUNT_MSR		0x35
 #define IA32_FEATURE_CONTROL		0x3a
+#define  FEATURE_CONTROL_LOCK_BIT	(1 << 0)
+#define  FEATURE_ENABLE_VMX_INSIDE_SMX	(1 << 1)
+#define  FEATURE_ENABLE_VMX_OUTSIDE_SMX	(1 << 2)
 #define  CPUID_VMX			(1 << 5)
 #define  CPUID_SMX			(1 << 6)
 #define MSR_PLATFORM_INFO		0xce