EDIT 02.2021: The blog post refers to the development stage of adding Trenchboot support for the Xen hypervisor. The upstream changes are available in the following commit: https://xenbits.xen.org/gitweb/?p=xen.git;a=commit;h=e4283bf38aae6c2f88cdbdaeef0f005a1a5f6c78
If you haven’t read previous blog posts from the TrenchBoot series, we strongly encourage you to catch up on it. The best way is to search under the TrenchBoot tag. In this blog post, we will describe the development of the Xen hypervisor support for TrenchBoot.
Global interrupt flag reinitialization
As we have mentioned in the previous blog post, until now the Landing Zone (LZ) has re-enabled the interrupts during the multiboot. But why it has to be done?
SKINIT
(Secure Init and Jump with Attestation) instruction securely
reinitializes the CPU and it allows startup of the trusted software such as
TrenchBoot. During the execution, the SKINIT
clears the global interrupts flag
(GIF). The GIF is a bit that controls whether interrupts and other events can be
taken by the processor. Disabled GIF causes the a panic error, because the CPU
is not able to drop into NMI context. The CPU uses the NMI context to prevent
crashes during sensitive operations. The logs presented below shows the panic
error caused by cleared GIF bit:
|
|
The solution to this problem is to set again the GIF after execution of
SKINIT
. We used STGI
(Set Global Interrupt Flag) instruction for this
purpose. We created the function in the secure virtual machine (SVM) header file
(svm.h
):
|
|
It calls STGI
instruction this sets GIF
. The function is called during the
CPU initialization, before the enabling NMIs in
common.c
:
|
|
With this change Xen hypervisor boots correctly:
Checking if Xen was started by SKINIT
Following GIF reinitialization should be done only when the CPU was started with
SKINIT
instruction. The SKINIT
is a specific instruction for AMD CPUs, so
first we check if the processor is AMD:
|
|
To this purpose, we are using the Processor Identification (CPUID). CPUID
functions provide information about the CPU and its feature set. Every CPUID
function consists of the function number and the output register(s). We will
explain CPUID
function at the example. When we are sure that processor is AMD,
we can check if the CPU supports SKINIT
and STGI
instruction. Following
CPUID
function holds information about SKINIT
support:
|
|
The number 8000_0001h
is the hexadecimal input value that is loaded to the
EAX
register. ECX
register is the output register. The 12th bit in the ECX
contains information about the SKINIT
support. In the Xen source, CPUID
instruction is implemented in the processor.h
file:
|
|
The function takes the CPUID
function number as an input. It calls CPUID
instruction and returns the ECX
register. The following function is called
during validation. We are checking if the 12th bit of the ECX
output register
is set:
|
|
When we know that CPU supports SKINIT
, we can safely determine whether the Xen
was started by this instruction. That fact is indicated by the R_INIT
bit in
the VM_CR MSR
register. This bit is set by the SKINIT
and should be cleared
after reading.
In code VM_CR MSR
can be read by rdmsrl
function which is a just wrap of the
assembly instruction rdmsrl
. It reads the content of model specific registers.
|
|
The R_INIT bit can be cleared with the following instructions:
|
|
Previously, the R_INIT
bit was reset by LZ. The R_INIT
is replaced with
__cpu_SKINIT
flag.
The changes are specified in the following pull request.
Summary
In the next blog post, we will present the remote attestation system using IETF RATS. So I encourage you to check our blog regularly. If you have any questions, suggestions, or ideas, feel free to share them in the comment section. If you are interested in similar content, I encourage you to sign up for our newsletter.