From d7933ef3ac81149a51ba43ddac9fe70405008aba Mon Sep 17 00:00:00 2001 From: Xu Wang Date: Thu, 11 Jun 2015 17:32:05 +0200 Subject: [PATCH 1/7] watchdog: change option wording to allow for more watchdogs We will introduce a new watchdog for s390x. Lets adopt qemu-options.hx to allow more watchdog devices. Signed-off-by: Xu Wang Reviewed-by: David Hildenbrand Signed-off-by: Christian Borntraeger [split out qemu-option.hx base changes] --- qemu-options.hx | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/qemu-options.hx b/qemu-options.hx index 1d281f6818..a295c0f82b 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -3152,7 +3152,7 @@ when the shift value is high (how high depends on the host machine). ETEXI DEF("watchdog", HAS_ARG, QEMU_OPTION_watchdog, \ - "-watchdog i6300esb|ib700\n" \ + "-watchdog model\n" \ " enable virtual hardware watchdog [default=none]\n", QEMU_ARCH_ALL) STEXI @@ -3160,16 +3160,21 @@ STEXI @findex -watchdog Create a virtual hardware watchdog device. Once enabled (by a guest action), the watchdog must be periodically polled by an agent inside -the guest or else the guest will be restarted. +the guest or else the guest will be restarted. Choose a model for +which your guest has drivers. -The @var{model} is the model of hardware watchdog to emulate. Choices -for model are: @code{ib700} (iBASE 700) which is a very simple ISA -watchdog with a single timer, or @code{i6300esb} (Intel 6300ESB I/O -controller hub) which is a much more featureful PCI-based dual-timer -watchdog. Choose a model for which your guest has drivers. - -Use @code{-watchdog help} to list available hardware models. Only one +The @var{model} is the model of hardware watchdog to emulate. Use +@code{-watchdog help} to list available hardware models. Only one watchdog can be enabled for a guest. + +The following models may be available: +@table @option +@item ib700 +iBASE 700 is a very simple ISA watchdog with a single timer. +@item i6300esb +Intel 6300ESB I/O controller hub is a much more featureful PCI-based +dual-timer watchdog. +@end table ETEXI DEF("watchdog-action", HAS_ARG, QEMU_OPTION_watchdog_action, \ From 188f24c2c149bcb0088c6317e99e09afc007de34 Mon Sep 17 00:00:00 2001 From: Xu Wang Date: Thu, 5 Feb 2015 18:28:32 +0800 Subject: [PATCH 2/7] s390x/watchdog: introduce diag288 watchdog device This patch introduces a new diag288 watchdog device that will, just like other watchdogs, monitor a guest and take corresponding actions when it detects that the guest is not responding. diag288 is s390x specific. The wiring to s390x KVM will be done in separate patches. Signed-off-by: Xu Wang Reviewed-by: David Hildenbrand Signed-off-by: Christian Borntraeger [split out qemu-option.hx base changes] --- default-configs/s390x-softmmu.mak | 1 + hw/watchdog/Makefile.objs | 1 + hw/watchdog/wdt_diag288.c | 110 ++++++++++++++++++++++++++++++ include/hw/watchdog/wdt_diag288.h | 36 ++++++++++ qemu-options.hx | 3 + 5 files changed, 151 insertions(+) create mode 100644 hw/watchdog/wdt_diag288.c create mode 100644 include/hw/watchdog/wdt_diag288.h diff --git a/default-configs/s390x-softmmu.mak b/default-configs/s390x-softmmu.mak index f9e13f177e..36e15de336 100644 --- a/default-configs/s390x-softmmu.mak +++ b/default-configs/s390x-softmmu.mak @@ -4,3 +4,4 @@ CONFIG_VIRTIO=y CONFIG_SCLPCONSOLE=y CONFIG_S390_FLIC=y CONFIG_S390_FLIC_KVM=$(CONFIG_KVM) +CONFIG_WDT_DIAG288=y diff --git a/hw/watchdog/Makefile.objs b/hw/watchdog/Makefile.objs index 4b0374a555..72e3ffd93c 100644 --- a/hw/watchdog/Makefile.objs +++ b/hw/watchdog/Makefile.objs @@ -1,3 +1,4 @@ common-obj-y += watchdog.o common-obj-$(CONFIG_WDT_IB6300ESB) += wdt_i6300esb.o common-obj-$(CONFIG_WDT_IB700) += wdt_ib700.o +common-obj-$(CONFIG_WDT_DIAG288) += wdt_diag288.o diff --git a/hw/watchdog/wdt_diag288.c b/hw/watchdog/wdt_diag288.c new file mode 100644 index 0000000000..351b5a8f9d --- /dev/null +++ b/hw/watchdog/wdt_diag288.c @@ -0,0 +1,110 @@ +/* + * watchdog device diag288 support + * + * Copyright IBM, Corp. 2015 + * + * Authors: + * Xu Wang + * + * This work is licensed under the terms of the GNU GPL, version 2 or (at your + * option) any later version. See the COPYING file in the top-level directory. + * + */ + +#include "sysemu/watchdog.h" +#include "hw/sysbus.h" +#include "qemu/timer.h" +#include "hw/watchdog/wdt_diag288.h" + +static WatchdogTimerModel model = { + .wdt_name = TYPE_WDT_DIAG288, + .wdt_description = "diag288 device for s390x platform", +}; + +static void wdt_diag288_reset(DeviceState *dev) +{ + DIAG288State *diag288 = DIAG288(dev); + + diag288->enabled = false; + timer_del(diag288->timer); +} + +static void diag288_timer_expired(void *dev) +{ + qemu_log_mask(CPU_LOG_RESET, "Watchdog timer expired.\n"); + watchdog_perform_action(); + wdt_diag288_reset(dev); +} + +static int wdt_diag288_handle_timer(DIAG288State *diag288, + uint64_t func, uint64_t timeout) +{ + switch (func) { + case WDT_DIAG288_INIT: + diag288->enabled = true; + /* fall through */ + case WDT_DIAG288_CHANGE: + if (!diag288->enabled) { + return -1; + } + timer_mod(diag288->timer, + qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + + timeout * get_ticks_per_sec()); + break; + case WDT_DIAG288_CANCEL: + if (!diag288->enabled) { + return -1; + } + diag288->enabled = false; + timer_del(diag288->timer); + break; + default: + return -1; + } + + return 0; +} + +static void wdt_diag288_realize(DeviceState *dev, Error **errp) +{ + DIAG288State *diag288 = DIAG288(dev); + + diag288->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, diag288_timer_expired, + dev); +} + +static void wdt_diag288_unrealize(DeviceState *dev, Error **errp) +{ + DIAG288State *diag288 = DIAG288(dev); + + timer_del(diag288->timer); + timer_free(diag288->timer); +} + +static void wdt_diag288_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + DIAG288Class *diag288 = DIAG288_CLASS(klass); + + dc->realize = wdt_diag288_realize; + dc->unrealize = wdt_diag288_unrealize; + dc->reset = wdt_diag288_reset; + set_bit(DEVICE_CATEGORY_MISC, dc->categories); + diag288->handle_timer = wdt_diag288_handle_timer; +} + +static const TypeInfo wdt_diag288_info = { + .class_init = wdt_diag288_class_init, + .parent = TYPE_DEVICE, + .name = TYPE_WDT_DIAG288, + .instance_size = sizeof(DIAG288State), + .class_size = sizeof(DIAG288Class), +}; + +static void wdt_diag288_register_types(void) +{ + watchdog_add_model(&model); + type_register_static(&wdt_diag288_info); +} + +type_init(wdt_diag288_register_types) diff --git a/include/hw/watchdog/wdt_diag288.h b/include/hw/watchdog/wdt_diag288.h new file mode 100644 index 0000000000..7f3fd450dc --- /dev/null +++ b/include/hw/watchdog/wdt_diag288.h @@ -0,0 +1,36 @@ +#ifndef WDT_DIAG288_H +#define WDT_DIAG288_H + +#include "hw/qdev.h" + +#define TYPE_WDT_DIAG288 "diag288" +#define DIAG288(obj) \ + OBJECT_CHECK(DIAG288State, (obj), TYPE_WDT_DIAG288) +#define DIAG288_CLASS(klass) \ + OBJECT_CLASS_CHECK(DIAG288Class, (klass), TYPE_WDT_DIAG288) +#define DIAG288_GET_CLASS(obj) \ + OBJECT_GET_CLASS(DIAG288Class, (obj), TYPE_WDT_DIAG288) + +#define WDT_DIAG288_INIT 0 +#define WDT_DIAG288_CHANGE 1 +#define WDT_DIAG288_CANCEL 2 + +typedef struct DIAG288State { + /*< private >*/ + DeviceState parent_obj; + QEMUTimer *timer; + bool enabled; + + /*< public >*/ +} DIAG288State; + +typedef struct DIAG288Class { + /*< private >*/ + DeviceClass parent_class; + + /*< public >*/ + int (*handle_timer)(DIAG288State *dev, + uint64_t func, uint64_t timeout); +} DIAG288Class; + +#endif /* WDT_DIAG288_H */ diff --git a/qemu-options.hx b/qemu-options.hx index a295c0f82b..d31fe35cae 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -3174,6 +3174,9 @@ iBASE 700 is a very simple ISA watchdog with a single timer. @item i6300esb Intel 6300ESB I/O controller hub is a much more featureful PCI-based dual-timer watchdog. +@item diag288 +A virtual watchdog for s390x backed by the diagnose 288 hypercall +(currently KVM only). @end table ETEXI From 8fc639af4b62930671b6988c1f7eedf9e7c9f7bc Mon Sep 17 00:00:00 2001 From: Xu Wang Date: Thu, 11 Jun 2015 13:55:26 +0200 Subject: [PATCH 3/7] s390x/kvm: diag288 instruction interception and handling Intercept the diag288 requests from kvm guests, and hand the requested command to the diag288 watchdog device for further handling. Signed-off-by: Xu Wang Reviewed-by: David Hildenbrand Signed-off-by: Christian Borntraeger --- target-s390x/cpu.h | 1 + target-s390x/kvm.c | 18 ++++++++++++++++++ target-s390x/misc_helper.c | 29 +++++++++++++++++++++++++++++ 3 files changed, 48 insertions(+) diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h index 584e74b89a..d63eb51186 100644 --- a/target-s390x/cpu.h +++ b/target-s390x/cpu.h @@ -1100,6 +1100,7 @@ uint32_t set_cc_nz_f128(float128 v); /* misc_helper.c */ #ifndef CONFIG_USER_ONLY +int handle_diag_288(CPUS390XState *env, uint64_t r1, uint64_t r3); void handle_diag_308(CPUS390XState *env, uint64_t r1, uint64_t r3); #endif void program_interrupt(CPUS390XState *env, uint32_t code, int ilen); diff --git a/target-s390x/kvm.c b/target-s390x/kvm.c index f6f61b9619..b02ff8d61d 100644 --- a/target-s390x/kvm.c +++ b/target-s390x/kvm.c @@ -98,6 +98,7 @@ #define PRIV_E3_MPCIFC 0xd0 #define PRIV_E3_STPCIFC 0xd4 +#define DIAG_TIMEREVENT 0x288 #define DIAG_IPL 0x308 #define DIAG_KVM_HYPERCALL 0x500 #define DIAG_KVM_BREAKPOINT 0x501 @@ -1267,6 +1268,20 @@ static int handle_hypercall(S390CPU *cpu, struct kvm_run *run) return ret; } +static void kvm_handle_diag_288(S390CPU *cpu, struct kvm_run *run) +{ + uint64_t r1, r3; + int rc; + + cpu_synchronize_state(CPU(cpu)); + r1 = (run->s390_sieic.ipa & 0x00f0) >> 4; + r3 = run->s390_sieic.ipa & 0x000f; + rc = handle_diag_288(&cpu->env, r1, r3); + if (rc) { + enter_pgmcheck(cpu, PGM_SPECIFICATION); + } +} + static void kvm_handle_diag_308(S390CPU *cpu, struct kvm_run *run) { uint64_t r1, r3; @@ -1306,6 +1321,9 @@ static int handle_diag(S390CPU *cpu, struct kvm_run *run, uint32_t ipb) */ func_code = decode_basedisp_rs(&cpu->env, ipb, NULL) & DIAG_KVM_CODE_MASK; switch (func_code) { + case DIAG_TIMEREVENT: + kvm_handle_diag_288(cpu, run); + break; case DIAG_IPL: kvm_handle_diag_308(cpu, run); break; diff --git a/target-s390x/misc_helper.c b/target-s390x/misc_helper.c index b375ab724b..6711504221 100644 --- a/target-s390x/misc_helper.c +++ b/target-s390x/misc_helper.c @@ -30,6 +30,7 @@ #include #endif #include "exec/cpu_ldst.h" +#include "hw/watchdog/wdt_diag288.h" #if !defined(CONFIG_USER_ONLY) #include "sysemu/cpus.h" @@ -153,6 +154,34 @@ static int load_normal_reset(S390CPU *cpu) return 0; } +int handle_diag_288(CPUS390XState *env, uint64_t r1, uint64_t r3) +{ + uint64_t func = env->regs[r1]; + uint64_t timeout = env->regs[r1 + 1]; + uint64_t action = env->regs[r3]; + Object *obj; + DIAG288State *diag288; + DIAG288Class *diag288_class; + + if (r1 % 2 || action != 0) { + return -1; + } + + /* Timeout must be more than 15 seconds except for timer deletion */ + if (func != WDT_DIAG288_CANCEL && timeout < 15) { + return -1; + } + + obj = object_resolve_path_type("", TYPE_WDT_DIAG288, NULL); + if (!obj) { + return -1; + } + + diag288 = DIAG288(obj); + diag288_class = DIAG288_GET_CLASS(diag288); + return diag288_class->handle_timer(diag288, func, timeout); +} + #define DIAG_308_RC_OK 0x0001 #define DIAG_308_RC_NO_CONF 0x0102 #define DIAG_308_RC_INVALID 0x0402 From d67f5fe63caa0f707fa91c760508c340e050b6f0 Mon Sep 17 00:00:00 2001 From: Xu Wang Date: Thu, 5 Feb 2015 18:28:34 +0800 Subject: [PATCH 4/7] s390x/watchdog: diag288 migration support Add vmstate structure to keep state and data during migration. Signed-off-by: Xu Wang Reviewed-by: David Hildenbrand Signed-off-by: Christian Borntraeger --- hw/watchdog/wdt_diag288.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/hw/watchdog/wdt_diag288.c b/hw/watchdog/wdt_diag288.c index 351b5a8f9d..1185e0681c 100644 --- a/hw/watchdog/wdt_diag288.c +++ b/hw/watchdog/wdt_diag288.c @@ -21,6 +21,17 @@ static WatchdogTimerModel model = { .wdt_description = "diag288 device for s390x platform", }; +static const VMStateDescription vmstate_diag288 = { + .name = "vmstate_diag288", + .version_id = 0, + .minimum_version_id = 0, + .fields = (VMStateField[]) { + VMSTATE_TIMER_PTR(timer, DIAG288State), + VMSTATE_BOOL(enabled, DIAG288State), + VMSTATE_END_OF_LIST() + } +}; + static void wdt_diag288_reset(DeviceState *dev) { DIAG288State *diag288 = DIAG288(dev); @@ -90,6 +101,7 @@ static void wdt_diag288_class_init(ObjectClass *klass, void *data) dc->unrealize = wdt_diag288_unrealize; dc->reset = wdt_diag288_reset; set_bit(DEVICE_CATEGORY_MISC, dc->categories); + dc->vmsd = &vmstate_diag288; diag288->handle_timer = wdt_diag288_handle_timer; } From f9a535e089abcbc7ac99db83c8c6e4644e395b12 Mon Sep 17 00:00:00 2001 From: Xu Wang Date: Thu, 5 Feb 2015 18:28:35 +0800 Subject: [PATCH 5/7] nmi: Implement inject_nmi() for non-monitor context use Let's introduce a general "inject_nmi()" function that doesn't rely on the cpu index of the monitor, but uses cpu index 0 as default (except for x86). This function can then later be used from a non-monitor context. Signed-off-by: Xu Wang Reviewed-by: David Hildenbrand CC: Alexey Kardashevskiy Signed-off-by: Christian Borntraeger --- hw/core/nmi.c | 20 ++++++++++++++++++++ include/hw/nmi.h | 1 + 2 files changed, 21 insertions(+) diff --git a/hw/core/nmi.c b/hw/core/nmi.c index 3dff020659..5260d6c1ec 100644 --- a/hw/core/nmi.c +++ b/hw/core/nmi.c @@ -21,6 +21,7 @@ #include "hw/nmi.h" #include "qapi/qmp/qerror.h" +#include "monitor/monitor.h" struct do_nmi_s { int cpu_index; @@ -70,6 +71,25 @@ void nmi_monitor_handle(int cpu_index, Error **errp) } } +void inject_nmi(void) +{ +#if defined(TARGET_I386) + CPUState *cs; + + CPU_FOREACH(cs) { + X86CPU *cpu = X86_CPU(cs); + + if (!cpu->apic_state) { + cpu_interrupt(cs, CPU_INTERRUPT_NMI); + } else { + apic_deliver_nmi(cpu->apic_state); + } + } +#else + nmi_monitor_handle(0, NULL); +#endif +} + static const TypeInfo nmi_info = { .name = TYPE_NMI, .parent = TYPE_INTERFACE, diff --git a/include/hw/nmi.h b/include/hw/nmi.h index b541772e1d..f4cec6257d 100644 --- a/include/hw/nmi.h +++ b/include/hw/nmi.h @@ -45,5 +45,6 @@ typedef struct NMIClass { } NMIClass; void nmi_monitor_handle(int cpu_index, Error **errp); +void inject_nmi(void); #endif /* NMI_H */ From 795dc6e46d953d70b4b7ddd3f4956f8f4b9d8565 Mon Sep 17 00:00:00 2001 From: Mao Chuan Li Date: Thu, 5 Feb 2015 18:28:36 +0800 Subject: [PATCH 6/7] watchdog: Add new Virtual Watchdog action INJECT-NMI This patch allows QEMU to inject a NMI into a guest when the watchdog expires. Signed-off-by: Mao Chuan Li Reviewed-by: David Hildenbrand CC: Eric Blake CC: Markus Armbruster Signed-off-by: Christian Borntraeger --- hw/watchdog/watchdog.c | 10 ++++++++++ qapi-schema.json | 6 +++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/hw/watchdog/watchdog.c b/hw/watchdog/watchdog.c index 54440c91c5..8d4b0eeeb0 100644 --- a/hw/watchdog/watchdog.c +++ b/hw/watchdog/watchdog.c @@ -27,6 +27,7 @@ #include "sysemu/sysemu.h" #include "sysemu/watchdog.h" #include "qapi-event.h" +#include "hw/nmi.h" /* Possible values for action parameter. */ #define WDT_RESET 1 /* Hard reset. */ @@ -35,6 +36,7 @@ #define WDT_PAUSE 4 /* Pause. */ #define WDT_DEBUG 5 /* Prints a message and continues running. */ #define WDT_NONE 6 /* Do nothing. */ +#define WDT_NMI 7 /* Inject nmi into the guest */ static int watchdog_action = WDT_RESET; static QLIST_HEAD(watchdog_list, WatchdogTimerModel) watchdog_list; @@ -95,6 +97,8 @@ int select_watchdog_action(const char *p) watchdog_action = WDT_DEBUG; else if (strcasecmp(p, "none") == 0) watchdog_action = WDT_NONE; + else if (strcasecmp(p, "inject-nmi") == 0) + watchdog_action = WDT_NMI; else return -1; @@ -138,5 +142,11 @@ void watchdog_perform_action(void) case WDT_NONE: qapi_event_send_watchdog(WATCHDOG_EXPIRATION_ACTION_NONE, &error_abort); break; + + case WDT_NMI: + qapi_event_send_watchdog(WATCHDOG_EXPIRATION_ACTION_INJECT_NMI, + &error_abort); + inject_nmi(); + break; } } diff --git a/qapi-schema.json b/qapi-schema.json index 6e17a5c36c..c4ee3ead48 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -3746,10 +3746,14 @@ # # @none: nothing is done # +# @inject-nmi: a non-maskable interrupt is injected into the first VCPU (all +# VCPUS on x86) (since 2.4) +# # Since: 2.1 ## { 'enum': 'WatchdogExpirationAction', - 'data': [ 'reset', 'shutdown', 'poweroff', 'pause', 'debug', 'none' ] } + 'data': [ 'reset', 'shutdown', 'poweroff', 'pause', 'debug', 'none', + 'inject-nmi' ] } ## # @IoOperationType From 8369e339d24f365750da456588e742674c153437 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Mon, 15 Jun 2015 12:24:03 +0200 Subject: [PATCH 7/7] s390/bios: build with -fdelete-null-pointer-checks Starting with version 4.9, GCC assumes it can't safely dereference null pointers, and uses this for some optimizations. On s390, the lowcore memory is located at address 0, so this assumption is wrong and breaks the s390-ccw firmware. Pass -fdelete-null-pointer-checks to avoid that. Cc: Cornelia Huck Cc: Christian Borntraeger Cc: Alexander Graf Signed-off-by: Aurelien Jarno Message-Id: <1434363843-14576-1-git-send-email-aurelien@aurel32.net> Signed-off-by: Christian Borntraeger --- pc-bios/s390-ccw/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pc-bios/s390-ccw/Makefile b/pc-bios/s390-ccw/Makefile index 009bb8de1c..746603a315 100644 --- a/pc-bios/s390-ccw/Makefile +++ b/pc-bios/s390-ccw/Makefile @@ -10,7 +10,7 @@ $(call set-vpath, $(SRC_PATH)/pc-bios/s390-ccw) .PHONY : all clean build-all OBJECTS = start.o main.o bootmap.o sclp-ascii.o virtio.o -CFLAGS += -fPIE -fno-stack-protector -ffreestanding +CFLAGS += -fPIE -fno-stack-protector -ffreestanding -fno-delete-null-pointer-checks LDFLAGS += -Wl,-pie -nostdlib build-all: s390-ccw.img