Kyösti Mälkki (kyosti.malkki@gmail.com) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/1007
-gerrit
commit 0b3e54c946353ba6bac93c34ab09f43a2dc96be9 Author: Kyösti Mälkki kyosti.malkki@gmail.com Date: Sat May 5 18:04:58 2012 +0300
Copy of serialice.c for refactoring
Change-Id: I77f49c011a6c4a29c9b9fc91375fc0fe77181e9d Signed-off-by: Kyösti Mälkki kyosti.malkki@gmail.com --- qemu-0.15.x/serialice-com.c | 1329 +++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 1329 insertions(+), 0 deletions(-)
diff --git a/qemu-0.15.x/serialice-com.c b/qemu-0.15.x/serialice-com.c new file mode 100644 index 0000000..a91f9c6 --- /dev/null +++ b/qemu-0.15.x/serialice-com.c @@ -0,0 +1,1329 @@ +/* + * 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. + */ + +/* Indented with: + * gnuindent -npro -kr -i4 -nut -bap -sob -l80 -ss -ncs serialice.* + */ + +/* 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/loader.h" +#include "hw/pc.h" +#include "hw/boards.h" +#include "console.h" +#include "serialice.h" +#include "sysemu.h" + +#define SERIALICE_BANNER 1 +#if SERIALICE_BANNER +#include "serialice_banner.h" +#endif + +#define DEFAULT_RAM_SIZE 128 +#define BIOS_FILENAME "bios.bin" + +#define SERIALICE_DEBUG 3 +#define BUFFER_SIZE 1024 +typedef struct { +#ifdef WIN32 + HANDLE fd; +#else + int fd; +#endif + DisplayState *ds; + char *buffer; + char *command; +} SerialICEState; + +static SerialICEState *s; + +int serialice_active = 0; +const char *serialice_lua_script = "serialice.lua"; + +const char *serialice_mainboard = NULL; + +#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); + static uint8_t num = 1; + uint32_t addr, size; + ram_addr_t phys; + char ram_name[16]; + + 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); + + if (num > 99) { + fprintf(stderr,"To much memory ranges registered\n"); + exit(1); + } + printf("Registering physical memory at 0x%08x (0x%08x bytes)\n", addr, size); + sprintf(ram_name, "serialice_ram%u", num); + phys = qemu_ram_alloc(NULL, ram_name, size); + cpu_register_physical_memory(addr, size, phys); + num++; + return 0; +} + +static int serialice_system_reset(lua_State * luastate) +{ + printf("Rebooting the emulated host CPU\n"); + qemu_system_reset_request(); + return 0; +} + +// ************************************************************************** +// LUA register access + +// some macros from target-i386/exec.h, which we can't include directly +#define env first_cpu +#define EAX (env->regs[R_EAX]) +#define ECX (env->regs[R_ECX]) +#define EDX (env->regs[R_EDX]) +#define EBX (env->regs[R_EBX]) +#define ESP (env->regs[R_ESP]) +#define EBP (env->regs[R_EBP]) +#define ESI (env->regs[R_ESI]) +#define EDI (env->regs[R_EDI]) +#define EIP (env->eip) +#define CS (env->segs[R_CS].base) +static int register_set(lua_State * L) +{ + const char *key = luaL_checkstring(L, 2); + int val = luaL_checkint(L, 3); + int ret = 1; + + if (strcmp(key, "eax") == 0) { + EAX = val; + } else if (strcmp(key, "ecx") == 0) { + ECX = val; + } else if (strcmp(key, "edx") == 0) { + EDX = val; + } else if (strcmp(key, "ebx") == 0) { + EBX = val; + } else if (strcmp(key, "esp") == 0) { + ESP = val; + } else if (strcmp(key, "ebp") == 0) { + EBP = val; + } else if (strcmp(key, "esi") == 0) { + ESI = val; + } else if (strcmp(key, "edi") == 0) { + EDI = val; + } else if (strcmp(key, "eip") == 0) { + EIP = val; + } else if (strcmp(key, "cs") == 0) { + CS = (val << 4); + } else { + lua_pushstring(L, "No such register."); + lua_error(L); + ret = 0; + } + return ret; +} + +static int register_get(lua_State * L) +{ + const char *key = luaL_checkstring(L, 2); + int ret = 1; + if (strcmp(key, "eax") == 0) { + lua_pushinteger(L, EAX); + } else if (strcmp(key, "ecx") == 0) { + lua_pushinteger(L, ECX); + } else if (strcmp(key, "edx") == 0) { + lua_pushinteger(L, EDX); + } else if (strcmp(key, "ebx") == 0) { + lua_pushinteger(L, EBX); + } else if (strcmp(key, "esp") == 0) { + lua_pushinteger(L, ESP); + } else if (strcmp(key, "ebp") == 0) { + lua_pushinteger(L, EBP); + } else if (strcmp(key, "esi") == 0) { + lua_pushinteger(L, ESI); + } else if (strcmp(key, "edi") == 0) { + lua_pushinteger(L, EDI); + } else if (strcmp(key, "eip") == 0) { + lua_pushinteger(L, EIP); + } else if (strcmp(key, "cs") == 0) { + lua_pushinteger(L, (CS >> 4)); + } else { + lua_pushstring(L, "No such register."); + lua_error(L); + ret = 0; + } + return ret; +} + +#undef env + +static int serialice_lua_registers(void) +{ + const struct luaL_Reg registermt[] = { + {"__index", register_get}, + {"__newindex", register_set}, + {NULL, NULL} + }; + + lua_newuserdata(L, sizeof(void *)); + luaL_newmetatable(L, "registermt"); +#if LUA_VERSION_NUM <= 501 + luaL_register(L, NULL, registermt); +#elif LUA_VERSION_NUM >= 502 + luaL_setfuncs(L, registermt, 0); +#endif + lua_setmetatable(L, -2); + lua_setglobal(L, "regs"); + + 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); + lua_register(L, "SerialICE_system_reset", serialice_system_reset); + + /* Set global variable SerialICE_mainboard */ + lua_pushstring(L, serialice_mainboard); + lua_setglobal(L, "SerialICE_mainboard"); + + /* Enable Register Access */ + serialice_lua_registers(); + + /* 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; +} + +const char *serialice_lua_execute(const char *cmd) +{ + int error; + char *errstring = NULL; + error = luaL_loadbuffer(L, cmd, strlen(cmd), "line") + || lua_pcall(L, 0, 0, 0); + if (error) { + errstring = strdup(lua_tostring(L, -1)); + lua_pop(L, 1); + } + + return errstring; +} + +static int serialice_io_read_filter(uint32_t * data, uint16_t port, int size) +{ + int ret, result; + + lua_getglobal(L, "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_getglobal(L, "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_getglobal(L, "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_getglobal(L, "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_getglobal(L, "SerialICE_msr_write_filter"); + } else { + lua_getglobal(L, "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_%s_filter: %s\n", + (flags & FILTER_WRITE) ? "write" : "read", 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(uint32_t eax, uint32_t ecx, + cpuid_regs_t * regs) +{ + int ret, result; + + lua_getglobal(L, "SerialICE_cpuid_filter"); + + lua_pushinteger(L, eax); // eax before calling + lua_pushinteger(L, ecx); // ecx before calling + // and the registers after calling cpuid + lua_pushinteger(L, regs->eax); // eax + lua_pushinteger(L, regs->ebx); // ebx + lua_pushinteger(L, regs->ecx); // ecx + lua_pushinteger(L, regs->edx); // edx + result = lua_pcall(L, 6, 5, 0); + if (result) { + fprintf(stderr, + "Failed to run function SerialICE_cpuid_filter: %s\n", + lua_tostring(L, -1)); + exit(1); + } + + ret = lua_toboolean(L, -5); + if (ret) { + regs->eax = lua_tointeger(L, -4); + regs->ebx = lua_tointeger(L, -3); + regs->ecx = lua_tointeger(L, -2); + regs->edx = lua_tointeger(L, -1); + } + 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_getglobal(L, "SerialICE_memory_write_log"); + } else if (!(flags & LOG_WRITE) && (flags & LOG_MEMORY)) { + lua_getglobal(L, "SerialICE_memory_read_log"); + } else if ((flags & LOG_WRITE) && !(flags & LOG_MEMORY)) { + lua_getglobal(L, "SerialICE_io_write_log"); + } else { // if (!(flags & LOG_WRITE) && !(flags & LOG_MEMORY)) + lua_getglobal(L, "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_getglobal(L, "SerialICE_msr_write_log"); + } else { // if (!(flags & LOG_WRITE)) + lua_getglobal(L, "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_getglobal(L, "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 handshake_mode = 0; + +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] && !handshake_mode) { + 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 + +static void serialice_get_version(void) +{ + int len = 0; + printf("SerialICE: Version.....: "); + serialice_command("*vi", 0); + + memset(s->buffer, 0, BUFFER_SIZE); + serialice_read(s, s->buffer, 1); + serialice_read(s, s->buffer, 1); + while (s->buffer[len++] != '\n') { + serialice_read(s, s->buffer + len, 1); + } + s->buffer[len - 1] = '\0'; + + printf("%s\n", s->buffer); +} + +static void serialice_get_mainboard(void) +{ + int len = 31; + + printf("SerialICE: Mainboard...: "); + serialice_command("*mb", 32); + while (len && s->buffer[len] == ' ') { + s->buffer[len--] = '\0'; + } + serialice_mainboard = strdup(s->buffer + 1); + printf("%s\n", serialice_mainboard); +} + +uint8_t serialice_inb(uint16_t port) +{ + uint8_t ret; + uint32_t data; + int filtered; + + filtered = serialice_io_read_filter(&data, port, 1); + + if (filtered) { + ret = data & 0xff; + } else { + 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; + int filtered; + + filtered = serialice_io_read_filter(&data, port, 2); + + if (filtered) { + ret = data & 0xffff; + } else { + 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; + int filtered; + + filtered = serialice_io_read_filter(&data, port, 4); + + if (filtered) { + ret = data; + } else { + 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; + int filtered; + + filtered = serialice_io_write_filter(&filtered_data, port, 1); + + if (filtered) { + data = (uint8_t) filtered_data; + } else { + data = (uint8_t) filtered_data; + sprintf(s->command, "*wi%04x.b=%02x", port, data); + serialice_command(s->command, 0); + } + + serialice_log(LOG_WRITE | LOG_IO, data, port, 1); +} + +void serialice_outw(uint16_t data, uint16_t port) +{ + uint32_t filtered_data = (uint32_t) data; + int filtered; + + filtered = serialice_io_write_filter(&filtered_data, port, 2); + + if (filtered) { + data = (uint16_t) filtered_data; + } else { + data = (uint16_t) filtered_data; + sprintf(s->command, "*wi%04x.w=%04x", port, data); + serialice_command(s->command, 0); + } + + serialice_log(LOG_WRITE | LOG_IO, data, port, 2); +} + +void serialice_outl(uint32_t data, uint16_t port) +{ + uint32_t filtered_data = data; + int filtered; + + filtered = serialice_io_write_filter(&filtered_data, port, 4); + + if (filtered) { + data = filtered_data; + } else { + data = filtered_data; + sprintf(s->command, "*wi%04x.l=%08x", port, data); + serialice_command(s->command, 0); + } + + serialice_log(LOG_WRITE | LOG_IO, data, port, 4); +} + +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 + + 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); + + filtered = serialice_cpuid_filter(eax, ecx, &ret); + + 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); +} + +static int screen_invalid = 1; + +static void serialice_refresh(void *opaque) +{ + uint8_t *dest; + int bpp, linesize; + + if (!screen_invalid) { + return; + } + + dest = ds_get_data(s->ds); + bpp = (ds_get_bits_per_pixel(s->ds) + 7) >> 3; + linesize = ds_get_linesize(s->ds); + + memset(dest, 0x00, linesize * ds_get_height(s->ds)); +#if SERIALICE_BANNER + int x, y; + if (bpp == 4) { + for (y = 0; y < 240; y++) { + for (x = 0; x < 320; x++) { + int doff = (y * linesize) + (x * bpp); + int soff = (y * (320 * 3)) + (x * 3); + dest[doff + 0] = serialice_banner[soff + 2]; // blue + dest[doff + 1] = serialice_banner[soff + 1]; // green + dest[doff + 2] = serialice_banner[soff + 0]; // red + } + } + } else { + printf("Banner enabled and BPP = %d (line size = %d)\n", bpp, linesize); + } +#endif + + dpy_update(s->ds, 0, 0, ds_get_width(s->ds), ds_get_height(s->ds)); + screen_invalid = 0; +} + +static void serialice_invalidate(void *opaque) +{ + screen_invalid = 1; +} + +// ************************************************************************** +// initialization and exit + +void serialice_init(void) +{ + s = qemu_mallocz(sizeof(SerialICEState)); + + s->ds = graphic_console_init(serialice_refresh, serialice_invalidate, + NULL, NULL, s); + qemu_console_resize(s->ds, 320, 240); + + 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); + } +#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... "); + + handshake_mode = 1; // Readback errors are to be expected in this phase. + + /* Trigger a prompt */ + serialice_write(s, "@", 1); + + /* ... and wait for it to appear */ + if (serialice_wait_prompt() == 0) { + printf("target alive!\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, "@", 1); + + handshake_mode = 0; // from now on, warn about readback errors. + + serialice_get_version(); + + serialice_get_mainboard(); + + printf("SerialICE: LUA init...\n"); + serialice_lua_init(); + + /* Let the rest of Qemu know we're alive */ + serialice_active = 1; +} + +void serialice_exit(void) +{ + serialice_lua_exit(); + qemu_free(s->command); + qemu_free(s->buffer); + qemu_free(s); +} + +static void pc_init_serialice(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) +{ + char *filename; + int ret, i, linux_boot; + int isa_bios_size, bios_size; + ram_addr_t bios_offset; + CPUState *env; + + if (ram_size != (DEFAULT_RAM_SIZE * 1024 * 1024)) { + printf + ("Warning: Running SerialICE with non-default ram size is not supported.\n"); + exit(1); + } + + linux_boot = (kernel_filename != NULL); + + /* init CPUs */ + if (cpu_model == NULL) { + //printf("Warning: Running SerialICE with generic CPU type might fail.\n"); +#ifdef TARGET_X86_64 + cpu_model = "qemu64"; +#else + cpu_model = "qemu32"; +#endif + } + + for (i = 0; i < smp_cpus; i++) { + env = cpu_init(cpu_model); + qemu_register_reset((QEMUResetHandler *) cpu_reset, env); + } + + /* Must not happen before CPUs are initialized */ + serialice_init(); + + /* BIOS load */ + if (bios_name == NULL) + bios_name = BIOS_FILENAME; + filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name); + if (filename) { + bios_size = get_image_size(filename); + } else { + bios_size = -1; + } + if (bios_size <= 0 || (bios_size % 65536) != 0) { + goto bios_error; + } + bios_offset = qemu_ram_alloc(NULL, "serialice_bios", bios_size); + ret = load_image(filename, qemu_get_ram_ptr(bios_offset)); + if (ret != bios_size) { + bios_error: + fprintf(stderr, "qemu: could not load PC BIOS '%s'\n", bios_name); + exit(1); + } + if (filename) { + qemu_free(filename); + } + /* map the last 128KB of the BIOS in ISA space */ + isa_bios_size = bios_size; + if (isa_bios_size > (128 * 1024)) + isa_bios_size = 128 * 1024; + + cpu_register_physical_memory(0x100000 - isa_bios_size, + isa_bios_size, + (bios_offset + bios_size - isa_bios_size)); + + /* map all the bios at the top of memory */ + cpu_register_physical_memory((uint32_t) (-bios_size), bios_size, + bios_offset | IO_MEM_ROM); + if (linux_boot) { + printf("Booting Linux in SerialICE mode is currently not supported.\n"); + exit(1); + } + +} + +static QEMUMachine serialice_machine = { + .name = "serialice-x86", + .alias = "serialice", + .desc = "SerialICE Debugger", + .init = pc_init_serialice, + .max_cpus = 255, + //.is_default = 1, +}; + +static void serialice_machine_init(void) +{ + qemu_register_machine(&serialice_machine); +} + +machine_init(serialice_machine_init);