Skip to content

Commit 4e788a9

Browse files
committed
arch/x86: support slaunch with AMD SKINIT
This mostly involves not running Intel-specific code when on AMD. There are only a few new AMD-specific implementation details: - finding SLB start and size and then mapping and protecting it - managing offset for adding the next TPM log entry (TXT-compatible data prepared by SKL is stored inside of vendor data field of TCG header) Signed-off-by: Sergii Dmytruk <[email protected]> Signed-off-by: Krystian Hebel <[email protected]>
1 parent cff8931 commit 4e788a9

File tree

3 files changed

+142
-19
lines changed

3 files changed

+142
-19
lines changed

xen/arch/x86/e820.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -447,7 +447,7 @@ static uint64_t __init mtrr_top_of_ram(void)
447447
rdmsrl(MSR_MTRRcap, mtrr_cap);
448448
rdmsrl(MSR_MTRRdefType, mtrr_def);
449449

450-
if ( slaunch_active )
450+
if ( slaunch_active && boot_cpu_data.x86_vendor == X86_VENDOR_INTEL )
451451
txt_restore_mtrrs(e820_verbose);
452452

453453
if ( e820_verbose )

xen/arch/x86/slaunch.c

Lines changed: 75 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@
1717
#include <asm/slaunch.h>
1818
#include <asm/tpm.h>
1919

20+
/* SLB is 64k, 64k-aligned */
21+
#define SKINIT_SLB_SIZE 0x10000
22+
#define SKINIT_SLB_ALIGN 0x10000
23+
2024
/* These variables are initialized by the code near an entry point. */
2125
bool __initdata slaunch_active;
2226
uint32_t __initdata slaunch_slrt;
@@ -48,8 +52,28 @@ int __init slaunch_map_l2(unsigned long paddr, unsigned long size)
4852
pages, PAGE_HYPERVISOR);
4953
}
5054

55+
static uint32_t get_slb_start(void)
56+
{
57+
/*
58+
* The runtime computation relies on size being a power of 2 and equal to
59+
* alignment. Make sure these assumptions hold.
60+
*/
61+
BUILD_BUG_ON(SKINIT_SLB_SIZE != SKINIT_SLB_ALIGN);
62+
BUILD_BUG_ON(SKINIT_SLB_SIZE == 0);
63+
BUILD_BUG_ON((SKINIT_SLB_SIZE & (SKINIT_SLB_SIZE - 1)) != 0);
64+
65+
/*
66+
* Rounding any address within SLB down to alignment gives SLB base and
67+
* SLRT is inside SLB on AMD.
68+
*/
69+
return slaunch_slrt & ~(SKINIT_SLB_SIZE - 1);
70+
}
71+
5172
static struct slr_table *get_slrt(void)
5273
{
74+
bool intel_cpu = (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL);
75+
uint16_t slrt_architecture = intel_cpu ? SLR_INTEL_TXT : SLR_AMD_SKINIT;
76+
5377
struct slr_table *slrt = __va(slaunch_slrt);
5478

5579
slaunch_map_l2(slaunch_slrt, PAGE_SIZE);
@@ -59,9 +83,9 @@ static struct slr_table *get_slrt(void)
5983
/* XXX: are newer revisions allowed? */
6084
if ( slrt->revision != SLR_TABLE_REVISION )
6185
panic("SLRT is of unsupported revision: %#04x!\n", slrt->revision);
62-
if ( slrt->architecture != SLR_INTEL_TXT )
63-
panic("SLRT is for unexpected architecture: %#04x!\n",
64-
slrt->architecture);
86+
if ( slrt->architecture != slrt_architecture )
87+
panic("SLRT is for unexpected architecture: %#04x != %#04x!\n",
88+
slrt->architecture, slrt_architecture);
6589
if ( slrt->size > slrt->max_size )
6690
panic("SLRT is larger than its max size: %#08x > %#08x!\n",
6791
slrt->size, slrt->max_size);
@@ -80,7 +104,10 @@ void __init slaunch_map_mem_regions(void)
80104
slaunch_map_l2(TPM_TIS_BASE, TPM_TIS_SIZE);
81105

82106
/* Vendor-specific part. */
83-
txt_map_mem_regions();
107+
if ( boot_cpu_data.x86_vendor == X86_VENDOR_INTEL )
108+
txt_map_mem_regions();
109+
else if ( boot_cpu_data.x86_vendor == X86_VENDOR_AMD )
110+
slaunch_map_l2(get_slb_start(), SKINIT_SLB_SIZE);
84111

85112
find_evt_log(get_slrt(), &evt_log_addr, &evt_log_size);
86113
if ( evt_log_addr != NULL )
@@ -106,7 +133,18 @@ void __init slaunch_reserve_mem_regions(void)
106133
}
107134

108135
/* Vendor-specific part. */
109-
txt_reserve_mem_regions();
136+
if ( boot_cpu_data.x86_vendor == X86_VENDOR_INTEL )
137+
{
138+
txt_reserve_mem_regions();
139+
}
140+
else if ( boot_cpu_data.x86_vendor == X86_VENDOR_AMD )
141+
{
142+
uint64_t slb_start = get_slb_start();
143+
uint64_t slb_end = slb_start + SKINIT_SLB_SIZE;
144+
printk("SLAUNCH: reserving SLB (%#lx - %#lx)\n", slb_start, slb_end);
145+
rc = reserve_e820_ram(&e820_raw, slb_start, slb_end);
146+
BUG_ON(rc == 0);
147+
}
110148
}
111149

112150
void slaunch_measure_slrt(void)
@@ -119,20 +157,41 @@ void slaunch_measure_slrt(void)
119157
* In revision one of the SLRT, only platform-specific info table is
120158
* measured.
121159
*/
122-
struct slr_entry_intel_info tmp;
123-
struct slr_entry_intel_info *entry;
160+
if ( boot_cpu_data.x86_vendor == X86_VENDOR_INTEL )
161+
{
162+
struct slr_entry_intel_info tmp;
163+
struct slr_entry_intel_info *entry;
124164

125-
entry = (struct slr_entry_intel_info *)
126-
slr_next_entry_by_tag(slrt, NULL, SLR_ENTRY_INTEL_INFO);
127-
if ( entry == NULL )
128-
panic("SLRT is missing Intel-specific information!\n");
165+
entry = (struct slr_entry_intel_info *)
166+
slr_next_entry_by_tag(slrt, NULL, SLR_ENTRY_INTEL_INFO);
167+
if ( entry == NULL )
168+
panic("SLRT is missing Intel-specific information!\n");
129169

130-
tmp = *entry;
131-
tmp.boot_params_base = 0;
132-
tmp.txt_heap = 0;
170+
tmp = *entry;
171+
tmp.boot_params_base = 0;
172+
tmp.txt_heap = 0;
133173

134-
tpm_hash_extend(DRTM_LOC, DRTM_DATA_PCR, (uint8_t *)&tmp,
135-
sizeof(tmp), DLE_EVTYPE_SLAUNCH, NULL, 0);
174+
tpm_hash_extend(DRTM_LOC, DRTM_DATA_PCR, (uint8_t *)&tmp,
175+
sizeof(tmp), DLE_EVTYPE_SLAUNCH, NULL, 0);
176+
}
177+
else if ( boot_cpu_data.x86_vendor == X86_VENDOR_AMD )
178+
{
179+
struct slr_entry_amd_info tmp;
180+
struct slr_entry_amd_info *entry;
181+
182+
entry = (struct slr_entry_amd_info *)
183+
slr_next_entry_by_tag(slrt, NULL, SLR_ENTRY_AMD_INFO);
184+
if ( entry == NULL )
185+
panic("SLRT is missing AMD-specific information!\n");
186+
187+
tmp = *entry;
188+
tmp.next = 0;
189+
tmp.slrt_base = 0;
190+
tmp.boot_params_base = 0;
191+
192+
tpm_hash_extend(DRTM_LOC, DRTM_DATA_PCR, (uint8_t *)&tmp,
193+
sizeof(tmp), DLE_EVTYPE_SLAUNCH, NULL, 0);
194+
}
136195
}
137196
else
138197
{

xen/arch/x86/tpm.c

Lines changed: 66 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include <asm/intel_txt.h>
1111
#include <asm/slaunch.h>
1212
#include <asm/tpm.h>
13+
#include <asm/x86-vendors.h>
1314

1415
#ifdef __EARLY_TPM__
1516

@@ -46,11 +47,31 @@ void *memcpy(void *dest, const void *src, size_t n)
4647
return dest;
4748
}
4849

50+
static bool is_amd_cpu(void)
51+
{
52+
/*
53+
* asm/processor.h can't be included in early code, which means neither
54+
* cpuid() function nor boot_cpu_data can be used here.
55+
*/
56+
uint32_t eax, ebx, ecx, edx;
57+
asm volatile ( "cpuid"
58+
: "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx)
59+
: "0" (0), "c" (0) );
60+
return ebx == X86_VENDOR_AMD_EBX
61+
&& ecx == X86_VENDOR_AMD_ECX
62+
&& edx == X86_VENDOR_AMD_EDX;
63+
}
64+
4965
#else /* __EARLY_TPM__ */
5066

5167
#include <xen/mm.h>
5268
#include <xen/pfn.h>
5369

70+
static bool is_amd_cpu(void)
71+
{
72+
return boot_cpu_data.x86_vendor == X86_VENDOR_AMD;
73+
}
74+
5475
#endif /* __EARLY_TPM__ */
5576

5677
#define TPM_LOC_REG(loc, reg) (0x1000 * (loc) + (reg))
@@ -237,6 +258,21 @@ struct TPM12_PCREvent {
237258
uint8_t Data[];
238259
};
239260

261+
struct tpm1_spec_id_event {
262+
uint32_t pcrIndex;
263+
uint32_t eventType;
264+
uint8_t digest[20];
265+
uint32_t eventSize;
266+
uint8_t signature[16];
267+
uint32_t platformClass;
268+
uint8_t specVersionMinor;
269+
uint8_t specVersionMajor;
270+
uint8_t specErrata;
271+
uint8_t uintnSize;
272+
uint8_t vendorInfoSize;
273+
uint8_t vendorInfo[0]; /* variable number of members */
274+
} __packed;
275+
240276
struct txt_ev_log_container_12 {
241277
char Signature[20]; /* "TXT Event Container", null-terminated */
242278
uint8_t Reserved[12];
@@ -380,6 +416,16 @@ static void *create_log_event12(struct txt_ev_log_container_12 *evt_log,
380416
{
381417
struct TPM12_PCREvent *new_entry;
382418

419+
if ( is_amd_cpu() )
420+
{
421+
/*
422+
* On AMD, TXT-compatible structure is stored as vendor data of
423+
* TCG-defined event log header.
424+
*/
425+
struct tpm1_spec_id_event *spec_id = (void *)evt_log;
426+
evt_log = (struct txt_ev_log_container_12 *)&spec_id->vendorInfo[0];
427+
}
428+
383429
new_entry = (void *)(((uint8_t *)evt_log) + evt_log->NextEventOffset);
384430

385431
/*
@@ -828,11 +874,29 @@ static uint32_t tpm2_hash_extend(unsigned loc, const uint8_t *buf,
828874

829875
#endif /* __EARLY_TPM__ */
830876

831-
static struct heap_event_log_pointer_element2_1 *find_evt_log_ext_data(void)
877+
static struct heap_event_log_pointer_element2_1 *
878+
find_evt_log_ext_data(struct tpm2_spec_id_event *evt_log)
832879
{
833880
struct txt_os_sinit_data *os_sinit;
834881
struct txt_ext_data_element *ext_data;
835882

883+
if ( is_amd_cpu() )
884+
{
885+
/*
886+
* Event log pointer is defined by TXT specification, but
887+
* secure-kernel-loader provides a compatible structure in vendor data
888+
* of the log.
889+
*/
890+
const uint8_t *data_size =
891+
(void *)&evt_log->digestSizes[evt_log->digestCount];
892+
893+
if ( *data_size != sizeof(struct heap_event_log_pointer_element2_1) )
894+
return NULL;
895+
896+
/* Vendor data directly follows one-byte size. */
897+
return (void *)(data_size + 1);
898+
}
899+
836900
os_sinit = txt_os_sinit_data_start(__va(read_txt_reg(TXTCR_HEAP_BASE)));
837901
ext_data = (void *)((uint8_t *)os_sinit + sizeof(*os_sinit));
838902

@@ -866,7 +930,7 @@ create_log_event20(struct tpm2_spec_id_event *evt_log, uint32_t evt_log_size,
866930
unsigned i;
867931
uint8_t *p;
868932

869-
log_ext_data = find_evt_log_ext_data();
933+
log_ext_data = find_evt_log_ext_data(evt_log);
870934
if ( log_ext_data == NULL )
871935
return log_hashes;
872936

0 commit comments

Comments
 (0)