diff --git a/devicemodel/Makefile b/devicemodel/Makefile index 21383069c..134e27ea7 100644 --- a/devicemodel/Makefile +++ b/devicemodel/Makefile @@ -78,6 +78,7 @@ SRCS += hw/platform/acpi/acpi.c SRCS += hw/platform/acpi/acpi_pm.c SRCS += hw/platform/rpmb/rpmb_sim.c SRCS += hw/platform/rpmb/rpmb_backend.c +SRCS += hw/platform/debugexit.c SRCS += hw/pci/wdt_i6300esb.c SRCS += hw/pci/lpc.c SRCS += hw/pci/xhci.c diff --git a/devicemodel/core/main.c b/devicemodel/core/main.c index 6122d93b5..1e977c877 100644 --- a/devicemodel/core/main.c +++ b/devicemodel/core/main.c @@ -84,6 +84,7 @@ bool stdio_in_use; static int virtio_msix = 1; static int x2apic_mode; /* default is xAPIC */ +static bool debugexit_enabled; static int strictmsr = 1; @@ -131,7 +132,7 @@ usage(int code) "Usage: %s [-abehuwxACHPSTWY] [-c vcpus] [-g ] [-l ]\n" " %*s [-m mem] [-p vcpu:hostcpu] [-s ] [-U uuid] \n" " %*s [--vsbl vsbl_file_name] [--part_info part_info_name]\n" - " %*s [--enable_trusty] \n" + " %*s [--enable_trusty] [--debugexit] \n" " -a: local apic is in xAPIC mode (deprecated)\n" " -A: create ACPI tables\n" " -b: enable bvmcons\n" @@ -160,7 +161,8 @@ usage(int code) " --vsbl: vsbl file path\n" " --part_info: guest partition info file path\n" " --enable_trusty: enable trusty for guest\n" - " --ptdev_no_reset: disable reset check for ptdev\n", + " --ptdev_no_reset: disable reset check for ptdev\n" + " --debugexit: enable debug exit function\n", progname, (int)strlen(progname), "", (int)strlen(progname), "", (int)strlen(progname), ""); @@ -439,6 +441,9 @@ vm_init_vdevs(struct vmctx *ctx) sci_init(ctx); init_bvmcons(); + if (debugexit_enabled) + init_debugexit(); + ret = monitor_init(ctx); if (ret < 0) goto monitor_fail; @@ -452,6 +457,9 @@ vm_init_vdevs(struct vmctx *ctx) pci_fail: monitor_close(); monitor_fail: + if (debugexit_enabled) + deinit_debugexit(); + deinit_bvmcons(); vpit_deinit(ctx); vpit_fail: @@ -469,6 +477,10 @@ vm_deinit_vdevs(struct vmctx *ctx) { deinit_pci(ctx); monitor_close(); + + if (debugexit_enabled) + deinit_debugexit(); + deinit_bvmcons(); vpit_deinit(ctx); vrtc_deinit(ctx); @@ -493,6 +505,10 @@ vm_reset_vdevs(struct vmctx *ctx) * could be assigned with different number after reset. */ atkbdc_deinit(ctx); + + if (debugexit_enabled) + deinit_debugexit(); + vpit_deinit(ctx); vrtc_deinit(ctx); @@ -505,6 +521,9 @@ vm_reset_vdevs(struct vmctx *ctx) vrtc_init(ctx); vpit_init(ctx); + if (debugexit_enabled) + init_debugexit(); + ioapic_init(ctx); init_pci(ctx); @@ -684,6 +703,7 @@ enum { CMD_OPT_PART_INFO, CMD_OPT_TRUSTY_ENABLE, CMD_OPT_PTDEV_NO_RESET, + CMD_OPT_DEBUGEXIT, }; static struct option long_options[] = { @@ -720,6 +740,7 @@ static struct option long_options[] = { CMD_OPT_TRUSTY_ENABLE}, {"ptdev_no_reset", no_argument, 0, CMD_OPT_PTDEV_NO_RESET}, + {"debugexit", no_argument, 0, CMD_OPT_DEBUGEXIT}, {0, 0, 0, 0 }, }; @@ -869,6 +890,9 @@ main(int argc, char *argv[]) case CMD_OPT_PTDEV_NO_RESET: ptdev_no_reset(true); break; + case CMD_OPT_DEBUGEXIT: + debugexit_enabled = true; + break; case 'h': usage(0); default: diff --git a/devicemodel/hw/platform/debugexit.c b/devicemodel/hw/platform/debugexit.c new file mode 100644 index 000000000..26ea1da96 --- /dev/null +++ b/devicemodel/hw/platform/debugexit.c @@ -0,0 +1,80 @@ +/*- + * Copyright (c) 2018 Intel + * All rights reserved. + * + * 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 ``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 +#include +#include +#include +#include + +#include "types.h" +#include "vmmapi.h" +#include "inout.h" +#include "mevent.h" + +#define DEBUG_IO_BASE (0xf4) +#define DEBUG_IO_SIZE (1) + +static int +debugexit_handler(struct vmctx *ctx, int vcpu, int in, int port, int bytes, + uint32_t *eax, void *arg) +{ + if (in) + *eax = 0xFFFF; + else { + vm_suspend(ctx, VM_SUSPEND_POWEROFF); + mevent_notify(); + } + return 0; +} + +void +init_debugexit(void) +{ + struct inout_port iop; + + memset(&iop, 0, sizeof(struct inout_port)); + iop.name = "debugexit"; + iop.port = DEBUG_IO_BASE; + iop.size = DEBUG_IO_SIZE; + iop.flags = IOPORT_F_INOUT; + iop.handler = debugexit_handler; + + register_inout(&iop); +} + +void +deinit_debugexit(void) +{ + struct inout_port iop; + + memset(&iop, 0, sizeof(struct inout_port)); + iop.name = "debugexit"; + iop.port = DEBUG_IO_BASE; + iop.size = DEBUG_IO_SIZE; + + unregister_inout(&iop); +} diff --git a/devicemodel/include/dm.h b/devicemodel/include/dm.h index b447c47f1..4869a82f6 100644 --- a/devicemodel/include/dm.h +++ b/devicemodel/include/dm.h @@ -49,4 +49,6 @@ void *paddr_guest2host(struct vmctx *ctx, uintptr_t addr, size_t len); void *dm_gpa2hva(uint64_t gpa, size_t size); int virtio_uses_msix(void); void ptdev_no_reset(bool enable); +void init_debugexit(void); +void deinit_debugexit(void); #endif