1from ..xmlbuilder import XMLBuilder, XMLProperty
2
3
4class DomainLaunchSecurity(XMLBuilder):
5    """
6    Class for generating <launchSecurity> XML element
7    """
8
9    XML_NAME = "launchSecurity"
10    _XML_PROP_ORDER = ["type", "cbitpos", "reducedPhysBits", "policy",
11            "session", "dhCert"]
12
13    type = XMLProperty("./@type")
14    cbitpos = XMLProperty("./cbitpos", is_int=True)
15    reducedPhysBits = XMLProperty("./reducedPhysBits", is_int=True)
16    policy = XMLProperty("./policy")
17    session = XMLProperty("./session")
18    dhCert = XMLProperty("./dhCert")
19
20    def is_sev(self):
21        return self.type == "sev"
22
23    def validate(self):
24        if not self.type:
25            raise RuntimeError(_("Missing mandatory attribute 'type'"))
26
27    def _set_defaults_sev(self, guest):
28        # SeaBIOS doesn't have support for SEV. Q35 defaults to virtio 1.0,
29        # which we need so let's not go through the 'virtio-transitional'
30        # exercise for pc-i440fx to make SEV work, AMD recommends Q35 anyway
31        # NOTE: at some point both of these platform checks should be put in
32        # validate(), once that accepts the 'guest' instance
33        if guest.os.is_q35() is False or guest.os.loader_type != "pflash":
34            raise RuntimeError(_("SEV launch security requires a Q35 UEFI machine"))
35
36        # libvirt or QEMU might not support SEV
37        domcaps = guest.lookup_domcaps()
38        if not domcaps.supports_sev_launch_security():
39            raise RuntimeError(_("SEV launch security is not supported on this platform"))
40
41        # 'policy' is a mandatory 4-byte argument for the SEV firmware,
42        # if missing, let's use 0x03 which, according to the table at
43        # https://libvirt.org/formatdomain.html#launchSecurity:
44        # (bit 0) - disables the debugging mode
45        # (bit 1) - disables encryption key sharing across multiple guests
46        if self.policy is None:
47            self.policy = "0x03"
48
49        if self.cbitpos is None:
50            self.cbitpos = domcaps.features.sev.cbitpos
51        if self.reducedPhysBits is None:
52            self.reducedPhysBits = domcaps.features.sev.reducedPhysBits
53
54    def set_defaults(self, guest):
55        if self.is_sev():
56            return self._set_defaults_sev(guest)
57