xref: /aosp_15_r20/external/coreboot/src/security/intel/txt/getsec.c (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 
3 #include <cf9_reset.h>
4 #include <console/console.h>
5 #include <cpu/intel/common/common.h>
6 #include <cpu/x86/cr.h>
7 #include <cpu/x86/cache.h>
8 #include <cpu/x86/mp.h>
9 #include <cpu/x86/msr.h>
10 #include <types.h>
11 
12 #include "txt_register.h"
13 #include "txt_getsec.h"
14 
15 /**
16  * Check for SMX support and enable it if possible.
17  *
18  * Returns false on error, true on success.
19  */
getsec_enabled(void)20 static bool getsec_enabled(void)
21 {
22 	unsigned int ecx = cpuid_ecx(1);
23 	/*
24 	 * Check if SMX and VMX is supported by CPU.
25 	 */
26 	if (!(ecx & CPUID_SMX) || !(ecx & CPUID_VMX)) {
27 		printk(BIOS_ERR, "SMX/VMX not supported by CPU\n");
28 		return false;
29 	}
30 	/*
31 	 * This requirement is not needed for ENTERACCS, but for SENTER (see SDM).
32 	 * Skip check in romstage because IA32_FEATURE_CONTROL cannot be unlocked
33 	 * even after a global reset e.g. on Sandy/IvyBridge. However the register
34 	 * gets set properly in ramstage where all CPUs are already initialized.
35 	 */
36 	if (!ENV_ROMSTAGE_OR_BEFORE) {
37 		/*
38 		* Check if SMX, VMX and GetSec instructions haven't been disabled.
39 		*/
40 		msr_t msr = rdmsr(IA32_FEATURE_CONTROL);
41 		if ((msr.lo & 0xff06) != 0xff06) {
42 			printk(BIOS_ERR, "GETSEC not enabled in IA32_FEATURE_CONTROL MSR\n");
43 			return false;
44 		}
45 	}
46 	/*
47 	 * Enable SMX. Required to execute GetSec instruction.
48 	 * Chapter 2.2.4.3
49 	 * Intel TXT Software Development Guide (Document: 315168-015)
50 	 */
51 	write_cr4(read_cr4() | CR4_SMXE);
52 
53 	return true;
54 }
55 
enable_getsec_or_reset(void)56 void enable_getsec_or_reset(void)
57 {
58 	msr_t msr = rdmsr(IA32_FEATURE_CONTROL);
59 
60 	if (!(msr.lo & FEATURE_CONTROL_LOCK_BIT)) {
61 		/*
62 		 * MSR not locked, enable necessary GETSEC and VMX settings.
63 		 * We do not lock this MSR here, though.
64 		 */
65 		msr.lo |= 0xff06;
66 		wrmsr(IA32_FEATURE_CONTROL, msr);
67 
68 	} else if ((msr.lo & 0xff06) != 0xff06) {
69 		/*
70 		 * MSR is locked without necessary GETSEC and VMX settings.
71 		 * This can happen after internally reflashing a coreboot
72 		 * image with different settings, and then doing a warm
73 		 * reboot. Perform a full reset in order to unlock the MSR.
74 		 */
75 		printk(BIOS_NOTICE,
76 		       "IA32_FEATURE_CONTROL MSR locked with GETSEC and/or VMX disabled.\n"
77 		       "Will perform a full reset to unlock this MSR.\n");
78 
79 		full_reset();
80 	}
81 }
82 
83 /**
84  * Get information as returned by getsec[PARAMETER].
85  * Arguments can be set to NULL if not needed.
86  *
87  * Returns false on error, true on success.
88  */
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)89 bool getsec_parameter(uint32_t *version_mask,
90 		      uint32_t *version_numbers_supported,
91 		      uint32_t *max_size_acm_area,
92 		      uint32_t *memory_type_mask,
93 		      uint32_t *senter_function_disable,
94 		      uint32_t *txt_feature_flags)
95 {
96 	uint32_t i, eax, ebx, ecx;
97 
98 	if (!getsec_enabled())
99 		return false;
100 
101 	/*
102 	 * SAFER MODE EXTENSIONS REFERENCE.
103 	 * Intel 64 and IA-32 Architectures Software Developer Manuals Vol 2D
104 	 */
105 	for (i = 0; i < 0x1f; i++) {
106 		/* Getsec[PARAMETERS] */
107 		asm volatile ("getsec\n"
108 			: "=a" (eax), "=b" (ebx), "=c" (ecx)
109 			: "a" (IA32_GETSEC_PARAMETERS), "b" (i) :);
110 		switch (eax & 0x1f) {
111 		case 0: /* NULL - Exit marker */
112 			return true;
113 		case 1: /* Supported AC module versions */
114 			if (version_mask)
115 				*version_mask = ebx;
116 			if (version_numbers_supported)
117 				*version_numbers_supported = ecx;
118 			break;
119 		case 2: /* Max size of authenticated code execution area */
120 			if (max_size_acm_area)
121 				*max_size_acm_area = eax & ~0x1f;
122 			break;
123 		case 3: /* External memory types supported during AC mode */
124 			if (memory_type_mask)
125 				*memory_type_mask = eax;
126 			break;
127 		case 4: /* Selective SENTER functionality control */
128 			if (senter_function_disable)
129 				*senter_function_disable = eax & (0x3f00);
130 			break;
131 		case 5: /* TXT extensions support */
132 			if (txt_feature_flags)
133 				*txt_feature_flags = eax & (0x60);
134 			break;
135 		}
136 	}
137 
138 	return true;
139 }
140 
141 /**
142  * Get capabilities as returned by getsec[CAPABILITIES].
143  *
144  * Returns false on error, true on success.
145  */
146 
getsec_capabilities(uint32_t * eax)147 bool getsec_capabilities(uint32_t *eax)
148 {
149 	if (!getsec_enabled())
150 		return false;
151 
152 	asm volatile ("getsec\n"
153 		: "=a" (*eax)
154 		: "a" (IA32_GETSEC_CAPABILITIES), "b" (0) :);
155 
156 	return true;
157 }
158