diff mbox

SerialICE - Qemu based (x86) firmware debugger

Message ID 4B082044.7080706@coresystems.de
State New
Headers show

Commit Message

Stefan Reinauer Nov. 21, 2009, 5:15 p.m. UTC
Dear x86 hardware and low-level software developers and enthusiasts!

coresystems GmbH is glad to finally release SerialICE 1.5, our
"Integrated Circuit Emulator over Serial".

SerialICE (http://www.serialice.com) is a BIOS/Firmware debugging tool.
It allows you to run and observe BIOS images (such as coreboot®:
http://www.coreboot.org/) written for real hardware in Qemu
(http://www.qemu.org) for debugging purposes. Thanks to Qemu's
compelling feature set, it's also possible to debug this BIOS code with
GNU GDB.

Among the new features of SerialICE version 1.5:

- Rework memory and IO filters to provide more control
- Improved PCI, PCIe and memory access logging
- Windows (MINGW and Cygwin) support
- New mainboard supported: ASUS P2B
- SerialICE connection now survives target resets
- CPUID now honors ECX values
- RDMSR/WRMSR now honor EDI unlock keys
- Add LUA patch to correctly operate on 32bit hosts
- Drop SerialICE specific machine type in Qemu


SerialICE consists of three parts:

- a serial console "rom shell" compiled with romcc, with minimal footprint.
- a patch to Qemu 0.11.0, which adds a new "SerialICE" machine.
- a LUA script that contains filters, loggers and other SerialICE
specific configuration and adaption.

SerialICE can be downloaded from http://www.serialice.com/. The patch
against Qemu 0.11.0 is attached to this mail for review. Dear Qemu developers: 
Please let us know what needs to be changed so this patch can be merged!

With "qemu -m serialice -serialice /dev/ttyS0 -L
path-to-your-bios.bin-dir -hda /dev/zero" you can run an arbitrary BIOS
binary written for your target hardware in Qemu, thus logging all IO and
memory accesses. Those operations will additionally be transmitted to
the target system's shell and are executed there, while their results
are submitted back to Qemu.

Operations sent to the target:
- memory reads/writes (some of them)
- IO reads/writes
- MSR reads/writes
- CPUID calls (the bios code path might rely on this)

Note: The code is still quite experimental and only supports a few
number of mainboard out of the box, but it was already useful in some
debugging scenarios we had and was able to reveil information that would
normally only be available with a hardware debugger of the price of a
new car. Don't expect SerialICE to completely replace a ICE/JTAG/ITP
device, but it might just work for your case, as it did for us.

The ROM code needs minimal board/chipset specific setup in order to
establish serial communication with Qemu. See mainboard/* for a few
examples.  This release contains setup code for 7 mainboards.
Also, some hardware accesses have to be caught in the LUA code
(scripts/serialice.lua) in order to prevent the system from locking up
(ie. when the BIOS is disabling the serial console).

Special thanks go to Patrick Georgi and Mark Marshall for their bug fixes and contributions to
this release.

See http://www.serialice.com/ for more information.

Comments and patches are of course very welcome!


Best regards,

Stefan Reinauer

Comments

JonY Nov. 23, 2009, 10:36 a.m. UTC | #1
On 11/22/2009 01:15, Stefan Reinauer wrote:
> Dear x86 hardware and low-level software developers and enthusiasts!
>
> coresystems GmbH is glad to finally release SerialICE 1.5, our
> "Integrated Circuit Emulator over Serial".
>
> SerialICE (http://www.serialice.com) is a BIOS/Firmware debugging tool.
> It allows you to run and observe BIOS images (such as coreboot®:
> http://www.coreboot.org/) written for real hardware in Qemu
> (http://www.qemu.org) for debugging purposes. Thanks to Qemu's
> compelling feature set, it's also possible to debug this BIOS code with
> GNU GDB.
>
> Among the new features of SerialICE version 1.5:
>
> - Rework memory and IO filters to provide more control
> - Improved PCI, PCIe and memory access logging
> - Windows (MINGW and Cygwin) support
> - New mainboard supported: ASUS P2B
> - SerialICE connection now survives target resets
> - CPUID now honors ECX values
> - RDMSR/WRMSR now honor EDI unlock keys
> - Add LUA patch to correctly operate on 32bit hosts
> - Drop SerialICE specific machine type in Qemu
>
>
> SerialICE consists of three parts:
>
> - a serial console "rom shell" compiled with romcc, with minimal footprint.
> - a patch to Qemu 0.11.0, which adds a new "SerialICE" machine.
> - a LUA script that contains filters, loggers and other SerialICE
> specific configuration and adaption.
>
> SerialICE can be downloaded from http://www.serialice.com/. The patch
> against Qemu 0.11.0 is attached to this mail for review. Dear Qemu developers:
> Please let us know what needs to be changed so this patch can be merged!
>
> With "qemu -m serialice -serialice /dev/ttyS0 -L
> path-to-your-bios.bin-dir -hda /dev/zero" you can run an arbitrary BIOS
> binary written for your target hardware in Qemu, thus logging all IO and
> memory accesses. Those operations will additionally be transmitted to
> the target system's shell and are executed there, while their results
> are submitted back to Qemu.
>
> Operations sent to the target:
> - memory reads/writes (some of them)
> - IO reads/writes
> - MSR reads/writes
> - CPUID calls (the bios code path might rely on this)
>
> Note: The code is still quite experimental and only supports a few
> number of mainboard out of the box, but it was already useful in some
> debugging scenarios we had and was able to reveil information that would
> normally only be available with a hardware debugger of the price of a
> new car. Don't expect SerialICE to completely replace a ICE/JTAG/ITP
> device, but it might just work for your case, as it did for us.
>
> The ROM code needs minimal board/chipset specific setup in order to
> establish serial communication with Qemu. See mainboard/* for a few
> examples.  This release contains setup code for 7 mainboards.
> Also, some hardware accesses have to be caught in the LUA code
> (scripts/serialice.lua) in order to prevent the system from locking up
> (ie. when the BIOS is disabling the serial console).
>
> Special thanks go to Patrick Georgi and Mark Marshall for their bug fixes and contributions to
> this release.
>
> See http://www.serialice.com/ for more information.
>
> Comments and patches are of course very welcome!
>

Hi,

This patch looks very interesting, anybody going to review this?
diff mbox

Patch

--- qemu-0.11.0/serialice.c
+++ qemu-0.11.0/serialice.c
@@ -0,0 +1,927 @@ 
+/*
+ * QEMU PC System Emulator
+ *
+ * Copyright (c) 2009 coresystems GmbH
+ *
+ * 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.
+ */
+
+/* System includes */
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <string.h>
+#ifdef WIN32
+#include <windows.h>
+#include <conio.h>
+#else
+#include <fcntl.h>
+#include <termios.h>
+#include <sys/ioctl.h>
+#endif
+
+/* LUA includes */
+#include <lua.h>
+#include <lauxlib.h>
+#include <lualib.h>
+
+/* Local includes */
+#include "hw/hw.h"
+#include "hw/pc.h"
+#include "serialice.h"
+#include "sysemu.h"
+
+#define SERIALICE_DEBUG 3
+#define BUFFER_SIZE 1024
+typedef struct {
+#ifdef WIN32
+	HANDLE fd;
+#else
+	int fd;
+#endif
+	char *buffer;
+	char *command;
+} SerialICEState;
+
+static SerialICEState *s;
+
+int serialice_active = 0;
+const char *serialice_lua_script="serialice.lua";
+
+#ifndef WIN32
+static struct termios options;
+#endif
+
+static lua_State *L;
+
+// **************************************************************************
+// LUA scripting interface and callbacks
+
+static int serialice_register_physical(lua_State *luastate)
+{
+	int n = lua_gettop(luastate);
+	uint32_t addr, size;
+	ram_addr_t phys;
+
+	if (n != 2) {
+		fprintf(stderr, "ERROR: Not called as SerialICE_register_physical(<addr> <size>)\n");
+		return 0;
+	}
+
+	addr = lua_tointeger(luastate, 1);
+	size = lua_tointeger(luastate, 2);
+
+	printf("Registering physical memory at 0x%08x (0x%08x bytes)\n", addr, size);
+	phys = qemu_ram_alloc(size);
+	cpu_register_physical_memory(addr, size, phys);
+
+	return 0;
+}
+
+static int serialice_lua_init(void)
+{
+    int status;
+
+    /* Create a LUA context and load LUA libraries */
+    L = luaL_newstate();
+    luaL_openlibs(L);
+
+    /* Register C function callbacks */
+    lua_register(L, "SerialICE_register_physical", serialice_register_physical);
+
+    /* Load the script file */
+    status = luaL_loadfile(L, serialice_lua_script);
+    if (status) {
+        fprintf(stderr, "Couldn't load SerialICE script: %s\n", lua_tostring(L, -1));
+        exit(1);
+    }
+
+    /* Ask Lua to run our little script */
+    status = lua_pcall(L, 0, 1, 0);
+    if (status) {
+        fprintf(stderr, "Failed to run script: %s\n", lua_tostring(L, -1));
+        exit(1);
+    }
+    lua_pop(L, 1);
+
+    return 0;
+}
+
+static int serialice_lua_exit(void)
+{
+        lua_close(L);
+	return 0;
+}
+
+static int serialice_io_read_filter(uint32_t *data, uint16_t port, int size)
+{
+    int ret, result;
+
+    lua_getfield(L, LUA_GLOBALSINDEX, "SerialICE_io_read_filter");
+    lua_pushinteger(L, port); // port
+    lua_pushinteger(L, size); // datasize
+    result = lua_pcall(L, 2, 2, 0);
+    if (result) {
+        fprintf(stderr, "Failed to run function SerialICE_io_read_filter: %s\n", lua_tostring(L, -1));
+        exit(1);
+    }
+    *data = lua_tointeger(L, -1);
+    ret = lua_toboolean(L, -2);
+    lua_pop(L, 2);
+
+    return ret;
+} 
+
+static int serialice_io_write_filter(uint32_t *data, uint16_t port, int size)
+{
+    int ret, result;
+
+    lua_getfield(L, LUA_GLOBALSINDEX, "SerialICE_io_write_filter");
+    lua_pushinteger(L, port); // port
+    lua_pushinteger(L, size); // datasize
+    lua_pushinteger(L, *data); // data
+
+    result = lua_pcall(L, 3, 2, 0);
+    if (result) {
+        fprintf(stderr, "Failed to run function SerialICE_io_write_filter: %s\n", lua_tostring(L, -1));
+        exit(1);
+    }
+    *data = lua_tointeger(L, -1);
+    ret = lua_toboolean(L, -2);
+    lua_pop(L, 2);
+
+    return ret;
+} 
+
+
+#define READ_FROM_QEMU		(1 << 0)
+#define READ_FROM_SERIALICE	(1 << 1)
+static int serialice_memory_read_filter(uint32_t addr, uint32_t *data, int size)
+{
+    int ret = 0, result;
+
+    lua_getfield(L, LUA_GLOBALSINDEX, "SerialICE_memory_read_filter");
+    lua_pushinteger(L, addr); // addr
+    lua_pushinteger(L, size); // datasize
+    result = lua_pcall(L, 2, 3, 0);
+    if (result) {
+        fprintf(stderr, "Failed to run function SerialICE_memory_read_filter: %s\n", lua_tostring(L, -1));
+        exit(1);
+    }
+
+    *data = lua_tointeger(L, -1); // result
+
+    ret |= lua_toboolean(L, -2) ? READ_FROM_QEMU : 0; // to_qemu
+    ret |= lua_toboolean(L, -3) ? READ_FROM_SERIALICE : 0; // to_hw
+
+    lua_pop(L, 3);
+
+    return ret;
+} 
+
+#define WRITE_TO_QEMU		(1 << 0)
+#define WRITE_TO_SERIALICE	(1 << 1)
+
+static int serialice_memory_write_filter(uint32_t addr, int size, uint32_t *data)
+{
+    int ret = 0, result;
+    int write_to_qemu, write_to_serialice;
+
+    lua_getfield(L, LUA_GLOBALSINDEX, "SerialICE_memory_write_filter");
+    lua_pushinteger(L, addr); // address
+    lua_pushinteger(L, size); // datasize
+    lua_pushinteger(L, *data); // data
+    result = lua_pcall(L, 3, 3, 0);
+    if (result) {
+        fprintf(stderr, "Failed to run function SerialICE_memory_write_filter: %s\n", lua_tostring(L, -1));
+        exit(1);
+    }
+    *data = lua_tointeger(L, -1);
+    write_to_qemu = lua_toboolean(L, -2);
+    write_to_serialice = lua_toboolean(L, -3);
+    lua_pop(L, 3);
+
+    ret |= write_to_qemu ? WRITE_TO_QEMU : 0;
+    ret |= write_to_serialice ? WRITE_TO_SERIALICE : 0;
+
+    return ret;
+} 
+
+#define FILTER_READ	0
+#define FILTER_WRITE	1
+
+static int serialice_msr_filter(int flags, uint32_t addr, uint32_t *hi, uint32_t *lo)
+{
+    int ret, result;
+
+    if (flags & FILTER_WRITE)
+    	lua_getfield(L, LUA_GLOBALSINDEX, "SerialICE_msr_write_filter");
+    else
+    	lua_getfield(L, LUA_GLOBALSINDEX, "SerialICE_msr_read_filter");
+
+    lua_pushinteger(L, addr); // port
+    lua_pushinteger(L, *hi);  // high
+    lua_pushinteger(L, *lo);  // low
+    result = lua_pcall(L, 3, 3, 0);
+    if (result) {
+        fprintf(stderr, "Failed to run function SerialICE_msr_read_filter: %s\n", lua_tostring(L, -1));
+        exit(1);
+    }
+    ret = lua_toboolean(L, -3);
+    if (ret) {
+     	*hi = lua_tointeger(L, -1);
+    	*lo = lua_tointeger(L, -2);
+    }
+    lua_pop(L, 3);
+
+    return ret;
+} 
+
+static int serialice_cpuid_filter(cpuid_regs_t *regs)
+{
+    int ret, result;
+
+    lua_getfield(L, LUA_GLOBALSINDEX, "SerialICE_cpuid_filter");
+
+    lua_pushinteger(L, regs->eax); // eax
+    lua_pushinteger(L, regs->ecx); // ecx
+    result = lua_pcall(L, 2, 5, 0);
+    if (result) {
+        fprintf(stderr, "Failed to run function SerialICE_msr_read_filter: %s\n", lua_tostring(L, -1));
+        exit(1);
+    }
+
+    ret = lua_toboolean(L, -5);
+    if (ret) {
+    	regs->eax = lua_tointeger(L, -1);
+    	regs->ebx = lua_tointeger(L, -2);
+    	regs->ecx = lua_tointeger(L, -3);
+    	regs->edx = lua_tointeger(L, -4);
+    }
+    lua_pop(L, 5);
+
+    return ret;
+} 
+
+
+/* SerialICE output loggers */
+
+#define LOG_IO		0
+#define LOG_MEMORY	1
+#define LOG_READ	0
+#define LOG_WRITE	2
+// these two are separate
+#define LOG_QEMU	4
+#define LOG_TARGET	8
+
+static void serialice_log(int flags, uint32_t data, uint32_t addr, int size)
+{
+    int result;
+
+    if ((flags & LOG_WRITE) && (flags & LOG_MEMORY))
+    	lua_getfield(L, LUA_GLOBALSINDEX, "SerialICE_memory_write_log");
+    else if (!(flags & LOG_WRITE) && (flags & LOG_MEMORY))
+    	lua_getfield(L, LUA_GLOBALSINDEX, "SerialICE_memory_read_log");
+    else if ((flags & LOG_WRITE) && !(flags & LOG_MEMORY))
+    	lua_getfield(L, LUA_GLOBALSINDEX, "SerialICE_io_write_log");
+    else // if (!(flags & LOG_WRITE) && !(flags & LOG_MEMORY))
+    	lua_getfield(L, LUA_GLOBALSINDEX, "SerialICE_io_read_log");
+
+    lua_pushinteger(L, addr); // addr/port
+    lua_pushinteger(L, size); // datasize
+    lua_pushinteger(L, data); // data
+    lua_pushboolean(L, ((flags & LOG_TARGET) != 0));
+
+    result = lua_pcall(L, 4, 0, 0);
+    if (result) {
+        fprintf(stderr, "Failed to run function SerialICE_%s_%s_log: %s\n",
+			(flags & LOG_MEMORY)?"memory":"io", 
+			(flags & LOG_WRITE)?"write":"read",
+			lua_tostring(L, -1));
+        exit(1);
+    }
+} 
+
+static void serialice_msr_log(int flags, uint32_t addr, uint32_t hi, uint32_t lo, int filtered)
+{
+    int result;
+
+    if (flags & LOG_WRITE)
+    	lua_getfield(L, LUA_GLOBALSINDEX, "SerialICE_msr_write_log");
+    else // if (!(flags & LOG_WRITE))
+    	lua_getfield(L, LUA_GLOBALSINDEX, "SerialICE_msr_read_log");
+
+    lua_pushinteger(L, addr); // addr/port
+    lua_pushinteger(L, hi); // datasize
+    lua_pushinteger(L, lo); // data
+    lua_pushboolean(L, filtered); // data
+    result = lua_pcall(L, 4, 0, 0);
+    if (result) {
+        fprintf(stderr, "Failed to run function SerialICE_msr_%s_log: %s\n",
+			(flags & LOG_WRITE)?"write":"read",
+			lua_tostring(L, -1));
+        exit(1);
+    }
+}
+
+static void serialice_cpuid_log(uint32_t eax, uint32_t ecx, cpuid_regs_t res, int filtered)
+{
+    int result;
+
+    lua_getfield(L, LUA_GLOBALSINDEX, "SerialICE_cpuid_log");
+
+    lua_pushinteger(L, eax); // input: eax
+    lua_pushinteger(L, ecx); // input: ecx
+    lua_pushinteger(L, res.eax); // output: eax
+    lua_pushinteger(L, res.ebx); // output: ebx
+    lua_pushinteger(L, res.ecx); // output: ecx
+    lua_pushinteger(L, res.edx); // output: edx
+    lua_pushboolean(L, filtered); // data
+    result = lua_pcall(L, 7, 0, 0);
+    if (result) {
+        fprintf(stderr, "Failed to run function SerialICE_cpuid_log: %s\n",
+			lua_tostring(L, -1));
+        exit(1);
+    }
+}
+
+
+// **************************************************************************
+// low level communication with the SerialICE shell (serial communication)
+
+static int serialice_read(SerialICEState *state, void *buf, size_t nbyte)
+{
+	int bytes_read = 0;
+
+	while (1) {
+#ifdef WIN32
+		int ret = 0;
+		ReadFile(state->fd, buf, nbyte - bytes_read, &ret, NULL);
+		if (!ret)
+			break;
+#else
+		int ret = read(state->fd, buf, nbyte - bytes_read);
+
+		if (ret == -1 && errno == EINTR)
+			continue;
+
+		if (ret == -1)
+			break;
+#endif
+
+		bytes_read += ret;
+		buf += ret;
+
+		if (bytes_read >= (int)nbyte)
+			break;
+	}
+
+	return bytes_read;
+}
+
+static int serialice_write(SerialICEState *state, const void *buf, size_t nbyte)
+{
+	char *buffer = (char *) buf;
+	char c;
+	int i;
+
+	for (i = 0; i < (int)nbyte; i++) {
+#ifdef WIN32
+		int ret = 0;
+		while (ret == 0)
+			WriteFile(state->fd, buffer + i, 1, &ret, NULL);
+		ret = 0;
+		while (ret == 0)
+			ReadFile(state->fd, &c, 1, &ret, NULL);
+#else
+		while (write(state->fd, buffer + i, 1) != 1) ;
+		while (read(state->fd, &c, 1) != 1) ;
+#endif
+		if (c != buffer[i]) {
+			printf("Readback error! %x/%x\n", c, buffer[i]);
+		}
+	}
+
+	return nbyte;
+}
+
+static int serialice_wait_prompt(void)
+{
+	char buf[3];
+	int l;
+
+	l = serialice_read(s, buf, 3);
+
+	if (l == -1) {
+		perror("SerialICE: Could not read from target");
+		exit(1);
+	}
+
+	while (buf[0] != '\n' || buf[1] != '>' || buf[2] != ' ') {
+		buf[0] = buf[1];
+		buf[1] = buf[2];
+		l = serialice_read(s, buf + 2, 1);
+		if (l == -1) {
+			perror("SerialICE: Could not read from target");
+			exit(1);
+		}
+	}
+
+	return 0;
+}
+
+static void serialice_command(const char *command, int reply_len)
+{
+#if SERIALICE_DEBUG > 5
+	int i;
+#endif
+	int l;
+
+	serialice_wait_prompt();
+
+	serialice_write(s, command, strlen(command));
+	
+	memset(s->buffer, 0, reply_len + 1); // clear enough of the buffer
+
+	l = serialice_read(s, s->buffer, reply_len);
+
+	if (l == -1) {
+		perror("SerialICE: Could not read from target");
+		exit(1);
+	}
+
+	// compensate for CR on the wire. Needed on Win32
+	if (s->buffer[0] == '\r') {
+		memmove(s->buffer, s->buffer+1, reply_len);
+		serialice_read(s, s->buffer+reply_len-1, 1);
+	}
+
+	if (l != reply_len) {
+		printf("SerialICE: command was not answered sufficiently: "
+				"(%d/%d bytes)\n'%s'\n", l, reply_len, s->buffer);
+		exit(1);
+	}
+
+#if SERIALICE_DEBUG > 5
+	for (i=0; i < reply_len; i++)
+		printf("%02x ", s->buffer[i]);
+	printf("\n");
+#endif
+}
+
+
+// **************************************************************************
+// high level communication with the SerialICE shell
+
+uint8_t serialice_inb(uint16_t port)
+{
+	uint8_t ret;
+	uint32_t data;
+
+	if (serialice_io_read_filter(&data, port, 1))
+		return data & 0xff;
+
+	sprintf(s->command, "*ri%04x.b", port);
+	// command read back: "\n00" (3 characters)
+	serialice_command(s->command, 3);
+	ret = (uint8_t)strtoul(s->buffer + 1, (char **)NULL, 16);
+
+	serialice_log(LOG_READ|LOG_IO, ret, port, 1);
+
+	return ret;
+}
+
+uint16_t serialice_inw(uint16_t port)
+{
+	uint16_t ret;
+	uint32_t data;
+
+	if (serialice_io_read_filter(&data, port, 1))
+		return data & 0xffff;
+
+	sprintf(s->command, "*ri%04x.w", port);
+	// command read back: "\n0000" (5 characters)
+	serialice_command(s->command, 5);
+	ret = (uint16_t)strtoul(s->buffer + 1, (char **)NULL, 16);
+
+	serialice_log(LOG_READ|LOG_IO, ret, port, 2);
+
+	return ret;
+}
+
+uint32_t serialice_inl(uint16_t port)
+{
+	uint32_t ret;
+	uint32_t data;
+
+	if (serialice_io_read_filter(&data, port, 1))
+		return data;
+
+	sprintf(s->command, "*ri%04x.l", port);
+	// command read back: "\n00000000" (9 characters)
+	serialice_command(s->command, 9);
+	ret = (uint32_t)strtoul(s->buffer + 1, (char **)NULL, 16);
+
+	serialice_log(LOG_READ|LOG_IO, ret, port, 4);
+
+	return ret;
+}
+
+void serialice_outb(uint8_t data, uint16_t port)
+{
+	uint32_t filtered_data = (uint32_t)data;
+
+	serialice_log(LOG_WRITE|LOG_IO, data, port, 1);
+
+	if (serialice_io_write_filter(&filtered_data, port, 1)) {
+		return;
+	}
+
+	data = (uint8_t)filtered_data;
+	sprintf(s->command, "*wi%04x.b=%02x", port, data);
+	serialice_command(s->command, 0);
+}
+
+void serialice_outw(uint16_t data, uint16_t port)
+{
+	uint32_t filtered_data = (uint32_t)data;
+
+	serialice_log(LOG_WRITE|LOG_IO, data, port, 2);
+
+	if (serialice_io_write_filter(&filtered_data, port, 2)) {
+		return;
+	}
+
+	data = (uint16_t)filtered_data;
+	sprintf(s->command, "*wi%04x.w=%04x", port, data);
+	serialice_command(s->command, 0);
+}
+
+void serialice_outl(uint32_t data, uint16_t port)
+{
+	uint32_t filtered_data = data;
+
+	serialice_log(LOG_WRITE|LOG_IO, data, port, 4);
+
+	if (serialice_io_write_filter(&filtered_data, port, 4)) {
+		return;
+	}
+
+	data = filtered_data;
+	sprintf(s->command, "*wi%04x.l=%08x", port, data);
+	serialice_command(s->command, 0);
+}
+
+uint8_t serialice_readb(uint32_t addr)
+{
+	uint8_t ret;
+	sprintf(s->command, "*rm%08x.b", addr);
+	// command read back: "\n00" (3 characters)
+	serialice_command(s->command, 3);
+	ret = (uint8_t)strtoul(s->buffer + 1, (char **)NULL, 16);
+	return ret;
+}
+
+uint16_t serialice_readw(uint32_t addr)
+{
+	uint16_t ret;
+	sprintf(s->command, "*rm%08x.w", addr);
+	// command read back: "\n0000" (5 characters)
+	serialice_command(s->command, 5);
+	ret = (uint16_t)strtoul(s->buffer + 1, (char **)NULL, 16);
+	return ret;
+}
+
+uint32_t serialice_readl(uint32_t addr)
+{
+	uint32_t ret;
+	sprintf(s->command, "*rm%08x.l", addr);
+	// command read back: "\n00000000" (9 characters)
+	serialice_command(s->command, 9);
+	ret = (uint32_t)strtoul(s->buffer + 1, (char **)NULL, 16);
+	return ret;
+}
+
+void serialice_writeb(uint8_t data, uint32_t addr)
+{
+	sprintf(s->command, "*wm%08x.b=%02x", addr, data);
+	serialice_command(s->command, 0);
+}
+
+void serialice_writew(uint16_t data, uint32_t addr)
+{
+	sprintf(s->command, "*wm%08x.w=%04x", addr, data);
+	serialice_command(s->command, 0);
+}
+
+void serialice_writel(uint32_t data, uint32_t addr)
+{
+	sprintf(s->command, "*wm%08x.l=%08x", addr, data);
+	serialice_command(s->command, 0);
+}
+
+uint64_t serialice_rdmsr(uint32_t addr, uint32_t key)
+{
+	uint32_t hi, lo;
+	uint64_t ret;
+	int filtered;
+
+	filtered = serialice_msr_filter(FILTER_READ, addr, &hi, &lo);
+	if (!filtered) {
+		sprintf(s->command, "*rc%08x.%08x", addr, key);
+
+		// command read back: "\n00000000.00000000" (18 characters)
+		serialice_command(s->command, 18);
+
+		s->buffer[9] = 0; // . -> \0
+		hi = (uint32_t)strtoul(s->buffer + 1, (char **)NULL, 16);
+		lo = (uint32_t)strtoul(s->buffer + 10, (char **)NULL, 16);
+	}
+
+	ret = hi;
+	ret <<= 32;
+	ret |= lo;
+
+	serialice_msr_log(LOG_READ, addr, hi, lo, filtered);
+
+	return ret;
+}
+
+void serialice_wrmsr(uint64_t data, uint32_t addr, uint32_t key)
+{
+	uint32_t hi, lo;
+	int filtered;
+
+	hi = (data >> 32);
+	lo = (data & 0xffffffff);
+
+	filtered = serialice_msr_filter(FILTER_WRITE, addr, &hi, &lo);
+
+	if (!filtered) {
+		sprintf(s->command, "*wc%08x.%08x=%08x.%08x", addr, key, hi, lo);
+		serialice_command(s->command, 0);
+	}
+
+	serialice_msr_log(LOG_WRITE, addr, hi, lo, filtered);
+}
+
+cpuid_regs_t serialice_cpuid(uint32_t eax, uint32_t ecx)
+{
+	cpuid_regs_t ret;
+	int filtered;
+
+	ret.eax = eax;
+	ret.ebx = 0; // either set by filter or by target
+	ret.ecx = ecx;
+	ret.edx = 0; // either set by filter or by target
+
+	filtered = serialice_cpuid_filter(&ret);
+	if (!filtered) {
+		sprintf(s->command, "*ci%08x.%08x", eax, ecx);
+
+		// command read back: "\n000006f2.00000000.00001234.12340324"
+		// (36 characters)
+		serialice_command(s->command, 36);
+
+		s->buffer[9] = 0; // . -> \0
+		s->buffer[18] = 0; // . -> \0
+		s->buffer[27] = 0; // . -> \0
+		ret.eax = (uint32_t)strtoul(s->buffer +  1, (char **)NULL, 16);
+		ret.ebx = (uint32_t)strtoul(s->buffer + 10, (char **)NULL, 16);
+		ret.ecx = (uint32_t)strtoul(s->buffer + 19, (char **)NULL, 16);
+		ret.edx = (uint32_t)strtoul(s->buffer + 28, (char **)NULL, 16);
+	}
+
+	serialice_cpuid_log(eax, ecx, ret, filtered);
+
+	return ret;
+}
+
+// **************************************************************************
+// memory load handling
+
+static uint32_t serialice_load_wrapper(uint32_t addr, unsigned int size)
+{
+	switch (size) {
+	case 1: return (uint32_t)serialice_readb(addr);
+	case 2: return (uint32_t)serialice_readw(addr);
+	case 4: return (uint32_t)serialice_readl(addr);
+	default: printf("WARNING: unknown read access size %d @%08x\n", size, addr);
+	}
+	return 0;
+}
+
+/**
+ * This function is called by the softmmu engine to update the status
+ * of a load cycle
+ */
+void serialice_log_load(int caught, uint32_t addr, uint32_t result, unsigned int data_size)
+{
+	if (caught)
+		serialice_log(LOG_READ|LOG_MEMORY|LOG_TARGET, result, addr, data_size);
+	else
+		serialice_log(LOG_READ|LOG_MEMORY, result, addr, data_size);
+}
+
+/* This function can grab Qemu load ops and forward them to the SerialICE
+ * target. 
+ *
+ * @return 0: pass on to Qemu; 1: handled locally.
+ */
+int serialice_handle_load(uint32_t addr, uint32_t *result, unsigned int data_size)
+{
+	int source;
+
+	source = serialice_memory_read_filter(addr, result, data_size);
+
+	if (source & READ_FROM_SERIALICE) {
+		*result = serialice_load_wrapper(addr, data_size);
+		return 1;
+	}
+
+	if (source & READ_FROM_QEMU) {
+		return 0;
+	}
+
+	/* No source for load, so the source is the script */
+	return 1;
+}
+
+// **************************************************************************
+// memory store handling
+
+static void serialice_store_wrapper(uint32_t addr, unsigned int size, uint32_t data)
+{
+	switch (size) {
+	case 1: serialice_writeb((uint8_t)data, addr); break;
+	case 2: serialice_writew((uint16_t)data, addr); break;
+	case 4: serialice_writel((uint32_t)data, addr); break;
+	default: printf("WARNING: unknown write access size %d @%08x\n", size, addr);
+	}
+}
+
+static void serialice_log_store(int caught, uint32_t addr, uint32_t val, unsigned int data_size)
+{
+	if (caught)
+		serialice_log(LOG_WRITE|LOG_MEMORY|LOG_TARGET, val, addr, data_size);
+	else
+		serialice_log(LOG_WRITE|LOG_MEMORY, val, addr, data_size);
+}
+
+/* This function can grab Qemu store ops and forward them to the SerialICE
+ * target
+ *
+ * @return 0: Qemu exclusive or shared; 1: SerialICE exclusive.
+ */
+
+int serialice_handle_store(uint32_t addr, uint32_t val, unsigned int data_size)
+{
+	int write_to_target, write_to_qemu, ret;
+	uint32_t filtered_data = val;
+
+	ret = serialice_memory_write_filter(addr, data_size, &filtered_data);
+
+	write_to_target = ((ret & WRITE_TO_SERIALICE) != 0);
+	write_to_qemu = ((ret & WRITE_TO_QEMU) != 0);
+
+	serialice_log_store(write_to_target, addr, filtered_data, data_size);
+
+	if (write_to_target)
+		serialice_store_wrapper(addr, data_size, filtered_data);
+
+	return (write_to_qemu == 0);
+}
+
+// **************************************************************************
+// initialization and exit
+
+void serialice_init(void)
+{
+	printf("SerialICE: Open connection to target hardware...\n");
+
+	if (serialice_device == NULL) {
+		printf("You need to specify a serial device to use SerialICE.\n");
+		exit(1);
+	}
+
+	s =  qemu_mallocz(sizeof(SerialICEState));
+#ifdef WIN32
+	s->fd = CreateFile(serialice_device, GENERIC_READ | GENERIC_WRITE,
+		0, NULL, OPEN_EXISTING, 0, NULL);
+
+	if (s->fd == INVALID_HANDLE_VALUE) {
+		perror("SerialICE: Could not connect to target TTY");
+		exit(1);
+	}
+
+	DCB dcb;
+	if (!GetCommState(s->fd, &dcb)) {
+		perror("SerialICE: Could not load config for target TTY");
+		exit(1);
+	}
+
+	dcb.BaudRate = CBR_115200;
+	dcb.ByteSize = 8;
+	dcb.Parity = NOPARITY;
+	dcb.StopBits = ONESTOPBIT;
+
+	if (!SetCommState(s->fd, &dcb)) {
+		perror("SerialICE: Could not store config for target TTY");
+		exit(1);
+	}
+
+#else
+	s->fd = open(serialice_device, O_RDWR | O_NOCTTY | O_NONBLOCK);
+
+	if (s->fd == -1) {
+		perror("SerialICE: Could not connect to target TTY");
+		exit(1);
+	}
+
+	if (ioctl(s->fd, TIOCEXCL) == -1) {
+		perror("SerialICE: TTY not exclusively available");
+		exit(1);
+	}
+
+	if (fcntl(s->fd, F_SETFL, 0) == -1) {
+		perror("SerialICE: Could not switch to blocking I/O");
+		exit(1);
+	}
+
+	if (tcgetattr(s->fd, &options) == -1) {
+		perror("SerialICE: Could not get TTY attributes");
+		exit(1);
+	}
+
+	cfsetispeed(&options, B115200);
+	cfsetospeed(&options, B115200);
+
+	/* set raw input, 1 second timeout */
+	options.c_cflag     |= (CLOCAL | CREAD);
+	options.c_lflag     &= ~(ICANON | ECHO | ECHOE | ISIG);
+	options.c_oflag     &= ~OPOST;
+	options.c_iflag     |= IGNCR;
+	options.c_cc[VMIN]  = 0;
+	options.c_cc[VTIME] = 100;
+
+	tcsetattr(s->fd, TCSANOW, &options);
+
+	tcflush(s->fd, TCIOFLUSH);
+#endif
+
+	s->buffer = qemu_mallocz(BUFFER_SIZE);
+	s->command = qemu_mallocz(BUFFER_SIZE);
+
+	printf("SerialICE: Waiting for handshake with target... ");
+
+	/* Trigger a prompt */
+	serialice_write(s, "\n", 1);
+
+	/* ... and wait for it to appear */
+	if (serialice_wait_prompt() == 0) {
+		printf("target alife!\n");
+	} else {
+		printf("target not ok!\n" );
+		exit(1);
+	}
+
+	/* Each serialice_command() waits for a prompt, so trigger one for the
+	 * first command, as we consumed the last one for the handshake
+	 */
+	serialice_write(s, "\n", 1);
+
+	printf("SerialICE: LUA init...\n");
+	serialice_lua_init();
+
+	/* Let the rest of Qemu know we're alife */
+	serialice_active = 1;
+}
+
+void serialice_exit(void)
+{
+	serialice_lua_exit();
+	qemu_free(s->command);
+	qemu_free(s->buffer);
+	qemu_free(s);
+}
+
+device_init(serialice_init)
+// no exit function
+
--- qemu-0.11.0/serialice.h
+++ qemu-0.11.0/serialice.h
@@ -0,0 +1,66 @@ 
+/*
+ * QEMU PC System Emulator
+ *
+ * Copyright (c) 2009 coresystems GmbH
+ *
+ * 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.
+ */
+
+#ifndef SERIALICE_H
+#define SERIALICE_H
+
+#include "config-host.h"
+
+extern const char *serialice_device;
+extern int serialice_active;
+
+void serialice_init(void);
+void serialice_exit(void);
+
+uint8_t serialice_inb(uint16_t port);
+uint16_t serialice_inw(uint16_t port);
+uint32_t serialice_inl(uint16_t port);
+
+void serialice_outb(uint8_t data, uint16_t port);
+void serialice_outw(uint16_t data, uint16_t port);
+void serialice_outl(uint32_t data, uint16_t port);
+
+uint8_t serialice_readb(uint32_t addr);
+uint16_t serialice_readw(uint32_t addr);
+uint32_t serialice_readl(uint32_t addr);
+
+void serialice_writeb(uint8_t data, uint32_t addr);
+void serialice_writew(uint16_t data, uint32_t addr);
+void serialice_writel(uint32_t data, uint32_t addr);
+
+uint64_t serialice_rdmsr(uint32_t addr, uint32_t key);
+void serialice_wrmsr(uint64_t data, uint32_t addr, uint32_t key);
+
+typedef struct {
+	uint32_t eax, ebx, ecx, edx;
+} cpuid_regs_t;
+
+
+cpuid_regs_t serialice_cpuid(uint32_t eax, uint32_t ecx);
+
+int serialice_handle_load(uint32_t addr, uint32_t *result, unsigned int data_size);
+void serialice_log_load(int caught, uint32_t addr, uint32_t result, unsigned int data_size);
+int serialice_handle_store(uint32_t addr, uint32_t val, unsigned int data_size);
+
+#endif
--- qemu-0.11.0/build.sh
+++ qemu-0.11.0/build.sh
@@ -0,0 +1,5 @@ 
+#!/bin/sh
+./configure --disable-kvm --disable-sdl --enable-serialice \
+	    --target-list="x86_64-softmmu, i386-softmmu"
+
+make
--- qemu-0.11.0/Makefile.target
+++ qemu-0.11.0/Makefile.target
@@ -488,6 +488,13 @@ 
 # Generic watchdog support and some watchdog devices
 obj-y += wdt_ib700.o wdt_i6300esb.o
 
+# Generic SerialICE support
+ifdef CONFIG_SERIALICE
+CPPFLAGS += $(CONFIG_SERIALICE_CFLAGS)
+LIBS += $(CONFIG_SERIALICE_LIBS)
+endif
+obj-$(CONFIG_SERIALICE) += serialice.o
+
 # Hardware support
 obj-i386-y = ide.o pckbd.o vga.o $(sound-obj-y) dma.o
 obj-i386-y += fdc.o mc146818rtc.o serial.o i8259.o i8254.o pcspk.o pc.o
--- qemu-0.11.0/vl.c
+++ qemu-0.11.0/vl.c
@@ -221,6 +221,9 @@ 
 int win2k_install_hack = 0;
 int rtc_td_hack = 0;
 #endif
+#ifdef CONFIG_SERIALICE
+const char *serialice_device = NULL;
+#endif
 int usb_enabled = 0;
 int singlestep = 0;
 int smp_cpus = 1;
@@ -5108,6 +5111,11 @@ 
                 display_type = DT_CURSES;
                 break;
 #endif
+#ifdef CONFIG_SERIALICE
+	   case QEMU_OPTION_serialice:
+		serialice_device = optarg;
+		break;
+#endif
             case QEMU_OPTION_portrait:
                 graphic_rotate = 1;
                 break;
--- qemu-0.11.0/qemu-char.c
+++ qemu-0.11.0/qemu-char.c
@@ -821,7 +821,7 @@ 
 #endif
 
 #if defined(__linux__) || defined(__sun__) || defined(__FreeBSD__) \
-    || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
+    || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) || defined(__APPLE__)
 
 typedef struct {
     int fd;
@@ -2262,7 +2262,7 @@ 
     } else
 #endif
 #if defined(__linux__) || defined(__sun__) || defined(__FreeBSD__) \
-    || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
+    || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) || defined(__APPLE__)
     if (strstart(filename, "/dev/", NULL)) {
         chr = qemu_chr_open_tty(filename);
     } else
--- qemu-0.11.0/softmmu_template.h
+++ qemu-0.11.0/softmmu_template.h
@@ -16,6 +16,9 @@ 
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
  */
+
+#include "serialice.h"
+
 #define DATA_SIZE (1 << SHIFT)
 
 #if DATA_SIZE == 8
@@ -91,6 +94,16 @@ 
     target_phys_addr_t addend;
     void *retaddr;
 
+#ifdef CONFIG_SERIALICE
+    uint32_t result;
+    int caught = 0;
+    if (serialice_active && serialice_handle_load((uint32_t)addr, &result, (unsigned int) DATA_SIZE)) {
+	res = (DATA_TYPE)result;
+	caught=1;
+	goto leave_ld;
+    }
+#endif
+
     /* test if there is match for unaligned or IO access */
     /* XXX: could done more in memory macro in a non portable way */
     index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
@@ -134,6 +147,12 @@ 
         tlb_fill(addr, READ_ACCESS_TYPE, mmu_idx, retaddr);
         goto redo;
     }
+
+#ifdef CONFIG_SERIALICE
+leave_ld:
+    if (serialice_active)
+        serialice_log_load(caught, addr, (uint32_t)res, (unsigned int)DATA_SIZE);
+#endif
     return res;
 }
 
@@ -234,6 +253,15 @@ 
     void *retaddr;
     int index;
 
+#ifdef CONFIG_SERIALICE
+    if (serialice_active && serialice_handle_store((uint32_t)addr, (uint32_t)val, (unsigned int) DATA_SIZE)) {
+	// For now, we just always keep a backup of _all_ writes in qemu's
+	// memory. At this point we can later decide what to do, if it becomes
+	// necessary.
+	// return;
+    }
+#endif
+
     index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
  redo:
     tlb_addr = env->tlb_table[mmu_idx][index].addr_write;
--- qemu-0.11.0/Makefile
+++ qemu-0.11.0/Makefile
@@ -212,6 +212,10 @@ 
 
 bt-host.o: CFLAGS += $(CONFIG_BLUEZ_CFLAGS)
 
+serialice.o: serialice.c serialice.h
+
+serialice.o: CFLAGS += $(CONFIG_SERIALICE_CFLAGS)
+
 libqemu_common.a: $(obj-y)
 
 #######################################################################
--- qemu-0.11.0/qemu-options.hx
+++ qemu-0.11.0/qemu-options.hx
@@ -1661,3 +1661,14 @@ 
 DEF("old-param", 0, QEMU_OPTION_old_param,
     "-old-param      old param mode\n")
 #endif
+
+#ifdef CONFIG_SERIALICE
+DEF("serialice", HAS_ARG, QEMU_OPTION_serialice,
+    "-serialice dev  Enable SerialICE debugging on serial device 'dev'\n")
+STEXI
+@item -serialice @var{dev}
+Enable SerialICE debugging on serial device @var{dev}.
+ETEXI
+#endif
+
+
--- qemu-0.11.0/exec-all.h
+++ qemu-0.11.0/exec-all.h
@@ -21,6 +21,7 @@ 
 #define _EXEC_ALL_H_
 
 #include "qemu-common.h"
+#include "serialice.h"
 
 /* allow to see translation results - the slowdown should be negligible, so we leave it */
 #define DEBUG_DISAS
@@ -328,6 +329,9 @@ 
 #if defined(TARGET_SPARC) || defined(TARGET_MIPS)
         do_unassigned_access(addr, 0, 1, 0, 4);
 #else
+#if defined(CONFIG_SERIALICE)
+    if (!serialice_active)
+#endif
         cpu_abort(env1, "Trying to execute code outside RAM or ROM at 0x" TARGET_FMT_lx "\n", addr);
 #endif
     }
--- qemu-0.11.0/configure
+++ qemu-0.11.0/configure
@@ -193,6 +193,7 @@ 
 io_thread="no"
 nptl="yes"
 mixemu="no"
+serialice="no"
 bluez="yes"
 kvm="no"
 kerneldir=""
@@ -491,6 +492,8 @@ 
   ;;
   --enable-mixemu) mixemu="yes"
   ;;
+  --enable-serialice) serialice="yes"
+  ;;
   --disable-pthread) pthread="no"
   ;;
   --disable-aio) aio="no"
@@ -624,6 +627,7 @@ 
 echo "  --audio-card-list=LIST   set list of emulated audio cards [$audio_card_list]"
 echo "                           Available cards: $audio_possible_cards"
 echo "  --enable-mixemu          enable mixer emulation"
+echo "  --enable-serialice       enable SerialICE debugger support"
 echo "  --disable-xen            disable xen backend driver support"
 echo "  --disable-brlapi         disable BrlAPI"
 echo "  --disable-vnc-tls        disable TLS encryption for VNC server"
@@ -1064,6 +1068,40 @@ 
 done
 
 ##########################################
+# LUA probe
+
+if test "$serialice" = "yes" ; then
+  serialice=no
+  cat > $TMPC << EOF
+#include <stdint.h>
+#include <lua.h>
+#include <lauxlib.h>
+#include <stdlib.h>
+#include <stdio.h>
+static lua_State *L;
+int main(void) { L=luaL_newstate(); return 0; }
+EOF
+  
+  LUA_CFLAGS="-I/usr/local/include"
+  LUA_LDFLAGS="-L/usr/local/lib -llua"
+  if $cc $EXTRA_CFLAGS $EXTRA_LDFLAGS $ARCH_CFLAGS $LUA_CFLAGS $LUA_LDFLAGS -o $TMPE $TMPC -llua > /dev/null 2> /dev/null ; then
+    serialice=yes
+  else
+    LUA_CFLAGS=`pkg-config --cflags lua`
+    LUA_LDFLAGS=`pkg-config --libs lua`
+    if $cc $EXTRA_CFLAGS $EXTRA_LDFLAGS $ARCH_CFLAGS $LUA_CFLAGS $LUA_LDFLAGS -o $TMPE $TMPC -llua > /dev/null 2> /dev/null ; then
+      serialice=yes
+    else
+      echo
+      echo "Error LUA not found, can't build with SerialICE support."
+      echo
+      exit 1
+    fi
+  fi
+fi # test "$serialice"
+
+
+##########################################
 # BrlAPI probe
 
 if test -z "$brlapi" ; then
@@ -1426,6 +1464,7 @@ 
 echo "Audio drivers     $audio_drv_list"
 echo "Extra audio cards $audio_card_list"
 echo "Mixer emulation   $mixemu"
+echo "SerialICE support $serialice"
 echo "VNC TLS support   $vnc_tls"
 if test "$vnc_tls" = "yes" ; then
     echo "    TLS CFLAGS    $vnc_tls_cflags"
@@ -1620,6 +1659,12 @@ 
   echo "CONFIG_MIXEMU=y" >> $config_host_mak
   echo "#define CONFIG_MIXEMU 1" >> $config_host_h
 fi
+if test "$serialice" = "yes" ; then
+  echo "CONFIG_SERIALICE=y" >> $config_host_mak
+  echo "CONFIG_SERIALICE_CFLAGS=$LUA_CFLAGS" >> $config_host_mak
+  echo "CONFIG_SERIALICE_LIBS=$LUA_LDFLAGS" >> $config_host_mak
+  echo "#define CONFIG_SERIALICE 1" >> $config_host_h
+fi
 if test "$vnc_tls" = "yes" ; then
   echo "CONFIG_VNC_TLS=y" >> $config_host_mak
   echo "CONFIG_VNC_TLS_CFLAGS=$vnc_tls_cflags" >> $config_host_mak
--- qemu-0.11.0/target-i386/op_helper.c
+++ qemu-0.11.0/target-i386/op_helper.c
@@ -23,6 +23,7 @@ 
 
 //#define DEBUG_PCALL
 
+#include "serialice.h"
 
 #ifdef DEBUG_PCALL
 #  define LOG_PCALL(...) qemu_log_mask(CPU_LOG_PCALL, ## __VA_ARGS__)
@@ -558,31 +559,64 @@ 
 
 void helper_outb(uint32_t port, uint32_t data)
 {
+#ifdef CONFIG_SERIALICE
+    if (serialice_active) {
+	    serialice_outb(data & 0xff, port);
+	    return;
+    }
+#endif
     cpu_outb(env, port, data & 0xff);
 }
 
 target_ulong helper_inb(uint32_t port)
 {
+#ifdef CONFIG_SERIALICE
+    if (serialice_active) {
+	    return (target_ulong)serialice_inb(port);
+    }
+#endif
     return cpu_inb(env, port);
 }
 
 void helper_outw(uint32_t port, uint32_t data)
 {
+#ifdef CONFIG_SERIALICE
+    if (serialice_active) {
+	    serialice_outw(data & 0xffff, port);
+	    return;
+    }
+#endif
     cpu_outw(env, port, data & 0xffff);
 }
 
 target_ulong helper_inw(uint32_t port)
 {
+#ifdef CONFIG_SERIALICE
+    if (serialice_active) {
+	    return (target_ulong)serialice_inw(port);
+    }
+#endif
     return cpu_inw(env, port);
 }
 
 void helper_outl(uint32_t port, uint32_t data)
 {
+#ifdef CONFIG_SERIALICE
+    if (serialice_active) {
+	    serialice_outl(data & 0xffffffff, port);
+	    return;
+    }
+#endif
     cpu_outl(env, port, data);
 }
 
 target_ulong helper_inl(uint32_t port)
 {
+#ifdef CONFIG_SERIALICE
+    if (serialice_active) {
+	    return (target_ulong)serialice_inl(port);
+    }
+#endif
     return cpu_inl(env, port);
 }
 
@@ -1940,6 +1974,18 @@ 
 
     helper_svm_check_intercept_param(SVM_EXIT_CPUID, 0);
 
+#ifdef CONFIG_SERIALICE
+    if (serialice_active) {
+        cpuid_regs_t ret;
+        ret = serialice_cpuid((uint32_t)EAX, (uint32_t)ECX);
+        EAX = ret.eax;
+        EBX = ret.ebx;
+        ECX = ret.ecx;
+        EDX = ret.edx;
+        return;
+    }
+#endif
+
     cpu_x86_cpuid(env, (uint32_t)EAX, (uint32_t)ECX, &eax, &ebx, &ecx, &edx);
     EAX = eax;
     EBX = ebx;
@@ -3030,6 +3076,13 @@ 
 
     val = ((uint32_t)EAX) | ((uint64_t)((uint32_t)EDX) << 32);
 
+#ifdef CONFIG_SERIALICE
+    if (serialice_active) {
+        serialice_wrmsr(val, (uint32_t)ECX, (uint32_t)EDI);
+        return;
+    }
+#endif
+
     switch((uint32_t)ECX) {
     case MSR_IA32_SYSENTER_CS:
         env->sysenter_cs = val & 0xffff;
@@ -3160,6 +3213,15 @@ 
 
     helper_svm_check_intercept_param(SVM_EXIT_MSR, 0);
 
+#ifdef CONFIG_SERIALICE
+    if (serialice_active) {
+	val = serialice_rdmsr((uint32_t)ECX, (uint32_t)EDI);
+        EAX = (uint32_t)(val);
+        EDX = (uint32_t)(val >> 32);
+	return;
+    }
+#endif
+
     switch((uint32_t)ECX) {
     case MSR_IA32_SYSENTER_CS:
         val = env->sysenter_cs;
--- qemu-0.11.0/hw/pc.c
+++ qemu-0.11.0/hw/pc.c
@@ -23,6 +23,7 @@ 
  */
 #include "hw.h"
 #include "pc.h"
+#include "serialice.h"
 #include "fdc.h"
 #include "pci.h"
 #include "block.h"
@@ -1152,6 +1153,10 @@ 
 
     /* allocate RAM */
     ram_addr = qemu_ram_alloc(0xa0000);
+#ifdef CONFIG_SERIALICE
+    if (serialice_active)
+        ram_addr |= IO_MEM_UNASSIGNED;
+#endif
     cpu_register_physical_memory(0, 0xa0000, ram_addr);
 
     /* Allocate, even though we won't register, so we don't break the
@@ -1160,6 +1165,10 @@ 
      */
     ram_addr = qemu_ram_alloc(0x100000 - 0xa0000);
     ram_addr = qemu_ram_alloc(below_4g_mem_size - 0x100000);
+#ifdef CONFIG_SERIALICE
+    if (serialice_active)
+        ram_addr |= IO_MEM_UNASSIGNED;
+#endif
     cpu_register_physical_memory(0x100000,
                  below_4g_mem_size - 0x100000,
                  ram_addr);
@@ -1170,6 +1179,10 @@ 
         hw_error("To much RAM for 32-bit physical address");
 #else
         ram_addr = qemu_ram_alloc(above_4g_mem_size);
+#ifdef CONFIG_SERIALICE
+        if (serialice_active)
+            ram_addr |= IO_MEM_UNASSIGNED;
+#endif
         cpu_register_physical_memory(0x100000000ULL,
                                      above_4g_mem_size,
                                      ram_addr);