From nobody Thu Dec 08 17:43:58 2022 X-Original-To: dev-commits-src-branches@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4NShNG68Q3z4k22c; Thu, 8 Dec 2022 17:43:58 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4NShNG59hLz4DN7; Thu, 8 Dec 2022 17:43:58 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1670521438; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=th4Iq/JAl+DU0UX4pSBKhaBQ0IhsX9a0HhAHF+2kg3s=; b=vq/evLT3YbNt0Ht+CM2tm2EM/LoIn2apL+fm/so5qvSByN+4j9JSbk/QVicQOm5giQwk6q w4kbh3g/nKJUB0uEfHXR1d1F4oBM4fMrf6ftT+FOv299TcRpNhesOBXC2/Mmhhscb5wkHr Sfg4m6fhRU8yMbUHDbcFwAyXpHg5gq19u4PyF3OYZEMC6mEt6n84OVI0gcP4BOuYmZgc4S swH14+BMgtsLKKBZPLsd9xIbVe2o2a7hRdPXKPRqR6Hgt1BH3RrnG80Meg9TegQhYt3Nsg IzCi5KHbuS67XkesmPm8LPRRy+7SGIk8wIehipSXtZKBZuLMA7qMefsNQJKo5Q== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1670521438; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=th4Iq/JAl+DU0UX4pSBKhaBQ0IhsX9a0HhAHF+2kg3s=; b=rNX5E/uPPrA+7Ixfd7o4WmKISUhkTMLSQ659dIJSHrYbRoMhVKd9ngJ/VHr++YbTaMBG0y j4HIiPMi8KklmAFiPNd3tiVsvOflHrE1fkx56jk6L93+DTIiKZtCApPy5svJqy/STnLy2p Nky8nSeNMkms9gHoYpLRBENK9UjUgSHodAYCTEdLH5kdK1cpg6hlZdvlalgAop4s/S0vHd tg9ILO1/6TolQagBO9O7iNW/922AwSfoIpZ8lphlHn8MUB7WOwpiQe7b0+ukgg2K9Nw552 H/g9qoOqogrxlRU018OWezIKwtHrRQIk44OzuNmyevwOUdov0D2xF19+mDsUWg== ARC-Authentication-Results: i=1; mx1.freebsd.org; none ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1670521438; a=rsa-sha256; cv=none; b=dAPhi20JGr1wVVoNAs2ERJGBL/YBJfzg/VWOLxiqHyHHR1IBVbE+kVnFEjbzKkw8jnnx7b hMuu/H4JQHsbE+IGlNnyFR4NNjK/KAiww3fLTPLl5XYF0wtd7z0r3R0m79gzAhbCcZbdQO y5OXRUsc2geBhGrvfIAH7TUC0MrDkADVGF3EEGMSm9tQeM6U5N/zsbXbMoUJt9hJXs8dpA wWVPiB3vrh005rhg8QcMs2VA+jT6C4olmjNW+4u3iUwY5b6mjhO9Y+jxrSJhnFvQnUr+2b 6y2GhrN1ycY1F4MsKqBE6FsnSM7mujVPxJ5fCirIgOdeYJsO0kskja1T0gQKlQ== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 4NShNG4CVGz147B; Thu, 8 Dec 2022 17:43:58 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org ([127.0.1.44]) by gitrepo.freebsd.org (8.16.1/8.16.1) with ESMTP id 2B8Hhw8G098757; Thu, 8 Dec 2022 17:43:58 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.16.1/8.16.1/Submit) id 2B8Hhw8p098756; Thu, 8 Dec 2022 17:43:58 GMT (envelope-from git) Date: Thu, 8 Dec 2022 17:43:58 GMT Message-Id: <202212081743.2B8Hhw8p098756@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org From: =?utf-8?Q?Corvin=20K=C3=B6hne?= Subject: git: d6c280fb36fe - stable/13 - bhyve: Support a _VARS.fd file for bootrom List-Id: Commits to the stable branches of the FreeBSD src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-branches List-Help: List-Post: List-Subscribe: List-Unsubscribe: Sender: owner-dev-commits-src-branches@freebsd.org X-BeenThere: dev-commits-src-branches@freebsd.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: corvink X-Git-Repository: src X-Git-Refname: refs/heads/stable/13 X-Git-Reftype: branch X-Git-Commit: d6c280fb36fea18cbb61a07653b737182d085cf6 Auto-Submitted: auto-generated X-ThisMailContainsUnwantedMimeParts: N The branch stable/13 has been updated by corvink: URL: https://cgit.FreeBSD.org/src/commit/?id=d6c280fb36fea18cbb61a07653b737182d085cf6 commit d6c280fb36fea18cbb61a07653b737182d085cf6 Author: Rebecca Cran AuthorDate: 2021-11-28 16:34:33 +0000 Commit: Corvin Köhne CommitDate: 2022-12-08 13:53:38 +0000 bhyve: Support a _VARS.fd file for bootrom OVMF creates two separate .fd files, a _CODE.fd file containing the UEFI code, and a _VARS.fd file containing a template of an empty UEFI variable store. OVMF decides to write variables to the memory range just below the boot rom code if it detects a CFI flash device. So here we add just the barest facsimile of CFI command handling to bootrom.c that is needed to placate OVMF. Submitted by: D Scott Phillips Sponsored by: Intel Corporation Differential Revision: https://reviews.freebsd.org/D19976 MFC After: 1 week (cherry picked from commit 866036f46c6e8884cc7a2aa029408366ede40a23) --- usr.sbin/bhyve/bhyve.8 | 23 ++++++++- usr.sbin/bhyve/bootrom.c | 132 ++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 145 insertions(+), 10 deletions(-) diff --git a/usr.sbin/bhyve/bhyve.8 b/usr.sbin/bhyve/bhyve.8 index f56f4e771b70..d9f31a09b7db 100644 --- a/usr.sbin/bhyve/bhyve.8 +++ b/usr.sbin/bhyve/bhyve.8 @@ -24,7 +24,7 @@ .\" .\" $FreeBSD$ .\" -.Dd August 19, 2022 +.Dd December 8, 2022 .Dt BHYVE 8 .Os .Sh NAME @@ -506,10 +506,15 @@ Use the host TTY device for serial port I/O. .Pp Boot ROM device backends: .Bl -tag -width 10n -.It Ar romfile +.It Ar romfile Ns Op Cm \&, Ns Ar varfile Map .Ar romfile in the guest address space reserved for boot firmware. +If +.Ar varfile +is provided, that file is also mapped in the boot firmware guest +address space, and any modifications the guest makes will be saved +to that file. .El .Pp Pass-through device backends: @@ -937,6 +942,20 @@ bhyve -c 2 -m 4G -w -H \\ -l bootrom,/usr/local/share/uefi-firmware/BHYVE_UEFI.fd \\ uefivm .Ed +.Pp +Run a UEFI virtual machine with a VARS file to save EFI variables. +Note that +.Nm +will write guest modifications to the given VARS file. +Be sure to create a per-guest copy of the template VARS file from +.Pa /usr . +.Bd -literal -offset indent +bhyve -c 2 -m 4g -w -H \\ + -s 0,hostbridge \\ + -s 31,lpc -p com1,stdio \\ + -l bootrom,/usr/local/share/uefi-firmware/BHYVE_UEFI_CODE.fd,BHYVE_UEFI_VARS.fd + uefivm +.Ed .Sh SEE ALSO .Xr bhyve 4 , .Xr netgraph 4 , diff --git a/usr.sbin/bhyve/bootrom.c b/usr.sbin/bhyve/bootrom.c index 38a50490eb0b..757ec07d4a54 100644 --- a/usr.sbin/bhyve/bootrom.c +++ b/usr.sbin/bhyve/bootrom.c @@ -39,14 +39,17 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include #include + #include "bhyverun.h" #include "bootrom.h" #include "debug.h" +#include "mem.h" #define BOOTROM_SIZE (16 * 1024 * 1024) /* 16 MB */ @@ -64,6 +67,56 @@ static vm_paddr_t gpa_base; /* GPA of low end of region. */ static vm_paddr_t gpa_allocbot; /* Low GPA of free region. */ static vm_paddr_t gpa_alloctop; /* High GPA, minus 1, of free region. */ +#define CFI_BCS_WRITE_BYTE 0x10 +#define CFI_BCS_CLEAR_STATUS 0x50 +#define CFI_BCS_READ_STATUS 0x70 +#define CFI_BCS_READ_ARRAY 0xff + +static struct bootrom_var_state { + uint8_t *mmap; + uint64_t gpa; + off_t size; + uint8_t cmd; +} var = { NULL, 0, 0, CFI_BCS_READ_ARRAY }; + +/* + * Emulate just those CFI basic commands that will convince EDK II + * that the Firmware Volume area is writable and persistent. + */ +static int +bootrom_var_mem_handler(struct vmctx *ctx, int vcpu, int dir, uint64_t addr, + int size, uint64_t *val, void *arg1, long arg2) +{ + off_t offset; + + offset = addr - var.gpa; + if (offset + size > var.size || offset < 0 || offset + size <= offset) + return (EINVAL); + + if (dir == MEM_F_WRITE) { + switch (var.cmd) { + case CFI_BCS_WRITE_BYTE: + memcpy(var.mmap + offset, val, size); + var.cmd = CFI_BCS_READ_ARRAY; + break; + default: + var.cmd = *(uint8_t *)val; + } + } else { + switch (var.cmd) { + case CFI_BCS_CLEAR_STATUS: + case CFI_BCS_READ_STATUS: + memset(val, 0, size); + var.cmd = CFI_BCS_READ_ARRAY; + break; + default: + memcpy(val, var.mmap + offset, size); + break; + } + } + return (0); +} + void init_bootrom(struct vmctx *ctx) { @@ -142,10 +195,16 @@ bootrom_loadrom(struct vmctx *ctx, const char *romfile) { struct stat sbuf; ssize_t rlen; - char *ptr; - int fd, i, rv; + off_t rom_size, var_size, total_size; + char *ptr, *varfile; + int fd, varfd, i, rv; rv = -1; + varfd = -1; + + varfile = strdup(romfile); + romfile = strsep(&varfile, ","); + fd = open(romfile, O_RDONLY); if (fd < 0) { EPRINTLN("Error opening bootrom \"%s\": %s", @@ -153,19 +212,56 @@ bootrom_loadrom(struct vmctx *ctx, const char *romfile) goto done; } - if (fstat(fd, &sbuf) < 0) { + if (varfile != NULL) { + varfd = open(varfile, O_RDWR); + if (varfd < 0) { + fprintf(stderr, "Error opening bootrom variable file " + "\"%s\": %s\n", varfile, strerror(errno)); + goto done; + } + } + + if (fstat(fd, &sbuf) < 0) { EPRINTLN("Could not fstat bootrom file \"%s\": %s", - romfile, strerror(errno)); + romfile, strerror(errno)); goto done; - } + } + + rom_size = sbuf.st_size; + if (varfd < 0) { + var_size = 0; + } else { + if (fstat(varfd, &sbuf) < 0) { + fprintf(stderr, "Could not fstat bootrom variable file \"%s\": %s\n", + varfile, strerror(errno)); + goto done; + } + var_size = sbuf.st_size; + } + + if (var_size > BOOTROM_SIZE || + (var_size != 0 && var_size < PAGE_SIZE)) { + fprintf(stderr, "Invalid bootrom variable size %ld\n", + var_size); + goto done; + } + + total_size = rom_size + var_size; + + if (total_size > BOOTROM_SIZE) { + fprintf(stderr, "Invalid bootrom and variable aggregate size " + "%ld\n", total_size); + goto done; + } /* Map the bootrom into the guest address space */ - if (bootrom_alloc(ctx, sbuf.st_size, PROT_READ | PROT_EXEC, - BOOTROM_ALLOC_TOP, &ptr, NULL) != 0) + if (bootrom_alloc(ctx, rom_size, PROT_READ | PROT_EXEC, + BOOTROM_ALLOC_TOP, &ptr, NULL) != 0) { goto done; + } /* Read 'romfile' into the guest address space */ - for (i = 0; i < sbuf.st_size / PAGE_SIZE; i++) { + for (i = 0; i < rom_size / PAGE_SIZE; i++) { rlen = read(fd, ptr + i * PAGE_SIZE, PAGE_SIZE); if (rlen != PAGE_SIZE) { EPRINTLN("Incomplete read of page %d of bootrom " @@ -173,6 +269,26 @@ bootrom_loadrom(struct vmctx *ctx, const char *romfile) goto done; } } + + if (varfd >= 0) { + var.mmap = mmap(NULL, var_size, PROT_READ | PROT_WRITE, + MAP_SHARED, varfd, 0); + if (var.mmap == MAP_FAILED) + goto done; + var.size = var_size; + var.gpa = (gpa_alloctop - var_size) + 1; + gpa_alloctop = var.gpa - 1; + rv = register_mem(&(struct mem_range){ + .name = "bootrom variable", + .flags = MEM_F_RW, + .handler = bootrom_var_mem_handler, + .base = var.gpa, + .size = var.size, + }); + if (rv != 0) + goto done; + } + rv = 0; done: if (fd >= 0)