Patchwork SerialICE - Qemu based (x86) firmware debugger

login
register
mail settings
Submitter Stefan Reinauer
Date Oct. 29, 2009, 12:08 p.m.
Message ID <4AE985B6.5080605@coresystems.de>
Download mbox | patch
Permalink /patch/37178/
State New
Headers show

Comments

Stefan Reinauer - Oct. 29, 2009, 12:08 p.m.
Dear x86 hardware and low-level software developers and enthusiasts!

It’s been a while, and we’ve been working on a new version of SerialICE.
After some intermediate steps that were shared among developers,
coresystems GmbH is glad to finally release SerialICE 1.4, 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.

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.

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).

Among the new features:
 - Completely scriptable filtering and logging with LUA and bitlib.
 - Kconfig/Kbuild support (make menuconfig)
 - New mainboards supported: Intel D945GCLF, ASUS M2V-MX SE, MSI MS6178,
Thomson IP1000, Dell PowerEdge s1850, RCA RM4100
 - Patch against latest Qemu version 0.11.0.
 - Support for compiling with XMMSTACK and ROMCC.
 - Many bugs fixed: serial communication, data corruption by
signed/unsigned casts, ...

Known issues:
- microcode updates from within emulated ROM code will fail.
- some rarely used calls of cpuid and rdmsr/wrmsr might not give the
correct information

Special thanks go to Daniel Liu, Rudolf Marek, Ron Minnich, Joe Smith,
Uwe Hermann 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

Patch

--- qemu-0.11.0/serialice.c
+++ qemu-0.11.0/serialice.c
@@ -0,0 +1,830 @@ 
+/*
+ * 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>
+#include <fcntl.h>
+#include <termios.h>
+#include <sys/ioctl.h>
+
+/* 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 {
+	int fd;
+	char *buffer;
+} SerialICEState;
+
+static SerialICEState *s;
+
+int serialice_active = 0;
+const char *serialice_lua_script="serialice.lua";
+
+static struct termios options;
+
+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, 1, 0);
+    if (result) {
+        fprintf(stderr, "Failed to run function SerialICE_io_write_filter: %s\n", lua_tostring(L, -1));
+        exit(1);
+    }
+    ret = lua_toboolean(L, -1);
+    lua_pop(L, 1);
+
+    return ret;
+} 
+
+static int serialice_memory_read_filter(uint32_t addr, int size)
+{
+    int ret, 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, 1, 0);
+    if (result) {
+        fprintf(stderr, "Failed to run function SerialICE_memory_read_filter: %s\n", lua_tostring(L, -1));
+        exit(1);
+    }
+    ret = lua_toboolean(L, -1);
+    lua_pop(L, 1);
+
+    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)
+{
+    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
+    result = lua_pcall(L, 2, 2, 0);
+    if (result) {
+        fprintf(stderr, "Failed to run function SerialICE_memory_write_filter: %s\n", lua_tostring(L, -1));
+        exit(1);
+    }
+    write_to_qemu = lua_toboolean(L, -1);
+    write_to_serialice = lua_toboolean(L, -2);
+    lua_pop(L, 2);
+
+    // ugly
+    if (write_to_qemu) ret |= WRITE_TO_QEMU;
+    if (write_to_serialice) ret |= WRITE_TO_SERIALICE;
+
+    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
+    result = lua_pcall(L, 3, 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);
+    }
+
+    // TODO
+#if 0
+	if (caught) {
+		printf(" *");
+	}
+
+	printf("\n");
+#endif
+} 
+
+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(int fd, void *buf, size_t nbyte)
+{
+	int bytes_read = 0;
+
+	while (1) {
+		int ret = read(fd, buf, nbyte);
+
+		if (ret == -1 && errno == EINTR)
+			continue;
+
+		if (ret == -1)
+			break;
+
+		bytes_read += ret;
+		buf += ret;
+
+		if (bytes_read >= (int)nbyte)
+			break;
+	}
+
+	return bytes_read;
+}
+
+static int serialice_write(int fd, const void *buf, size_t nbyte)
+{
+	char *buffer = (char *) buf;
+	char c;
+	int i;
+
+	for (i = 0; i < (int)nbyte; i++) {
+		while (write(fd, buffer + i, 1) != 1) ;
+		while (read(fd, &c, 1) != 1) ;
+		if (c != buffer[i]) {
+			printf("Readback error! %x/%x\n", c, buffer[i]);
+		}
+	}
+
+	return nbyte;
+}
+
+static void serialice_command(const char *command, int reply_len)
+{
+#if SERIALICE_DEBUG > 5
+	int i;
+#endif
+	int l;
+
+	serialice_write(s->fd, command, strlen(command));
+	
+	memset(s->buffer, 0, reply_len + 1); // clear enough of the buffer
+
+	l = serialice_read(s->fd, s->buffer, reply_len);
+
+	if (l == -1) {
+		perror("SerialICE: Could not read from target");
+		exit(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;
+	char command[16];
+
+	uint32_t data;
+	if (serialice_io_read_filter(&data, port, 1))
+		return data & 0xff;
+
+	sprintf(command, "*ri%04x.b", port);
+	// command read back: "\n00\n> " (6 characters)
+	serialice_command(command, 6);
+	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;
+	char command[16];
+
+	uint32_t data;
+	if (serialice_io_read_filter(&data, port, 1))
+		return data & 0xffff;
+
+	sprintf(command, "*ri%04x.w", port);
+	// command read back: "\n0000\n> " (8 characters)
+	serialice_command(command, 8);
+	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;
+	char command[16];
+
+	uint32_t data;
+	if (serialice_io_read_filter(&data, port, 1))
+		return data;
+
+	sprintf(command, "*ri%04x.l", port);
+	// command read back: "\n00000000\n> " (12 characters)
+	serialice_command(command, 12);
+	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)
+{
+	char command[19];
+
+	serialice_log(LOG_WRITE|LOG_IO, data, port, 1);
+
+	if (serialice_io_write_filter(data, port, 1)) {
+		return;
+	}
+
+	sprintf(command, "*wi%04x.b=%02x", port, data);
+	// command read back: "\n> " (3 characters)
+	serialice_command(command, 3);
+}
+
+void serialice_outw(uint16_t data, uint16_t port)
+{
+	char command[21];
+
+	serialice_log(LOG_WRITE|LOG_IO, data, port, 2);
+
+	if (serialice_io_write_filter(data, port, 2)) {
+		return;
+	}
+
+	sprintf(command, "*wi%04x.w=%04x", port, data);
+	// command read back: "\n> " (3 characters)
+	serialice_command(command, 3);
+}
+
+void serialice_outl(uint32_t data, uint16_t port)
+{
+	char command[25];
+
+	serialice_log(LOG_WRITE|LOG_IO, data, port, 4);
+
+	if (serialice_io_write_filter(data, port, 4)) {
+		return;
+	}
+
+	sprintf(command, "*wi%04x.l=%08x", port, data);
+	// command read back: "\n> " (3 characters)
+	serialice_command(command, 3);
+}
+
+uint8_t serialice_readb(uint32_t addr)
+{
+	uint8_t ret;
+	char command[20];
+	sprintf(command, "*rm%08x.b", addr);
+	// command read back: "\n00\n> " (6 characters)
+	serialice_command(command, 6);
+	ret = (uint8_t)strtoul(s->buffer + 1, (char **)NULL, 16);
+	return ret;
+}
+
+uint16_t serialice_readw(uint32_t addr)
+{
+	uint16_t ret;
+	char command[20];
+	sprintf(command, "*rm%08x.w", addr);
+	// command read back: "\n0000\n> " (8 characters)
+	serialice_command(command, 8);
+	ret = (uint16_t)strtoul(s->buffer + 1, (char **)NULL, 16);
+	return ret;
+}
+
+uint32_t serialice_readl(uint32_t addr)
+{
+	uint32_t ret;
+	char command[20];
+	sprintf(command, "*rm%08x.l", addr);
+	// command read back: "\n00000000\n> " (12 characters)
+	serialice_command(command, 12);
+	ret = (uint32_t)strtoul(s->buffer + 1, (char **)NULL, 16);
+	return ret;
+}
+
+void serialice_writeb(uint8_t data, uint32_t addr)
+{
+	char command[24];
+	sprintf(command, "*wm%08x.b=%02x", addr, data);
+	// command read back: "\n> " (3 characters)
+	serialice_command(command, 3);
+}
+
+void serialice_writew(uint16_t data, uint32_t addr)
+{
+	char command[25];
+	sprintf(command, "*wm%08x.w=%04x", addr, data);
+	// command read back: "\n> " (3 characters)
+	serialice_command(command, 3);
+}
+
+void serialice_writel(uint32_t data, uint32_t addr)
+{
+	char command[29];
+	sprintf(command, "*wm%08x.l=%08x", addr, data);
+	// command read back: "\n> " (3 characters)
+	serialice_command(command, 3);
+}
+
+uint64_t serialice_rdmsr(uint32_t addr)
+{
+	uint32_t hi, lo;
+	uint64_t ret;
+	int filtered;
+
+	filtered = serialice_msr_filter(FILTER_READ, addr, &hi, &lo);
+	if (!filtered) {
+		char command[18];
+
+		sprintf(command, "*rc%08x", addr);
+
+		// command read back: "\n00000000.00000000\n> " (21 characters)
+		serialice_command(command, 21);
+
+		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 hi, lo;
+	int filtered;
+
+	hi = (data >> 32);
+	lo = (data & 0xffffffff);
+
+	filtered = serialice_msr_filter(FILTER_WRITE, addr, &hi, &lo);
+
+	if (!filtered) {
+		char command[30];
+		sprintf(command, "*wc%08x=%08x.%08x", addr, hi, lo);
+		// command read back: "\n> " (3 characters)
+		serialice_command(command, 3);
+	}
+
+	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) {
+		char command[27];
+
+		sprintf(command, "*ci%08x.%08x", eax, ecx);
+
+		// command read back: "\n000006f2.00000000.00001234.12340324\n> "
+		// (39 characters)
+		serialice_command(command, 39);
+
+		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: Qemu exclusive or shared; 1: SerialICE exclusive.
+ */
+int serialice_handle_load(uint32_t addr, uint32_t *result, unsigned int data_size)
+{
+	int read_from_target;
+
+	read_from_target = serialice_memory_read_filter(addr, data_size);
+	if (read_from_target) {
+		*result = serialice_load_wrapper(addr, data_size);
+		return 1;
+	}
+	return 0;
+}
+
+
+// **************************************************************************
+// 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;
+
+	ret = serialice_memory_write_filter(addr, data_size);
+
+	write_to_target = ((ret & WRITE_TO_SERIALICE) != 0);
+	write_to_qemu = ((ret & WRITE_TO_QEMU) != 0);
+
+	serialice_log_store(write_to_target, addr, val, data_size);
+
+	if (write_to_target)
+		serialice_store_wrapper(addr, data_size, val);
+
+	return (write_to_qemu == 0);
+}
+
+// **************************************************************************
+// external 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));
+
+	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);
+
+	s->buffer = qemu_mallocz(BUFFER_SIZE);
+
+	printf("SerialICE: Waiting for handshake with target... ");
+	serialice_command("\n", 3);
+
+	if (!strncmp("\n> ", s->buffer, 3)) {
+		printf("target alife!\n");
+	} else {
+		printf("target not ok! (%s)\n", s->buffer );
+		exit(1);
+	}
+
+	printf("SerialICE: LUA init...\n");
+	serialice_lua_init();
+}
+
+void serialice_exit(void)
+{
+	serialice_lua_exit();
+}
+
--- qemu-0.11.0/serialice.h
+++ qemu-0.11.0/serialice.h
@@ -0,0 +1,42 @@ 
+#ifndef HW_SERIALICE_H
+#define HW_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);
+void serialice_wrmsr(uint64_t data, uint32_t addr);
+
+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);
+        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);
+        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);
@@ -1468,6 +1481,24 @@ 
              initrd_filename, cpu_model, 0);
 }
 
+#ifdef CONFIG_SERIALICE
+static void serialice_init_pci(ram_addr_t ram_size,
+                        const char *boot_device,
+                        const char *kernel_filename,
+                        const char *kernel_cmdline,
+                        const char *initrd_filename,
+                        const char *cpu_model)
+{
+    serialice_active = 1;
+
+    pc_init1(ram_size, boot_device,
+             kernel_filename, kernel_cmdline,
+             initrd_filename, cpu_model, 1);
+
+    serialice_init();
+}
+#endif
+
 /* set CMOS shutdown status register (index 0xF) as S3_resume(0xFE)
    BIOS will read it and start S3 resume at POST Entry */
 void cmos_set_s3_resume(void)
@@ -1515,11 +1546,23 @@ 
     .max_cpus = 1,
 };
 
+#ifdef CONFIG_SERIALICE
+static QEMUMachine serialice_machine = {
+    .name = "serialice",
+    .desc = "SerialICE",
+    .init = serialice_init_pci,
+    .max_cpus = 255,
+};
+#endif
+
 static void pc_machine_init(void)
 {
     qemu_register_machine(&pc_machine);
     qemu_register_machine(&pc_machine_v0_10);
     qemu_register_machine(&isapc_machine);
+#ifdef CONFIG_SERIALICE
+    qemu_register_machine(&serialice_machine);
+#endif
 }
 
 machine_init(pc_machine_init);