soc/intel: Rename GNVS struct member to match ASL
[coreboot.git] / src / soc / intel / common / block / sgx / sgx.c
blobb21e665ac80f4626de5ba613ca22b88d0904d73b
1 /* SPDX-License-Identifier: GPL-2.0-only */
3 #include <console/console.h>
4 #include <cpu/x86/msr.h>
5 #include <cpu/x86/mtrr.h>
6 #include <cpu/intel/microcode.h>
7 #include <cpu/intel/common/common.h>
8 #include <intelblocks/cpulib.h>
9 #include <intelblocks/msr.h>
10 #include <intelblocks/sgx.h>
11 #include <intelblocks/systemagent.h>
12 #include <soc/cpu.h>
13 #include <soc/nvs.h>
14 #include <soc/pci_devs.h>
16 static inline uint64_t sgx_resource(uint32_t low, uint32_t high)
18 uint64_t val;
19 val = (uint64_t)(high & SGX_RESOURCE_MASK_HI) << 32;
20 val |= low & SGX_RESOURCE_MASK_LO;
21 return val;
24 static int is_sgx_supported(void)
26 struct cpuid_result cpuid_regs;
27 msr_t msr;
29 cpuid_regs = cpuid_ext(0x7, 0x0); /* EBX[2] is feature capability */
30 msr = rdmsr(MTRR_CAP_MSR); /* Bit 12 is PRMRR enablement */
31 return ((cpuid_regs.ebx & SGX_SUPPORTED) && (msr.lo & MTRR_CAP_PRMRR));
34 void prmrr_core_configure(void)
36 union {
37 uint64_t data64;
38 struct {
39 uint32_t lo;
40 uint32_t hi;
41 } data32;
42 } prmrr_base, prmrr_mask;
43 msr_t msr;
46 * Software Developer's Manual Volume 4:
47 * Order Number: 335592-068US
48 * Chapter 2.16.1
49 * MSR_PRMRR_PHYS_MASK is in scope "Core"
50 * MSR_PRMRR_PHYS_BASE is in scope "Core"
51 * Return if Hyper-Threading is enabled and not thread 0
53 if (!is_sgx_supported() || intel_ht_sibling())
54 return;
56 /* PRMRR_PHYS_MASK is in scope "Core" */
57 msr = rdmsr(MSR_PRMRR_PHYS_MASK);
58 /* If it is locked don't attempt to write PRMRR MSRs. */
59 if (msr.lo & PRMRR_PHYS_MASK_LOCK)
60 return;
62 /* PRMRR base and mask are read from the UNCORE PRMRR MSRs
63 * that are already set in FSP-M. */
64 if (soc_get_uncore_prmmr_base_and_mask(&prmrr_base.data64,
65 &prmrr_mask.data64) < 0) {
66 printk(BIOS_ERR, "SGX: Failed to get PRMRR base and mask\n");
67 return;
70 if (!prmrr_base.data32.lo) {
71 printk(BIOS_ERR, "SGX Error: Uncore PRMRR is not set!\n");
72 return;
75 printk(BIOS_INFO, "SGX: prmrr_base = 0x%llx\n", prmrr_base.data64);
76 printk(BIOS_INFO, "SGX: prmrr_mask = 0x%llx\n", prmrr_mask.data64);
78 /* Program core PRMRR MSRs.
79 * - Set cache writeback mem attrib in PRMRR base MSR
80 * - Clear the valid bit in PRMRR mask MSR
81 * - Lock PRMRR MASK MSR */
82 prmrr_base.data32.lo |= MTRR_TYPE_WRBACK;
83 wrmsr(MSR_PRMRR_PHYS_BASE, (msr_t) {.lo = prmrr_base.data32.lo,
84 .hi = prmrr_base.data32.hi});
85 prmrr_mask.data32.lo &= ~PRMRR_PHYS_MASK_VALID;
86 prmrr_mask.data32.lo |= PRMRR_PHYS_MASK_LOCK;
87 wrmsr(MSR_PRMRR_PHYS_MASK, (msr_t) {.lo = prmrr_mask.data32.lo,
88 .hi = prmrr_mask.data32.hi});
91 static int is_prmrr_set(void)
93 msr_t prmrr_base, prmrr_mask;
94 prmrr_base = rdmsr(MSR_PRMRR_PHYS_BASE);
95 prmrr_mask = rdmsr(MSR_PRMRR_PHYS_MASK);
97 /* If PRMRR base is zero and PRMRR mask is locked
98 * then PRMRR is not set */
99 if ((prmrr_base.hi == 0) && (prmrr_base.lo == 0)
100 && (prmrr_mask.lo & PRMRR_PHYS_MASK_LOCK))
101 return 0;
102 return 1;
105 static void enable_sgx(void)
107 msr_t msr;
110 * Intel 64 and IA-32 ArchitecturesSoftware Developer's ManualVolume 3C
111 * Order Number: 326019-060US
112 * Chapter 35.10.2 "Additional MSRs Supported by Intel"
113 * IA32_FEATURE_CONTROL is in scope "Thread"
115 msr = rdmsr(IA32_FEATURE_CONTROL);
116 /* Only enable it when it is not locked */
117 if ((msr.lo & FEATURE_CONTROL_LOCK_BIT) == 0) {
118 msr.lo |= SGX_GLOBAL_ENABLE; /* Enable it */
119 wrmsr(IA32_FEATURE_CONTROL, msr);
123 static void lock_sgx(void)
125 msr_t msr;
128 * Intel 64 and IA-32 ArchitecturesSoftware Developer's ManualVolume 3C
129 * Order Number: 326019-060US
130 * Chapter 35.10.2 "Additional MSRs Supported by Intel"
131 * IA32_FEATURE_CONTROL is in scope "Thread"
133 msr = rdmsr(IA32_FEATURE_CONTROL);
134 /* If it is locked don't attempt to lock it again. */
135 if ((msr.lo & 1) == 0) {
136 msr.lo |= 1; /* Lock it */
137 wrmsr(IA32_FEATURE_CONTROL, msr);
141 static int owner_epoch_update(void)
143 /* TODO - the Owner Epoch update mechanism is not determined yet,
144 * for PoC just write '0's to the MSRs. */
145 msr_t msr = {0, 0};
147 /* SGX_OWNEREPOCH is in scope "Package" */
148 wrmsr(MSR_SGX_OWNEREPOCH0, msr);
149 wrmsr(MSR_SGX_OWNEREPOCH1, msr);
150 return 0;
153 static void activate_sgx(void)
155 msr_t msr;
157 /* Activate SGX feature by writing 1b to MSR 0x7A on all threads.
158 * BIOS must ensure bit 0 is set prior to writing to it, then read it
159 * back and verify the bit is cleared to confirm SGX activation. */
160 msr = rdmsr(MSR_BIOS_UPGD_TRIG);
161 if (msr.lo & SGX_ACTIVATE_BIT) {
162 wrmsr(MSR_BIOS_UPGD_TRIG,
163 (msr_t) {.lo = SGX_ACTIVATE_BIT, .hi = 0});
164 /* Read back to verify it is activated */
165 msr = rdmsr(MSR_BIOS_UPGD_TRIG);
166 if (msr.lo & SGX_ACTIVATE_BIT)
167 printk(BIOS_ERR, "SGX activation failed.\n");
168 else
169 printk(BIOS_INFO, "SGX activation was successful.\n");
170 } else {
171 printk(BIOS_ERR, "SGX feature is deactivated.\n");
175 static int is_prmrr_approved(void)
177 msr_t msr;
178 msr = rdmsr(MSR_PRMRR_PHYS_MASK);
179 if (msr.lo & PRMRR_PHYS_MASK_VALID) {
180 printk(BIOS_INFO, "SGX: MCHECK approved SGX PRMRR\n");
181 return 1;
184 printk(BIOS_INFO, "SGX: MCHECK did not approve SGX PRMRR\n");
185 return 0;
189 * Configures SGX according to "Intel Software Guard Extensions Technology"
190 * Document Number: 565432
192 void sgx_configure(void *unused)
195 if (!is_sgx_supported() || !is_prmrr_set()) {
196 printk(BIOS_ERR, "SGX: not supported or pre-conditions not met\n");
197 return;
200 /* Enable the SGX feature on all threads. */
201 enable_sgx();
203 /* Update the owner epoch value */
204 if (owner_epoch_update() < 0)
205 return;
207 /* Ensure to lock memory before reloading microcode patch */
208 if (CONFIG(SOC_INTEL_COMMON_BLOCK_SGX_LOCK_MEMORY))
209 cpu_lt_lock_memory();
212 * Update just on the first CPU in the core. Other siblings
213 * get the update automatically according to Document: 253668-060US
214 * Intel SDM Chapter 9.11.6.3
215 * "Update in a System Supporting Intel Hyper-Threading Technology"
216 * Intel Hyper-Threading Technology has implications on the loading of the
217 * microcode update. The update must be loaded for each core in a physical
218 * processor. Thus, for a processor supporting Intel Hyper-Threading
219 * Technology, only one logical processor per core is required to load the
220 * microcode update. Each individual logical processor can independently
221 * load the update. However, MP initialization must provide some mechanism
222 * (e.g. a software semaphore) to force serialization of microcode update
223 * loads and to prevent simultaneous load attempts to the same core.
225 if (!intel_ht_sibling()) {
226 const void *microcode_patch = intel_microcode_find();
227 intel_microcode_load_unlocked(microcode_patch);
230 /* Lock the SGX feature on all threads. */
231 lock_sgx();
233 /* Activate the SGX feature, if PRMRR config was approved by MCHECK */
234 if (is_prmrr_approved())
235 activate_sgx();
238 void sgx_fill_gnvs(struct global_nvs *gnvs)
240 struct cpuid_result cpuid_regs;
242 if (!is_sgx_supported()) {
243 printk(BIOS_DEBUG,
244 "SGX: not supported. skip gnvs fill\n");
245 return;
248 /* Get EPC base and size.
249 * Intel SDM: Table 36-6. CPUID Leaf 12H, Sub-Leaf Index 2 or
250 * Higher for enumeration of SGX Resources. Same Table mentions
251 * about return values of the CPUID */
252 cpuid_regs = cpuid_ext(SGX_RESOURCE_ENUM_CPUID_LEAF,
253 SGX_RESOURCE_ENUM_CPUID_SUBLEAF);
255 if (cpuid_regs.eax & SGX_RESOURCE_ENUM_BIT) {
256 /* EPC section enumerated */
257 gnvs->epcs = 1;
258 gnvs->emna = sgx_resource(cpuid_regs.eax, cpuid_regs.ebx);
259 gnvs->elng = sgx_resource(cpuid_regs.ecx, cpuid_regs.edx);
262 printk(BIOS_DEBUG,
263 "SGX: gnvs ECP status = %d base = 0x%llx len = 0x%llx\n",
264 gnvs->epcs, gnvs->emna, gnvs->elng);