diff options
author | Reyk Floeter <reyk@cvs.openbsd.org> | 2017-03-15 18:06:19 +0000 |
---|---|---|
committer | Reyk Floeter <reyk@cvs.openbsd.org> | 2017-03-15 18:06:19 +0000 |
commit | 974f439890b16f213d8a0db6ceaa4ddee96110f0 (patch) | |
tree | a86b4e312bb9b69448faaf505814aecb01fd869d /sys | |
parent | 41c91327ff3f69d093863d0345bc9077f6386d2a (diff) |
Improve vmmci(4) shutdown and reboot.
This change handles various cases to power off the VM, even if it is
unresponsive, stuck in ddb, or when the shutdown was initiated from
the VM guest side. Usage of timeout and VM ACKs make sure that the VM
is really turned off at some point.
OK mlarkin@
Diffstat (limited to 'sys')
-rw-r--r-- | sys/dev/pv/vmmci.c | 49 |
1 files changed, 43 insertions, 6 deletions
diff --git a/sys/dev/pv/vmmci.c b/sys/dev/pv/vmmci.c index 1dfd5e7eaf2..ee9c7c195b0 100644 --- a/sys/dev/pv/vmmci.c +++ b/sys/dev/pv/vmmci.c @@ -1,4 +1,4 @@ -/* $OpenBSD: vmmci.c,v 1.1 2017/01/21 11:23:14 reyk Exp $ */ +/* $OpenBSD: vmmci.c,v 1.2 2017/03/15 18:06:18 reyk Exp $ */ /* * Copyright (c) 2017 Reyk Floeter <reyk@openbsd.org> @@ -51,6 +51,7 @@ struct vmmci_softc { int vmmci_match(struct device *, void *, void *); void vmmci_attach(struct device *, struct device *, void *); +int vmmci_activate(struct device *, int); int vmmci_config_change(struct virtio_softc *); void vmmci_tick(void *); @@ -60,7 +61,8 @@ struct cfattach vmmci_ca = { sizeof(struct vmmci_softc), vmmci_match, vmmci_attach, - NULL + NULL, + vmmci_activate }; /* Configuration registers */ @@ -70,6 +72,7 @@ struct cfattach vmmci_ca = { /* Feature bits */ #define VMMCI_F_TIMESYNC (1<<0) +#define VMMCI_F_ACK (1<<1) struct cfdriver vmmci_cd = { NULL, "vmmci", DV_DULL @@ -100,7 +103,7 @@ vmmci_attach(struct device *parent, struct device *self, void *aux) vsc->sc_ipl = IPL_NET; sc->sc_virtio = vsc; - features = VMMCI_F_TIMESYNC; + features = VMMCI_F_TIMESYNC|VMMCI_F_ACK; features = virtio_negotiate_features(vsc, features, NULL); if (features & VMMCI_F_TIMESYNC) { @@ -118,13 +121,42 @@ vmmci_attach(struct device *parent, struct device *self, void *aux) } int +vmmci_activate(struct device *self, int act) +{ + struct vmmci_softc *sc = (struct vmmci_softc *)self; + struct virtio_softc *vsc = sc->sc_virtio; + + if ((vsc->sc_features & VMMCI_F_ACK) == 0) + return (0); + + switch (act) { + case DVACT_POWERDOWN: + printf("%s: powerdown\n", sc->sc_dev.dv_xname); + + /* + * Tell the host that we are shutting down. The host will + * start a timer and kill our VM if we didn't reboot before + * expiration. This avoids being stuck in the + * "Please press any key to reboot" handler on RB_HALT; + * without hooking into the MD code directly. + */ + virtio_write_device_config_4(vsc, VMMCI_CONFIG_COMMAND, + VMMCI_SHUTDOWN); + break; + default: + break; + } + return (0); +} + +int vmmci_config_change(struct virtio_softc *vsc) { - struct vmmci_softc *sc = (struct vmmci_softc *)vsc->sc_child; - int cmd; + struct vmmci_softc *sc = (struct vmmci_softc *)vsc->sc_child; + uint32_t cmd; /* Check for command */ - cmd = virtio_read_device_config_1(vsc, VMMCI_CONFIG_COMMAND); + cmd = virtio_read_device_config_4(vsc, VMMCI_CONFIG_COMMAND); if (cmd == sc->sc_cmd) return (0); sc->sc_cmd = cmd; @@ -141,9 +173,14 @@ vmmci_config_change(struct virtio_softc *vsc) break; default: printf("%s: invalid command %d\n", sc->sc_dev.dv_xname, cmd); + cmd = VMMCI_NONE; break; } + if ((cmd != VMMCI_NONE) && + (vsc->sc_features & VMMCI_F_ACK)) + virtio_write_device_config_4(vsc, VMMCI_CONFIG_COMMAND, cmd); + return (1); } |