Skip to content

Commit a9f4275

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 bd2771f commit a9f4275

File tree

4 files changed

+122
-16
lines changed

4 files changed

+122
-16
lines changed

xen/arch/x86/e820.c

+1-1
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

+2
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

+55-13
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@
99
#include <xen/mm.h>
1010
#include <xen/multiboot.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

+64-2
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
/*
@@ -68,11 +69,31 @@ void *memcpy(void *dest, const void *src, size_t n)
6869
return dest;
6970
}
7071

72+
static bool is_amd_cpu(void)
73+
{
74+
/*
75+
* asm/processor.h can't be included in early code, which means neither
76+
* cpuid() function nor boot_cpu_data can be used here.
77+
*/
78+
uint32_t eax, ebx, ecx, edx;
79+
asm volatile ( "cpuid"
80+
: "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx)
81+
: "0" (0), "c" (0) );
82+
return ebx == X86_VENDOR_AMD_EBX
83+
&& ecx == X86_VENDOR_AMD_ECX
84+
&& edx == X86_VENDOR_AMD_EDX;
85+
}
86+
7187
#else /* __EARLY_TPM__ */
7288

7389
#include <xen/mm.h>
7490
#include <xen/pfn.h>
7591

92+
static bool is_amd_cpu(void)
93+
{
94+
return boot_cpu_data.x86_vendor == X86_VENDOR_AMD;
95+
}
96+
7697
#endif /* __EARLY_TPM__ */
7798

7899
#define TPM_LOC_REG(loc, reg) (0x1000 * (loc) + (reg))
@@ -258,6 +279,21 @@ struct TPM12_PCREvent {
258279
uint8_t Data[];
259280
};
260281

282+
struct tpm1_spec_id_event {
283+
uint32_t pcrIndex;
284+
uint32_t eventType;
285+
uint8_t digest[20];
286+
uint32_t eventSize;
287+
uint8_t signature[16];
288+
uint32_t platformClass;
289+
uint8_t specVersionMinor;
290+
uint8_t specVersionMajor;
291+
uint8_t specErrata;
292+
uint8_t uintnSize;
293+
uint8_t vendorInfoSize;
294+
uint8_t vendorInfo[0]; /* variable number of members */
295+
} __packed;
296+
261297
struct txt_ev_log_container_12 {
262298
char Signature[20]; /* "TXT Event Container", null-terminated */
263299
uint8_t Reserved[12];
@@ -400,6 +436,15 @@ static void *create_log_event12(struct txt_ev_log_container_12 *evt_log,
400436
{
401437
struct TPM12_PCREvent *new_entry;
402438

439+
if ( is_amd_cpu() ) {
440+
/*
441+
* On AMD, TXT-compatible structure is stored as vendor data of
442+
* TCG-defined event log header.
443+
*/
444+
struct tpm1_spec_id_event *spec_id = (void *)evt_log;
445+
evt_log = (struct txt_ev_log_container_12 *)&spec_id->vendorInfo[0];
446+
}
447+
403448
new_entry = (void *)(((uint8_t *)evt_log) + evt_log->NextEventOffset);
404449

405450
/*
@@ -835,11 +880,28 @@ static uint32_t tpm2_hash_extend(unsigned loc, uint8_t *buf, unsigned size,
835880

836881
#endif /* __EARLY_TPM__ */
837882

838-
static struct heap_event_log_pointer_element2_1 *find_evt_log_ext_data(void)
883+
static struct heap_event_log_pointer_element2_1 *
884+
find_evt_log_ext_data(struct tpm2_spec_id_event *evt_log)
839885
{
840886
struct txt_os_sinit_data *os_sinit;
841887
struct txt_ext_data_element *ext_data;
842888

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

@@ -872,7 +934,7 @@ create_log_event20(struct tpm2_spec_id_event *evt_log, uint32_t evt_log_size,
872934
unsigned i;
873935
uint8_t *p;
874936

875-
log_ext_data = find_evt_log_ext_data();
937+
log_ext_data = find_evt_log_ext_data(evt_log);
876938
if ( log_ext_data == NULL )
877939
return log_hashes;
878940

0 commit comments

Comments
 (0)