Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Xen upstream #4

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open

Xen upstream #4

wants to merge 2 commits into from

Conversation

Asiderr
Copy link
Contributor

@Asiderr Asiderr commented Dec 23, 2020

No description provided.

@Asiderr Asiderr changed the title Xen upstream WIP: Xen upstream Dec 23, 2020
@Asiderr Asiderr force-pushed the xen_upstream branch 2 times, most recently from e978ba3 to 148e83a Compare December 23, 2020 17:40
Comment on lines 840 to 841
* initialized with AMD SKINIT. Also funtion clears the INIT_R bit, which
* indicates that the CPU was initialized with AMD SKINIT.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

INIT_R is not cleared in this commit, so the comment does not reflect the code.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've merged first to commits.

* 12th bit in ECX register for CPUID function numbered 8000_0001h
* indicates support for SKINIT.
*/
if (cpuid_ecx(0x80000001) & 0x1000)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you should also check if this is AMD processor. On Intel this bit is marked as reserved in current SDM, but they may decide to use it at some point in the future.

Copy link
Contributor Author

@Asiderr Asiderr Dec 28, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added the AuthenticAMD check.

@@ -586,6 +586,8 @@ static inline void enable_nmis(void)
[cs] "r" (__HYPERVISOR_CS) );
}

void clr_initr_stgi(void);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This probably won't be called outside of common.c, so maybe make it static there and don't declare it here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

@@ -413,6 +415,8 @@ void start_secondary(void *unused)

/* We can take interrupts now: we're officially "up". */
local_irq_enable();
if (__xen_run_by_SKINIT)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this be __cpu_SKINIT?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

@@ -431,49 +435,52 @@ static int wakeup_secondary_cpu(int phys_apicid, unsigned long start_eip)
apic_write(APIC_ESR, 0);
apic_read(APIC_ESR);

Dprintk("Asserting INIT.\n");
if (!__cpu_SKINIT)
Copy link
Member

@krystian-hebel krystian-hebel Dec 23, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add a comment that after SKINIT APs are already in wait-for-SIPI state and sending another INIT would break security, and something similar in the commit message.

https://www.amd.com/system/files/TechDocs/24593.pdf section 15.27.8:

A Startup IPI normally causes an AP to start execution at a location provided by the IPI. To support secure MP startup, each AP responds to a startup IPI by additionally clearing its GIF and setting the DPD, R_INIT and DIS_A20M flags in the VM_CR registerif, and only if, the BSP has indicated that it has executed an SKINIT. All other aspects of Startup IPI behavior remain unchanged.

and then a bit lower in AP Startup Sequence:

Care must also be taken to avoid issuing another INIT IPI from any processor after the BSP executes SKINIT and before all APs have received a Startup IPI, as this could compromise the integrity of AP initialization.

Copy link
Contributor Author

@Asiderr Asiderr Dec 28, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added the comment and the commit message.

@Asiderr Asiderr force-pushed the xen_upstream branch 3 times, most recently from 79e1012 to c94cccd Compare December 28, 2020 15:32
@Asiderr Asiderr changed the title WIP: Xen upstream Xen upstream Dec 28, 2020
@@ -413,6 +415,9 @@ void start_secondary(void *unused)

/* We can take interrupts now: we're officially "up". */
local_irq_enable();
/* If cpu was run with SKINIT, set global interrupts flag (GIF). */
if (__cpu_SKINIT)
svm_stgi();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cpu_init() is already called earlier in start_secondary(). No need for any SKINIT logic here

rdmsrl(MSR_K8_VM_CR, msr_content);
if (msr_content & K8_VMCR_R_INIT)
{
/* Clear INIT_R*/
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment needs extending. It is strictly necessary to clear R_INIT before stgi, so a pending INIT doesn't turn into #SX and we panic with an unknown exception.

Comment on lines 847 to 858
char id[12];
uint32_t eax = 0;
uint64_t msr_content;

/*
* 12th bit in ECX register for CPUID function numbered 8000_0001h
* indicates support for SKINIT.
*/
cpuid(0, &eax, (uint32_t *)&id[0], (uint32_t *)&id[8],
(uint32_t *)&id[4]);
if ((memcmp(id, "AuthenticAMD", 12) == 0)
&& (cpuid_ecx(0x80000001) & 0x1000))
Copy link
Contributor

@andyhhp andyhhp Dec 30, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use this hunk:

diff --git a/xen/include/asm-x86/cpufeature.h b/xen/include/asm-x86/cpufeature.h
index ad3d84bdde..f62e526a96 100644
--- a/xen/include/asm-x86/cpufeature.h
+++ b/xen/include/asm-x86/cpufeature.h
@@ -76,6 +76,7 @@
 #define cpu_has_svm             boot_cpu_has(X86_FEATURE_SVM)
 #define cpu_has_sse4a           boot_cpu_has(X86_FEATURE_SSE4A)
 #define cpu_has_xop             boot_cpu_has(X86_FEATURE_XOP)
+#define cpu_has_skinit          boot_cpu_has(X86_FEATURE_SKINIT)
 #define cpu_has_fma4            boot_cpu_has(X86_FEATURE_FMA4)
 #define cpu_has_tbm             boot_cpu_has(X86_FEATURE_TBM)

to wrap Xen's existing CPUID infrastructure, then use simply if ( cpu_has_skinit ) here. However, if you use it in its opposite form, you reduce the quantity of indentation in the rest of the function.

Amongst other things, you don't want to rule out Hygon CPUs which I believe also have SKINIT support.

&& (cpuid_ecx(0x80000001) & 0x1000))
{
/* Check is R_INIT bit set to determinate if xen was run by SKINIT */
rdmsrl(MSR_K8_VM_CR, msr_content);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's probably best to use rdmsr_safe() and wrmsr_safe() lower down. I don't trust virtual environments to get this emulation correct ;)

Comment on lines 909 to 910
* When CPU is initialized by AMD SKINIT, set GIF before before enabling
* NMIs. Otherwise CPU will not be able to drop into NMI context.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Its not really about enabling NMIs - that was merely the first thing which broke. Its about enabling all interrupt sources. How about /* When the CPU is initialised by AMD SKINIT, GIF is clear to prevent external interrupts interfering with secure startup. Re-enable all interrupts now that we are suitably set up. */

@@ -321,6 +321,8 @@
/* MSR_K8_VM_CR bits: */
#define _K8_VMCR_SVME_DISABLE 4
#define K8_VMCR_SVME_DISABLE (1 << _K8_VMCR_SVME_DISABLE)
#define _K8_VMCR_R_INIT 1
#define K8_VMCR_R_INIT (1 << _K8_VMCR_R_INIT)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We're attempting to drop redundant symbols. Nothing uses the shift value, so just define this as (_AC(1, ULL) << 1). I'll do a patch to clean up the adjacent SVME_DISABLE.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cleanup patch https://lore.kernel.org/xen-devel/20201230193525.12290-1-andrew.cooper3@citrix.com/T/#u. On top of this patch, you'll want

diff --git a/xen/include/asm-x86/msr-index.h b/xen/include/asm-x86/msr-index.h
index ff583cf0ed..1f5a5d0e38 100644
--- a/xen/include/asm-x86/msr-index.h
+++ b/xen/include/asm-x86/msr-index.h
@@ -117,6 +117,7 @@
 #define  PASID_VALID                        (_AC(1, ULL) << 31)
 
 #define MSR_K8_VM_CR                        0xc0010114
+#define  VM_CR_INIT_REDIRECTION             (_AC(1, ULL) <<  1)
 #define  VM_CR_SVM_DISABLE                  (_AC(1, ULL) <<  4)
 
 /*

@Asiderr
Copy link
Contributor Author

Asiderr commented Jan 7, 2021

@andyhhp I added suggestions and fixes to the commits.

@dozylynx
Copy link
Contributor

dozylynx commented Jan 7, 2021

Successful test report: I have booted into Xen 4.14.1-pre with the two patches from this PR applied on a PC Engines APU2 with the current latest firmware, and it shows PCRs 17 and 18 populated. Bootable image built using meta-trenchboot and with this patch applied to grub:
3mdeb/grub#13
3mdeb/grub@529ecde

I have no-real-mode on the Xen command line, as per the wic partition-building script in meta-trenchboot, and used Linux 5.5.3 from the 3mdeb repository for the dom0 kernel. I hope that it will be possible to update to use a modern 5.10 kernel with it soon.

Thanks for this work and best of luck with integrating it upstream.

Copy link
Contributor

@andyhhp andyhhp left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One other thing to say. It's getting close to the Xen 4.15 last-post deadline. If you want these fixes in Xen 4.15, v1 of them need posting to xen-devel within the next week.

In addition to these changes, are there any other bugs which need addressing? no-real-mode isn't something we can do in the timeframe (and at least there is a workaround for that), but I suspect Xen blindly assuming that the BDA exists in frame 0 probably wants fixing.

* 12th bit in ECX register for CPUID function numbered 8000_0001h
* indicates support for SKINIT.
*/
if (cpu_has_skinit)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

    if ( !cpu_has_skinit )
        return;

This reduces the indentation later in the function. Note the spaces as well inside the outermost brackes (yes - Xen style is a little weird, and it is further complicated here as you're modifying files which use different styles). Also, no need for the comment, seeing as there are no magic numbers in the if condition.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added your style suggestions (Xen style is sometimes confusing) and I deleted the comment.

Comment on lines 855 to 859
/* Check is R_INIT bit set to determinate if xen was run by SKINIT */
rdmsr_safe(MSR_K8_VM_CR, msr_content);
if (msr_content & VM_CR_INIT_REDIRECTION)
{
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need to check the return value from rdmsr_safe().

    if ( rdmsr_safe(MSR_K8_VM_CR, msr_content) ||
         !(msr_content & VM_CR_INIT_REDIRECTION) )
        return;

Also, all R_INIT's in comments need updating per the change to the VM_CR_INIT_REDIRECTION constant

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

Comment on lines 39 to 45
static inline void svm_stgi(void)
{
asm volatile (
".byte 0x0f,0x01,0xdc" /* STGI */
: : : "memory" );
}

Copy link
Contributor

@andyhhp andyhhp Jan 11, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, please just write this inline, rather than making a helper.

For one, we don't want to include lots of HVM internals into the common boot code, and there are no other places in C to legitimately use STGI. Also, feel free to collapse it into one line, rather than 3.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

@@ -45,10 +45,12 @@
#include <asm/spec_ctrl.h>
#include <asm/time.h>
#include <asm/tboot.h>
#include <asm/hvm/svm/svm.h>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale import now.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Deleted.

#include <irq_vectors.h>
#include <mach_apic.h>

unsigned long __read_mostly trampoline_phys;
extern bool __cpu_SKINIT;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We've got 3 different AP startup sequences. I think it would be better to have

enum ap_boot_method
{
    AP_BOOT_NORMAL,
    AP_BOOT_TXT,
    AP_BOOT_SKINIT,
};
extern enum ap_boot_method ap_boot_method;

in xen/include/asm-x86/processor.h (probably), with

enum ap_boot_method ap_boot_method = AP_BOOT_NORMAL;

in smpboot.c

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I created switch.

phys_apicid);

if ( !x2apic_enabled )
if (!__cpu_SKINIT)
Copy link
Contributor

@andyhhp andyhhp Jan 11, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This wants to turn into switch ( ap_boot_method ) (per the above enum suggestion) rather than being a nested if-else chain.

It would probably be better to split this patch into two - the first which introduces the enum, and converts the existing path (finding an appropriate point in the tboot code to set ap_boot_method = AP_BOOT_TXT rather than constantly calling tboot_in_measured_env()), and a second patch which adds the new AP_BOOT_SKINIT case.

[Edit] Depending on preference, you could keep the series as two patches. One cleanup patch for ap_boot_method and TXT, and the second patch which does both the AP_BOOT_SKINIT case and STGI in cpu_init(). This has the advantage that you introduce and set AP_BOOT_SKINIT together, rather than split across two patches.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I created the ap_boot_method for AP boot sequences and I placed ap_boot_method = AP_BOOT_TXT in tboot.c. I replaced tboot_in_measured_env() with ap_boot_method == AP_BOOT_TXT.

@pietrushnic
Copy link
Member

pietrushnic commented Jan 11, 2021

@dozylynx thank you very much for testing and @andyhhp for review.

x86/tboot: Replace tboot_in_measured_env with AP_BOOT_TXT compare

There are three different AP startup sequences which are declared
in ap_boot_method. Each method could be used to recognise startup
sequence. This patch replace tboot_in_measured_env is replaced with
AP_BOOT_TXT comparison.

Signed-off-by: Norbert Kamiński <norbert.kaminski@3mdeb.com>

if ( !cpu_has_skinit )
return;
if ( cpu_has_skinit )
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Drop this if, it is redundant

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

x86/cpu: Clear R_INIT bit and set AP_BOOT_SKINIT

When CPU is initialized with AMD SKINIT, GIF is clear to
prevent external interrupts interfering with secure startup.
STGI re-enable all interrupts, when the CPU is suitably
set up. R_INIT bit indicates that CPU was initialized with
SKINIT. This patch clears R_INIT bit to prevent turning
INIT into security exception (#SX). It would cause a panic
with an unknown exception. The AP_BOOT_SKINIT ap_boot_method
replace R_INIT bit.

Signed-off-by: Marek Kasiewicz <marek.kasiewicz@3mdeb.com>
Signed-off-by: Norbert Kamiński <norbert.kaminski@3mdeb.com>
@krystian-hebel
Copy link
Member

I have no-real-mode on the Xen command line, as per the wic partition-building script in meta-trenchboot, and used Linux 5.5.3 from the 3mdeb repository for the dom0 kernel. I hope that it will be possible to update to use a modern 5.10 kernel with it soon.

FYI, you don't need a special kernel for dom0 (at least for now, when only AMD is supported), unmodified one will do just fine - every measurement happens earlier, in LZ, thanks to condensed and easily parsable format of Multiboot2. It almost seems as if it was developed with this use case in mind, though I doubt its creators were aware of it back then 😃

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants