IA32_FEATURE_CONTROL does not need to be checked by BIOS, in fact these bits are needed only by SENTER and SINIT ACM. ACM ENTERACCS does not check these bits according to Intel SDM. Also noticed that the lock bit of IA32_FEATURE_CONTROL cannot be cleared by issuing neither global reset nor full reset on Sandybridge/Ivybridge platforms which results in a reset loop. However, check the IA32_FEATURE_CONTROL SENTER bits in ramstage where the register is properly set on all cores already. TEST=Run ACM SCLEAN on Dell OptiPlex 9010 with i7-3770/Q77 Signed-off-by: Michał Żygowski <michal.zygowski@3mdeb.com> Change-Id: Ie9103041498f557b85019a56e1252090a4fcd0c9 Reviewed-on: https://review.coreboot.org/c/coreboot/+/59520 Tested-by: build bot (Jenkins) <no-reply@coreboot.org> Reviewed-by: Patrick Rudolph <siro@das-labor.org>
160 lines
4.0 KiB
C
160 lines
4.0 KiB
C
/* SPDX-License-Identifier: GPL-2.0-only */
|
|
|
|
#include <cf9_reset.h>
|
|
#include <console/console.h>
|
|
#include <cpu/intel/common/common.h>
|
|
#include <cpu/x86/lapic.h>
|
|
#include <cpu/x86/cr.h>
|
|
#include <cpu/x86/cache.h>
|
|
#include <cpu/x86/mp.h>
|
|
#include <cpu/x86/msr.h>
|
|
#include <types.h>
|
|
#include <rules.h>
|
|
|
|
#include "txt_register.h"
|
|
#include "txt_getsec.h"
|
|
|
|
/**
|
|
* Check for SMX support and enable it if possible.
|
|
*
|
|
* Returns false on error, true on success.
|
|
*/
|
|
static bool getsec_enabled(void)
|
|
{
|
|
unsigned int ecx = cpuid_ecx(1);
|
|
/*
|
|
* Check if SMX and VMX is supported by CPU.
|
|
*/
|
|
if (!(ecx & CPUID_SMX) || !(ecx & CPUID_VMX)) {
|
|
printk(BIOS_ERR, "SMX/VMX not supported by CPU\n");
|
|
return false;
|
|
}
|
|
/*
|
|
* This requirement is not needed for ENTERACCS, but for SENTER (see SDM).
|
|
* Skip check in romstage because IA32_FEATURE_CONTROL cannot be unlocked
|
|
* even after a global reset e.g. on Sandy/IvyBridge. However the register
|
|
* gets set properly in ramstage where all CPUs are already initialized.
|
|
*/
|
|
if (!ENV_ROMSTAGE_OR_BEFORE) {
|
|
/*
|
|
* Check if SMX, VMX and GetSec instructions haven't been disabled.
|
|
*/
|
|
msr_t msr = rdmsr(IA32_FEATURE_CONTROL);
|
|
if ((msr.lo & 0xff06) != 0xff06) {
|
|
printk(BIOS_ERR, "GETSEC not enabled in IA32_FEATURE_CONTROL MSR\n");
|
|
return false;
|
|
}
|
|
}
|
|
/*
|
|
* Enable SMX. Required to execute GetSec instruction.
|
|
* Chapter 2.2.4.3
|
|
* Intel TXT Software Development Guide (Document: 315168-015)
|
|
*/
|
|
write_cr4(read_cr4() | CR4_SMXE);
|
|
|
|
return true;
|
|
}
|
|
|
|
void enable_getsec_or_reset(void)
|
|
{
|
|
msr_t msr = rdmsr(IA32_FEATURE_CONTROL);
|
|
|
|
if (!(msr.lo & FEATURE_CONTROL_LOCK_BIT)) {
|
|
/*
|
|
* MSR not locked, enable necessary GETSEC and VMX settings.
|
|
* We do not lock this MSR here, though.
|
|
*/
|
|
msr.lo |= 0xff06;
|
|
wrmsr(IA32_FEATURE_CONTROL, msr);
|
|
|
|
} else if ((msr.lo & 0xff06) != 0xff06) {
|
|
/*
|
|
* MSR is locked without necessary GETSEC and VMX settings.
|
|
* This can happen after internally reflashing a coreboot
|
|
* image with different settings, and then doing a warm
|
|
* reboot. Perform a full reset in order to unlock the MSR.
|
|
*/
|
|
printk(BIOS_NOTICE,
|
|
"IA32_FEATURE_CONTROL MSR locked with GETSEC and/or VMX disabled.\n"
|
|
"Will perform a full reset to unlock this MSR.\n");
|
|
|
|
full_reset();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get information as returned by getsec[PARAMETER].
|
|
* Arguments can be set to NULL if not needed.
|
|
*
|
|
* Returns false on error, true on success.
|
|
*/
|
|
bool getsec_parameter(uint32_t *version_mask,
|
|
uint32_t *version_numbers_supported,
|
|
uint32_t *max_size_acm_area,
|
|
uint32_t *memory_type_mask,
|
|
uint32_t *senter_function_disable,
|
|
uint32_t *txt_feature_flags)
|
|
{
|
|
uint32_t i, eax, ebx, ecx;
|
|
|
|
if (!getsec_enabled())
|
|
return false;
|
|
|
|
/*
|
|
* SAFER MODE EXTENSIONS REFERENCE.
|
|
* Intel 64 and IA-32 Architectures Software Developer Manuals Vol 2D
|
|
*/
|
|
for (i = 0; i < 0x1f; i++) {
|
|
/* Getsec[PARAMETERS] */
|
|
asm volatile ("getsec\n"
|
|
: "=a" (eax), "=b" (ebx), "=c" (ecx)
|
|
: "a" (IA32_GETSEC_PARAMETERS), "b" (i) :);
|
|
switch (eax & 0x1f) {
|
|
case 0: /* NULL - Exit marker */
|
|
return true;
|
|
case 1: /* Supported AC module versions */
|
|
if (version_mask)
|
|
*version_mask = ebx;
|
|
if (version_numbers_supported)
|
|
*version_numbers_supported = ecx;
|
|
break;
|
|
case 2: /* Max size of authenticated code execution area */
|
|
if (max_size_acm_area)
|
|
*max_size_acm_area = eax & ~0x1f;
|
|
break;
|
|
case 3: /* External memory types supported during AC mode */
|
|
if (memory_type_mask)
|
|
*memory_type_mask = eax;
|
|
break;
|
|
case 4: /* Selective SENTER functionality control */
|
|
if (senter_function_disable)
|
|
*senter_function_disable = eax & (0x3f00);
|
|
break;
|
|
case 5: /* TXT extensions support */
|
|
if (txt_feature_flags)
|
|
*txt_feature_flags = eax & (0x60);
|
|
break;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Get capabilities as returned by getsec[CAPABILITIES].
|
|
*
|
|
* Returns false on error, true on success.
|
|
*/
|
|
|
|
bool getsec_capabilities(uint32_t *eax)
|
|
{
|
|
if (!getsec_enabled())
|
|
return false;
|
|
|
|
asm volatile ("getsec\n"
|
|
: "=a" (*eax)
|
|
: "a" (IA32_GETSEC_CAPABILITIES), "b" (0) :);
|
|
|
|
return true;
|
|
}
|