@@ -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
+
@@ -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
@@ -0,0 +1,5 @@
+#!/bin/sh
+./configure --disable-kvm --disable-sdl --enable-serialice \
+ --target-list="x86_64-softmmu, i386-softmmu"
+
+make
@@ -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
@@ -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;
@@ -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
@@ -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;
@@ -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)
#######################################################################
@@ -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
+
+
@@ -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
}
@@ -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
@@ -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;
@@ -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);