From: Markus Frank <m.frank@proxmox.com>
To: pve-devel@lists.proxmox.com
Subject: [pve-devel] [PATCH qemu-server v5 2/3] config: QEMU AMD SEV enable
Date: Fri, 19 Apr 2024 12:10:48 +0200 [thread overview]
Message-ID: <20240419101049.697299-2-m.frank@proxmox.com> (raw)
In-Reply-To: <20240419101049.697299-1-m.frank@proxmox.com>
This patch is for enabling AMD SEV (Secure Encrypted
Virtualization) support in QEMU
VM-Config-Examples:
amd_sev: type=std,nodbg=1,noks=1
amd_sev: es,nodbg=1,kernel-hashes=1
Node-Config-Example (gets generated automatically):
amd_sev: cbitpos=47,reduced-phys-bios=1
kernel-hashes, reduced-phys-bios & cbitpos correspond to the varibles
with the same name in qemu.
kernel-hashes=1 adds kernel-hashes to enable measured linux kernel
launch since it is per default off for backward compatibility.
reduced-phys-bios and cbitpos are system specific and are read out by
the amd-sev-support.service on boot and saved to the /run/amd-sev-params
file. This file is parsed and than used by qemu-server to correctly
start a AMD SEV VM.
type=std stands for standard sev to differentiate it from sev-es (es)
or sev-snp (snp) when support is upstream.
QEMU's sev-guest policy gets calculated with the parameters nodbg & noks
These parameters correspond to policy-bits 0 & 1.
If type is 'es' than policy-bit 2 gets set to 1 to activate SEV-ES.
Policy bit 3 (nosend) is always set to 1, because migration
features for sev are not upstream yet and are attackable.
SEV-ES is highly experimental since it could not be tested.
see coherent doc patch
Signed-off-by: Markus Frank <m.frank@proxmox.com>
---
v5:
* parse /run/amd-sev-params for hardware parameters
* removed NodeConfig dependency
* only disallow live-migration and snapshots with vmstate
-> allow offline migration and snapshots without vmstate
v4:
* reduced lines of code
* added text that SEV-ES is experimental
PVE/API2/Qemu.pm | 10 +++++
PVE/QemuMigrate.pm | 4 ++
PVE/QemuServer.pm | 102 +++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 116 insertions(+)
diff --git a/PVE/API2/Qemu.pm b/PVE/API2/Qemu.pm
index 497987f..b35ab69 100644
--- a/PVE/API2/Qemu.pm
+++ b/PVE/API2/Qemu.pm
@@ -4490,6 +4490,10 @@ __PACKAGE__->register_method({
push $local_resources->@*, "clipboard=vnc";
}
+ if ($res->{running} && $vmconf->{amd_sev}) {
+ push $local_resources->@*, "amd_sev";
+ }
+
# if vm is not running, return target nodes where local storage/mapped devices are available
# for offline migration
if (!$res->{running}) {
@@ -5170,6 +5174,12 @@ __PACKAGE__->register_method({
die "unable to use snapshot name 'pending' (reserved name)\n"
if lc($snapname) eq 'pending';
+ my $conf = PVE::QemuConfig->load_config($vmid);
+ if ($param->{vmstate} && $conf->{amd_sev}) {
+ die "Snapshots that include memory are not supported while memory"
+ ." is encrypted by AMD SEV.\n"
+ }
+
my $realcmd = sub {
PVE::Cluster::log_msg('info', $authuser, "snapshot VM $vmid: $snapname");
PVE::QemuConfig->snapshot_create($vmid, $snapname, $param->{vmstate},
diff --git a/PVE/QemuMigrate.pm b/PVE/QemuMigrate.pm
index 8d9b35a..7db18b2 100644
--- a/PVE/QemuMigrate.pm
+++ b/PVE/QemuMigrate.pm
@@ -260,6 +260,10 @@ sub prepare {
die "VMs with 'clipboard' set to 'vnc' are not live migratable!\n";
}
+ if ($running && $conf->{'amd_sev'}) {
+ die "VMs with AMD SEV are not live migratable!\n";
+ }
+
my $vollist = PVE::QemuServer::get_vm_volumes($conf);
my $storages = {};
diff --git a/PVE/QemuServer.pm b/PVE/QemuServer.pm
index 6e2c805..e1ad190 100644
--- a/PVE/QemuServer.pm
+++ b/PVE/QemuServer.pm
@@ -185,6 +185,59 @@ my $agent_fmt = {
},
};
+my $sev_fmt = {
+ type => {
+ description => "Enable standard SEV with type='std' or enable experimental SEV-ES"
+ ." with the 'es' option.",
+ type => 'string',
+ default_key => 1,
+ format_description => "qemu-sev-type",
+ enum => ['std', 'es'],
+ maxLength => 3,
+ },
+ nodbg => {
+ description => "Sets policy bit 0 to 1 to disallow debugging of guest",
+ type => 'boolean',
+ format_description => "qemu-sev-nodbg",
+ default => 0,
+ optional => 1,
+ },
+ noks => {
+ description => "Sets policy bit 1 to 1 to disallow key sharing with other guests",
+ type => 'boolean',
+ format_description => "qemu-sev-noks",
+ default => 0,
+ optional => 1,
+ },
+ "kernel-hashes" => {
+ description => "Add kernel hashes to guest firmware for measured linux kernel launch",
+ type => 'boolean',
+ format_description => "qemu-sev-kernel-hashes",
+ default => 0,
+ optional => 1,
+ },
+};
+PVE::JSONSchema::register_format('pve-qemu-sev-fmt', $sev_fmt);
+
+my $sev_node_fmt = {
+ cbitpos => {
+ description => "C-bit: marks if a memory page is protected. System dependent",
+ type => 'integer',
+ default => 47,
+ optional => 1,
+ minimum => 0,
+ maximum => 100,
+ },
+ 'reduced-phys-bits' => {
+ description => "Number of bits the physical address space is reduced by. System dependent",
+ type => 'integer',
+ default => 1,
+ optional => 1,
+ minimum => 0,
+ maximum => 100,
+ },
+};
+
my $vga_fmt = {
type => {
description => "Select the VGA type.",
@@ -366,6 +419,12 @@ my $confdesc = {
description => "Memory properties.",
format => $PVE::QemuServer::Memory::memory_fmt
},
+ amd_sev => {
+ description => "Secure Encrypted Virtualization (SEV) features by AMD CPUs",
+ optional => 1,
+ format => 'pve-qemu-sev-fmt',
+ type => 'string',
+ },
balloon => {
optional => 1,
type => 'integer',
@@ -4084,6 +4143,39 @@ sub config_to_command {
}
push @$machineFlags, "type=${machine_type_min}";
+ if ($conf->{amd_sev}) {
+ if ($conf->{bios} && $conf->{bios} ne 'ovmf') {
+ die "For using SEV you need to change your guest bios to ovmf.\n";
+ }
+
+ my $amd_sev_conf = parse_property_string($sev_fmt, $conf->{amd_sev});
+ my $sev_hw_params = get_sev_hw_parameters();
+
+ if (!$sev_hw_params->{sev}) {
+ die "Your CPU does not support AMD SEV!\n";
+ }
+ if ($amd_sev_conf->{type} eq 'es' && !$sev_hw_params->{'sev-es'}) {
+ die "Your CPU does not support AMD SEV-ES!\n";
+ }
+
+ my $sev_mem_object = 'sev-guest,id=sev0'
+ .',cbitpos='.$sev_hw_params->{cbitpos}
+ .',reduced-phys-bits='.$sev_hw_params->{'reduced-phys-bits'};
+
+ my $policy = 0b0;
+ $policy += 0b1 if ($amd_sev_conf->{nodbg});
+ $policy += 0b10 if ($amd_sev_conf->{noks});
+ $policy += 0b100 if ($amd_sev_conf->{type} eq 'es');
+ # disable migration with bit 3 nosend to prevent amd-sev-migration-attack
+ $policy += 0b1000;
+
+ $sev_mem_object .= ',policy='.sprintf("%#x", $policy);
+ $sev_mem_object .= ',kernel-hashes=on' if ($amd_sev_conf->{'kernel-hashes'});
+
+ push @$devices, '-object' , $sev_mem_object;
+ push @$machineFlags, 'confidential-guest-support=sev0';
+ }
+
push @$cmd, @$devices;
push @$cmd, '-rtc', join(',', @$rtcFlags) if scalar(@$rtcFlags);
push @$cmd, '-machine', join(',', @$machineFlags) if scalar(@$machineFlags);
@@ -4127,6 +4219,16 @@ sub check_rng_source {
}
}
+sub get_sev_hw_parameters {
+ # Get reduced-phys-bits & cbitpos from /run/amd-sev-params
+ my $filename = '/run/amd-sev-params';
+ open my $fh, '<', $filename or die "Could not open '$filename' for reading: $!";
+ my $json_text = do { local $/; <$fh> };
+ close $fh;
+ my $sev_params = JSON->new->decode($json_text);
+ return $sev_params;
+}
+
sub spice_port {
my ($vmid) = @_;
--
2.39.2
_______________________________________________
pve-devel mailing list
pve-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
next prev parent reply other threads:[~2024-04-19 10:12 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-04-19 10:10 [pve-devel] [PATCH qemu-server v5 1/3] add C program to get AMD SEV hardware parameters from CPUID Markus Frank
2024-04-19 10:10 ` Markus Frank [this message]
2024-04-19 10:10 ` [pve-devel] [PATCH docs v5 3/3] add AMD SEV documentation Markus Frank
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20240419101049.697299-2-m.frank@proxmox.com \
--to=m.frank@proxmox.com \
--cc=pve-devel@lists.proxmox.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.
Service provided by Proxmox Server Solutions GmbH | Privacy | Legal