Skip to content

Commit 61d5a16

Browse files
SergiiDmytrukkrystian-hebel
authored andcommitted
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 a9e02d4 commit 61d5a16

File tree

4 files changed

+122
-16
lines changed

4 files changed

+122
-16
lines changed

xen/arch/x86/e820.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -457,7 +457,7 @@ static uint64_t __init mtrr_top_of_ram(void)
457457
rdmsrl(MSR_MTRRcap, mtrr_cap);
458458
rdmsrl(MSR_MTRRdefType, mtrr_def);
459459

460-
if ( slaunch_active )
460+
if ( slaunch_active && boot_cpu_data.x86_vendor == X86_VENDOR_INTEL )
461461
txt_restore_mtrrs(e820_verbose);
462462

463463
if ( e820_verbose )

xen/arch/x86/include/asm/slaunch.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
/*
1212
* Secure Launch event log entry types. The TXT specification defines the
1313
* base event value as 0x400 for DRTM values.
14+
*
15+
* Using the same values for AMD SKINIT.
1416
*/
1517
#define TXT_EVTYPE_BASE 0x400
1618
#define DLE_EVTYPE_SLAUNCH (TXT_EVTYPE_BASE + 0x102)

xen/arch/x86/slaunch.c

Lines changed: 55 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@
99
#include <xen/mm.h>
1010
#include <asm/bootinfo.h>
1111

12+
/* SLB is 64k, 64k-aligned */
13+
#define SKINIT_SLB_SIZE 0x10000
14+
#define SKINIT_SLB_ALIGN 0x10000
15+
1216
bool __initdata slaunch_active;
1317
uint32_t __initdata slaunch_slrt;
1418

@@ -37,6 +41,19 @@ int __init map_l2(unsigned long paddr, unsigned long size)
3741
pages, PAGE_HYPERVISOR);
3842
}
3943

44+
static uint32_t get_slb_start(void)
45+
{
46+
/* The runtime computation relies on size being a power of 2 and equal to
47+
* alignment. Make sure these assumptions hold. */
48+
BUILD_BUG_ON(SKINIT_SLB_SIZE != SKINIT_SLB_ALIGN);
49+
BUILD_BUG_ON(SKINIT_SLB_SIZE == 0);
50+
BUILD_BUG_ON((SKINIT_SLB_SIZE & (SKINIT_SLB_SIZE - 1)) != 0);
51+
52+
/* Rounding any address within SLB down to alignment gives SLB base and
53+
* SLRT is inside SLB on AMD. */
54+
return slaunch_slrt & ~(SKINIT_SLB_SIZE - 1);
55+
}
56+
4057
void __init map_slaunch_mem_regions(void)
4158
{
4259
void *evt_log_addr;
@@ -45,7 +62,14 @@ void __init map_slaunch_mem_regions(void)
4562
map_l2(TPM_TIS_BASE, TPM_TIS_SIZE);
4663

4764
/* Vendor-specific part. It may include contain slaunch_slrt. */
48-
map_txt_mem_regions();
65+
if ( boot_cpu_data.x86_vendor == X86_VENDOR_INTEL )
66+
{
67+
map_txt_mem_regions();
68+
}
69+
else if ( boot_cpu_data.x86_vendor == X86_VENDOR_AMD )
70+
{
71+
map_l2(get_slb_start(), SKINIT_SLB_SIZE);
72+
}
4973

5074
find_evt_log(__va(slaunch_slrt), &evt_log_addr, &evt_log_size);
5175
if ( evt_log_addr != NULL )
@@ -71,11 +95,25 @@ void __init protect_slaunch_mem_regions(void)
7195
}
7296

7397
/* Vendor-specific part. */
74-
protect_txt_mem_regions();
98+
if ( boot_cpu_data.x86_vendor == X86_VENDOR_INTEL )
99+
{
100+
protect_txt_mem_regions();
101+
}
102+
else if ( boot_cpu_data.x86_vendor == X86_VENDOR_AMD )
103+
{
104+
uint64_t slb_start = get_slb_start();
105+
uint64_t slb_end = slb_start + SKINIT_SLB_SIZE;
106+
printk("SLAUNCH: reserving SLB (%#lx - %#lx)\n", slb_start, slb_end);
107+
e820_change_range_type(&e820_raw, slb_start, slb_end,
108+
E820_RAM, E820_RESERVED);
109+
}
75110
}
76111

77112
static struct slr_table *slr_get_table(void)
78113
{
114+
bool intel_cpu = (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL);
115+
uint16_t slrt_architecture = intel_cpu ? SLR_INTEL_TXT : SLR_AMD_SKINIT;
116+
79117
struct slr_table *slrt = __va(slaunch_slrt);
80118

81119
map_l2(slaunch_slrt, PAGE_SIZE);
@@ -85,9 +123,9 @@ static struct slr_table *slr_get_table(void)
85123
/* XXX: are newer revisions allowed? */
86124
if ( slrt->revision != SLR_TABLE_REVISION )
87125
panic("SLRT is of unsupported revision: %#04x!\n", slrt->revision);
88-
if ( slrt->architecture != SLR_INTEL_TXT )
89-
panic("SLRT is for unexpected architecture: %#04x!\n",
90-
slrt->architecture);
126+
if ( slrt->architecture != slrt_architecture )
127+
panic("SLRT is for unexpected architecture: %#04x != %#04x!\n",
128+
slrt->architecture, slrt_architecture);
91129
if ( slrt->size > slrt->max_size )
92130
panic("SLRT is larger than its max size: %#08x > %#08x!\n",
93131
slrt->size, slrt->max_size);
@@ -104,14 +142,18 @@ void tpm_measure_slrt(void)
104142

105143
if ( slrt->revision == 1 )
106144
{
107-
/* In revision one of the SLRT, only Intel info table is measured. */
108-
struct slr_entry_intel_info *intel_info =
109-
(void *)slr_next_entry_by_tag(slrt, NULL, SLR_ENTRY_INTEL_INFO);
110-
if ( intel_info == NULL )
111-
panic("SLRT is missing Intel-specific information!\n");
112-
113-
tpm_hash_extend(DRTM_LOC, DRTM_DATA_PCR, (uint8_t *)intel_info,
114-
sizeof(*intel_info), DLE_EVTYPE_SLAUNCH, NULL, 0);
145+
if ( boot_cpu_data.x86_vendor == X86_VENDOR_INTEL )
146+
{
147+
/* In revision one of the SLRT, only Intel info table is
148+
* measured. */
149+
struct slr_entry_intel_info *intel_info =
150+
(void *)slr_next_entry_by_tag(slrt, NULL, SLR_ENTRY_INTEL_INFO);
151+
if ( intel_info == NULL )
152+
panic("SLRT is missing Intel-specific information!\n");
153+
154+
tpm_hash_extend(DRTM_LOC, DRTM_DATA_PCR, (uint8_t *)intel_info,
155+
sizeof(*intel_info), DLE_EVTYPE_SLAUNCH, NULL, 0);
156+
}
115157
}
116158
else
117159
{

xen/arch/x86/tpm.c

Lines changed: 64 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include <asm/intel_txt.h>
2222
#include <asm/slaunch.h>
2323
#include <asm/tpm.h>
24+
#include <asm/x86-vendors.h>
2425

2526
#ifdef __EARLY_TPM__
2627

@@ -57,11 +58,31 @@ void *memcpy(void *dest, const void *src, size_t n)
5758
return dest;
5859
}
5960

61+
static bool is_amd_cpu(void)
62+
{
63+
/*
64+
* asm/processor.h can't be included in early code, which means neither
65+
* cpuid() function nor boot_cpu_data can be used here.
66+
*/
67+
uint32_t eax, ebx, ecx, edx;
68+
asm volatile ( "cpuid"
69+
: "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx)
70+
: "0" (0), "c" (0) );
71+
return ebx == X86_VENDOR_AMD_EBX
72+
&& ecx == X86_VENDOR_AMD_ECX
73+
&& edx == X86_VENDOR_AMD_EDX;
74+
}
75+
6076
#else /* __EARLY_TPM__ */
6177

6278
#include <xen/mm.h>
6379
#include <xen/pfn.h>
6480

81+
static bool is_amd_cpu(void)
82+
{
83+
return boot_cpu_data.x86_vendor == X86_VENDOR_AMD;
84+
}
85+
6586
#endif /* __EARLY_TPM__ */
6687

6788
#define TPM_LOC_REG(loc, reg) (0x1000 * (loc) + (reg))
@@ -247,6 +268,21 @@ struct TPM12_PCREvent {
247268
uint8_t Data[];
248269
};
249270

271+
struct tpm1_spec_id_event {
272+
uint32_t pcrIndex;
273+
uint32_t eventType;
274+
uint8_t digest[20];
275+
uint32_t eventSize;
276+
uint8_t signature[16];
277+
uint32_t platformClass;
278+
uint8_t specVersionMinor;
279+
uint8_t specVersionMajor;
280+
uint8_t specErrata;
281+
uint8_t uintnSize;
282+
uint8_t vendorInfoSize;
283+
uint8_t vendorInfo[0]; /* variable number of members */
284+
} __packed;
285+
250286
struct txt_ev_log_container_12 {
251287
char Signature[20]; /* "TXT Event Container", null-terminated */
252288
uint8_t Reserved[12];
@@ -389,6 +425,15 @@ static void *create_log_event12(struct txt_ev_log_container_12 *evt_log,
389425
{
390426
struct TPM12_PCREvent *new_entry;
391427

428+
if ( is_amd_cpu() ) {
429+
/*
430+
* On AMD, TXT-compatible structure is stored as vendor data of
431+
* TCG-defined event log header.
432+
*/
433+
struct tpm1_spec_id_event *spec_id = (void *)evt_log;
434+
evt_log = (struct txt_ev_log_container_12 *)&spec_id->vendorInfo[0];
435+
}
436+
392437
new_entry = (void *)(((uint8_t *)evt_log) + evt_log->NextEventOffset);
393438

394439
/*
@@ -824,11 +869,28 @@ static uint32_t tpm2_hash_extend(unsigned loc, uint8_t *buf, unsigned size,
824869

825870
#endif /* __EARLY_TPM__ */
826871

827-
static struct heap_event_log_pointer_element2_1 *find_evt_log_ext_data(void)
872+
static struct heap_event_log_pointer_element2_1 *
873+
find_evt_log_ext_data(struct tpm2_spec_id_event *evt_log)
828874
{
829875
struct txt_os_sinit_data *os_sinit;
830876
struct txt_ext_data_element *ext_data;
831877

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

@@ -861,7 +923,7 @@ create_log_event20(struct tpm2_spec_id_event *evt_log, uint32_t evt_log_size,
861923
unsigned i;
862924
uint8_t *p;
863925

864-
log_ext_data = find_evt_log_ext_data();
926+
log_ext_data = find_evt_log_ext_data(evt_log);
865927
if ( log_ext_data == NULL )
866928
return log_hashes;
867929

0 commit comments

Comments
 (0)