mirror of
https://github.com/freebsd/freebsd-src
synced 2024-09-06 09:10:28 +00:00
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 commitca14781c81
) 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:ca14781c81
("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 commit26d9f973d8
)
This commit is contained in:
parent
8caac07ce9
commit
b1fffed683
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -7,13 +7,18 @@
|
|||
|
||||
#include <sys/param.h>
|
||||
#include <sys/endian.h>
|
||||
#include <sys/queue.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <machine/vmm.h>
|
||||
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#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 @@ qemu_fwcfg_init(struct vmctx *const ctx)
|
|||
|
||||
return (error);
|
||||
}
|
||||
|
||||
static void
|
||||
qemu_fwcfg_usage(const char *opt)
|
||||
{
|
||||
warnx("Invalid fw_cfg option \"%s\"", opt);
|
||||
warnx("-f [name=]<name>,(string|file)=<value>");
|
||||
}
|
||||
|
||||
/*
|
||||
* Parses the cmdline argument for user defined fw_cfg items. The cmdline
|
||||
* argument has the format:
|
||||
* "-f [name=]<name>,(string|file)=<value>"
|
||||
*
|
||||
* 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 <name> */
|
||||
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 <name> */
|
||||
opt_end = strchr(opt_ptr, ',');
|
||||
if (opt_end == NULL) {
|
||||
qemu_fwcfg_usage(opt);
|
||||
return (EINVAL);
|
||||
}
|
||||
|
||||
/* check if <name> is too long */
|
||||
if (opt_end - opt_ptr >= QEMU_FWCFG_MAX_NAME) {
|
||||
warnx("fw_cfg name too long: \"%s\"", opt);
|
||||
return (EINVAL);
|
||||
}
|
||||
|
||||
/* save <name> */
|
||||
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 <value> */
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue