@@ -197,7 +197,7 @@ obj-i386-y += fdc.o mc146818rtc.o serial.o i8259.o i8254.o pcspk.o pc.o
obj-i386-y += cirrus_vga.o apic.o ioapic.o parallel.o acpi.o piix_pci.o
obj-i386-y += usb-uhci.o vmmouse.o vmport.o vmware_vga.o hpet.o
obj-i386-y += device-hotplug.o pci-hotplug.o smbios.o wdt_ib700.o
-obj-i386-y += ne2000-isa.o
+obj-i386-y += ne2000-isa.o debugcon.o
# shared objects
obj-ppc-y = ppc.o ide/core.o ide/qdev.o ide/isa.o ide/pci.o ide/macio.o
new file mode 100644
@@ -0,0 +1,118 @@
+/*
+ * QEMU Bochs-style debug console ("port E9") emulation
+ *
+ * Copyright (c) 2003-2004 Fabrice Bellard
+ * Copyright (c) 2008 Citrix Systems, Inc.
+ * Copyright (c) Intel Corporation; author: H. Peter Anvin
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "hw.h"
+#include "qemu-char.h"
+#include "isa.h"
+#include "pc.h"
+
+//#define DEBUG_DEBUGCON
+
+struct DebugconState {
+ CharDriverState *chr;
+ uint32_t readback;
+};
+
+typedef struct ISADebugconState {
+ ISADevice dev;
+ uint32_t iobase;
+ DebugconState state;
+} ISADebugconState;
+
+static void debugcon_ioport_write(void *opaque, uint32_t addr, uint32_t val)
+{
+ DebugconState *s = opaque;
+ unsigned char ch = val;
+
+#ifdef DEBUG_DEBUGCON
+ printf("debugcon: write addr=0x%04x val=0x%02x\n", addr, val);
+#endif
+
+ qemu_chr_write(s->chr, &ch, 1);
+}
+
+
+static uint32_t debugcon_ioport_read(void *opaque, uint32_t addr)
+{
+ DebugconState *s = opaque;
+
+#ifdef DEBUG_DEBUGCON
+ printf("debugcon: read addr=0x%04x\n", addr, val);
+#endif
+
+ return s->readback;
+}
+
+static void debugcon_init_core(DebugconState *s)
+{
+ if (!s->chr) {
+ fprintf(stderr, "Can't create debugcon device, empty char device\n");
+ exit(1);
+ }
+
+ qemu_chr_add_handlers(s->chr, NULL, NULL, NULL, s);
+}
+
+static int debugcon_isa_initfn(ISADevice *dev)
+{
+ ISADebugconState *isa = DO_UPCAST(ISADebugconState, dev, dev);
+ DebugconState *s = &isa->state;
+
+ debugcon_init_core(s);
+ register_ioport_write(isa->iobase, 1, 1, debugcon_ioport_write, s);
+ register_ioport_read(isa->iobase, 1, 1, debugcon_ioport_read, s);
+ return 0;
+}
+
+DebugconState *debugcon_isa_init(int index, CharDriverState *chr)
+{
+ ISADevice *dev;
+
+ dev = isa_create("isa-debugcon");
+ qdev_prop_set_chr(&dev->qdev, "chardev", chr);
+ if (qdev_init(&dev->qdev) < 0)
+ return NULL;
+ return &DO_UPCAST(ISADebugconState, dev, dev)->state;
+}
+
+static ISADeviceInfo debugcon_isa_info = {
+ .qdev.name = "isa-debugcon",
+ .qdev.size = sizeof(ISADebugconState),
+ .init = debugcon_isa_initfn,
+ .qdev.props = (Property[]) {
+ DEFINE_PROP_HEX32("iobase", ISADebugconState, iobase, 0xe9),
+ DEFINE_PROP_CHR("chardev", ISADebugconState, state.chr),
+ DEFINE_PROP_HEX32("readback", ISADebugconState, state.readback, 0xe9),
+ DEFINE_PROP_END_OF_LIST(),
+ },
+};
+
+static void debugcon_register_devices(void)
+{
+ isa_qdev_register(&debugcon_isa_info);
+}
+
+device_init(debugcon_register_devices)
@@ -1159,6 +1159,12 @@ static void pc_init1(ram_addr_t ram_size,
}
}
+ for(i = 0; i < MAX_DEBUGCON_PORTS; i++) {
+ if (debugcon_hds[i]) {
+ debugcon_isa_init(i, debugcon_hds[i]);
+ }
+ }
+
for(i = 0; i < nb_nics; i++) {
NICInfo *nd = &nd_table[i];
@@ -21,6 +21,10 @@ typedef struct ParallelState ParallelState;
ParallelState *parallel_init(int index, CharDriverState *chr);
ParallelState *parallel_mm_init(target_phys_addr_t base, int it_shift, qemu_irq irq, CharDriverState *chr);
+/* debugcon.c */
+
+DebugconState *debugcon_isa_init(int index, CharDriverState *chr);
+
/* i8259.c */
typedef struct PicState2 PicState2;
@@ -208,6 +208,7 @@ typedef struct uWireSlave uWireSlave;
typedef struct I2SCodec I2SCodec;
typedef struct DeviceState DeviceState;
typedef struct SSIBus SSIBus;
+typedef struct DebugconState DebugconState;
/* CPU save/load. */
void cpu_save(QEMUFile *f, void *opaque);
@@ -1586,6 +1586,17 @@ The default device is @code{vc} in graphical mode and @code{stdio} in
non graphical mode.
ETEXI
+DEF("debugcon", HAS_ARG, QEMU_OPTION_debugcon, \
+ "-debugcon dev redirect the debug console to char device 'dev'\n")
+STEXI
+@item -monitor @var{dev}
+Redirect the debug console to host device @var{dev} (same devices as the
+serial port). The debug console is an I/O port which is typically port
+0xe9; writing to that I/O port sends output to this device.
+The default device is @code{vc} in graphical mode and @code{stdio} in
+non graphical mode.
+ETEXI
+
DEF("pidfile", HAS_ARG, QEMU_OPTION_pidfile, \
"-pidfile file write PID to 'file'\n")
STEXI
@@ -225,6 +225,12 @@ extern CharDriverState *parallel_hds[MAX_PARALLEL_PORTS];
extern CharDriverState *virtcon_hds[MAX_VIRTIO_CONSOLES];
+/* debugging ports */
+
+#define MAX_DEBUGCON_PORTS 1
+
+extern CharDriverState *debugcon_hds[MAX_DEBUGCON_PORTS];
+
#define TFR(expr) do { if ((expr) != -1) break; } while (errno == EINTR)
#ifdef HAS_AUDIO
@@ -212,6 +212,7 @@ int no_quit = 0;
CharDriverState *serial_hds[MAX_SERIAL_PORTS];
CharDriverState *parallel_hds[MAX_PARALLEL_PORTS];
CharDriverState *virtcon_hds[MAX_VIRTIO_CONSOLES];
+CharDriverState *debugcon_hds[MAX_DEBUGCON_PORTS];
#ifdef TARGET_I386
int win2k_install_hack = 0;
int rtc_td_hack = 0;
@@ -4598,6 +4599,8 @@ int main(int argc, char **argv, char **envp)
int parallel_device_index;
const char *virtio_consoles[MAX_VIRTIO_CONSOLES];
int virtio_console_index;
+ const char *debugcon_devices[MAX_DEBUGCON_PORTS];
+ int debugcon_device_index;
const char *loadvm = NULL;
QEMUMachine *machine;
const char *cpu_model;
@@ -4683,6 +4686,11 @@ int main(int argc, char **argv, char **envp)
}
monitor_device_index = 0;
+ debugcon_devices[0] = "vc:80Cx24C";
+ for(i = 1; i < MAX_DEBUGCON_PORTS; i++)
+ debugcon_devices[i] = NULL;
+ debugcon_device_index = 0;
+
for (i = 0; i < MAX_NODES; i++) {
node_mem[i] = 0;
node_cpumask[i] = 0;
@@ -5121,6 +5129,14 @@ int main(int argc, char **argv, char **envp)
serial_devices[serial_device_index] = optarg;
serial_device_index++;
break;
+ case QEMU_OPTION_debugcon:
+ if (debugcon_device_index >= MAX_DEBUGCON_PORTS) {
+ fprintf(stderr, "qemu: too many debugcon ports\n");
+ exit(1);
+ }
+ debugcon_devices[debugcon_device_index] = optarg;
+ debugcon_device_index++;
+ break;
case QEMU_OPTION_watchdog:
if (watchdog) {
fprintf(stderr,
@@ -5428,6 +5444,8 @@ int main(int argc, char **argv, char **envp)
if (strncmp(monitor_devices[0], "vc", 2) == 0) {
monitor_devices[0] = "stdio";
}
+ if (debugcon_device_index == 0)
+ debugcon_devices[0] = "stdio";
}
#ifndef _WIN32
@@ -5689,6 +5707,20 @@ int main(int argc, char **argv, char **envp)
}
}
+ for(i = 0; i < MAX_DEBUGCON_PORTS; i++) {
+ const char *devname = debugcon_devices[i];
+ if (devname && strcmp(devname, "none")) {
+ char label[32];
+ snprintf(label, sizeof(label), "debugcon%d", i);
+ debugcon_hds[i] = qemu_chr_open(label, devname, NULL);
+ if (!debugcon_hds[i]) {
+ fprintf(stderr, "qemu: could not open debugcon device '%s': %s\n",
+ devname, strerror(errno));
+ exit(1);
+ }
+ }
+ }
+
module_call_init(MODULE_INIT_DEVICE);
if (watchdog) {
@@ -5824,6 +5856,14 @@ int main(int argc, char **argv, char **envp)
}
}
+ for(i = 0; i < MAX_DEBUGCON_PORTS; i++) {
+ const char *devname = debugcon_devices[i];
+ if (devname && strcmp(devname, "none")) {
+ if (strstart(devname, "vc", 0))
+ qemu_chr_printf(debugcon_hds[i], "debugcon%d console\r\n", i);
+ }
+ }
+
if (gdbstub_dev && gdbserver_start(gdbstub_dev) < 0) {
fprintf(stderr, "qemu: could not open gdbserver on device '%s'\n",
gdbstub_dev);