From nobody Sun Dec 12 15:08:26 2021 X-Original-To: dev-commits-src-main@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 52F9D18C85BC; Sun, 12 Dec 2021 15:08:27 +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 4JBp1Q72zZz4t85; Sun, 12 Dec 2021 15:08:26 +0000 (UTC) (envelope-from git@FreeBSD.org) 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 CBC73230AA; Sun, 12 Dec 2021 15:08:26 +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 1BCF8Q2x012271; Sun, 12 Dec 2021 15:08:26 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.16.1/8.16.1/Submit) id 1BCF8Q8P012270; Sun, 12 Dec 2021 15:08:26 GMT (envelope-from git) Date: Sun, 12 Dec 2021 15:08:26 GMT Message-Id: <202112121508.1BCF8Q8P012270@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: Rebecca Cran Subject: git: 866036f46c6e - main - bhyve: Support a _VARS.fd file for bootrom List-Id: Commit messages for the main branch of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-main List-Help: List-Post: List-Subscribe: List-Unsubscribe: Sender: owner-dev-commits-src-main@freebsd.org X-BeenThere: dev-commits-src-main@freebsd.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: bcran X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: 866036f46c6e8884cc7a2aa029408366ede40a23 Auto-Submitted: auto-generated ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1639321707; 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=5/3b6JVbQpcPitH3s2g0YaxdQNBIdvU4zPRPpO+fq3k=; b=geOyHlW8yT+MSbnkS19q8/6ScIF+mH1sxSRgee9C6BHuDxH36blHeXU4eGKunksL74Kpab GQLnv8fc9tEWp1wwP6I6FrurEQdq3wKdJdfj9S3iCrsFfOIvvhrvYOFqqH5HJu/9+jYk6u 89evhsY12Wzx0afEF1iiLJXS2nJ+7twtxhsj3oHT8b5BcPsZ5BO3Ob5t642NHgIBDBdROC QTXSAse9tfoXQmMMd7Ka69lrV7MfxHuPmNeTbkWLK4PF1ZANCmQwGZATzq2j88tjS8iI/k raM9mS7ZhUb4Y4rhU9hG9deroBaM7QFEm2ZRRIJapURwKuiOIBz48zLvgHAemQ== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1639321707; a=rsa-sha256; cv=none; b=VbfZCHoLYujbmYqxglvAJ9SdTBAYSmPKNrCxmU+LaTwVSxwHy1UnAHx/rn8Po6Ggcwe80a pWnTX7rgCbTCKDf5AO7vJ65lMc0swp7wg99P85YfdhpM7TUKykaR8CLmWrF8Gfk8WtE5Lb pYKTdByzYuqaTvQx+fY3WO1Dcs+qO5QCTBADKLz/dwofwb5yG8xmH1HpzTfl6HGHRVFwMt CGFnm5u8izjzI5ayfdQCxMGK7Fn1uotaCGpf03K3Ad4FXnR5lzhIVfwux2eSPGIFqdHxZB 5vbrm8ztdS/FAOCvHAAC9VS5wNHFXCpShOPAZcl1D2pDOUT2DLen9Sb7XsLryA== ARC-Authentication-Results: i=1; mx1.freebsd.org; none X-ThisMailContainsUnwantedMimeParts: N The branch main has been updated by bcran: URL: https://cgit.FreeBSD.org/src/commit/?id=866036f46c6e8884cc7a2aa029408366ede40a23 commit 866036f46c6e8884cc7a2aa029408366ede40a23 Author: Rebecca Cran AuthorDate: 2021-11-28 16:34:33 +0000 Commit: Rebecca Cran CommitDate: 2021-12-12 15:07:27 +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 --- 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 3b7bf6b65467..fe4eb3ffaaeb 100644 --- a/usr.sbin/bhyve/bhyve.8 +++ b/usr.sbin/bhyve/bhyve.8 @@ -24,7 +24,7 @@ .\" .\" $FreeBSD$ .\" -.Dd October 13, 2021 +.Dd November 28, 2021 .Dt BHYVE 8 .Os .Sh NAME @@ -500,10 +500,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: @@ -916,6 +921,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)