summaryrefslogtreecommitdiff
path: root/src/security/intel/txt/getsec.c
blob: e2cb6cd4dcc4cf31da32e6bb8316726c98904600 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
/* SPDX-License-Identifier: GPL-2.0-only */

#include <cf9_reset.h>
#include <console/console.h>
#include <cpu/intel/common/common.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 "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;
}