|
| 1 | +diff --git a/hw/char/debugcon.c b/hw/char/debugcon.c |
| 2 | +index fdb04fe..bfb3daf 100644 |
| 3 | +--- a/hw/char/debugcon.c |
| 4 | ++++ b/hw/char/debugcon.c |
| 5 | +@@ -26,6 +26,7 @@ |
| 6 | + |
| 7 | + #include "qemu/osdep.h" |
| 8 | + #include "qapi/error.h" |
| 9 | ++#include "qapi/qapi-events-control.h" |
| 10 | + #include "qemu/module.h" |
| 11 | + #include "chardev/char-fe.h" |
| 12 | + #include "hw/isa/isa.h" |
| 13 | +@@ -34,6 +35,7 @@ |
| 14 | + #include "qom/object.h" |
| 15 | + |
| 16 | + #define TYPE_ISA_DEBUGCON_DEVICE "isa-debugcon" |
| 17 | ++#define DEBUGCON_NO_BOOTABLE_DEVICE "No bootable device." |
| 18 | + OBJECT_DECLARE_SIMPLE_TYPE(ISADebugconState, ISA_DEBUGCON_DEVICE) |
| 19 | + |
| 20 | + //#define DEBUG_DEBUGCON |
| 21 | +@@ -42,6 +44,9 @@ typedef struct DebugconState { |
| 22 | + MemoryRegion io; |
| 23 | + CharBackend chr; |
| 24 | + uint32_t readback; |
| 25 | ++ bool watch_no_bootable_device; |
| 26 | ++ char match_buf[sizeof(DEBUGCON_NO_BOOTABLE_DEVICE) - 1]; |
| 27 | ++ size_t match_len; |
| 28 | + } DebugconState; |
| 29 | + |
| 30 | + struct ISADebugconState { |
| 31 | +@@ -51,6 +56,27 @@ struct ISADebugconState { |
| 32 | + DebugconState state; |
| 33 | + }; |
| 34 | + |
| 35 | ++static void debugcon_maybe_emit_no_bootable_device(DebugconState *s, |
| 36 | ++ unsigned char ch) |
| 37 | ++{ |
| 38 | ++ if (!s->watch_no_bootable_device) { |
| 39 | ++ return; |
| 40 | ++ } |
| 41 | ++ |
| 42 | ++ if (s->match_len < sizeof(s->match_buf)) { |
| 43 | ++ s->match_buf[s->match_len++] = ch; |
| 44 | ++ } else { |
| 45 | ++ memmove(s->match_buf, s->match_buf + 1, sizeof(s->match_buf) - 1); |
| 46 | ++ s->match_buf[sizeof(s->match_buf) - 1] = ch; |
| 47 | ++ } |
| 48 | ++ |
| 49 | ++ if (s->match_len == sizeof(s->match_buf) && |
| 50 | ++ memcmp(s->match_buf, DEBUGCON_NO_BOOTABLE_DEVICE, |
| 51 | ++ sizeof(s->match_buf)) == 0) { |
| 52 | ++ qapi_event_send_no_bootable_device(); |
| 53 | ++ } |
| 54 | ++} |
| 55 | ++ |
| 56 | + static void debugcon_ioport_write(void *opaque, hwaddr addr, uint64_t val, |
| 57 | + unsigned width) |
| 58 | + { |
| 59 | +@@ -64,6 +90,7 @@ static void debugcon_ioport_write(void *opaque, hwaddr addr, uint64_t val, |
| 60 | + /* XXX this blocks entire thread. Rewrite to use |
| 61 | + * qemu_chr_fe_write and background I/O callbacks */ |
| 62 | + qemu_chr_fe_write_all(&s->chr, &ch, 1); |
| 63 | ++ debugcon_maybe_emit_no_bootable_device(s, ch); |
| 64 | + } |
| 65 | + |
| 66 | + |
| 67 | +@@ -112,6 +139,7 @@ static void debugcon_isa_realizefn(DeviceState *dev, Error **errp) |
| 68 | + TYPE_ISA_DEBUGCON_DEVICE, 1); |
| 69 | + memory_region_add_subregion(isa_address_space_io(d), |
| 70 | + isa->iobase, &s->io); |
| 71 | ++ s->watch_no_bootable_device = isa->iobase == 0x403; |
| 72 | + } |
| 73 | + |
| 74 | + static Property debugcon_isa_properties[] = { |
| 75 | +diff --git a/qapi/control.json b/qapi/control.json |
| 76 | +index 336386f..2026992 100644 |
| 77 | +--- a/qapi/control.json |
| 78 | ++++ b/qapi/control.json |
| 79 | +@@ -209,3 +209,13 @@ |
| 80 | + '*pretty': 'bool', |
| 81 | + 'chardev': 'str' |
| 82 | + } } |
| 83 | ++ |
| 84 | ++## |
| 85 | ++# @NO_BOOTABLE_DEVICE: |
| 86 | ++# |
| 87 | ++# Emitted when `isa-debugcon` at I/O port 0x403 receives the |
| 88 | ++# string "No bootable device.". |
| 89 | ++# |
| 90 | ++# Since: 0.14 |
| 91 | ++## |
| 92 | ++{ 'event': 'NO_BOOTABLE_DEVICE' } |
| 93 | +diff --git a/tests/qtest/qmp-test.c b/tests/qtest/qmp-test.c |
| 94 | +index 22957fa..76915c0 100644 |
| 95 | +--- a/tests/qtest/qmp-test.c |
| 96 | ++++ b/tests/qtest/qmp-test.c |
| 97 | +@@ -337,6 +337,24 @@ static void test_qmp_missing_any_arg(void) |
| 98 | + qtest_quit(qts); |
| 99 | + } |
| 100 | + |
| 101 | ++static void test_qmp_no_bootable_device_event(void) |
| 102 | ++{ |
| 103 | ++ static const char trigger[] = "No bootable device."; |
| 104 | ++ QTestState *qts; |
| 105 | ++ size_t i; |
| 106 | ++ |
| 107 | ++ qts = qtest_initf("-nodefaults -machine q35 " |
| 108 | ++ "-chardev null,id=debugcon " |
| 109 | ++ "-device isa-debugcon,iobase=0x403,chardev=debugcon"); |
| 110 | ++ |
| 111 | ++ for (i = 0; i < sizeof(trigger) - 1; i++) { |
| 112 | ++ qtest_outb(qts, 0x403, trigger[i]); |
| 113 | ++ } |
| 114 | ++ |
| 115 | ++ qtest_qmp_eventwait(qts, "NO_BOOTABLE_DEVICE"); |
| 116 | ++ qtest_quit(qts); |
| 117 | ++} |
| 118 | ++ |
| 119 | + int main(int argc, char *argv[]) |
| 120 | + { |
| 121 | + g_test_init(&argc, &argv, NULL); |
| 122 | +@@ -348,6 +366,8 @@ int main(int argc, char *argv[]) |
| 123 | + #endif |
| 124 | + qtest_add_func("qmp/preconfig", test_qmp_preconfig); |
| 125 | + qtest_add_func("qmp/missing-any-arg", test_qmp_missing_any_arg); |
| 126 | ++ qtest_add_func("qmp/no-bootable-device-event", |
| 127 | ++ test_qmp_no_bootable_device_event); |
| 128 | + |
| 129 | + return g_test_run(); |
| 130 | + } |
0 commit comments