Re: git: 0e1f5ab7db2c - main - virtio_mmio: Support command-line parameters

From: Jessica Clarke <jrtc27_at_freebsd.org>
Date: Tue, 18 Oct 2022 15:12:59 UTC
On 18 Oct 2022, at 07:03, Colin Percival <cperciva@FreeBSD.org> wrote:
> 
> The branch main has been updated by cperciva:
> 
> URL: https://cgit.FreeBSD.org/src/commit/?id=0e1f5ab7db2cd2837f97f169122897b19c185dbd
> 
> commit 0e1f5ab7db2cd2837f97f169122897b19c185dbd
> Author:     Colin Percival <cperciva@FreeBSD.org>
> AuthorDate: 2022-08-13 00:54:26 +0000
> Commit:     Colin Percival <cperciva@FreeBSD.org>
> CommitDate: 2022-10-18 06:02:21 +0000
> 
>    virtio_mmio: Support command-line parameters
> 
>    The Virtio MMIO bus driver was added in 2014 with support for devices
>    exposed via FDT; in 2018 support was added to discover Virtio MMIO
>    devices via ACPI tables, as in QEMU.  The Firecracker VMM eschews both
>    FDT and ACPI, instead presenting device information via kernel command
>    line arguments of the form virtio_mmio.device=<parameters>.
> 
>    These command line parameters get converted into kernel environment
>    variables; this adds support for parsing those variables and attaching
>    virtio_mmio children to nexus.
> 
>    There is a case to be made that it would be cleaner to have a new
>    "cmdlinebus" attached to nexus and virtio_mmio children attached to
>    that.  A future commit might do that.
> 
>    Discussed with: imp, jrtc27
>    Sponsored by:   https://patreon.com/cperciva
>    Differential Revision:  https://reviews.freebsd.org/D36189
> ---
> sys/conf/files                            |   1 +
> sys/dev/virtio/mmio/virtio_mmio_cmdline.c | 150 ++++++++++++++++++++++++++++++
> 2 files changed, 151 insertions(+)
> 
> diff --git a/sys/conf/files b/sys/conf/files
> index b7da3626111d..39e6d4aaf0a8 100644
> --- a/sys/conf/files
> +++ b/sys/conf/files
> @@ -3437,6 +3437,7 @@ dev/virtio/pci/virtio_pci_legacy.c	optional	virtio_pci
> dev/virtio/pci/virtio_pci_modern.c	optional	virtio_pci
> dev/virtio/mmio/virtio_mmio.c		optional	virtio_mmio
> dev/virtio/mmio/virtio_mmio_acpi.c	optional	virtio_mmio acpi
> +dev/virtio/mmio/virtio_mmio_cmdline.c	optional	virtio_mmio

As I said in the review, this definitely doesn’t work for INTRNG due to
IRQ number virtualisation, among other things, yet this enables it for
all architectures, and I believe it should also get its own config
option as it’s rather dangerous to use (Linux separates it out from
virtio_mmio and has it off-by-default).

Jess

> dev/virtio/mmio/virtio_mmio_fdt.c	optional	virtio_mmio fdt
> dev/virtio/mmio/virtio_mmio_if.m	optional	virtio_mmio
> dev/virtio/network/if_vtnet.c		optional	vtnet
> diff --git a/sys/dev/virtio/mmio/virtio_mmio_cmdline.c b/sys/dev/virtio/mmio/virtio_mmio_cmdline.c
> new file mode 100644
> index 000000000000..cb4762adc964
> --- /dev/null
> +++ b/sys/dev/virtio/mmio/virtio_mmio_cmdline.c
> @@ -0,0 +1,150 @@
> +/*-
> + * Copyright (c) 2022 Colin Percival
> + *
> + * Redistribution and use in source and binary forms, with or without
> + * modification, are permitted provided that the following conditions
> + * are met:
> + * 1. Redistributions of source code must retain the above copyright
> + *    notice, this list of conditions and the following disclaimer.
> + * 2. Redistributions in binary form must reproduce the above copyright
> + *    notice, this list of conditions and the following disclaimer in the
> + *    documentation and/or other materials provided with the distribution.
> + *
> + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
> + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
> + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
> + * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
> + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
> + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
> + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
> + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
> + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
> + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
> + * SUCH DAMAGE.
> + */
> +
> +#include <sys/param.h>
> +#include <sys/systm.h>
> +#include <sys/bus.h>
> +#include <sys/kernel.h>
> +#include <sys/limits.h>
> +#include <sys/malloc.h>
> +#include <sys/module.h>
> +#include <sys/rman.h>
> +
> +#include <machine/bus.h>
> +#include <machine/resource.h>
> +
> +#include <dev/virtio/mmio/virtio_mmio.h>
> +
> +/* Parse <size>@<baseaddr>:<irq>[:<id>] and add a child. */
> +static void
> +parsearg(driver_t *driver, device_t parent, char * arg)
> +{
> +	device_t child;
> +	char * p;
> +	unsigned long sz;
> +	unsigned long baseaddr;
> +	unsigned long irq;
> +	unsigned long id;
> +
> +	/* <size> */
> +	sz = strtoul(arg, &p, 0);
> +	if ((sz == 0) || (sz == ULONG_MAX))
> +		goto bad;
> +	switch (*p) {
> +	case 'E': case 'e':
> +		sz <<= 10;
> +		/* FALLTHROUGH */
> +	case 'P': case 'p':
> +		sz <<= 10;
> +		/* FALLTHROUGH */
> +	case 'T': case 't':
> +		sz <<= 10;
> +		/* FALLTHROUGH */
> +	case 'G': case 'g':
> +		sz <<= 10;
> +		/* FALLTHROUGH */
> +	case 'M': case 'm':
> +		sz <<= 10;
> +		/* FALLTHROUGH */
> +	case 'K': case 'k':
> +		sz <<= 10;
> +		p++;
> +		break;
> +	}
> +
> +	/* @<baseaddr> */
> +	if (*p++ != '@')
> +		goto bad;
> +	baseaddr = strtoul(p, &p, 0);
> +	if ((baseaddr == 0) || (baseaddr == ULONG_MAX))
> +		goto bad;
> +
> +	/* :<irq> */
> +	if (*p++ != ':')
> +		goto bad;
> +	irq = strtoul(p, &p, 0);
> +	if ((irq == 0) || (irq == ULONG_MAX))
> +		goto bad;
> +
> +	/* Optionally, :<id> */
> +	if (*p) {
> +		if (*p++ != ':')
> +			goto bad;
> +		id = strtoul(p, &p, 0);
> +		if ((id == 0) || (id == ULONG_MAX))
> +			goto bad;
> +	} else {
> +		id = 0;
> +	}
> +
> +	/* Should have reached the end of the string. */
> +	if (*p)
> +		goto bad;
> +
> +	/* Create the child and assign its resources. */
> +	child = BUS_ADD_CHILD(parent, 0, driver->name, id ? id : -1);
> +	bus_set_resource(child, SYS_RES_MEMORY, 0, baseaddr, sz);
> +	bus_set_resource(child, SYS_RES_IRQ, 0, irq, 1);
> +	device_set_driver(child, driver);
> +
> +	return;
> +
> +bad:
> +	printf("Error parsing virtio_mmio parameter: %s\n", arg);
> +}
> +
> +static void
> +vtmmio_cmdline_identify(driver_t *driver, device_t parent)
> +{
> +	size_t n;
> +	char name[] = "virtio_mmio.device_XXXX";
> +	char * val;
> +
> +	/* First variable just has its own name. */
> +	if ((val = kern_getenv("virtio_mmio.device")) == NULL)
> +		return;
> +	parsearg(driver, parent, val);
> +	freeenv(val);
> +
> +	/* The rest have _%zu suffixes. */
> +	for (n = 1; n <= 9999; n++) {
> +		sprintf(name, "virtio_mmio.device_%zu", n);
> +		if ((val = kern_getenv(name)) == NULL)
> +			return;
> +		parsearg(driver, parent, val);
> +		freeenv(val);
> +	}
> +}
> +
> +static device_method_t vtmmio_cmdline_methods[] = {
> +        /* Device interface. */
> +	DEVMETHOD(device_identify,	vtmmio_cmdline_identify),
> +	DEVMETHOD(device_probe,		vtmmio_probe),
> +
> +        DEVMETHOD_END
> +};
> +DEFINE_CLASS_1(virtio_mmio, vtmmio_cmdline_driver, vtmmio_cmdline_methods,
> +    sizeof(struct vtmmio_softc), vtmmio_driver);
> +DRIVER_MODULE(vtmmio_cmdline, nexus, vtmmio_cmdline_driver, 0, 0);