mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-12-22 05:35:25 +00:00
tools: support automatically constructing SEV-ES vCPU state
The VMSA files contain the expected CPU register state for the VM. Their content varies based on a few pieces of the stack - AMD CPU architectural initial state - KVM hypervisor VM CPU initialization - QEMU userspace VM CPU initialization - AMD CPU SKU (family/model/stepping) The first three pieces of information we can obtain through code inspection. The last piece of information we can take on the command line. This allows a user to validate a SEV-ES guest merely by providing the CPU SKU information, using --cpu-family, --cpu-model, --cpu-stepping. This avoids the need to obtain or construct VMSA files directly. Reviewed-by: Cole Robinson <crobinso@redhat.com> Reviewed-by: Ján Tomko <jtomko@redhat.com> Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
This commit is contained in:
parent
3e7b7da9e0
commit
676df5b358
@ -245,6 +245,24 @@ Validate the measurement of a SEV-ES SMP guest booting from disk:
|
||||
--build-id 13 \
|
||||
--policy 7
|
||||
|
||||
Validate the measurement of a SEV-ES SMP guest booting from disk, with
|
||||
automatically constructed VMSA:
|
||||
|
||||
::
|
||||
|
||||
# virt-dom-sev-validate \
|
||||
--firmware OVMF.sev.fd \
|
||||
--num-cpus 2 \
|
||||
--cpu-family 23 \
|
||||
--cpu-model 49 \
|
||||
--cpu-stepping 0 \
|
||||
--tk this-guest-tk.bin \
|
||||
--measurement Zs2pf19ubFSafpZ2WKkwquXvACx9Wt/BV+eJwQ/taO8jhyIj/F8swFrybR1fZ2ID \
|
||||
--api-major 0 \
|
||||
--api-minor 24 \
|
||||
--build-id 13 \
|
||||
--policy 7
|
||||
|
||||
Fetch from remote libvirt
|
||||
-------------------------
|
||||
|
||||
@ -291,6 +309,20 @@ Validate the measurement of a SEV-ES SMP guest booting from disk:
|
||||
--tk this-guest-tk.bin \
|
||||
--domain fedora34x86_64
|
||||
|
||||
Validate the measurement of a SEV-ES SMP guest booting from disk, with
|
||||
automatically constructed VMSA:
|
||||
|
||||
::
|
||||
|
||||
# virt-dom-sev-validate \
|
||||
--connect qemu+ssh://root@some.remote.host/system \
|
||||
--firmware OVMF.sev.fd \
|
||||
--cpu-family 23 \
|
||||
--cpu-model 49 \
|
||||
--cpu-stepping 0 \
|
||||
--tk this-guest-tk.bin \
|
||||
--domain fedora34x86_64
|
||||
|
||||
Fetch from local libvirt
|
||||
------------------------
|
||||
|
||||
@ -332,6 +364,19 @@ Validate the measurement of a SEV-ES SMP guest booting from disk:
|
||||
--tk this-guest-tk.bin \
|
||||
--domain fedora34x86_64
|
||||
|
||||
Validate the measurement of a SEV-ES SMP guest booting from disk, with
|
||||
automatically constructed VMSA:
|
||||
|
||||
::
|
||||
|
||||
# virt-dom-sev-validate \
|
||||
--insecure \
|
||||
--cpu-family 23 \
|
||||
--cpu-model 49 \
|
||||
--cpu-stepping 0 \
|
||||
--tk this-guest-tk.bin \
|
||||
--domain fedora34x86_64
|
||||
|
||||
EXIT STATUS
|
||||
===========
|
||||
|
||||
|
@ -42,6 +42,7 @@ import hmac
|
||||
import logging
|
||||
import re
|
||||
import socket
|
||||
from struct import pack
|
||||
import sys
|
||||
import traceback
|
||||
from uuid import UUID
|
||||
@ -72,6 +73,427 @@ class InvalidStateException(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class Field(object):
|
||||
U8 = 0
|
||||
U16 = 2
|
||||
U32 = 4
|
||||
U64 = 8
|
||||
|
||||
SCALAR = 0
|
||||
BITMASK = 1
|
||||
ARRAY = 2
|
||||
|
||||
def __init__(self, name, size, fmt, value, order):
|
||||
self.name = name
|
||||
self.size = size
|
||||
self.value = value
|
||||
self.fmt = fmt
|
||||
self.order = order
|
||||
|
||||
|
||||
class Struct(object):
|
||||
def __init__(self, size):
|
||||
self._fields = {}
|
||||
self.size = size
|
||||
|
||||
def register_field(self, name, size, fmt=Field.SCALAR, defvalue=0):
|
||||
self._fields[name] = Field(name, size, fmt,
|
||||
defvalue, len(self.fields))
|
||||
|
||||
@property
|
||||
def fields(self):
|
||||
return sorted(self._fields.values(), key=lambda f: f.order)
|
||||
|
||||
def __getattr__(self, name):
|
||||
return self._fields[name]
|
||||
|
||||
def __setattr__(self, name, value):
|
||||
if name in ["_fields", "size"]:
|
||||
super().__setattr__(name, value)
|
||||
else:
|
||||
self._fields[name].value = value
|
||||
|
||||
def binary_format(self):
|
||||
fmt = ["<"]
|
||||
datalen = 0
|
||||
for field in self.fields:
|
||||
if field.size == Field.U8:
|
||||
if field.fmt == Field.ARRAY:
|
||||
datalen += len(field.value)
|
||||
fmt += ["%dB" % len(field.value)]
|
||||
else:
|
||||
datalen += 1
|
||||
fmt += ["B"]
|
||||
elif field.size == Field.U16:
|
||||
datalen += 2
|
||||
fmt += ["H"]
|
||||
elif field.size == Field.U32:
|
||||
datalen += 4
|
||||
fmt += ["L"]
|
||||
elif field.size == Field.U64:
|
||||
datalen += 8
|
||||
fmt += ["Q"]
|
||||
|
||||
pad = self.size - datalen
|
||||
assert self.size >= 1
|
||||
fmt += ["%dB" % pad]
|
||||
|
||||
return "".join(fmt), pad
|
||||
|
||||
def pack(self):
|
||||
fmt, pad = self.binary_format()
|
||||
|
||||
values = []
|
||||
for field in self.fields:
|
||||
if field.size == Field.U8 and field.fmt == Field.ARRAY:
|
||||
for _, k in enumerate(field.value):
|
||||
values.append(k)
|
||||
else:
|
||||
values.append(field.value)
|
||||
values.extend([0] * pad)
|
||||
|
||||
return pack(fmt, *values)
|
||||
|
||||
|
||||
class VMSA(Struct):
|
||||
ATTR_G_SHIFT = 23
|
||||
ATTR_G_MASK = (1 << ATTR_G_SHIFT)
|
||||
ATTR_B_SHIFT = 22
|
||||
ATTR_B_MASK = (1 << ATTR_B_SHIFT)
|
||||
ATTR_L_SHIFT = 21
|
||||
ATTR_L_MASK = (1 << ATTR_L_SHIFT)
|
||||
ATTR_AVL_SHIFT = 20
|
||||
ATTR_AVL_MASK = (1 << ATTR_AVL_SHIFT)
|
||||
ATTR_P_SHIFT = 15
|
||||
ATTR_P_MASK = (1 << ATTR_P_SHIFT)
|
||||
ATTR_DPL_SHIFT = 13
|
||||
ATTR_DPL_MASK = (3 << ATTR_DPL_SHIFT)
|
||||
ATTR_S_SHIFT = 12
|
||||
ATTR_S_MASK = (1 << ATTR_S_SHIFT)
|
||||
ATTR_TYPE_SHIFT = 8
|
||||
ATTR_TYPE_MASK = (15 << ATTR_TYPE_SHIFT)
|
||||
ATTR_A_MASK = (1 << 8)
|
||||
|
||||
ATTR_CS_MASK = (1 << 11)
|
||||
ATTR_C_MASK = (1 << 10)
|
||||
ATTR_R_MASK = (1 << 9)
|
||||
|
||||
ATTR_E_MASK = (1 << 10)
|
||||
ATTR_W_MASK = (1 << 9)
|
||||
|
||||
def __init__(self):
|
||||
super().__init__(4096)
|
||||
|
||||
# From Linux arch/x86/include/asm/svm.h, we're unpacking the
|
||||
# struct vmcb_save_area
|
||||
|
||||
self.register_field("es_selector", Field.U16)
|
||||
self.register_field("es_attrib", Field.U16, Field.BITMASK)
|
||||
self.register_field("es_limit", Field.U32)
|
||||
self.register_field("es_base", Field.U64)
|
||||
|
||||
self.register_field("cs_selector", Field.U16)
|
||||
self.register_field("cs_attrib", Field.U16, Field.BITMASK)
|
||||
self.register_field("cs_limit", Field.U32)
|
||||
self.register_field("cs_base", Field.U64)
|
||||
|
||||
self.register_field("ss_selector", Field.U16)
|
||||
self.register_field("ss_attrib", Field.U16, Field.BITMASK)
|
||||
self.register_field("ss_limit", Field.U32)
|
||||
self.register_field("ss_base", Field.U64)
|
||||
|
||||
self.register_field("ds_selector", Field.U16)
|
||||
self.register_field("ds_attrib", Field.U16, Field.BITMASK)
|
||||
self.register_field("ds_limit", Field.U32)
|
||||
self.register_field("ds_base", Field.U64)
|
||||
|
||||
self.register_field("fs_selector", Field.U16)
|
||||
self.register_field("fs_attrib", Field.U16, Field.BITMASK)
|
||||
self.register_field("fs_limit", Field.U32)
|
||||
self.register_field("fs_base", Field.U64)
|
||||
|
||||
self.register_field("gs_selector", Field.U16)
|
||||
self.register_field("gs_attrib", Field.U16, Field.BITMASK)
|
||||
self.register_field("gs_limit", Field.U32)
|
||||
self.register_field("gs_base", Field.U64)
|
||||
|
||||
self.register_field("gdtr_selector", Field.U16)
|
||||
self.register_field("gdtr_attrib", Field.U16, Field.BITMASK)
|
||||
self.register_field("gdtr_limit", Field.U32)
|
||||
self.register_field("gdtr_base", Field.U64)
|
||||
|
||||
self.register_field("ldtr_selector", Field.U16)
|
||||
self.register_field("ldtr_attrib", Field.U16, Field.BITMASK)
|
||||
self.register_field("ldtr_limit", Field.U32)
|
||||
self.register_field("ldtr_base", Field.U64)
|
||||
|
||||
self.register_field("idtr_selector", Field.U16)
|
||||
self.register_field("idtr_attrib", Field.U16, Field.BITMASK)
|
||||
self.register_field("idtr_limit", Field.U32)
|
||||
self.register_field("idtr_base", Field.U64)
|
||||
|
||||
self.register_field("tr_selector", Field.U16)
|
||||
self.register_field("tr_attrib", Field.U16, Field.BITMASK)
|
||||
self.register_field("tr_limit", Field.U32)
|
||||
self.register_field("tr_base", Field.U64)
|
||||
|
||||
self.register_field("reserved_1",
|
||||
Field.U8, Field.ARRAY, bytearray([0] * 43))
|
||||
|
||||
self.register_field("cpl", Field.U8)
|
||||
|
||||
self.register_field("reserved_2",
|
||||
Field.U8, Field.ARRAY, bytearray([0] * 4))
|
||||
|
||||
self.register_field("efer", Field.U64)
|
||||
|
||||
self.register_field("reserved_3",
|
||||
Field.U8, Field.ARRAY, bytearray([0] * 104))
|
||||
|
||||
self.register_field("xss", Field.U64)
|
||||
self.register_field("cr4", Field.U64)
|
||||
self.register_field("cr3", Field.U64)
|
||||
self.register_field("cr0", Field.U64)
|
||||
self.register_field("dr7", Field.U64)
|
||||
self.register_field("dr6", Field.U64)
|
||||
self.register_field("rflags", Field.U64)
|
||||
self.register_field("rip", Field.U64)
|
||||
|
||||
self.register_field("reserved_4",
|
||||
Field.U8, Field.ARRAY, bytearray([0] * 88))
|
||||
|
||||
self.register_field("rsp", Field.U64)
|
||||
|
||||
self.register_field("reserved_5",
|
||||
Field.U8, Field.ARRAY, bytearray([0] * 24))
|
||||
|
||||
self.register_field("rax", Field.U64)
|
||||
self.register_field("star", Field.U64)
|
||||
self.register_field("lstar", Field.U64)
|
||||
self.register_field("cstar", Field.U64)
|
||||
self.register_field("sfmask", Field.U64)
|
||||
self.register_field("kernel_gs_base", Field.U64)
|
||||
self.register_field("sysenter_cs", Field.U64)
|
||||
self.register_field("sysenter_esp", Field.U64)
|
||||
self.register_field("sysenter_eip", Field.U64)
|
||||
self.register_field("cr2", Field.U64)
|
||||
|
||||
self.register_field("reserved_6",
|
||||
Field.U8, Field.ARRAY, bytearray([0] * 32))
|
||||
|
||||
self.register_field("g_pat", Field.U64)
|
||||
self.register_field("dbgctl", Field.U64)
|
||||
self.register_field("br_from", Field.U64)
|
||||
self.register_field("br_to", Field.U64)
|
||||
self.register_field("last_excp_from", Field.U64)
|
||||
self.register_field("last_excp_to", Field.U64)
|
||||
|
||||
self.register_field("reserved_7",
|
||||
Field.U8, Field.ARRAY, bytearray([0] * 72))
|
||||
|
||||
self.register_field("spec_ctrl", Field.U32)
|
||||
|
||||
self.register_field("reserved_7b",
|
||||
Field.U8, Field.ARRAY, bytearray([0] * 4))
|
||||
|
||||
self.register_field("pkru", Field.U32)
|
||||
|
||||
self.register_field("reserved_7a",
|
||||
Field.U8, Field.ARRAY, bytearray([0] * 20))
|
||||
|
||||
self.register_field("reserved_8", Field.U64) # rax duplicate
|
||||
|
||||
self.register_field("rcx", Field.U64)
|
||||
self.register_field("rdx", Field.U64, Field.BITMASK)
|
||||
self.register_field("rbx", Field.U64)
|
||||
|
||||
self.register_field("reserved_9", Field.U64) # rsp duplicate
|
||||
|
||||
self.register_field("rbp", Field.U64)
|
||||
self.register_field("rsi", Field.U64)
|
||||
self.register_field("rdi", Field.U64)
|
||||
self.register_field("r8", Field.U64)
|
||||
self.register_field("r9", Field.U64)
|
||||
self.register_field("r10", Field.U64)
|
||||
self.register_field("r11", Field.U64)
|
||||
self.register_field("r12", Field.U64)
|
||||
self.register_field("r13", Field.U64)
|
||||
self.register_field("r14", Field.U64)
|
||||
self.register_field("r15", Field.U64)
|
||||
|
||||
self.register_field("reserved_10",
|
||||
Field.U8, Field.ARRAY, bytearray([0] * 16))
|
||||
|
||||
self.register_field("sw_exit_code", Field.U64)
|
||||
self.register_field("sw_exit_info_1", Field.U64)
|
||||
self.register_field("sw_exit_info_2", Field.U64)
|
||||
self.register_field("sw_scratch", Field.U64)
|
||||
|
||||
self.register_field("reserved_11",
|
||||
Field.U8, Field.ARRAY, bytearray([0] * 56))
|
||||
|
||||
self.register_field("xcr0", Field.U64)
|
||||
self.register_field("valid_bitmap",
|
||||
Field.U8, Field.ARRAY, bytearray([0] * 16))
|
||||
self.register_field("x87_state_gpa",
|
||||
Field.U64)
|
||||
|
||||
def amd64_cpu_init(self):
|
||||
# AMD64 Architecture Programmer’s Manual
|
||||
# Volume 2: System Programming.
|
||||
#
|
||||
# 14.1.3 Processor Initialization State
|
||||
#
|
||||
# Values after INIT
|
||||
|
||||
self.cr0 = (1 << 4)
|
||||
self.rip = 0xfff0
|
||||
|
||||
self.cs_selector = 0xf000
|
||||
self.cs_base = 0xffff0000
|
||||
self.cs_limit = 0xffff
|
||||
|
||||
self.ds_limit = 0xffff
|
||||
|
||||
self.es_limit = 0xffff
|
||||
self.fs_limit = 0xffff
|
||||
self.gs_limit = 0xffff
|
||||
self.ss_limit = 0xffff
|
||||
|
||||
self.gdtr_limit = 0xffff
|
||||
self.idtr_limit = 0xffff
|
||||
|
||||
self.ldtr_limit = 0xffff
|
||||
self.tr_limit = 0xffff
|
||||
|
||||
self.dr6 = 0xffff0ff0
|
||||
self.dr7 = 0x0400
|
||||
self.rflags = 0x2
|
||||
self.xcr0 = 0x1
|
||||
|
||||
def kvm_cpu_init(self):
|
||||
# svm_set_cr4() sets guest X86_CR4_MCE bit if host
|
||||
# has X86_CR4_MCE enabled
|
||||
self.cr4 = 0x40
|
||||
|
||||
# svm_set_efer sets guest EFER_SVME (Secure Virtual Machine enable)
|
||||
self.efer = 0x1000
|
||||
|
||||
# init_vmcb + init_sys_seg() sets
|
||||
# SVM_SELECTOR_P_MASK | SEG_TYPE_LDT
|
||||
self.ldtr_attrib = 0x0082
|
||||
|
||||
# init_vmcb + init_sys_seg() sets
|
||||
# SVM_SELECTOR_P_MASK | SEG_TYPE_BUSY_TSS16
|
||||
self.tr_attrib = 0x0083
|
||||
|
||||
# kvm_arch_vcpu_create() in arch/x86/kvm/x86.c
|
||||
self.g_pat = 0x0007040600070406
|
||||
|
||||
def qemu_cpu_init(self):
|
||||
# Based on logic in x86_cpu_reset()
|
||||
#
|
||||
# file target/i386/cpu.c
|
||||
|
||||
def attr(mask):
|
||||
return (mask >> VMSA.ATTR_TYPE_SHIFT)
|
||||
|
||||
self.ldtr_attrib = attr(VMSA.ATTR_P_MASK |
|
||||
(2 << VMSA.ATTR_TYPE_SHIFT))
|
||||
self.tr_attrib = attr(VMSA.ATTR_P_MASK |
|
||||
(11 << VMSA.ATTR_TYPE_SHIFT))
|
||||
self.cs_attrib = attr(VMSA.ATTR_P_MASK |
|
||||
VMSA.ATTR_S_MASK |
|
||||
VMSA.ATTR_CS_MASK |
|
||||
VMSA.ATTR_R_MASK |
|
||||
VMSA.ATTR_A_MASK)
|
||||
self.ds_attrib = attr(VMSA.ATTR_P_MASK |
|
||||
VMSA.ATTR_S_MASK |
|
||||
VMSA.ATTR_W_MASK |
|
||||
VMSA.ATTR_A_MASK)
|
||||
self.es_attrib = attr(VMSA.ATTR_P_MASK |
|
||||
VMSA.ATTR_S_MASK |
|
||||
VMSA.ATTR_W_MASK |
|
||||
VMSA.ATTR_A_MASK)
|
||||
self.ss_attrib = attr(VMSA.ATTR_P_MASK |
|
||||
VMSA.ATTR_S_MASK |
|
||||
VMSA.ATTR_W_MASK |
|
||||
VMSA.ATTR_A_MASK)
|
||||
self.fs_attrib = attr(VMSA.ATTR_P_MASK |
|
||||
VMSA.ATTR_S_MASK |
|
||||
VMSA.ATTR_W_MASK |
|
||||
VMSA.ATTR_A_MASK)
|
||||
self.gs_attrib = attr(VMSA.ATTR_P_MASK |
|
||||
VMSA.ATTR_S_MASK |
|
||||
VMSA.ATTR_W_MASK |
|
||||
VMSA.ATTR_A_MASK)
|
||||
|
||||
self.g_pat = 0x0007040600070406
|
||||
|
||||
def cpu_sku(self, family, model, stepping):
|
||||
stepping &= 0xf
|
||||
model &= 0xff
|
||||
family &= 0xfff
|
||||
|
||||
self.rdx.value = stepping
|
||||
|
||||
if family > 0xf:
|
||||
self.rdx.value |= 0xf00 | ((family - 0x0f) << 20)
|
||||
else:
|
||||
self.rdx.value |= family << 8
|
||||
|
||||
self.rdx.value |= ((model & 0xf) << 4) | ((model >> 4) << 16)
|
||||
|
||||
def reset_addr(self, reset_addr):
|
||||
reset_cs = reset_addr & 0xffff0000
|
||||
reset_ip = reset_addr & 0x0000ffff
|
||||
|
||||
self.rip.value = reset_ip
|
||||
self.cs_base.value = reset_cs
|
||||
|
||||
|
||||
class OVMF(object):
|
||||
|
||||
OVMF_TABLE_FOOTER_GUID = UUID("96b582de-1fb2-45f7-baea-a366c55a082d")
|
||||
SEV_INFO_BLOCK_GUID = UUID("00f771de-1a7e-4fcb-890e-68c77e2fb44e")
|
||||
|
||||
def __init__(self):
|
||||
self.entries = {}
|
||||
|
||||
def load(self, content):
|
||||
expect = OVMF.OVMF_TABLE_FOOTER_GUID.bytes_le
|
||||
actual = content[-48:-32]
|
||||
if expect != actual:
|
||||
raise Exception("OVMF footer GUID not found")
|
||||
|
||||
tablelen = int.from_bytes(content[-50:-48], byteorder='little')
|
||||
|
||||
if tablelen == 0:
|
||||
raise Exception("OVMF tables zero length")
|
||||
|
||||
table = content[-(32 + tablelen):-50]
|
||||
|
||||
self.parse_table(table)
|
||||
|
||||
def parse_table(self, data):
|
||||
while len(data) > 0:
|
||||
entryuuid = UUID(bytes_le=data[-16:])
|
||||
entrylen = int.from_bytes(data[-18:-16], byteorder='little')
|
||||
entrydata = data[-entrylen:-18]
|
||||
|
||||
self.entries[str(entryuuid)] = entrydata
|
||||
|
||||
data = data[0:-entrylen]
|
||||
|
||||
def reset_addr(self):
|
||||
if str(OVMF.SEV_INFO_BLOCK_GUID) not in self.entries:
|
||||
raise Exception("SEV info block GUID not found")
|
||||
|
||||
reset_addr = int.from_bytes(
|
||||
self.entries[str(OVMF.SEV_INFO_BLOCK_GUID)], "little")
|
||||
return reset_addr
|
||||
|
||||
|
||||
class GUIDTable(abc.ABC):
|
||||
GUID_LEN = 16
|
||||
|
||||
@ -242,6 +664,26 @@ class ConfidentialVM(object):
|
||||
log.debug("VMSA CPU 1(sha256): %s",
|
||||
sha256(self.vmsa_cpu1).hexdigest())
|
||||
|
||||
def build_vmsas(self, family, model, stepping):
|
||||
ovmf = OVMF()
|
||||
ovmf.load(self.firmware)
|
||||
|
||||
vmsa = VMSA()
|
||||
vmsa.amd64_cpu_init()
|
||||
vmsa.kvm_cpu_init()
|
||||
vmsa.qemu_cpu_init()
|
||||
|
||||
vmsa.cpu_sku(family, model, stepping)
|
||||
|
||||
self.vmsa_cpu0 = vmsa.pack()
|
||||
log.debug("VMSA CPU 0(sha256): %s",
|
||||
sha256(self.vmsa_cpu0).hexdigest())
|
||||
|
||||
vmsa.reset_addr(ovmf.reset_addr())
|
||||
self.vmsa_cpu1 = vmsa.pack()
|
||||
log.debug("VMSA CPU 1(sha256): %s",
|
||||
sha256(self.vmsa_cpu1).hexdigest())
|
||||
|
||||
def get_cpu_state(self):
|
||||
if self.num_cpus is None:
|
||||
raise UnsupportedUsageException(
|
||||
@ -514,6 +956,12 @@ def parse_command_line():
|
||||
help='VMSA state for the boot CPU')
|
||||
vmconfig.add_argument('--vmsa-cpu1', '-1',
|
||||
help='VMSA state for the additional CPUs')
|
||||
vmconfig.add_argument('--cpu-family', type=int,
|
||||
help='Hypervisor host CPU family number')
|
||||
vmconfig.add_argument('--cpu-model', type=int,
|
||||
help='Hypervisor host CPU model number')
|
||||
vmconfig.add_argument('--cpu-stepping', type=int,
|
||||
help='Hypervisor host CPU stepping number')
|
||||
vmconfig.add_argument('--tik',
|
||||
help='TIK file for domain')
|
||||
vmconfig.add_argument('--tek',
|
||||
@ -577,6 +1025,20 @@ def check_usage(args):
|
||||
raise UnsupportedUsageException(
|
||||
"--initrd/--cmdline require --kernel")
|
||||
|
||||
sku = [args.cpu_family, args.cpu_model, args.cpu_stepping]
|
||||
if sku.count(None) == len(sku):
|
||||
if args.vmsa_cpu1 is not None and args.vmsa_cpu0 is None:
|
||||
raise UnsupportedUsageException(
|
||||
"VMSA for additional CPU also requires VMSA for boot CPU")
|
||||
else:
|
||||
if args.vmsa_cpu0 is not None or args.vmsa_cpu1 is not None:
|
||||
raise UnsupportedUsageException(
|
||||
"VMSA files are mutually exclusive with CPU SKU")
|
||||
|
||||
if sku.count(None) != 0:
|
||||
raise UnsupportedUsageException(
|
||||
"CPU SKU needs family, model and stepping for SEV-ES domain")
|
||||
|
||||
|
||||
def attest(args):
|
||||
if args.domain is None:
|
||||
@ -617,6 +1079,11 @@ def attest(args):
|
||||
if args.vmsa_cpu1 is not None:
|
||||
cvm.load_vmsa_cpu1(args.vmsa_cpu1)
|
||||
|
||||
if args.cpu_family is not None:
|
||||
cvm.build_vmsas(args.cpu_family,
|
||||
args.cpu_model,
|
||||
args.cpu_stepping)
|
||||
|
||||
if args.domain is not None:
|
||||
cvm.load_domain(args.connect,
|
||||
args.domain,
|
||||
|
Loading…
Reference in New Issue
Block a user