summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--cpu-all.h4
-rw-r--r--exec.c23
-rw-r--r--gdbstub.c17
-rw-r--r--target-i386/translate.c8
-rw-r--r--vl.c97
5 files changed, 125 insertions, 24 deletions
diff --git a/cpu-all.h b/cpu-all.h
index 43c03c96cf..00b9399e55 100644
--- a/cpu-all.h
+++ b/cpu-all.h
@@ -377,6 +377,10 @@ int cpu_breakpoint_insert(CPUState *env, uint32_t pc);
int cpu_breakpoint_remove(CPUState *env, uint32_t pc);
void cpu_single_step(CPUState *env, int enabled);
+#define CPU_LOG_ALL 1
+void cpu_set_log(int log_flags);
+void cpu_set_log_filename(const char *filename);
+
/* memory API */
typedef void CPUWriteMemoryFunc(uint32_t addr, uint32_t value);
diff --git a/exec.c b/exec.c
index 46cccb5deb..f4f6a9bc41 100644
--- a/exec.c
+++ b/exec.c
@@ -78,6 +78,11 @@ CPUWriteMemoryFunc *io_mem_write[IO_MEM_NB_ENTRIES][4];
CPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][4];
static int io_mem_nb;
+/* log support */
+char *logfilename = "/tmp/qemu.log";
+FILE *logfile;
+int loglevel;
+
static void page_init(void)
{
/* NOTE: we can always suppose that host_page_size >=
@@ -676,6 +681,24 @@ void cpu_single_step(CPUState *env, int enabled)
#endif
}
+/* enable or disable low levels log */
+void cpu_set_log(int log_flags)
+{
+ loglevel = log_flags;
+ if (loglevel && !logfile) {
+ logfile = fopen(logfilename, "w");
+ if (!logfile) {
+ perror(logfilename);
+ _exit(1);
+ }
+ setvbuf(logfile, NULL, _IOLBF, 0);
+ }
+}
+
+void cpu_set_log_filename(const char *filename)
+{
+ logfilename = strdup(filename);
+}
/* mask must never be zero */
void cpu_interrupt(CPUState *env, int mask)
diff --git a/gdbstub.c b/gdbstub.c
index d73a7efe36..15b3940ed6 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -437,7 +437,24 @@ int cpu_gdbstub(void *opaque, int (*main_loop)(void *opaque), int port)
goto breakpoint_error;
}
break;
+ case 'Q':
+ if (!strncmp(p, "Tinit", 5)) {
+ /* init traces */
+ put_packet("OK");
+ } else if (!strncmp(p, "TStart", 6)) {
+ /* start log (gdb 'tstart' command) */
+ cpu_set_log(CPU_LOG_ALL);
+ put_packet("OK");
+ } else if (!strncmp(p, "TStop", 5)) {
+ /* stop log (gdb 'tstop' command) */
+ cpu_set_log(0);
+ put_packet("OK");
+ } else {
+ goto unknown_command;
+ }
+ break;
default:
+ unknown_command:
/* put empty packet */
buf[0] = '\0';
put_packet(buf);
diff --git a/target-i386/translate.c b/target-i386/translate.c
index 4d89ccbba9..43d3bbcbb8 100644
--- a/target-i386/translate.c
+++ b/target-i386/translate.c
@@ -60,6 +60,7 @@ typedef struct DisasContext {
int cpl;
int iopl;
int tf; /* TF cpu flag */
+ int singlestep_enabled; /* "hardware" single step enabled */
int jmp_opt; /* use direct block chaining for direct jumps */
int mem_index; /* select memory access functions */
struct TranslationBlock *tb;
@@ -1712,7 +1713,9 @@ static void gen_eob(DisasContext *s)
{
if (s->cc_op != CC_OP_DYNAMIC)
gen_op_set_cc_op(s->cc_op);
- if (s->tf) {
+ if (s->singlestep_enabled) {
+ gen_op_debug();
+ } else if (s->tf) {
gen_op_raise_exception(EXCP01_SSTP);
} else {
gen_op_movl_T0_0();
@@ -4368,6 +4371,7 @@ static inline int gen_intermediate_code_internal(CPUState *env,
dc->cpl = (flags >> HF_CPL_SHIFT) & 3;
dc->iopl = (flags >> IOPL_SHIFT) & 3;
dc->tf = (flags >> TF_SHIFT) & 1;
+ dc->singlestep_enabled = env->singlestep_enabled;
dc->cc_op = CC_OP_DYNAMIC;
dc->cs_base = cs_base;
dc->tb = tb;
@@ -4425,7 +4429,7 @@ static inline int gen_intermediate_code_internal(CPUState *env,
break;
/* if single step mode, we generate only one instruction and
generate an exception */
- if (dc->tf) {
+ if (dc->tf || dc->singlestep_enabled) {
gen_op_jmp_im(pc_ptr - dc->cs_base);
gen_eob(dc);
break;
diff --git a/vl.c b/vl.c
index 2978694d63..f027bebb9e 100644
--- a/vl.c
+++ b/vl.c
@@ -50,7 +50,6 @@
#include "vl.h"
-#define DEBUG_LOGFILE "/tmp/vl.log"
#define DEFAULT_NETWORK_SCRIPT "/etc/qemu-ifup"
#define BIOS_FILENAME "bios.bin"
#define VGABIOS_FILENAME "vgabios.bin"
@@ -209,8 +208,6 @@ static const char *bios_dir = CONFIG_QEMU_SHAREDIR;
char phys_ram_file[1024];
CPUX86State *global_env;
CPUX86State *cpu_single_env;
-FILE *logfile = NULL;
-int loglevel;
IOPortReadFunc *ioport_read_table[3][MAX_IOPORTS];
IOPortWriteFunc *ioport_write_table[3][MAX_IOPORTS];
BlockDriverState *bs_table[MAX_DISKS];
@@ -832,20 +829,76 @@ int speaker_data_on;
int dummy_refresh_clock;
int pit_min_timer_count = 0;
-int64_t get_clock(void)
+
+#if defined(__powerpc__)
+
+static inline uint32_t get_tbl(void)
{
- struct timeval tv;
- gettimeofday(&tv, NULL);
- return tv.tv_sec * 1000000LL + tv.tv_usec;
+ uint32_t tbl;
+ asm volatile("mftb %0" : "=r" (tbl));
+ return tbl;
}
-int64_t cpu_get_ticks(void)
+static inline uint32_t get_tbu(void)
+{
+ uint32_t tbl;
+ asm volatile("mftbu %0" : "=r" (tbl));
+ return tbl;
+}
+
+int64_t cpu_get_real_ticks(void)
+{
+ uint32_t l, h, h1;
+ /* NOTE: we test if wrapping has occurred */
+ do {
+ h = get_tbu();
+ l = get_tbl();
+ h1 = get_tbu();
+ } while (h != h1);
+ return ((int64_t)h << 32) | l;
+}
+
+#elif defined(__i386__)
+
+int64_t cpu_get_real_ticks(void)
{
int64_t val;
asm("rdtsc" : "=A" (val));
return val;
}
+#else
+#error unsupported CPU
+#endif
+
+static int64_t cpu_ticks_offset;
+static int64_t cpu_ticks_last;
+
+int64_t cpu_get_ticks(void)
+{
+ return cpu_get_real_ticks() + cpu_ticks_offset;
+}
+
+/* enable cpu_get_ticks() */
+void cpu_enable_ticks(void)
+{
+ cpu_ticks_offset = cpu_ticks_last - cpu_get_real_ticks();
+}
+
+/* disable cpu_get_ticks() : the clock is stopped. You must not call
+ cpu_get_ticks() after that. */
+void cpu_disable_ticks(void)
+{
+ cpu_ticks_last = cpu_get_ticks();
+}
+
+int64_t get_clock(void)
+{
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ return tv.tv_sec * 1000000LL + tv.tv_usec;
+}
+
void cpu_calibrate_ticks(void)
{
int64_t usec, ticks;
@@ -3297,12 +3350,17 @@ int main_loop(void *opaque)
}
serial_ok = 1;
+ cpu_enable_ticks();
for(;;) {
ret = cpu_x86_exec(env);
- if (reset_requested)
+ if (reset_requested) {
+ ret = EXCP_INTERRUPT;
break;
- if (ret == EXCP_DEBUG)
- return EXCP_DEBUG;
+ }
+ if (ret == EXCP_DEBUG) {
+ ret = EXCP_DEBUG;
+ break;
+ }
/* if hlt instruction, we wait until the next IRQ */
if (ret == EXCP_HLT)
timeout = 10;
@@ -3359,8 +3417,10 @@ int main_loop(void *opaque)
uint8_t buf[1];
/* stop emulation if requested by gdb */
n = read(gdbstub_fd, buf, 1);
- if (n == 1)
+ if (n == 1) {
+ ret = EXCP_INTERRUPT;
break;
+ }
}
}
@@ -3377,7 +3437,8 @@ int main_loop(void *opaque)
gui_refresh_pending = 0;
}
}
- return EXCP_INTERRUPT;
+ cpu_disable_ticks();
+ return ret;
}
void help(void)
@@ -3535,7 +3596,7 @@ int main(int argc, char **argv)
}
break;
case 'd':
- loglevel = 1;
+ cpu_set_log(CPU_LOG_ALL);
break;
case 'n':
pstrcpy(network_script, sizeof(network_script), optarg);
@@ -3563,14 +3624,6 @@ int main(int argc, char **argv)
/* init debug */
setvbuf(stdout, NULL, _IOLBF, 0);
- if (loglevel) {
- logfile = fopen(DEBUG_LOGFILE, "w");
- if (!logfile) {
- perror(DEBUG_LOGFILE);
- _exit(1);
- }
- setvbuf(logfile, NULL, _IOLBF, 0);
- }
/* init network tun interface */
if (net_fd < 0)