diff --git a/ui/xemu-monitor.c b/ui/xemu-monitor.c
new file mode 100644
index 0000000000..4e137880a4
--- /dev/null
+++ b/ui/xemu-monitor.c
@@ -0,0 +1,122 @@
+/*
+ * xemu QEMU Monitor Interface
+ *
+ * Copyright (c) 2020 Matt Borgerson
+ *
+ * Based on gdbstub.c
+ *
+ * Copyright (c) 2003-2005 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see .
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "qemu-common.h"
+#include "ui/console.h"
+#include "ui/input.h"
+#include "ui/sdl2.h"
+#include "sysemu/sysemu.h"
+#include "monitor/monitor.h"
+#include "chardev/char.h"
+
+#include "xemu-monitor.h"
+
+#define TYPE_CHARDEV_XEMU_MONITOR "chardev-xemu-monitor"
+
+static Chardev *mon_chr;
+static char mon_buffer[8*4096];
+static const size_t mon_buffer_size = 8*4096;
+static size_t offset;
+
+static void char_xemu_class_init(ObjectClass *oc, void *data);
+static void xemu_monitor_open(Chardev *chr, ChardevBackend *backend,
+ bool *be_opened, Error **errp);
+static int xemu_monitor_buffer_append(Chardev *chr, const uint8_t *buf, int len);
+
+static void char_xemu_class_init(ObjectClass *oc, void *data)
+{
+ ChardevClass *cc = CHARDEV_CLASS(oc);
+
+ cc->internal = true;
+ cc->open = xemu_monitor_open;
+ cc->chr_write = xemu_monitor_buffer_append;
+}
+
+static void xemu_monitor_open(Chardev *chr, ChardevBackend *backend,
+ bool *be_opened, Error **errp)
+{
+ *be_opened = false;
+}
+
+void xemu_monitor_init(void)
+{
+ /* For simplicity, assume this is only created once */
+ assert(mon_chr == NULL);
+ mon_chr = qemu_chardev_new(NULL, TYPE_CHARDEV_XEMU_MONITOR,
+ NULL, NULL, &error_abort);
+ monitor_init_hmp(mon_chr, false);
+}
+
+char *xemu_get_monitor_buffer(void)
+{
+ return mon_buffer;
+}
+
+static int xemu_monitor_buffer_append(Chardev *chr, const uint8_t *buf, int len)
+{
+ if ((offset+len+1) >= mon_buffer_size) {
+ /* Reached the end of the buffer. Keep it simple and
+ * just start back at the beginning.
+ */
+ offset = 0;
+ }
+
+ /* Copy string into the monitor buffer and terminate */
+ assert((len+1) <= mon_buffer_size);
+ memcpy(&mon_buffer[offset], buf, len);
+ offset += len;
+ mon_buffer[offset] = '\x00';
+
+ return len;
+}
+
+void xemu_run_monitor_command(const char *cmd)
+{
+ /* Copy command into buffer */
+ xemu_monitor_buffer_append(mon_chr, (const uint8_t*)"# ", 2);
+ xemu_monitor_buffer_append(mon_chr, (const uint8_t*)cmd, strlen(cmd));
+ xemu_monitor_buffer_append(mon_chr, (const uint8_t*)"\n", 1);
+
+ /* Send command to monitor */
+ int len = strlen(cmd)+1;
+
+ /* FIXME: qemu_chr_be_write needs to be fixed to declare inbuf as const. It
+ * does not modify the data. Accept the warning for now as a reminder.
+ */
+ qemu_chr_be_write(mon_chr, cmd, len);
+}
+
+static const TypeInfo char_xemu_type_info = {
+ .name = TYPE_CHARDEV_XEMU_MONITOR,
+ .parent = TYPE_CHARDEV,
+ .class_init = char_xemu_class_init,
+};
+
+static void register_types(void)
+{
+ type_register_static(&char_xemu_type_info);
+}
+
+type_init(register_types);
diff --git a/ui/xemu-monitor.h b/ui/xemu-monitor.h
new file mode 100644
index 0000000000..959f21c7c9
--- /dev/null
+++ b/ui/xemu-monitor.h
@@ -0,0 +1,39 @@
+/*
+ * xemu QEMU Monitor Interface
+ *
+ * Copyright (c) 2020 Matt Borgerson
+ *
+ * Based on gdbstub.c
+ *
+ * Copyright (c) 2003-2005 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see .
+ */
+
+#ifndef XEMU_MONITOR_H
+#define XEMU_MONITOR_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void xemu_monitor_init(void);
+char *xemu_get_monitor_buffer(void);
+void xemu_run_monitor_command(const char *cmd);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif