From nobody Fri Aug 18 07:28:40 2023 X-Original-To: dev-commits-src-all@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 4RRtlY0H6Xz4qqhJ; Fri, 18 Aug 2023 07:28:41 +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 4RRtlX5Fhtz3DdR; Fri, 18 Aug 2023 07:28:40 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1692343720; 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=sftZjTwyoKzOtiL9J6Eqq3IUEULtEck8gV68l0+3nXg=; b=QH1dZeYkLb9yNAiGfApjFz5geAReQzxGYsBtI9kd963r1jigYqclMVHJhXhwpV7owoBOl6 jLoRu5DtRYksXWvfmtdd9xQdzIYxd7dmK2LruHEjJd6vKPXcfN4lKNrGNSoRh4MoR7IGPk QTxA4MnJtbwBBWx13fz5pJRK/Y2ynyhDjfLkR8YSR8JXLq4ewFD82C/Jr59+X7xg6VB06q g5t4P7d9hz6N7whDkuMNn7No+2hvGIDLnsWLlb35pTQJX2Q3JYQG4o1W7ouDNjb92GtZ4F zjLfNoIJCN8IOdfnvOLucDQ7NhAPv9mQqh6ejUS79vpgMXtndC3BjZ5EKeJ/Pw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1692343720; 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=sftZjTwyoKzOtiL9J6Eqq3IUEULtEck8gV68l0+3nXg=; b=H2n4GSjxUPtReMuUjnMx7bcGiCxWWFMuyjNx+sUQuB6Nii2IqY1B+iioLMQMEEJZ3Rykr0 hiGdngY36UhZluktmIf43HbN4BxXcveHGoSErt8Jv3yjvm+0VxRlrhsGAwDl435DZk/0uj e6cVEssPFr68sdQRPkxtI4A7S6oh/RbRFZpM+3DqvbOOy4vAZI2I3H8UEhG3jeRRl+tFYd PYN7XjJfTKY0pGcn1g30OxKmeTLZVB9kOPO7aXOpdqdxungAywC8EuUveVbb0zRLFn2QYU C+nAJHN2Umpt79EcvYfuc12HOxENz955/tWQjT0+zxnqF+DGsvxS9TseLdi98g== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1692343720; a=rsa-sha256; cv=none; b=r+F6KWmegyPGcuWjSrB3efW2jbZmFPI2zVPft6tNaVUwX0FeL/I47uwKkJ+59iddPTFS7A /9bXLYdoaLYosgONeSyvcSC3YD0Ol5Fzz0IriaY6tZ2pnK5gaJuRY8vZWt7ev5R38qSwpa PMdK065tYjoDYHnYt7S2b9l0FdSzDJT0VvelG2TndoXRy3gnm6DzjpX3QXGHcBiXoS9fc1 B3c8RvS3JvkwhAPMjoIu5577JF8Sif3Wmen5Jx0gKAZkjYICv7gt0Qu+mRtYymxnJXI4gT UmgpjGSsffI3zjuFaFfvbTKY7HKQRl+lv8ljl0HAPPJ354MWiDdSE4gxPL0ZvQ== ARC-Authentication-Results: i=1; mx1.freebsd.org; none 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 4RRtlX4LDhz16Wc; Fri, 18 Aug 2023 07:28:40 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org ([127.0.1.44]) by gitrepo.freebsd.org (8.17.1/8.17.1) with ESMTP id 37I7Sejh034238; Fri, 18 Aug 2023 07:28:40 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.17.1/8.17.1/Submit) id 37I7SelL034235; Fri, 18 Aug 2023 07:28:40 GMT (envelope-from git) Date: Fri, 18 Aug 2023 07:28:40 GMT Message-Id: <202308180728.37I7SelL034235@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org From: Corvin =?utf-8?Q?K=C3=B6hne?= Subject: git: b1fffed683ab - stable/13 - bhyve: add cmdline option for user defined fw_cfg items List-Id: Commit messages for all branches of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-all List-Help: List-Post: List-Subscribe: List-Unsubscribe: Sender: owner-dev-commits-src-all@freebsd.org X-BeenThere: dev-commits-src-all@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: b1fffed683ab82b2693e7b5bb81ca72be4d348ba Auto-Submitted: auto-generated The branch stable/13 has been updated by corvink: URL: https://cgit.FreeBSD.org/src/commit/?id=b1fffed683ab82b2693e7b5bb81ca72be4d348ba commit b1fffed683ab82b2693e7b5bb81ca72be4d348ba Author: Corvin Köhne AuthorDate: 2021-09-08 09:31:21 +0000 Commit: Corvin Köhne CommitDate: 2023-08-18 07:24:54 +0000 bhyve: add cmdline option for user defined fw_cfg items Some guest allow to configure themself by fw_cfg. E.g. Fedora CoreOs can be provisioned by adding a JSON file as fw_cfg item. Reviewed by: jhb MFC after: 1 week Sponsored by: Beckhoff Automation GmbH & Co. KG Differential Revision: https://reviews.freebsd.org/D38338 (cherry picked from commit ca14781c8170f3517ae79e198c0c880dbc3142dd) bhyve: error out if fwcfg user file isn't read completely At the moment, fwcfg reads the file once at startup and passes these data to the guest. Therefore, we should always read the whole file. Otherwise we should error out. Additionally, GCC12 complains that the comparison whether fwcfg_file->size is lower than 0 is always false due to the limited range of data type. Reviewed by: markj Fixes: ca14781c8170f3517ae79e198c0c880dbc3142dd ("bhyve: add cmdline option for user defined fw_cfg items") MFC after: 1 week Sponsored by: Beckhoff Automation GmbH & Co. KG Differential Revision: https://reviews.freebsd.org/D40076 (cherry picked from commit 26d9f973d8691eccc098ded7326137d6f76ad243) --- usr.sbin/bhyve/bhyve.8 | 19 ++++++ usr.sbin/bhyve/bhyverun.c | 9 ++- usr.sbin/bhyve/qemu_fwcfg.c | 145 ++++++++++++++++++++++++++++++++++++++++++++ usr.sbin/bhyve/qemu_fwcfg.h | 1 + 4 files changed, 172 insertions(+), 2 deletions(-) diff --git a/usr.sbin/bhyve/bhyve.8 b/usr.sbin/bhyve/bhyve.8 index ed9c045c3159..b764807c7980 100644 --- a/usr.sbin/bhyve/bhyve.8 +++ b/usr.sbin/bhyve/bhyve.8 @@ -45,6 +45,15 @@ .Op Cm ,threads= Ar n .Oc .Sm on +.Oo Fl f +.Sm off +.Ar name Cm \&, +.Oo +.Cm string No | Cm file +.Oc +.Cm \&= Ar data +.Sm on +.Oc .Oo .Sm off .Fl G\~ @@ -145,6 +154,16 @@ Force .Nm to exit when a guest issues an access to an I/O port that is not emulated. This is intended for debug purposes. +.It Fl f Ar name Ns Cm \&, Ns Oo Cm string Ns No | Ns Cm file Ns Oc Ns Cm \&= Ns Ar data +Add a fw_cfg file +.Ar name +to the fw_cfg interface. +If a +.Cm string +is specified, the fw_cfg file contains the string as data. +If a +.Cm file +is specified, bhyve reads the file and adds the file content as fw_cfg data. .It Fl G Xo .Sm off .Oo Ar w Oc diff --git a/usr.sbin/bhyve/bhyverun.c b/usr.sbin/bhyve/bhyverun.c index 4db8274335cd..7cc293827518 100644 --- a/usr.sbin/bhyve/bhyverun.c +++ b/usr.sbin/bhyve/bhyverun.c @@ -1258,9 +1258,9 @@ main(int argc, char *argv[]) progname = basename(argv[0]); #ifdef BHYVE_SNAPSHOT - optstr = "aehuwxACDHIPSWYk:o:p:G:c:s:m:l:K:U:r:"; + optstr = "aehuwxACDHIPSWYk:f:o:p:G:c:s:m:l:K:U:r:"; #else - optstr = "aehuwxACDHIPSWYk:o:p:G:c:s:m:l:K:U:"; + optstr = "aehuwxACDHIPSWYk:f:o:p:G:c:s:m:l:K:U:"; #endif while ((c = getopt(argc, argv, optstr)) != -1) { switch (c) { @@ -1288,6 +1288,11 @@ main(int argc, char *argv[]) case 'C': set_config_bool("memory.guest_in_core", true); break; + case 'f': + if (qemu_fwcfg_parse_cmdline_arg(optarg) != 0) { + errx(EX_USAGE, "invalid fwcfg item '%s'", optarg); + } + break; case 'G': parse_gdb_options(optarg); break; diff --git a/usr.sbin/bhyve/qemu_fwcfg.c b/usr.sbin/bhyve/qemu_fwcfg.c index e88608d90cae..e845c70950b1 100644 --- a/usr.sbin/bhyve/qemu_fwcfg.c +++ b/usr.sbin/bhyve/qemu_fwcfg.c @@ -7,13 +7,18 @@ #include #include +#include +#include #include #include #include +#include +#include #include #include +#include #include "acpi_device.h" #include "bhyverun.h" @@ -98,6 +103,15 @@ struct qemu_fwcfg_softc { static struct qemu_fwcfg_softc fwcfg_sc; +struct qemu_fwcfg_user_file { + STAILQ_ENTRY(qemu_fwcfg_user_file) chain; + uint8_t name[QEMU_FWCFG_MAX_NAME]; + uint32_t size; + void *data; +}; +static STAILQ_HEAD(qemu_fwcfg_user_file_list, + qemu_fwcfg_user_file) user_files = STAILQ_HEAD_INITIALIZER(user_files); + static int qemu_fwcfg_selector_port_handler(struct vmctx *const ctx __unused, const int in, const int port __unused, const int bytes, uint32_t *const eax, @@ -384,6 +398,22 @@ qemu_fwcfg_add_file(const char *name, const uint32_t size, void *const data) return (0); } +static int +qemu_fwcfg_add_user_files(void) +{ + const struct qemu_fwcfg_user_file *fwcfg_file; + int error; + + STAILQ_FOREACH(fwcfg_file, &user_files, chain) { + error = qemu_fwcfg_add_file(fwcfg_file->name, fwcfg_file->size, + fwcfg_file->data); + if (error) + return (error); + } + + return (0); +} + static const struct acpi_device_emul qemu_fwcfg_acpi_device_emul = { .name = QEMU_FWCFG_ACPI_DEVICE_NAME, .hid = QEMU_FWCFG_ACPI_HARDWARE_ID, @@ -458,6 +488,11 @@ qemu_fwcfg_init(struct vmctx *const ctx) } if ((error = qemu_fwcfg_add_item_file_dir()) != 0) { warnx("%s: Unable to add file_dir item", __func__); + } + + /* add user defined fwcfg files */ + if ((error = qemu_fwcfg_add_user_files()) != 0) { + warnx("%s: Unable to add user files", __func__); goto done; } @@ -468,3 +503,113 @@ done: return (error); } + +static void +qemu_fwcfg_usage(const char *opt) +{ + warnx("Invalid fw_cfg option \"%s\"", opt); + warnx("-f [name=],(string|file)="); +} + +/* + * Parses the cmdline argument for user defined fw_cfg items. The cmdline + * argument has the format: + * "-f [name=],(string|file)=" + * + * E.g.: "-f opt/com.page/example,string=Hello" + */ +int +qemu_fwcfg_parse_cmdline_arg(const char *opt) +{ + struct qemu_fwcfg_user_file *fwcfg_file; + struct stat sb; + const char *opt_ptr, *opt_end; + ssize_t bytes_read; + int fd; + + fwcfg_file = malloc(sizeof(*fwcfg_file)); + if (fwcfg_file == NULL) { + warnx("Unable to allocate fw_cfg_user_file"); + return (ENOMEM); + } + + /* get pointer to */ + opt_ptr = opt; + /* If [name=] is specified, skip it */ + if (strncmp(opt_ptr, "name=", sizeof("name=") - 1) == 0) { + opt_ptr += sizeof("name=") - 1; + } + + /* get the end of */ + opt_end = strchr(opt_ptr, ','); + if (opt_end == NULL) { + qemu_fwcfg_usage(opt); + return (EINVAL); + } + + /* check if is too long */ + if (opt_end - opt_ptr >= QEMU_FWCFG_MAX_NAME) { + warnx("fw_cfg name too long: \"%s\"", opt); + return (EINVAL); + } + + /* save */ + strncpy(fwcfg_file->name, opt_ptr, opt_end - opt_ptr); + fwcfg_file->name[opt_end - opt_ptr] = '\0'; + + /* set opt_ptr and opt_end to */ + opt_ptr = opt_end + 1; + opt_end = opt_ptr + strlen(opt_ptr); + + if (strncmp(opt_ptr, "string=", sizeof("string=") - 1) == 0) { + opt_ptr += sizeof("string=") - 1; + fwcfg_file->data = strdup(opt_ptr); + if (fwcfg_file->data == NULL) { + warnx("Can't duplicate fw_cfg_user_file string \"%s\"", + opt_ptr); + return (ENOMEM); + } + fwcfg_file->size = strlen(opt_ptr) + 1; + } else if (strncmp(opt_ptr, "file=", sizeof("file=") - 1) == 0) { + opt_ptr += sizeof("file=") - 1; + + fd = open(opt_ptr, O_RDONLY); + if (fd < 0) { + warn("Can't open fw_cfg_user_file file \"%s\"", + opt_ptr); + return (EINVAL); + } + + if (fstat(fd, &sb) < 0) { + warn("Unable to get size of file \"%s\"", opt_ptr); + close(fd); + return (-1); + } + + fwcfg_file->data = malloc(sb.st_size); + if (fwcfg_file->data == NULL) { + warnx( + "Can't allocate fw_cfg_user_file file \"%s\" (size: 0x%16lx)", + opt_ptr, sb.st_size); + close(fd); + return (ENOMEM); + } + bytes_read = read(fd, fwcfg_file->data, sb.st_size); + if (bytes_read < 0 || bytes_read != sb.st_size) { + warn("Unable to read file \"%s\"", opt_ptr); + free(fwcfg_file->data); + close(fd); + return (-1); + } + fwcfg_file->size = bytes_read; + + close(fd); + } else { + qemu_fwcfg_usage(opt); + return (EINVAL); + } + + STAILQ_INSERT_TAIL(&user_files, fwcfg_file, chain); + + return (0); +} diff --git a/usr.sbin/bhyve/qemu_fwcfg.h b/usr.sbin/bhyve/qemu_fwcfg.h index def0487fdf02..5c73e8309c6e 100644 --- a/usr.sbin/bhyve/qemu_fwcfg.h +++ b/usr.sbin/bhyve/qemu_fwcfg.h @@ -23,3 +23,4 @@ struct qemu_fwcfg_item { int qemu_fwcfg_add_file(const char *name, const uint32_t size, void *const data); int qemu_fwcfg_init(struct vmctx *const ctx); +int qemu_fwcfg_parse_cmdline_arg(const char *opt);