Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4690764bba | ||
|
|
3c1cf9fa86 | ||
|
|
1f47a9223e | ||
|
|
33e3963e1b | ||
|
|
cd4c3e888a | ||
|
|
7916e2245d | ||
|
|
abd0aaff03 | ||
|
|
c39d5b78f6 | ||
|
|
4d40895f2c | ||
|
|
e477b8b81b | ||
|
|
b118d61e55 | ||
|
|
2f62b397b5 | ||
|
|
907a5b2690 | ||
|
|
0849bf0821 | ||
|
|
305034817d | ||
|
|
ec410fc9ce | ||
|
|
68a7931591 | ||
|
|
c9159e5321 | ||
|
|
8c9b861e74 | ||
|
|
5797fa5d7e | ||
|
|
8ef9a8ece3 | ||
|
|
fc01f7e7f9 | ||
|
|
3b0dca51b0 | ||
|
|
da415d54bf | ||
|
|
b4608c0455 | ||
|
|
d5a0b50c6f | ||
|
|
87858c89ca | ||
|
|
a6f816d697 | ||
|
|
0ad041d476 |
No files matched your search
@@ -1,3 +1,19 @@
|
||||
version 0.4.2:
|
||||
|
||||
- many exception handling fixes (can compile a Linux kernel inside vl)
|
||||
- IDE emulation support
|
||||
- initial GDB stub support
|
||||
- deferred update support for disk images (Rusty Russell)
|
||||
- accept user mode Linux Copy On Write disk images
|
||||
- SMP kernels can at least be booted
|
||||
|
||||
version 0.4.1:
|
||||
|
||||
- more accurate timer support in vl.
|
||||
- more reliable NE2000 probe in vl.
|
||||
- added 2.5.66 kernel in vl-test.
|
||||
- added VLTMPDIR environment variable in vl.
|
||||
|
||||
version 0.4:
|
||||
|
||||
- initial support for ring 0 x86 processor emulation
|
||||
|
||||
@@ -28,7 +28,7 @@ else
|
||||
LDFLAGS+=-Wl,-shared
|
||||
endif
|
||||
ifeq ($(TARGET_ARCH), i386)
|
||||
PROGS+=vl
|
||||
PROGS+=vl vlmkcow
|
||||
endif
|
||||
endif
|
||||
|
||||
@@ -98,7 +98,7 @@ SRCS:= $(OBJS:.o=.c)
|
||||
OBJS+= libqemu.a
|
||||
|
||||
# cpu emulator library
|
||||
LIBOBJS=thunk.o exec.o translate.o cpu-exec.o
|
||||
LIBOBJS=thunk.o exec.o translate.o cpu-exec.o gdbstub.o
|
||||
|
||||
ifeq ($(TARGET_ARCH), i386)
|
||||
LIBOBJS+=translate-i386.o op-i386.o helper-i386.o
|
||||
@@ -140,9 +140,12 @@ ifeq ($(ARCH),alpha)
|
||||
endif
|
||||
|
||||
# must use static linking to avoid leaving stuff in virtual address space
|
||||
vl: vl.o libqemu.a
|
||||
vl: vl.o block.o libqemu.a
|
||||
$(CC) -static -Wl,-T,i386-vl.ld -o $@ $^ $(LIBS)
|
||||
|
||||
vlmkcow: vlmkcow.o
|
||||
$(CC) -o $@ $^ $(LIBS)
|
||||
|
||||
depend: $(SRCS)
|
||||
$(CC) -MM $(CFLAGS) $^ 1>.depend
|
||||
|
||||
@@ -174,7 +177,7 @@ op-$(TARGET_ARCH).o: op-$(TARGET_ARCH).c
|
||||
helper-$(TARGET_ARCH).o: helper-$(TARGET_ARCH).c
|
||||
$(CC) $(HELPER_CFLAGS) $(DEFINES) -c -o $@ $<
|
||||
|
||||
op-i386.o: op-i386.c opreg_template.h ops_template.h
|
||||
op-i386.o: op-i386.c opreg_template.h ops_template.h ops_template_mem.h
|
||||
|
||||
op-arm.o: op-arm.c op-arm-template.h
|
||||
|
||||
@@ -189,6 +192,7 @@ distclean: clean
|
||||
rm -f config.mak config.h
|
||||
|
||||
install: $(PROGS)
|
||||
mkdir -p $(prefix)/bin
|
||||
install -m 755 -s $(PROGS) $(prefix)/bin
|
||||
|
||||
# various test targets
|
||||
@@ -209,11 +213,11 @@ dyngen.c dyngen.h dyngen-exec.h ioctls.h syscall_types.h \
|
||||
Makefile elf.h elfload.c main.c signal.c qemu.h \
|
||||
syscall.c syscall_defs.h vm86.c path.c mmap.c \
|
||||
i386.ld ppc.ld alpha.ld s390.ld sparc.ld arm.ld\
|
||||
vl.c i386-vl.ld\
|
||||
vl.c i386-vl.ld vl.h block.c vlmkcow.c\
|
||||
thunk.c cpu-exec.c translate.c cpu-all.h thunk.h exec.h\
|
||||
exec.c cpu-exec.c\
|
||||
exec.c cpu-exec.c gdbstub.c\
|
||||
cpu-i386.h op-i386.c helper-i386.c syscall-i386.h translate-i386.c \
|
||||
exec-i386.h ops_template.h op_string.h opreg_template.h \
|
||||
exec-i386.h ops_template.h ops_template_mem.h op_string.h opreg_template.h \
|
||||
cpu-arm.h syscall-arm.h exec-arm.h op-arm.c translate-arm.c op-arm-template.h \
|
||||
dis-asm.h disas.c disas.h alpha-dis.c ppc-dis.c i386-dis.c sparc-dis.c \
|
||||
arm-dis.c \
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
|
||||
- finish segment ops (call far, ret far, load_seg suppressed)
|
||||
- fix arm fpu rounding (at least for float->integer conversions)
|
||||
- optimize FPU operations (evaluate x87 stack pointer statically) and
|
||||
fix cr0.TS emulation
|
||||
- fix CCOP optimisation
|
||||
- optimize FPU operations (evaluate x87 stack pointer statically)
|
||||
- fpush not before mem load restarting
|
||||
- fix all remaining thread lock issues (must put TBs in a specific invalid
|
||||
state, find a solution for tb_flush()).
|
||||
- add gcc 2.96 test configure (some gcc3 flags are needed)
|
||||
- cpu loop optimisation (optimise ret case as the cpu state does not change)
|
||||
- fix arm fpu rounding (at least for float->integer conversions)
|
||||
- add IPC syscalls
|
||||
|
||||
lower priority:
|
||||
--------------
|
||||
- sysenter/sysexit emulation
|
||||
- SMP support
|
||||
- finish segment ops (call far, ret far, load_seg suppressed)
|
||||
- use -msoft-float on ARM
|
||||
- use kernel traps for unaligned accesses on ARM ?
|
||||
- handle rare page fault cases (in particular if page fault in heplers or
|
||||
|
||||
@@ -0,0 +1,326 @@
|
||||
/*
|
||||
* QEMU System Emulator block driver
|
||||
*
|
||||
* Copyright (c) 2003 Fabrice Bellard
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <getopt.h>
|
||||
#include <inttypes.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/mman.h>
|
||||
#include <fcntl.h>
|
||||
#include <signal.h>
|
||||
#include <time.h>
|
||||
#include <sys/time.h>
|
||||
#include <malloc.h>
|
||||
#include <termios.h>
|
||||
#include <sys/poll.h>
|
||||
#include <errno.h>
|
||||
#include <sys/wait.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
#include "vl.h"
|
||||
|
||||
#define NO_THUNK_TYPE_SIZE
|
||||
#include "thunk.h"
|
||||
|
||||
struct BlockDriverState {
|
||||
int fd; /* if -1, only COW mappings */
|
||||
int64_t total_sectors;
|
||||
int read_only;
|
||||
|
||||
uint8_t *cow_bitmap; /* if non NULL, COW mappings are used first */
|
||||
uint8_t *cow_bitmap_addr; /* mmap address of cow_bitmap */
|
||||
int cow_bitmap_size;
|
||||
int cow_fd;
|
||||
int64_t cow_sectors_offset;
|
||||
char filename[1024];
|
||||
};
|
||||
|
||||
BlockDriverState *bdrv_open(const char *filename, int snapshot)
|
||||
{
|
||||
BlockDriverState *bs;
|
||||
int fd, cow_fd;
|
||||
int64_t size;
|
||||
char template[] = "/tmp/vl.XXXXXX";
|
||||
struct cow_header_v2 cow_header;
|
||||
struct stat st;
|
||||
|
||||
bs = malloc(sizeof(BlockDriverState));
|
||||
if(!bs)
|
||||
return NULL;
|
||||
bs->read_only = 0;
|
||||
bs->fd = -1;
|
||||
bs->cow_fd = -1;
|
||||
bs->cow_bitmap = NULL;
|
||||
strcpy(bs->filename, filename);
|
||||
|
||||
/* open standard HD image */
|
||||
fd = open(filename, O_RDWR | O_LARGEFILE);
|
||||
if (fd < 0) {
|
||||
/* read only image on disk */
|
||||
fd = open(filename, O_RDONLY | O_LARGEFILE);
|
||||
if (fd < 0) {
|
||||
perror(filename);
|
||||
goto fail;
|
||||
}
|
||||
if (!snapshot)
|
||||
bs->read_only = 1;
|
||||
}
|
||||
bs->fd = fd;
|
||||
|
||||
/* see if it is a cow image */
|
||||
if (read(fd, &cow_header, sizeof(cow_header)) != sizeof(cow_header)) {
|
||||
fprintf(stderr, "%s: could not read header\n", filename);
|
||||
goto fail;
|
||||
}
|
||||
if (cow_header.magic == htonl(COW_MAGIC) &&
|
||||
cow_header.version == htonl(COW_VERSION)) {
|
||||
/* cow image found */
|
||||
size = cow_header.size;
|
||||
#ifndef WORDS_BIGENDIAN
|
||||
size = bswap64(size);
|
||||
#endif
|
||||
bs->total_sectors = size / 512;
|
||||
|
||||
bs->cow_fd = fd;
|
||||
bs->fd = -1;
|
||||
if (cow_header.backing_file[0] != '\0') {
|
||||
if (stat(cow_header.backing_file, &st) != 0) {
|
||||
fprintf(stderr, "%s: could not find original disk image '%s'\n", filename, cow_header.backing_file);
|
||||
goto fail;
|
||||
}
|
||||
if (st.st_mtime != htonl(cow_header.mtime)) {
|
||||
fprintf(stderr, "%s: original raw disk image '%s' does not match saved timestamp\n", filename, cow_header.backing_file);
|
||||
goto fail;
|
||||
}
|
||||
fd = open(cow_header.backing_file, O_RDONLY | O_LARGEFILE);
|
||||
if (fd < 0)
|
||||
goto fail;
|
||||
bs->fd = fd;
|
||||
}
|
||||
/* mmap the bitmap */
|
||||
bs->cow_bitmap_size = ((bs->total_sectors + 7) >> 3) + sizeof(cow_header);
|
||||
bs->cow_bitmap_addr = mmap(get_mmap_addr(bs->cow_bitmap_size),
|
||||
bs->cow_bitmap_size,
|
||||
PROT_READ | PROT_WRITE,
|
||||
MAP_SHARED, bs->cow_fd, 0);
|
||||
if (bs->cow_bitmap_addr == MAP_FAILED)
|
||||
goto fail;
|
||||
bs->cow_bitmap = bs->cow_bitmap_addr + sizeof(cow_header);
|
||||
bs->cow_sectors_offset = (bs->cow_bitmap_size + 511) & ~511;
|
||||
snapshot = 0;
|
||||
} else {
|
||||
/* standard raw image */
|
||||
size = lseek64(fd, 0, SEEK_END);
|
||||
bs->total_sectors = size / 512;
|
||||
bs->fd = fd;
|
||||
}
|
||||
|
||||
if (snapshot) {
|
||||
/* create a temporary COW file */
|
||||
cow_fd = mkstemp(template);
|
||||
if (cow_fd < 0)
|
||||
goto fail;
|
||||
bs->cow_fd = cow_fd;
|
||||
unlink(template);
|
||||
|
||||
/* just need to allocate bitmap */
|
||||
bs->cow_bitmap_size = (bs->total_sectors + 7) >> 3;
|
||||
bs->cow_bitmap_addr = mmap(get_mmap_addr(bs->cow_bitmap_size),
|
||||
bs->cow_bitmap_size,
|
||||
PROT_READ | PROT_WRITE,
|
||||
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||
if (bs->cow_bitmap_addr == MAP_FAILED)
|
||||
goto fail;
|
||||
bs->cow_bitmap = bs->cow_bitmap_addr;
|
||||
bs->cow_sectors_offset = 0;
|
||||
}
|
||||
|
||||
return bs;
|
||||
fail:
|
||||
bdrv_close(bs);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void bdrv_close(BlockDriverState *bs)
|
||||
{
|
||||
/* we unmap the mapping so that it is written to the COW file */
|
||||
if (bs->cow_bitmap_addr)
|
||||
munmap(bs->cow_bitmap_addr, bs->cow_bitmap_size);
|
||||
if (bs->cow_fd >= 0)
|
||||
close(bs->cow_fd);
|
||||
if (bs->fd >= 0)
|
||||
close(bs->fd);
|
||||
free(bs);
|
||||
}
|
||||
|
||||
static inline void set_bit(uint8_t *bitmap, int64_t bitnum)
|
||||
{
|
||||
bitmap[bitnum / 8] |= (1 << (bitnum%8));
|
||||
}
|
||||
|
||||
static inline int is_bit_set(const uint8_t *bitmap, int64_t bitnum)
|
||||
{
|
||||
return !!(bitmap[bitnum / 8] & (1 << (bitnum%8)));
|
||||
}
|
||||
|
||||
|
||||
/* Return true if first block has been changed (ie. current version is
|
||||
* in COW file). Set the number of continuous blocks for which that
|
||||
* is true. */
|
||||
static int is_changed(uint8_t *bitmap,
|
||||
int64_t sector_num, int nb_sectors,
|
||||
int *num_same)
|
||||
{
|
||||
int changed;
|
||||
|
||||
if (!bitmap || nb_sectors == 0) {
|
||||
*num_same = nb_sectors;
|
||||
return 0;
|
||||
}
|
||||
|
||||
changed = is_bit_set(bitmap, sector_num);
|
||||
for (*num_same = 1; *num_same < nb_sectors; (*num_same)++) {
|
||||
if (is_bit_set(bitmap, sector_num + *num_same) != changed)
|
||||
break;
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
/* commit COW file into the raw image */
|
||||
int bdrv_commit(BlockDriverState *bs)
|
||||
{
|
||||
int64_t i;
|
||||
uint8_t *cow_bitmap;
|
||||
|
||||
if (!bs->cow_bitmap) {
|
||||
fprintf(stderr, "Already committed to %s\n", bs->filename);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (bs->read_only) {
|
||||
fprintf(stderr, "Can't commit to %s: read-only\n", bs->filename);
|
||||
return -1;
|
||||
}
|
||||
|
||||
cow_bitmap = bs->cow_bitmap;
|
||||
for (i = 0; i < bs->total_sectors; i++) {
|
||||
if (is_bit_set(cow_bitmap, i)) {
|
||||
unsigned char sector[512];
|
||||
if (bdrv_read(bs, i, sector, 1) != 0) {
|
||||
fprintf(stderr, "Error reading sector %lli: aborting commit\n",
|
||||
(long long)i);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Make bdrv_write write to real file for a moment. */
|
||||
bs->cow_bitmap = NULL;
|
||||
if (bdrv_write(bs, i, sector, 1) != 0) {
|
||||
fprintf(stderr, "Error writing sector %lli: aborting commit\n",
|
||||
(long long)i);
|
||||
bs->cow_bitmap = cow_bitmap;
|
||||
return -1;
|
||||
}
|
||||
bs->cow_bitmap = cow_bitmap;
|
||||
}
|
||||
}
|
||||
fprintf(stderr, "Committed snapshot to %s\n", bs->filename);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* return -1 if error */
|
||||
int bdrv_read(BlockDriverState *bs, int64_t sector_num,
|
||||
uint8_t *buf, int nb_sectors)
|
||||
{
|
||||
int ret, n, fd;
|
||||
int64_t offset;
|
||||
|
||||
while (nb_sectors > 0) {
|
||||
if (is_changed(bs->cow_bitmap, sector_num, nb_sectors, &n)) {
|
||||
fd = bs->cow_fd;
|
||||
offset = bs->cow_sectors_offset;
|
||||
} else {
|
||||
fd = bs->fd;
|
||||
offset = 0;
|
||||
}
|
||||
|
||||
if (fd < 0) {
|
||||
/* no file, just return empty sectors */
|
||||
memset(buf, 0, n * 512);
|
||||
} else {
|
||||
offset += sector_num * 512;
|
||||
lseek64(fd, offset, SEEK_SET);
|
||||
ret = read(fd, buf, n * 512);
|
||||
if (ret != n * 512) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
nb_sectors -= n;
|
||||
sector_num += n;
|
||||
buf += n * 512;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* return -1 if error */
|
||||
int bdrv_write(BlockDriverState *bs, int64_t sector_num,
|
||||
const uint8_t *buf, int nb_sectors)
|
||||
{
|
||||
int ret, fd, i;
|
||||
int64_t offset, retl;
|
||||
|
||||
if (bs->read_only)
|
||||
return -1;
|
||||
|
||||
if (bs->cow_bitmap) {
|
||||
fd = bs->cow_fd;
|
||||
offset = bs->cow_sectors_offset;
|
||||
} else {
|
||||
fd = bs->fd;
|
||||
offset = 0;
|
||||
}
|
||||
|
||||
offset += sector_num * 512;
|
||||
retl = lseek64(fd, offset, SEEK_SET);
|
||||
if (retl == -1) {
|
||||
return -1;
|
||||
}
|
||||
ret = write(fd, buf, nb_sectors * 512);
|
||||
if (ret != nb_sectors * 512) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (bs->cow_bitmap) {
|
||||
for (i = 0; i < nb_sectors; i++)
|
||||
set_bit(bs->cow_bitmap, sector_num + i);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void bdrv_get_geometry(BlockDriverState *bs, int64_t *nb_sectors_ptr)
|
||||
{
|
||||
*nb_sectors_ptr = bs->total_sectors;
|
||||
}
|
||||
@@ -304,7 +304,18 @@ void page_unprotect_range(uint8_t *data, unsigned long data_size);
|
||||
|
||||
#endif /* SINGLE_CPU_DEFINES */
|
||||
|
||||
#define DEFAULT_GDBSTUB_PORT 1234
|
||||
|
||||
void cpu_abort(CPUState *env, const char *fmt, ...);
|
||||
extern CPUState *cpu_single_env;
|
||||
|
||||
#define CPU_INTERRUPT_EXIT 0x01 /* wants exit from main loop */
|
||||
#define CPU_INTERRUPT_HARD 0x02 /* hardware interrupt pending */
|
||||
void cpu_interrupt(CPUState *s, int mask);
|
||||
|
||||
/* gdb stub API */
|
||||
extern int gdbstub_fd;
|
||||
CPUState *cpu_gdbstub_get_env(void *opaque);
|
||||
int cpu_gdbstub(void *opaque, void (*main_loop)(void *opaque), int port);
|
||||
|
||||
#endif /* CPU_ALL_H */
|
||||
@@ -49,7 +49,6 @@ typedef struct CPUARMState {
|
||||
|
||||
CPUARMState *cpu_arm_init(void);
|
||||
int cpu_arm_exec(CPUARMState *s);
|
||||
void cpu_arm_interrupt(CPUARMState *s);
|
||||
void cpu_arm_close(CPUARMState *s);
|
||||
/* you can call this signal handler from your SIGBUS and SIGSEGV
|
||||
signal handlers to inform the virtual CPU of exceptions. non zero
|
||||
|
||||
+30
-20
@@ -71,7 +71,7 @@ int cpu_exec(CPUState *env1)
|
||||
#ifdef __sparc__
|
||||
int saved_i7, tmp_T0;
|
||||
#endif
|
||||
int code_gen_size, ret;
|
||||
int code_gen_size, ret, interrupt_request;
|
||||
void (*gen_func)(void);
|
||||
TranslationBlock *tb, **ptb;
|
||||
uint8_t *tc_ptr, *cs_base, *pc;
|
||||
@@ -139,7 +139,6 @@ int cpu_exec(CPUState *env1)
|
||||
#else
|
||||
#error unsupported target CPU
|
||||
#endif
|
||||
env->interrupt_request = 0;
|
||||
env->exception_index = -1;
|
||||
|
||||
/* prepare setjmp context for exception handling */
|
||||
@@ -176,28 +175,39 @@ int cpu_exec(CPUState *env1)
|
||||
}
|
||||
env->exception_index = -1;
|
||||
}
|
||||
#if defined(TARGET_I386)
|
||||
/* if hardware interrupt pending, we execute it */
|
||||
if (env->hard_interrupt_request &&
|
||||
(env->eflags & IF_MASK)) {
|
||||
int intno;
|
||||
intno = cpu_x86_get_pic_interrupt(env);
|
||||
if (loglevel) {
|
||||
fprintf(logfile, "Servicing hardware INT=0x%02x\n", intno);
|
||||
}
|
||||
do_interrupt(intno, 0, 0, 0);
|
||||
env->hard_interrupt_request = 0;
|
||||
}
|
||||
#endif
|
||||
T0 = 0; /* force lookup of first TB */
|
||||
for(;;) {
|
||||
#ifdef __sparc__
|
||||
/* g1 can be modified by some libc? functions */
|
||||
tmp_T0 = T0;
|
||||
#endif
|
||||
if (env->interrupt_request) {
|
||||
env->exception_index = EXCP_INTERRUPT;
|
||||
cpu_loop_exit();
|
||||
interrupt_request = env->interrupt_request;
|
||||
if (interrupt_request) {
|
||||
#if defined(TARGET_I386)
|
||||
/* if hardware interrupt pending, we execute it */
|
||||
if ((interrupt_request & CPU_INTERRUPT_HARD) &&
|
||||
(env->eflags & IF_MASK)) {
|
||||
int intno;
|
||||
intno = cpu_x86_get_pic_interrupt(env);
|
||||
if (loglevel) {
|
||||
fprintf(logfile, "Servicing hardware INT=0x%02x\n", intno);
|
||||
}
|
||||
do_interrupt(intno, 0, 0, 0);
|
||||
env->interrupt_request &= ~CPU_INTERRUPT_HARD;
|
||||
/* ensure that no TB jump will be modified as
|
||||
the program flow was changed */
|
||||
#ifdef __sparc__
|
||||
tmp_T0 = 0;
|
||||
#else
|
||||
T0 = 0;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
if (interrupt_request & CPU_INTERRUPT_EXIT) {
|
||||
env->interrupt_request &= ~CPU_INTERRUPT_EXIT;
|
||||
env->exception_index = EXCP_INTERRUPT;
|
||||
cpu_loop_exit();
|
||||
}
|
||||
}
|
||||
#ifdef DEBUG_EXEC
|
||||
if (loglevel) {
|
||||
@@ -212,7 +222,7 @@ int cpu_exec(CPUState *env1)
|
||||
env->regs[R_EBP] = EBP;
|
||||
env->regs[R_ESP] = ESP;
|
||||
env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
|
||||
cpu_x86_dump_state(env, logfile, 0);
|
||||
cpu_x86_dump_state(env, logfile, X86_DUMP_CCOP);
|
||||
env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
|
||||
#elif defined(TARGET_ARM)
|
||||
cpu_arm_dump_state(env, logfile, 0);
|
||||
@@ -454,7 +464,7 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
|
||||
{
|
||||
TranslationBlock *tb;
|
||||
int ret;
|
||||
|
||||
|
||||
if (cpu_single_env)
|
||||
env = cpu_single_env; /* XXX: find a correct solution for multithread */
|
||||
#if defined(DEBUG_SIGNAL)
|
||||
|
||||
+15
-5
@@ -125,6 +125,15 @@
|
||||
#define PG_ERROR_U_MASK 0x04
|
||||
#define PG_ERROR_RSVD_MASK 0x08
|
||||
|
||||
#define MSR_IA32_APICBASE 0x1b
|
||||
#define MSR_IA32_APICBASE_BSP (1<<8)
|
||||
#define MSR_IA32_APICBASE_ENABLE (1<<11)
|
||||
#define MSR_IA32_APICBASE_BASE (0xfffff<<12)
|
||||
|
||||
#define MSR_IA32_SYSENTER_CS 0x174
|
||||
#define MSR_IA32_SYSENTER_ESP 0x175
|
||||
#define MSR_IA32_SYSENTER_EIP 0x176
|
||||
|
||||
#define EXCP00_DIVZ 0
|
||||
#define EXCP01_SSTP 1
|
||||
#define EXCP02_NMI 2
|
||||
@@ -244,6 +253,11 @@ typedef struct CPUX86State {
|
||||
SegmentCache tr;
|
||||
SegmentCache gdt; /* only base and limit are used */
|
||||
SegmentCache idt; /* only base and limit are used */
|
||||
|
||||
/* sysenter registers */
|
||||
uint32_t sysenter_cs;
|
||||
uint32_t sysenter_esp;
|
||||
uint32_t sysenter_eip;
|
||||
|
||||
/* exception/interrupt handling */
|
||||
jmp_buf jmp_env;
|
||||
@@ -254,10 +268,7 @@ typedef struct CPUX86State {
|
||||
struct TranslationBlock *current_tb; /* currently executing TB */
|
||||
uint32_t cr[5]; /* NOTE: cr1 is unused */
|
||||
uint32_t dr[8]; /* debug registers */
|
||||
int interrupt_request; /* if true, will exit from cpu_exec() ASAP */
|
||||
/* if true, will call cpu_x86_get_pic_interrupt() ASAP to get the
|
||||
request interrupt number */
|
||||
int hard_interrupt_request;
|
||||
int interrupt_request;
|
||||
int user_mode_only; /* user mode only simulation */
|
||||
|
||||
/* user data */
|
||||
@@ -275,7 +286,6 @@ int cpu_x86_inl(CPUX86State *env, int addr);
|
||||
|
||||
CPUX86State *cpu_x86_init(void);
|
||||
int cpu_x86_exec(CPUX86State *s);
|
||||
void cpu_x86_interrupt(CPUX86State *s);
|
||||
void cpu_x86_close(CPUX86State *s);
|
||||
int cpu_x86_get_pic_interrupt(CPUX86State *s);
|
||||
|
||||
|
||||
@@ -108,6 +108,7 @@ typedef uint64_t host_ulong;
|
||||
#define SHT_RELOC SHT_REL
|
||||
#endif
|
||||
|
||||
#define NO_THUNK_TYPE_SIZE
|
||||
#include "thunk.h"
|
||||
|
||||
enum {
|
||||
@@ -1200,6 +1201,10 @@ int load_elf(const char *filename, FILE *outfile, int out_type)
|
||||
|
||||
if (out_type == OUT_INDEX_OP) {
|
||||
fprintf(outfile, "DEF(end, 0, 0)\n");
|
||||
fprintf(outfile, "DEF(nop, 0, 0)\n");
|
||||
fprintf(outfile, "DEF(nop1, 1, 0)\n");
|
||||
fprintf(outfile, "DEF(nop2, 2, 0)\n");
|
||||
fprintf(outfile, "DEF(nop3, 3, 0)\n");
|
||||
for(i = 0, sym = symtab; i < nb_syms; i++, sym++) {
|
||||
const char *name, *p;
|
||||
name = strtab + sym->st_name;
|
||||
@@ -1269,6 +1274,17 @@ fprintf(outfile,
|
||||
}
|
||||
|
||||
fprintf(outfile,
|
||||
" case INDEX_op_nop:\n"
|
||||
" break;\n"
|
||||
" case INDEX_op_nop1:\n"
|
||||
" opparam_ptr++;\n"
|
||||
" break;\n"
|
||||
" case INDEX_op_nop2:\n"
|
||||
" opparam_ptr += 2;\n"
|
||||
" break;\n"
|
||||
" case INDEX_op_nop3:\n"
|
||||
" opparam_ptr += 3;\n"
|
||||
" break;\n"
|
||||
" default:\n"
|
||||
" goto the_end;\n"
|
||||
" }\n");
|
||||
|
||||
@@ -159,6 +159,8 @@ void helper_idivl_EAX_T0(uint32_t eip);
|
||||
void helper_cmpxchg8b(void);
|
||||
void helper_cpuid(void);
|
||||
void helper_rdtsc(void);
|
||||
void helper_rdmsr(void);
|
||||
void helper_wrmsr(void);
|
||||
void helper_lsl(void);
|
||||
void helper_lar(void);
|
||||
|
||||
|
||||
@@ -617,11 +617,12 @@ static void tb_reset_jump_recursive(TranslationBlock *tb)
|
||||
tb_reset_jump_recursive2(tb, 1);
|
||||
}
|
||||
|
||||
void cpu_interrupt(CPUState *env)
|
||||
/* mask must never be zero */
|
||||
void cpu_interrupt(CPUState *env, int mask)
|
||||
{
|
||||
TranslationBlock *tb;
|
||||
|
||||
env->interrupt_request = 1;
|
||||
|
||||
env->interrupt_request |= mask;
|
||||
/* if the cpu is currently executing code, we must unlink it and
|
||||
all the potentially executing TB */
|
||||
tb = env->current_tb;
|
||||
|
||||
@@ -219,10 +219,12 @@ label ## n:\
|
||||
#define JUMP_TB(tbparam, n, eip)\
|
||||
do {\
|
||||
static void __attribute__((unused)) *__op_label ## n = &&label ## n;\
|
||||
static void __attribute__((unused)) *dummy ## n = &&dummy_label ## n;\
|
||||
goto *(void *)(((TranslationBlock *)tbparam)->tb_next[n]);\
|
||||
label ## n:\
|
||||
T0 = (long)(tbparam) + (n);\
|
||||
EIP = eip;\
|
||||
dummy_label ## n:\
|
||||
} while (0)
|
||||
|
||||
#endif
|
||||
@@ -322,6 +324,7 @@ typedef int spinlock_t;
|
||||
|
||||
#define SPIN_LOCK_UNLOCKED 0
|
||||
|
||||
#if 1
|
||||
static inline void spin_lock(spinlock_t *lock)
|
||||
{
|
||||
while (testandset(lock));
|
||||
@@ -336,6 +339,20 @@ static inline int spin_trylock(spinlock_t *lock)
|
||||
{
|
||||
return !testandset(lock);
|
||||
}
|
||||
#else
|
||||
static inline void spin_lock(spinlock_t *lock)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void spin_unlock(spinlock_t *lock)
|
||||
{
|
||||
}
|
||||
|
||||
static inline int spin_trylock(spinlock_t *lock)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
extern spinlock_t tb_lock;
|
||||
|
||||
@@ -0,0 +1,390 @@
|
||||
/*
|
||||
* gdb server stub
|
||||
*
|
||||
* Copyright (c) 2003 Fabrice Bellard
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include "config.h"
|
||||
#ifdef TARGET_I386
|
||||
#include "cpu-i386.h"
|
||||
#endif
|
||||
#ifdef TARGET_ARM
|
||||
#include "cpu-arm.h"
|
||||
#endif
|
||||
#include "thunk.h"
|
||||
#include "exec.h"
|
||||
|
||||
//#define DEBUG_GDB
|
||||
|
||||
int gdbstub_fd = -1;
|
||||
|
||||
/* return 0 if OK */
|
||||
static int gdbstub_open(int port)
|
||||
{
|
||||
struct sockaddr_in sockaddr;
|
||||
socklen_t len;
|
||||
int fd, val, ret;
|
||||
|
||||
fd = socket(PF_INET, SOCK_STREAM, 0);
|
||||
if (fd < 0) {
|
||||
perror("socket");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* allow fast reuse */
|
||||
val = 1;
|
||||
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
|
||||
|
||||
sockaddr.sin_family = AF_INET;
|
||||
sockaddr.sin_port = htons(port);
|
||||
sockaddr.sin_addr.s_addr = 0;
|
||||
ret = bind(fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr));
|
||||
if (ret < 0) {
|
||||
perror("bind");
|
||||
return -1;
|
||||
}
|
||||
ret = listen(fd, 0);
|
||||
if (ret < 0) {
|
||||
perror("listen");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* now wait for one connection */
|
||||
for(;;) {
|
||||
len = sizeof(sockaddr);
|
||||
gdbstub_fd = accept(fd, (struct sockaddr *)&sockaddr, &len);
|
||||
if (gdbstub_fd < 0 && errno != EINTR) {
|
||||
perror("accept");
|
||||
return -1;
|
||||
} else if (gdbstub_fd >= 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* set short latency */
|
||||
val = 1;
|
||||
setsockopt(gdbstub_fd, SOL_TCP, TCP_NODELAY, &val, sizeof(val));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int get_char(void)
|
||||
{
|
||||
uint8_t ch;
|
||||
int ret;
|
||||
|
||||
for(;;) {
|
||||
ret = read(gdbstub_fd, &ch, 1);
|
||||
if (ret < 0) {
|
||||
if (errno != EINTR && errno != EAGAIN)
|
||||
return -1;
|
||||
} else if (ret == 0) {
|
||||
return -1;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return ch;
|
||||
}
|
||||
|
||||
static void put_buffer(const uint8_t *buf, int len)
|
||||
{
|
||||
int ret;
|
||||
|
||||
while (len > 0) {
|
||||
ret = write(gdbstub_fd, buf, len);
|
||||
if (ret < 0) {
|
||||
if (errno != EINTR && errno != EAGAIN)
|
||||
return;
|
||||
} else {
|
||||
buf += ret;
|
||||
len -= ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline int fromhex(int v)
|
||||
{
|
||||
if (v >= '0' && v <= '9')
|
||||
return v - '0';
|
||||
else if (v >= 'A' && v <= 'F')
|
||||
return v - 'A' + 10;
|
||||
else if (v >= 'a' && v <= 'f')
|
||||
return v - 'a' + 10;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int tohex(int v)
|
||||
{
|
||||
if (v < 10)
|
||||
return v + '0';
|
||||
else
|
||||
return v - 10 + 'a';
|
||||
}
|
||||
|
||||
static void memtohex(char *buf, const uint8_t *mem, int len)
|
||||
{
|
||||
int i, c;
|
||||
char *q;
|
||||
q = buf;
|
||||
for(i = 0; i < len; i++) {
|
||||
c = mem[i];
|
||||
*q++ = tohex(c >> 4);
|
||||
*q++ = tohex(c & 0xf);
|
||||
}
|
||||
*q = '\0';
|
||||
}
|
||||
|
||||
static void hextomem(uint8_t *mem, const char *buf, int len)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i = 0; i < len; i++) {
|
||||
mem[i] = (fromhex(buf[0]) << 4) | fromhex(buf[1]);
|
||||
buf += 2;
|
||||
}
|
||||
}
|
||||
|
||||
/* return -1 if error or EOF */
|
||||
static int get_packet(char *buf, int buf_size)
|
||||
{
|
||||
int ch, len, csum, csum1;
|
||||
char reply[1];
|
||||
|
||||
for(;;) {
|
||||
for(;;) {
|
||||
ch = get_char();
|
||||
if (ch < 0)
|
||||
return -1;
|
||||
if (ch == '$')
|
||||
break;
|
||||
}
|
||||
len = 0;
|
||||
csum = 0;
|
||||
for(;;) {
|
||||
ch = get_char();
|
||||
if (ch < 0)
|
||||
return -1;
|
||||
if (ch == '#')
|
||||
break;
|
||||
if (len > buf_size - 1)
|
||||
return -1;
|
||||
buf[len++] = ch;
|
||||
csum += ch;
|
||||
}
|
||||
buf[len] = '\0';
|
||||
ch = get_char();
|
||||
if (ch < 0)
|
||||
return -1;
|
||||
csum1 = fromhex(ch) << 4;
|
||||
ch = get_char();
|
||||
if (ch < 0)
|
||||
return -1;
|
||||
csum1 |= fromhex(ch);
|
||||
if ((csum & 0xff) != csum1) {
|
||||
reply[0] = '-';
|
||||
put_buffer(reply, 1);
|
||||
} else {
|
||||
reply[0] = '+';
|
||||
put_buffer(reply, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
#ifdef DEBUG_GDB
|
||||
printf("command='%s'\n", buf);
|
||||
#endif
|
||||
return len;
|
||||
}
|
||||
|
||||
/* return -1 if error, 0 if OK */
|
||||
static int put_packet(char *buf)
|
||||
{
|
||||
char buf1[3];
|
||||
int len, csum, ch, i;
|
||||
|
||||
#ifdef DEBUG_GDB
|
||||
printf("reply='%s'\n", buf);
|
||||
#endif
|
||||
|
||||
for(;;) {
|
||||
buf1[0] = '$';
|
||||
put_buffer(buf1, 1);
|
||||
len = strlen(buf);
|
||||
put_buffer(buf, len);
|
||||
csum = 0;
|
||||
for(i = 0; i < len; i++) {
|
||||
csum += buf[i];
|
||||
}
|
||||
buf1[0] = '#';
|
||||
buf1[1] = tohex((csum >> 4) & 0xf);
|
||||
buf1[2] = tohex((csum) & 0xf);
|
||||
|
||||
put_buffer(buf1, 3);
|
||||
|
||||
ch = get_char();
|
||||
if (ch < 0)
|
||||
return -1;
|
||||
if (ch == '+')
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int memory_rw(uint8_t *buf, uint32_t addr, int len, int is_write)
|
||||
{
|
||||
int l, flags;
|
||||
uint32_t page;
|
||||
|
||||
while (len > 0) {
|
||||
page = addr & TARGET_PAGE_MASK;
|
||||
l = (page + TARGET_PAGE_SIZE) - addr;
|
||||
if (l > len)
|
||||
l = len;
|
||||
flags = page_get_flags(page);
|
||||
if (!(flags & PAGE_VALID))
|
||||
return -1;
|
||||
if (is_write) {
|
||||
if (!(flags & PAGE_WRITE))
|
||||
return -1;
|
||||
memcpy((uint8_t *)addr, buf, l);
|
||||
} else {
|
||||
if (!(flags & PAGE_READ))
|
||||
return -1;
|
||||
memcpy(buf, (uint8_t *)addr, l);
|
||||
}
|
||||
len -= l;
|
||||
buf += l;
|
||||
addr += l;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* port = 0 means default port */
|
||||
int cpu_gdbstub(void *opaque, void (*main_loop)(void *opaque), int port)
|
||||
{
|
||||
CPUState *env;
|
||||
const char *p;
|
||||
int ret, ch, nb_regs, i;
|
||||
char buf[4096];
|
||||
uint8_t mem_buf[2000];
|
||||
uint32_t *registers;
|
||||
uint32_t addr, len;
|
||||
|
||||
printf("Waiting gdb connection on port %d\n", port);
|
||||
if (gdbstub_open(port) < 0)
|
||||
return -1;
|
||||
printf("Connected\n");
|
||||
for(;;) {
|
||||
ret = get_packet(buf, sizeof(buf));
|
||||
if (ret < 0)
|
||||
break;
|
||||
p = buf;
|
||||
ch = *p++;
|
||||
switch(ch) {
|
||||
case '?':
|
||||
snprintf(buf, sizeof(buf), "S%02x", SIGTRAP);
|
||||
put_packet(buf);
|
||||
break;
|
||||
case 'c':
|
||||
main_loop(opaque);
|
||||
snprintf(buf, sizeof(buf), "S%02x", 0);
|
||||
put_packet(buf);
|
||||
break;
|
||||
case 'g':
|
||||
env = cpu_gdbstub_get_env(opaque);
|
||||
registers = (void *)mem_buf;
|
||||
#if defined(TARGET_I386)
|
||||
for(i = 0; i < 8; i++) {
|
||||
registers[i] = tswapl(env->regs[i]);
|
||||
}
|
||||
registers[8] = env->eip;
|
||||
registers[9] = env->eflags;
|
||||
registers[10] = env->segs[R_CS].selector;
|
||||
registers[11] = env->segs[R_SS].selector;
|
||||
registers[12] = env->segs[R_DS].selector;
|
||||
registers[13] = env->segs[R_ES].selector;
|
||||
registers[14] = env->segs[R_FS].selector;
|
||||
registers[15] = env->segs[R_GS].selector;
|
||||
nb_regs = 16;
|
||||
#endif
|
||||
memtohex(buf, (const uint8_t *)registers,
|
||||
sizeof(registers[0]) * nb_regs);
|
||||
put_packet(buf);
|
||||
break;
|
||||
case 'G':
|
||||
env = cpu_gdbstub_get_env(opaque);
|
||||
registers = (void *)mem_buf;
|
||||
#if defined(TARGET_I386)
|
||||
hextomem((uint8_t *)registers, p, 16 * 4);
|
||||
for(i = 0; i < 8; i++) {
|
||||
env->regs[i] = tswapl(registers[i]);
|
||||
}
|
||||
env->eip = registers[8];
|
||||
env->eflags = registers[9];
|
||||
#define LOAD_SEG(index, sreg)\
|
||||
if (tswapl(registers[index]) != env->segs[sreg].selector)\
|
||||
cpu_x86_load_seg(env, sreg, tswapl(registers[index]));
|
||||
LOAD_SEG(10, R_CS);
|
||||
LOAD_SEG(11, R_SS);
|
||||
LOAD_SEG(12, R_DS);
|
||||
LOAD_SEG(13, R_ES);
|
||||
LOAD_SEG(14, R_FS);
|
||||
LOAD_SEG(15, R_GS);
|
||||
#endif
|
||||
put_packet("OK");
|
||||
break;
|
||||
case 'm':
|
||||
addr = strtoul(p, (char **)&p, 16);
|
||||
if (*p == ',')
|
||||
p++;
|
||||
len = strtoul(p, NULL, 16);
|
||||
if (memory_rw(mem_buf, addr, len, 0) != 0)
|
||||
memset(mem_buf, 0, len);
|
||||
memtohex(buf, mem_buf, len);
|
||||
put_packet(buf);
|
||||
break;
|
||||
case 'M':
|
||||
addr = strtoul(p, (char **)&p, 16);
|
||||
if (*p == ',')
|
||||
p++;
|
||||
len = strtoul(p, (char **)&p, 16);
|
||||
if (*p == ',')
|
||||
p++;
|
||||
hextomem(mem_buf, p, len);
|
||||
if (memory_rw(mem_buf, addr, len, 1) != 0)
|
||||
put_packet("ENN");
|
||||
else
|
||||
put_packet("OK");
|
||||
break;
|
||||
default:
|
||||
/* put empty packet */
|
||||
buf[0] = '\0';
|
||||
put_packet(buf);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
+70
-61
@@ -947,6 +947,45 @@ void helper_rdtsc(void)
|
||||
EDX = val >> 32;
|
||||
}
|
||||
|
||||
void helper_wrmsr(void)
|
||||
{
|
||||
switch(ECX) {
|
||||
case MSR_IA32_SYSENTER_CS:
|
||||
env->sysenter_cs = EAX & 0xffff;
|
||||
break;
|
||||
case MSR_IA32_SYSENTER_ESP:
|
||||
env->sysenter_esp = EAX;
|
||||
break;
|
||||
case MSR_IA32_SYSENTER_EIP:
|
||||
env->sysenter_eip = EAX;
|
||||
break;
|
||||
default:
|
||||
/* XXX: exception ? */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void helper_rdmsr(void)
|
||||
{
|
||||
switch(ECX) {
|
||||
case MSR_IA32_SYSENTER_CS:
|
||||
EAX = env->sysenter_cs;
|
||||
EDX = 0;
|
||||
break;
|
||||
case MSR_IA32_SYSENTER_ESP:
|
||||
EAX = env->sysenter_esp;
|
||||
EDX = 0;
|
||||
break;
|
||||
case MSR_IA32_SYSENTER_EIP:
|
||||
EAX = env->sysenter_eip;
|
||||
EDX = 0;
|
||||
break;
|
||||
default:
|
||||
/* XXX: exception ? */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void helper_lsl(void)
|
||||
{
|
||||
unsigned int selector, limit;
|
||||
@@ -981,7 +1020,11 @@ void helper_lar(void)
|
||||
#ifndef USE_X86LDOUBLE
|
||||
void helper_fldt_ST0_A0(void)
|
||||
{
|
||||
ST0 = helper_fldt((uint8_t *)A0);
|
||||
int new_fpstt;
|
||||
new_fpstt = (env->fpstt - 1) & 7;
|
||||
env->fpregs[new_fpstt] = helper_fldt((uint8_t *)A0);
|
||||
env->fpstt = new_fpstt;
|
||||
env->fptags[new_fpstt] = 0; /* validate stack entry */
|
||||
}
|
||||
|
||||
void helper_fstt_ST0_A0(void)
|
||||
@@ -996,81 +1039,47 @@ void helper_fstt_ST0_A0(void)
|
||||
|
||||
void helper_fbld_ST0_A0(void)
|
||||
{
|
||||
uint8_t *seg;
|
||||
CPU86_LDouble fpsrcop;
|
||||
int m32i;
|
||||
CPU86_LDouble tmp;
|
||||
uint64_t val;
|
||||
unsigned int v;
|
||||
int i;
|
||||
|
||||
/* in this code, seg/m32i will be used as temporary ptr/int */
|
||||
seg = (uint8_t *)A0 + 8;
|
||||
v = ldub(seg--);
|
||||
/* XXX: raise exception */
|
||||
if (v != 0)
|
||||
return;
|
||||
v = ldub(seg--);
|
||||
/* XXX: raise exception */
|
||||
if ((v & 0xf0) != 0)
|
||||
return;
|
||||
m32i = v; /* <-- d14 */
|
||||
v = ldub(seg--);
|
||||
m32i = MUL10(m32i) + (v >> 4); /* <-- val * 10 + d13 */
|
||||
m32i = MUL10(m32i) + (v & 0xf); /* <-- val * 10 + d12 */
|
||||
v = ldub(seg--);
|
||||
m32i = MUL10(m32i) + (v >> 4); /* <-- val * 10 + d11 */
|
||||
m32i = MUL10(m32i) + (v & 0xf); /* <-- val * 10 + d10 */
|
||||
v = ldub(seg--);
|
||||
m32i = MUL10(m32i) + (v >> 4); /* <-- val * 10 + d9 */
|
||||
m32i = MUL10(m32i) + (v & 0xf); /* <-- val * 10 + d8 */
|
||||
fpsrcop = ((CPU86_LDouble)m32i) * 100000000.0;
|
||||
|
||||
v = ldub(seg--);
|
||||
m32i = (v >> 4); /* <-- d7 */
|
||||
m32i = MUL10(m32i) + (v & 0xf); /* <-- val * 10 + d6 */
|
||||
v = ldub(seg--);
|
||||
m32i = MUL10(m32i) + (v >> 4); /* <-- val * 10 + d5 */
|
||||
m32i = MUL10(m32i) + (v & 0xf); /* <-- val * 10 + d4 */
|
||||
v = ldub(seg--);
|
||||
m32i = MUL10(m32i) + (v >> 4); /* <-- val * 10 + d3 */
|
||||
m32i = MUL10(m32i) + (v & 0xf); /* <-- val * 10 + d2 */
|
||||
v = ldub(seg);
|
||||
m32i = MUL10(m32i) + (v >> 4); /* <-- val * 10 + d1 */
|
||||
m32i = MUL10(m32i) + (v & 0xf); /* <-- val * 10 + d0 */
|
||||
fpsrcop += ((CPU86_LDouble)m32i);
|
||||
if ( ldub(seg+9) & 0x80 )
|
||||
fpsrcop = -fpsrcop;
|
||||
ST0 = fpsrcop;
|
||||
val = 0;
|
||||
for(i = 8; i >= 0; i--) {
|
||||
v = ldub((uint8_t *)A0 + i);
|
||||
val = (val * 100) + ((v >> 4) * 10) + (v & 0xf);
|
||||
}
|
||||
tmp = val;
|
||||
if (ldub((uint8_t *)A0 + 9) & 0x80)
|
||||
tmp = -tmp;
|
||||
fpush();
|
||||
ST0 = tmp;
|
||||
}
|
||||
|
||||
void helper_fbst_ST0_A0(void)
|
||||
{
|
||||
CPU86_LDouble fptemp;
|
||||
CPU86_LDouble fpsrcop;
|
||||
CPU86_LDouble tmp;
|
||||
int v;
|
||||
uint8_t *mem_ref, *mem_end;
|
||||
int64_t val;
|
||||
|
||||
fpsrcop = rint(ST0);
|
||||
tmp = rint(ST0);
|
||||
val = (int64_t)tmp;
|
||||
mem_ref = (uint8_t *)A0;
|
||||
mem_end = mem_ref + 8;
|
||||
if ( fpsrcop < 0.0 ) {
|
||||
stw(mem_end, 0x8000);
|
||||
fpsrcop = -fpsrcop;
|
||||
mem_end = mem_ref + 9;
|
||||
if (val < 0) {
|
||||
stb(mem_end, 0x80);
|
||||
val = -val;
|
||||
} else {
|
||||
stw(mem_end, 0x0000);
|
||||
stb(mem_end, 0x00);
|
||||
}
|
||||
while (mem_ref < mem_end) {
|
||||
if (fpsrcop == 0.0)
|
||||
if (val == 0)
|
||||
break;
|
||||
fptemp = floor(fpsrcop/10.0);
|
||||
v = ((int)(fpsrcop - fptemp*10.0));
|
||||
if (fptemp == 0.0) {
|
||||
stb(mem_ref++, v);
|
||||
break;
|
||||
}
|
||||
fpsrcop = fptemp;
|
||||
fptemp = floor(fpsrcop/10.0);
|
||||
v |= (((int)(fpsrcop - fptemp*10.0)) << 4);
|
||||
v = val % 100;
|
||||
val = val / 100;
|
||||
v = ((v / 10) << 4) | (v % 10);
|
||||
stb(mem_ref++, v);
|
||||
fpsrcop = fptemp;
|
||||
}
|
||||
while (mem_ref < mem_end) {
|
||||
stb(mem_ref++, 0);
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@ ENTRY(_start)
|
||||
SECTIONS
|
||||
{
|
||||
/* Read-only sections, merged into text segment: */
|
||||
. = 0xa0000000 + SIZEOF_HEADERS;
|
||||
. = 0xa8000000 + SIZEOF_HEADERS;
|
||||
.interp : { *(.interp) }
|
||||
.hash : { *(.hash) }
|
||||
.dynsym : { *(.dynsym) }
|
||||
|
||||
+1
-1
@@ -333,7 +333,7 @@ static void host_signal_handler(int host_signum, siginfo_t *info,
|
||||
host_to_target_siginfo_noswap(&tinfo, info);
|
||||
if (queue_signal(sig, &tinfo) == 1) {
|
||||
/* interrupt the virtual CPU as soon as possible */
|
||||
cpu_interrupt(global_env);
|
||||
cpu_interrupt(global_env, CPU_INTERRUPT_EXIT);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -80,62 +80,34 @@ static inline int lshift(int x, int n)
|
||||
|
||||
/* operations with flags */
|
||||
|
||||
void OPPROTO op_addl_T0_T1_cc(void)
|
||||
/* update flags with T0 and T1 (add/sub case) */
|
||||
void OPPROTO op_update2_cc(void)
|
||||
{
|
||||
CC_SRC = T0;
|
||||
T0 += T1;
|
||||
CC_SRC = T1;
|
||||
CC_DST = T0;
|
||||
}
|
||||
|
||||
void OPPROTO op_orl_T0_T1_cc(void)
|
||||
/* update flags with T0 (logic operation case) */
|
||||
void OPPROTO op_update1_cc(void)
|
||||
{
|
||||
T0 |= T1;
|
||||
CC_DST = T0;
|
||||
}
|
||||
|
||||
void OPPROTO op_andl_T0_T1_cc(void)
|
||||
void OPPROTO op_update_neg_cc(void)
|
||||
{
|
||||
T0 &= T1;
|
||||
CC_DST = T0;
|
||||
}
|
||||
|
||||
void OPPROTO op_subl_T0_T1_cc(void)
|
||||
{
|
||||
CC_SRC = T0;
|
||||
T0 -= T1;
|
||||
CC_DST = T0;
|
||||
}
|
||||
|
||||
void OPPROTO op_xorl_T0_T1_cc(void)
|
||||
{
|
||||
T0 ^= T1;
|
||||
CC_SRC = -T0;
|
||||
CC_DST = T0;
|
||||
}
|
||||
|
||||
void OPPROTO op_cmpl_T0_T1_cc(void)
|
||||
{
|
||||
CC_SRC = T0;
|
||||
CC_SRC = T1;
|
||||
CC_DST = T0 - T1;
|
||||
}
|
||||
|
||||
void OPPROTO op_negl_T0_cc(void)
|
||||
{
|
||||
CC_SRC = 0;
|
||||
T0 = -T0;
|
||||
CC_DST = T0;
|
||||
}
|
||||
|
||||
void OPPROTO op_incl_T0_cc(void)
|
||||
void OPPROTO op_update_inc_cc(void)
|
||||
{
|
||||
CC_SRC = cc_table[CC_OP].compute_c();
|
||||
T0++;
|
||||
CC_DST = T0;
|
||||
}
|
||||
|
||||
void OPPROTO op_decl_T0_cc(void)
|
||||
{
|
||||
CC_SRC = cc_table[CC_OP].compute_c();
|
||||
T0--;
|
||||
CC_DST = T0;
|
||||
}
|
||||
|
||||
@@ -779,6 +751,16 @@ void OPPROTO op_cpuid(void)
|
||||
helper_cpuid();
|
||||
}
|
||||
|
||||
void OPPROTO op_rdmsr(void)
|
||||
{
|
||||
helper_rdmsr();
|
||||
}
|
||||
|
||||
void OPPROTO op_wrmsr(void)
|
||||
{
|
||||
helper_wrmsr();
|
||||
}
|
||||
|
||||
/* bcd */
|
||||
|
||||
/* XXX: exception */
|
||||
@@ -1434,28 +1416,40 @@ void OPPROTO op_fildll_FT0_A0(void)
|
||||
|
||||
void OPPROTO op_flds_ST0_A0(void)
|
||||
{
|
||||
int new_fpstt;
|
||||
new_fpstt = (env->fpstt - 1) & 7;
|
||||
#ifdef USE_FP_CONVERT
|
||||
FP_CONVERT.i32 = ldl((void *)A0);
|
||||
ST0 = FP_CONVERT.f;
|
||||
env->fpregs[new_fpstt] = FP_CONVERT.f;
|
||||
#else
|
||||
ST0 = ldfl((void *)A0);
|
||||
env->fpregs[new_fpstt] = ldfl((void *)A0);
|
||||
#endif
|
||||
env->fpstt = new_fpstt;
|
||||
env->fptags[new_fpstt] = 0; /* validate stack entry */
|
||||
}
|
||||
|
||||
void OPPROTO op_fldl_ST0_A0(void)
|
||||
{
|
||||
int new_fpstt;
|
||||
new_fpstt = (env->fpstt - 1) & 7;
|
||||
#ifdef USE_FP_CONVERT
|
||||
FP_CONVERT.i64 = ldq((void *)A0);
|
||||
ST0 = FP_CONVERT.d;
|
||||
env->fpregs[new_fpstt] = FP_CONVERT.d;
|
||||
#else
|
||||
ST0 = ldfq((void *)A0);
|
||||
env->fpregs[new_fpstt] = ldfq((void *)A0);
|
||||
#endif
|
||||
env->fpstt = new_fpstt;
|
||||
env->fptags[new_fpstt] = 0; /* validate stack entry */
|
||||
}
|
||||
|
||||
#ifdef USE_X86LDOUBLE
|
||||
void OPPROTO op_fldt_ST0_A0(void)
|
||||
{
|
||||
ST0 = *(long double *)A0;
|
||||
int new_fpstt;
|
||||
new_fpstt = (env->fpstt - 1) & 7;
|
||||
env->fpregs[new_fpstt] = *(long double *)A0;
|
||||
env->fpstt = new_fpstt;
|
||||
env->fptags[new_fpstt] = 0; /* validate stack entry */
|
||||
}
|
||||
#else
|
||||
void OPPROTO op_fldt_ST0_A0(void)
|
||||
@@ -1469,17 +1463,29 @@ void OPPROTO op_fldt_ST0_A0(void)
|
||||
|
||||
void helper_fild_ST0_A0(void)
|
||||
{
|
||||
ST0 = (CPU86_LDouble)ldsw((void *)A0);
|
||||
int new_fpstt;
|
||||
new_fpstt = (env->fpstt - 1) & 7;
|
||||
env->fpregs[new_fpstt] = (CPU86_LDouble)ldsw((void *)A0);
|
||||
env->fpstt = new_fpstt;
|
||||
env->fptags[new_fpstt] = 0; /* validate stack entry */
|
||||
}
|
||||
|
||||
void helper_fildl_ST0_A0(void)
|
||||
{
|
||||
ST0 = (CPU86_LDouble)((int32_t)ldl((void *)A0));
|
||||
int new_fpstt;
|
||||
new_fpstt = (env->fpstt - 1) & 7;
|
||||
env->fpregs[new_fpstt] = (CPU86_LDouble)((int32_t)ldl((void *)A0));
|
||||
env->fpstt = new_fpstt;
|
||||
env->fptags[new_fpstt] = 0; /* validate stack entry */
|
||||
}
|
||||
|
||||
void helper_fildll_ST0_A0(void)
|
||||
{
|
||||
ST0 = (CPU86_LDouble)((int64_t)ldq((void *)A0));
|
||||
int new_fpstt;
|
||||
new_fpstt = (env->fpstt - 1) & 7;
|
||||
env->fpregs[new_fpstt] = (CPU86_LDouble)((int64_t)ldq((void *)A0));
|
||||
env->fpstt = new_fpstt;
|
||||
env->fptags[new_fpstt] = 0; /* validate stack entry */
|
||||
}
|
||||
|
||||
void OPPROTO op_fild_ST0_A0(void)
|
||||
@@ -1501,32 +1507,44 @@ void OPPROTO op_fildll_ST0_A0(void)
|
||||
|
||||
void OPPROTO op_fild_ST0_A0(void)
|
||||
{
|
||||
int new_fpstt;
|
||||
new_fpstt = (env->fpstt - 1) & 7;
|
||||
#ifdef USE_FP_CONVERT
|
||||
FP_CONVERT.i32 = ldsw((void *)A0);
|
||||
ST0 = (CPU86_LDouble)FP_CONVERT.i32;
|
||||
env->fpregs[new_fpstt] = (CPU86_LDouble)FP_CONVERT.i32;
|
||||
#else
|
||||
ST0 = (CPU86_LDouble)ldsw((void *)A0);
|
||||
env->fpregs[new_fpstt] = (CPU86_LDouble)ldsw((void *)A0);
|
||||
#endif
|
||||
env->fpstt = new_fpstt;
|
||||
env->fptags[new_fpstt] = 0; /* validate stack entry */
|
||||
}
|
||||
|
||||
void OPPROTO op_fildl_ST0_A0(void)
|
||||
{
|
||||
int new_fpstt;
|
||||
new_fpstt = (env->fpstt - 1) & 7;
|
||||
#ifdef USE_FP_CONVERT
|
||||
FP_CONVERT.i32 = (int32_t) ldl((void *)A0);
|
||||
ST0 = (CPU86_LDouble)FP_CONVERT.i32;
|
||||
env->fpregs[new_fpstt] = (CPU86_LDouble)FP_CONVERT.i32;
|
||||
#else
|
||||
ST0 = (CPU86_LDouble)((int32_t)ldl((void *)A0));
|
||||
env->fpregs[new_fpstt] = (CPU86_LDouble)((int32_t)ldl((void *)A0));
|
||||
#endif
|
||||
env->fpstt = new_fpstt;
|
||||
env->fptags[new_fpstt] = 0; /* validate stack entry */
|
||||
}
|
||||
|
||||
void OPPROTO op_fildll_ST0_A0(void)
|
||||
{
|
||||
int new_fpstt;
|
||||
new_fpstt = (env->fpstt - 1) & 7;
|
||||
#ifdef USE_FP_CONVERT
|
||||
FP_CONVERT.i64 = (int64_t) ldq((void *)A0);
|
||||
ST0 = (CPU86_LDouble)FP_CONVERT.i64;
|
||||
env->fpregs[new_fpstt] = (CPU86_LDouble)FP_CONVERT.i64;
|
||||
#else
|
||||
ST0 = (CPU86_LDouble)((int64_t)ldq((void *)A0));
|
||||
env->fpregs[new_fpstt] = (CPU86_LDouble)((int64_t)ldq((void *)A0));
|
||||
#endif
|
||||
env->fpstt = new_fpstt;
|
||||
env->fptags[new_fpstt] = 0; /* validate stack entry */
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
+6
-7
@@ -2,7 +2,6 @@
|
||||
void OPPROTO glue(glue(op_movs, SUFFIX), STRING_SUFFIX)(void)
|
||||
{
|
||||
int v, inc;
|
||||
inc = (DF << SHIFT);
|
||||
v = glue(ldu, SUFFIX)(SI_ADDR);
|
||||
glue(st, SUFFIX)(DI_ADDR, v);
|
||||
inc = (DF << SHIFT);
|
||||
@@ -86,7 +85,7 @@ void OPPROTO glue(glue(op_scas, SUFFIX), STRING_SUFFIX)(void)
|
||||
v = glue(ldu, SUFFIX)(DI_ADDR);
|
||||
inc = (DF << SHIFT);
|
||||
INC_DI();
|
||||
CC_SRC = EAX;
|
||||
CC_SRC = v;
|
||||
CC_DST = EAX - v;
|
||||
}
|
||||
|
||||
@@ -105,7 +104,7 @@ void OPPROTO glue(glue(op_repz_scas, SUFFIX), STRING_SUFFIX)(void)
|
||||
if (v1 != v2)
|
||||
break;
|
||||
} while (CX != 0);
|
||||
CC_SRC = v1;
|
||||
CC_SRC = v2;
|
||||
CC_DST = v1 - v2;
|
||||
CC_OP = CC_OP_SUBB + SHIFT;
|
||||
}
|
||||
@@ -127,7 +126,7 @@ void OPPROTO glue(glue(op_repnz_scas, SUFFIX), STRING_SUFFIX)(void)
|
||||
if (v1 == v2)
|
||||
break;
|
||||
} while (CX != 0);
|
||||
CC_SRC = v1;
|
||||
CC_SRC = v2;
|
||||
CC_DST = v1 - v2;
|
||||
CC_OP = CC_OP_SUBB + SHIFT;
|
||||
}
|
||||
@@ -142,7 +141,7 @@ void OPPROTO glue(glue(op_cmps, SUFFIX), STRING_SUFFIX)(void)
|
||||
inc = (DF << SHIFT);
|
||||
INC_SI();
|
||||
INC_DI();
|
||||
CC_SRC = v1;
|
||||
CC_SRC = v2;
|
||||
CC_DST = v1 - v2;
|
||||
}
|
||||
|
||||
@@ -160,7 +159,7 @@ void OPPROTO glue(glue(op_repz_cmps, SUFFIX), STRING_SUFFIX)(void)
|
||||
if (v1 != v2)
|
||||
break;
|
||||
} while (CX != 0);
|
||||
CC_SRC = v1;
|
||||
CC_SRC = v2;
|
||||
CC_DST = v1 - v2;
|
||||
CC_OP = CC_OP_SUBB + SHIFT;
|
||||
}
|
||||
@@ -181,7 +180,7 @@ void OPPROTO glue(glue(op_repnz_cmps, SUFFIX), STRING_SUFFIX)(void)
|
||||
if (v1 == v2)
|
||||
break;
|
||||
} while (CX != 0);
|
||||
CC_SRC = v1;
|
||||
CC_SRC = v2;
|
||||
CC_DST = v1 - v2;
|
||||
CC_OP = CC_OP_SUBB + SHIFT;
|
||||
}
|
||||
|
||||
+38
-335
@@ -93,8 +93,8 @@ static int glue(compute_all_sub, SUFFIX)(void)
|
||||
{
|
||||
int cf, pf, af, zf, sf, of;
|
||||
int src1, src2;
|
||||
src1 = CC_SRC;
|
||||
src2 = CC_SRC - CC_DST;
|
||||
src1 = CC_DST + CC_SRC;
|
||||
src2 = CC_SRC;
|
||||
cf = (DATA_TYPE)src1 < (DATA_TYPE)src2;
|
||||
pf = parity_table[(uint8_t)CC_DST];
|
||||
af = (CC_DST ^ src1 ^ src2) & 0x10;
|
||||
@@ -107,8 +107,8 @@ static int glue(compute_all_sub, SUFFIX)(void)
|
||||
static int glue(compute_c_sub, SUFFIX)(void)
|
||||
{
|
||||
int src1, src2, cf;
|
||||
src1 = CC_SRC;
|
||||
src2 = CC_SRC - CC_DST;
|
||||
src1 = CC_DST + CC_SRC;
|
||||
src2 = CC_SRC;
|
||||
cf = (DATA_TYPE)src1 < (DATA_TYPE)src2;
|
||||
return cf;
|
||||
}
|
||||
@@ -117,8 +117,8 @@ static int glue(compute_all_sbb, SUFFIX)(void)
|
||||
{
|
||||
int cf, pf, af, zf, sf, of;
|
||||
int src1, src2;
|
||||
src1 = CC_SRC;
|
||||
src2 = CC_SRC - CC_DST - 1;
|
||||
src1 = CC_DST + CC_SRC + 1;
|
||||
src2 = CC_SRC;
|
||||
cf = (DATA_TYPE)src1 <= (DATA_TYPE)src2;
|
||||
pf = parity_table[(uint8_t)CC_DST];
|
||||
af = (CC_DST ^ src1 ^ src2) & 0x10;
|
||||
@@ -131,8 +131,8 @@ static int glue(compute_all_sbb, SUFFIX)(void)
|
||||
static int glue(compute_c_sbb, SUFFIX)(void)
|
||||
{
|
||||
int src1, src2, cf;
|
||||
src1 = CC_SRC;
|
||||
src2 = CC_SRC - CC_DST - 1;
|
||||
src1 = CC_DST + CC_SRC + 1;
|
||||
src2 = CC_SRC;
|
||||
cf = (DATA_TYPE)src1 <= (DATA_TYPE)src2;
|
||||
return cf;
|
||||
}
|
||||
@@ -234,8 +234,8 @@ static int glue(compute_all_sar, SUFFIX)(void)
|
||||
void OPPROTO glue(op_jb_sub, SUFFIX)(void)
|
||||
{
|
||||
int src1, src2;
|
||||
src1 = CC_SRC;
|
||||
src2 = CC_SRC - CC_DST;
|
||||
src1 = CC_DST + CC_SRC;
|
||||
src2 = CC_SRC;
|
||||
|
||||
if ((DATA_TYPE)src1 < (DATA_TYPE)src2)
|
||||
JUMP_TB(PARAM1, 0, PARAM2);
|
||||
@@ -256,8 +256,8 @@ void OPPROTO glue(op_jz_sub, SUFFIX)(void)
|
||||
void OPPROTO glue(op_jbe_sub, SUFFIX)(void)
|
||||
{
|
||||
int src1, src2;
|
||||
src1 = CC_SRC;
|
||||
src2 = CC_SRC - CC_DST;
|
||||
src1 = CC_DST + CC_SRC;
|
||||
src2 = CC_SRC;
|
||||
|
||||
if ((DATA_TYPE)src1 <= (DATA_TYPE)src2)
|
||||
JUMP_TB(PARAM1, 0, PARAM2);
|
||||
@@ -278,8 +278,8 @@ void OPPROTO glue(op_js_sub, SUFFIX)(void)
|
||||
void OPPROTO glue(op_jl_sub, SUFFIX)(void)
|
||||
{
|
||||
int src1, src2;
|
||||
src1 = CC_SRC;
|
||||
src2 = CC_SRC - CC_DST;
|
||||
src1 = CC_DST + CC_SRC;
|
||||
src2 = CC_SRC;
|
||||
|
||||
if ((DATA_STYPE)src1 < (DATA_STYPE)src2)
|
||||
JUMP_TB(PARAM1, 0, PARAM2);
|
||||
@@ -291,8 +291,8 @@ void OPPROTO glue(op_jl_sub, SUFFIX)(void)
|
||||
void OPPROTO glue(op_jle_sub, SUFFIX)(void)
|
||||
{
|
||||
int src1, src2;
|
||||
src1 = CC_SRC;
|
||||
src2 = CC_SRC - CC_DST;
|
||||
src1 = CC_DST + CC_SRC;
|
||||
src2 = CC_SRC;
|
||||
|
||||
if ((DATA_STYPE)src1 <= (DATA_STYPE)src2)
|
||||
JUMP_TB(PARAM1, 0, PARAM2);
|
||||
@@ -361,8 +361,8 @@ void OPPROTO glue(op_jecxz, SUFFIX)(void)
|
||||
void OPPROTO glue(op_setb_T0_sub, SUFFIX)(void)
|
||||
{
|
||||
int src1, src2;
|
||||
src1 = CC_SRC;
|
||||
src2 = CC_SRC - CC_DST;
|
||||
src1 = CC_DST + CC_SRC;
|
||||
src2 = CC_SRC;
|
||||
|
||||
T0 = ((DATA_TYPE)src1 < (DATA_TYPE)src2);
|
||||
}
|
||||
@@ -375,8 +375,8 @@ void OPPROTO glue(op_setz_T0_sub, SUFFIX)(void)
|
||||
void OPPROTO glue(op_setbe_T0_sub, SUFFIX)(void)
|
||||
{
|
||||
int src1, src2;
|
||||
src1 = CC_SRC;
|
||||
src2 = CC_SRC - CC_DST;
|
||||
src1 = CC_DST + CC_SRC;
|
||||
src2 = CC_SRC;
|
||||
|
||||
T0 = ((DATA_TYPE)src1 <= (DATA_TYPE)src2);
|
||||
}
|
||||
@@ -389,8 +389,8 @@ void OPPROTO glue(op_sets_T0_sub, SUFFIX)(void)
|
||||
void OPPROTO glue(op_setl_T0_sub, SUFFIX)(void)
|
||||
{
|
||||
int src1, src2;
|
||||
src1 = CC_SRC;
|
||||
src2 = CC_SRC - CC_DST;
|
||||
src1 = CC_DST + CC_SRC;
|
||||
src2 = CC_SRC;
|
||||
|
||||
T0 = ((DATA_STYPE)src1 < (DATA_STYPE)src2);
|
||||
}
|
||||
@@ -398,135 +398,14 @@ void OPPROTO glue(op_setl_T0_sub, SUFFIX)(void)
|
||||
void OPPROTO glue(op_setle_T0_sub, SUFFIX)(void)
|
||||
{
|
||||
int src1, src2;
|
||||
src1 = CC_SRC;
|
||||
src2 = CC_SRC - CC_DST;
|
||||
src1 = CC_DST + CC_SRC;
|
||||
src2 = CC_SRC;
|
||||
|
||||
T0 = ((DATA_STYPE)src1 <= (DATA_STYPE)src2);
|
||||
}
|
||||
|
||||
/* shifts */
|
||||
|
||||
void OPPROTO glue(glue(op_rol, SUFFIX), _T0_T1_cc)(void)
|
||||
{
|
||||
int count, src;
|
||||
count = T1 & SHIFT_MASK;
|
||||
if (count) {
|
||||
CC_SRC = cc_table[CC_OP].compute_all() & ~(CC_O | CC_C);
|
||||
src = T0;
|
||||
T0 &= DATA_MASK;
|
||||
T0 = (T0 << count) | (T0 >> (DATA_BITS - count));
|
||||
CC_SRC |= (lshift(src ^ T0, 11 - (DATA_BITS - 1)) & CC_O) |
|
||||
(T0 & CC_C);
|
||||
CC_OP = CC_OP_EFLAGS;
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_rol, SUFFIX), _T0_T1)(void)
|
||||
{
|
||||
int count;
|
||||
count = T1 & SHIFT_MASK;
|
||||
if (count) {
|
||||
T0 &= DATA_MASK;
|
||||
T0 = (T0 << count) | (T0 >> (DATA_BITS - count));
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_ror, SUFFIX), _T0_T1_cc)(void)
|
||||
{
|
||||
int count, src;
|
||||
count = T1 & SHIFT_MASK;
|
||||
if (count) {
|
||||
CC_SRC = cc_table[CC_OP].compute_all() & ~(CC_O | CC_C);
|
||||
src = T0;
|
||||
T0 &= DATA_MASK;
|
||||
T0 = (T0 >> count) | (T0 << (DATA_BITS - count));
|
||||
CC_SRC |= (lshift(src ^ T0, 11 - (DATA_BITS - 1)) & CC_O) |
|
||||
((T0 >> (DATA_BITS - 1)) & CC_C);
|
||||
CC_OP = CC_OP_EFLAGS;
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_ror, SUFFIX), _T0_T1)(void)
|
||||
{
|
||||
int count;
|
||||
count = T1 & SHIFT_MASK;
|
||||
if (count) {
|
||||
T0 &= DATA_MASK;
|
||||
T0 = (T0 >> count) | (T0 << (DATA_BITS - count));
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_rcl, SUFFIX), _T0_T1_cc)(void)
|
||||
{
|
||||
int count, res, eflags;
|
||||
unsigned int src;
|
||||
|
||||
count = T1 & 0x1f;
|
||||
#if DATA_BITS == 16
|
||||
count = rclw_table[count];
|
||||
#elif DATA_BITS == 8
|
||||
count = rclb_table[count];
|
||||
#endif
|
||||
if (count) {
|
||||
eflags = cc_table[CC_OP].compute_all();
|
||||
T0 &= DATA_MASK;
|
||||
src = T0;
|
||||
res = (T0 << count) | ((eflags & CC_C) << (count - 1));
|
||||
if (count > 1)
|
||||
res |= T0 >> (DATA_BITS + 1 - count);
|
||||
T0 = res;
|
||||
CC_SRC = (eflags & ~(CC_C | CC_O)) |
|
||||
(lshift(src ^ T0, 11 - (DATA_BITS - 1)) & CC_O) |
|
||||
((src >> (DATA_BITS - count)) & CC_C);
|
||||
CC_OP = CC_OP_EFLAGS;
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_rcr, SUFFIX), _T0_T1_cc)(void)
|
||||
{
|
||||
int count, res, eflags;
|
||||
unsigned int src;
|
||||
|
||||
count = T1 & 0x1f;
|
||||
#if DATA_BITS == 16
|
||||
count = rclw_table[count];
|
||||
#elif DATA_BITS == 8
|
||||
count = rclb_table[count];
|
||||
#endif
|
||||
if (count) {
|
||||
eflags = cc_table[CC_OP].compute_all();
|
||||
T0 &= DATA_MASK;
|
||||
src = T0;
|
||||
res = (T0 >> count) | ((eflags & CC_C) << (DATA_BITS - count));
|
||||
if (count > 1)
|
||||
res |= T0 << (DATA_BITS + 1 - count);
|
||||
T0 = res;
|
||||
CC_SRC = (eflags & ~(CC_C | CC_O)) |
|
||||
(lshift(src ^ T0, 11 - (DATA_BITS - 1)) & CC_O) |
|
||||
((src >> (count - 1)) & CC_C);
|
||||
CC_OP = CC_OP_EFLAGS;
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_shl, SUFFIX), _T0_T1_cc)(void)
|
||||
{
|
||||
int count;
|
||||
count = T1 & 0x1f;
|
||||
if (count) {
|
||||
CC_SRC = (DATA_TYPE)T0 << (count - 1);
|
||||
T0 = T0 << count;
|
||||
CC_DST = T0;
|
||||
CC_OP = CC_OP_SHLB + SHIFT;
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_shl, SUFFIX), _T0_T1)(void)
|
||||
{
|
||||
int count;
|
||||
@@ -535,20 +414,6 @@ void OPPROTO glue(glue(op_shl, SUFFIX), _T0_T1)(void)
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_shr, SUFFIX), _T0_T1_cc)(void)
|
||||
{
|
||||
int count;
|
||||
count = T1 & 0x1f;
|
||||
if (count) {
|
||||
T0 &= DATA_MASK;
|
||||
CC_SRC = T0 >> (count - 1);
|
||||
T0 = T0 >> count;
|
||||
CC_DST = T0;
|
||||
CC_OP = CC_OP_SARB + SHIFT;
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_shr, SUFFIX), _T0_T1)(void)
|
||||
{
|
||||
int count;
|
||||
@@ -558,20 +423,6 @@ void OPPROTO glue(glue(op_shr, SUFFIX), _T0_T1)(void)
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_sar, SUFFIX), _T0_T1_cc)(void)
|
||||
{
|
||||
int count, src;
|
||||
count = T1 & 0x1f;
|
||||
if (count) {
|
||||
src = (DATA_STYPE)T0;
|
||||
CC_SRC = src >> (count - 1);
|
||||
T0 = src >> count;
|
||||
CC_DST = T0;
|
||||
CC_OP = CC_OP_SARB + SHIFT;
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_sar, SUFFIX), _T0_T1)(void)
|
||||
{
|
||||
int count, src;
|
||||
@@ -581,166 +432,11 @@ void OPPROTO glue(glue(op_sar, SUFFIX), _T0_T1)(void)
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
#if DATA_BITS == 16
|
||||
/* XXX: overflow flag might be incorrect in some cases in shldw */
|
||||
void OPPROTO glue(glue(op_shld, SUFFIX), _T0_T1_im_cc)(void)
|
||||
{
|
||||
int count;
|
||||
unsigned int res;
|
||||
count = PARAM1;
|
||||
T1 &= 0xffff;
|
||||
res = T1 | (T0 << 16);
|
||||
CC_SRC = res >> (32 - count);
|
||||
res <<= count;
|
||||
if (count > 16)
|
||||
res |= T1 << (count - 16);
|
||||
T0 = res >> 16;
|
||||
CC_DST = T0;
|
||||
}
|
||||
#undef MEM_WRITE
|
||||
#include "ops_template_mem.h"
|
||||
|
||||
void OPPROTO glue(glue(op_shld, SUFFIX), _T0_T1_ECX_cc)(void)
|
||||
{
|
||||
int count;
|
||||
unsigned int res;
|
||||
count = ECX & 0x1f;
|
||||
if (count) {
|
||||
T1 &= 0xffff;
|
||||
res = T1 | (T0 << 16);
|
||||
CC_SRC = res >> (32 - count);
|
||||
res <<= count;
|
||||
if (count > 16)
|
||||
res |= T1 << (count - 16);
|
||||
T0 = res >> 16;
|
||||
CC_DST = T0;
|
||||
CC_OP = CC_OP_SARB + SHIFT;
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_shrd, SUFFIX), _T0_T1_im_cc)(void)
|
||||
{
|
||||
int count;
|
||||
unsigned int res;
|
||||
|
||||
count = PARAM1;
|
||||
res = (T0 & 0xffff) | (T1 << 16);
|
||||
CC_SRC = res >> (count - 1);
|
||||
res >>= count;
|
||||
if (count > 16)
|
||||
res |= T1 << (32 - count);
|
||||
T0 = res;
|
||||
CC_DST = T0;
|
||||
}
|
||||
|
||||
|
||||
void OPPROTO glue(glue(op_shrd, SUFFIX), _T0_T1_ECX_cc)(void)
|
||||
{
|
||||
int count;
|
||||
unsigned int res;
|
||||
|
||||
count = ECX & 0x1f;
|
||||
if (count) {
|
||||
res = (T0 & 0xffff) | (T1 << 16);
|
||||
CC_SRC = res >> (count - 1);
|
||||
res >>= count;
|
||||
if (count > 16)
|
||||
res |= T1 << (32 - count);
|
||||
T0 = res;
|
||||
CC_DST = T0;
|
||||
CC_OP = CC_OP_SARB + SHIFT;
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
#endif
|
||||
|
||||
#if DATA_BITS == 32
|
||||
void OPPROTO glue(glue(op_shld, SUFFIX), _T0_T1_im_cc)(void)
|
||||
{
|
||||
int count;
|
||||
count = PARAM1;
|
||||
T0 &= DATA_MASK;
|
||||
T1 &= DATA_MASK;
|
||||
CC_SRC = T0 << (count - 1);
|
||||
T0 = (T0 << count) | (T1 >> (DATA_BITS - count));
|
||||
CC_DST = T0;
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_shld, SUFFIX), _T0_T1_ECX_cc)(void)
|
||||
{
|
||||
int count;
|
||||
count = ECX & 0x1f;
|
||||
if (count) {
|
||||
T0 &= DATA_MASK;
|
||||
T1 &= DATA_MASK;
|
||||
CC_SRC = T0 << (count - 1);
|
||||
T0 = (T0 << count) | (T1 >> (DATA_BITS - count));
|
||||
CC_DST = T0;
|
||||
CC_OP = CC_OP_SHLB + SHIFT;
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_shrd, SUFFIX), _T0_T1_im_cc)(void)
|
||||
{
|
||||
int count;
|
||||
count = PARAM1;
|
||||
T0 &= DATA_MASK;
|
||||
T1 &= DATA_MASK;
|
||||
CC_SRC = T0 >> (count - 1);
|
||||
T0 = (T0 >> count) | (T1 << (DATA_BITS - count));
|
||||
CC_DST = T0;
|
||||
}
|
||||
|
||||
|
||||
void OPPROTO glue(glue(op_shrd, SUFFIX), _T0_T1_ECX_cc)(void)
|
||||
{
|
||||
int count;
|
||||
count = ECX & 0x1f;
|
||||
if (count) {
|
||||
T0 &= DATA_MASK;
|
||||
T1 &= DATA_MASK;
|
||||
CC_SRC = T0 >> (count - 1);
|
||||
T0 = (T0 >> count) | (T1 << (DATA_BITS - count));
|
||||
CC_DST = T0;
|
||||
CC_OP = CC_OP_SARB + SHIFT;
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
#endif
|
||||
|
||||
/* carry add/sub (we only need to set CC_OP differently) */
|
||||
|
||||
void OPPROTO glue(glue(op_adc, SUFFIX), _T0_T1_cc)(void)
|
||||
{
|
||||
int cf;
|
||||
cf = cc_table[CC_OP].compute_c();
|
||||
CC_SRC = T0;
|
||||
T0 = T0 + T1 + cf;
|
||||
CC_DST = T0;
|
||||
CC_OP = CC_OP_ADDB + SHIFT + cf * 3;
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_sbb, SUFFIX), _T0_T1_cc)(void)
|
||||
{
|
||||
int cf;
|
||||
cf = cc_table[CC_OP].compute_c();
|
||||
CC_SRC = T0;
|
||||
T0 = T0 - T1 - cf;
|
||||
CC_DST = T0;
|
||||
CC_OP = CC_OP_SUBB + SHIFT + cf * 3;
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_cmpxchg, SUFFIX), _T0_T1_EAX_cc)(void)
|
||||
{
|
||||
CC_SRC = EAX;
|
||||
CC_DST = EAX - T0;
|
||||
if ((DATA_TYPE)CC_DST == 0) {
|
||||
T0 = T1;
|
||||
} else {
|
||||
EAX = (EAX & ~DATA_MASK) | (T0 & DATA_MASK);
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
#define MEM_WRITE
|
||||
#include "ops_template_mem.h"
|
||||
|
||||
/* bit operations */
|
||||
#if DATA_BITS >= 16
|
||||
@@ -756,7 +452,7 @@ void OPPROTO glue(glue(op_bts, SUFFIX), _T0_T1_cc)(void)
|
||||
{
|
||||
int count;
|
||||
count = T1 & SHIFT_MASK;
|
||||
CC_SRC = T0 >> count;
|
||||
T1 = T0 >> count;
|
||||
T0 |= (1 << count);
|
||||
}
|
||||
|
||||
@@ -764,7 +460,7 @@ void OPPROTO glue(glue(op_btr, SUFFIX), _T0_T1_cc)(void)
|
||||
{
|
||||
int count;
|
||||
count = T1 & SHIFT_MASK;
|
||||
CC_SRC = T0 >> count;
|
||||
T1 = T0 >> count;
|
||||
T0 &= ~(1 << count);
|
||||
}
|
||||
|
||||
@@ -772,7 +468,7 @@ void OPPROTO glue(glue(op_btc, SUFFIX), _T0_T1_cc)(void)
|
||||
{
|
||||
int count;
|
||||
count = T1 & SHIFT_MASK;
|
||||
CC_SRC = T0 >> count;
|
||||
T1 = T0 >> count;
|
||||
T0 ^= (1 << count);
|
||||
}
|
||||
|
||||
@@ -814,6 +510,13 @@ void OPPROTO glue(glue(op_bsr, SUFFIX), _T0_cc)(void)
|
||||
|
||||
#endif
|
||||
|
||||
#if DATA_BITS == 32
|
||||
void OPPROTO op_update_bt_cc(void)
|
||||
{
|
||||
CC_SRC = T1;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* string operations */
|
||||
/* XXX: maybe use lower level instructions to ease 16 bit / segment handling */
|
||||
|
||||
|
||||
@@ -0,0 +1,423 @@
|
||||
/*
|
||||
* i386 micro operations (included several times to generate
|
||||
* different operand sizes)
|
||||
*
|
||||
* Copyright (c) 2003 Fabrice Bellard
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
#ifdef MEM_WRITE
|
||||
|
||||
#if DATA_BITS == 8
|
||||
#define MEM_SUFFIX b_mem
|
||||
#elif DATA_BITS == 16
|
||||
#define MEM_SUFFIX w_mem
|
||||
#elif DATA_BITS == 32
|
||||
#define MEM_SUFFIX l_mem
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
#define MEM_SUFFIX SUFFIX
|
||||
|
||||
#endif
|
||||
|
||||
void OPPROTO glue(glue(op_rol, MEM_SUFFIX), _T0_T1_cc)(void)
|
||||
{
|
||||
int count, src;
|
||||
count = T1 & SHIFT_MASK;
|
||||
if (count) {
|
||||
src = T0;
|
||||
T0 &= DATA_MASK;
|
||||
T0 = (T0 << count) | (T0 >> (DATA_BITS - count));
|
||||
#ifdef MEM_WRITE
|
||||
glue(st, SUFFIX)((uint8_t *)A0, T0);
|
||||
#endif
|
||||
CC_SRC = (cc_table[CC_OP].compute_all() & ~(CC_O | CC_C)) |
|
||||
(lshift(src ^ T0, 11 - (DATA_BITS - 1)) & CC_O) |
|
||||
(T0 & CC_C);
|
||||
CC_OP = CC_OP_EFLAGS;
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_ror, MEM_SUFFIX), _T0_T1_cc)(void)
|
||||
{
|
||||
int count, src;
|
||||
count = T1 & SHIFT_MASK;
|
||||
if (count) {
|
||||
src = T0;
|
||||
T0 &= DATA_MASK;
|
||||
T0 = (T0 >> count) | (T0 << (DATA_BITS - count));
|
||||
#ifdef MEM_WRITE
|
||||
glue(st, SUFFIX)((uint8_t *)A0, T0);
|
||||
#endif
|
||||
CC_SRC = (cc_table[CC_OP].compute_all() & ~(CC_O | CC_C)) |
|
||||
(lshift(src ^ T0, 11 - (DATA_BITS - 1)) & CC_O) |
|
||||
((T0 >> (DATA_BITS - 1)) & CC_C);
|
||||
CC_OP = CC_OP_EFLAGS;
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_rol, MEM_SUFFIX), _T0_T1)(void)
|
||||
{
|
||||
int count;
|
||||
count = T1 & SHIFT_MASK;
|
||||
if (count) {
|
||||
T0 &= DATA_MASK;
|
||||
T0 = (T0 << count) | (T0 >> (DATA_BITS - count));
|
||||
#ifdef MEM_WRITE
|
||||
glue(st, SUFFIX)((uint8_t *)A0, T0);
|
||||
#endif
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_ror, MEM_SUFFIX), _T0_T1)(void)
|
||||
{
|
||||
int count;
|
||||
count = T1 & SHIFT_MASK;
|
||||
if (count) {
|
||||
T0 &= DATA_MASK;
|
||||
T0 = (T0 >> count) | (T0 << (DATA_BITS - count));
|
||||
#ifdef MEM_WRITE
|
||||
glue(st, SUFFIX)((uint8_t *)A0, T0);
|
||||
#endif
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_rcl, MEM_SUFFIX), _T0_T1_cc)(void)
|
||||
{
|
||||
int count, res, eflags;
|
||||
unsigned int src;
|
||||
|
||||
count = T1 & 0x1f;
|
||||
#if DATA_BITS == 16
|
||||
count = rclw_table[count];
|
||||
#elif DATA_BITS == 8
|
||||
count = rclb_table[count];
|
||||
#endif
|
||||
if (count) {
|
||||
eflags = cc_table[CC_OP].compute_all();
|
||||
T0 &= DATA_MASK;
|
||||
src = T0;
|
||||
res = (T0 << count) | ((eflags & CC_C) << (count - 1));
|
||||
if (count > 1)
|
||||
res |= T0 >> (DATA_BITS + 1 - count);
|
||||
T0 = res;
|
||||
#ifdef MEM_WRITE
|
||||
glue(st, SUFFIX)((uint8_t *)A0, T0);
|
||||
#endif
|
||||
CC_SRC = (eflags & ~(CC_C | CC_O)) |
|
||||
(lshift(src ^ T0, 11 - (DATA_BITS - 1)) & CC_O) |
|
||||
((src >> (DATA_BITS - count)) & CC_C);
|
||||
CC_OP = CC_OP_EFLAGS;
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_rcr, MEM_SUFFIX), _T0_T1_cc)(void)
|
||||
{
|
||||
int count, res, eflags;
|
||||
unsigned int src;
|
||||
|
||||
count = T1 & 0x1f;
|
||||
#if DATA_BITS == 16
|
||||
count = rclw_table[count];
|
||||
#elif DATA_BITS == 8
|
||||
count = rclb_table[count];
|
||||
#endif
|
||||
if (count) {
|
||||
eflags = cc_table[CC_OP].compute_all();
|
||||
T0 &= DATA_MASK;
|
||||
src = T0;
|
||||
res = (T0 >> count) | ((eflags & CC_C) << (DATA_BITS - count));
|
||||
if (count > 1)
|
||||
res |= T0 << (DATA_BITS + 1 - count);
|
||||
T0 = res;
|
||||
#ifdef MEM_WRITE
|
||||
glue(st, SUFFIX)((uint8_t *)A0, T0);
|
||||
#endif
|
||||
CC_SRC = (eflags & ~(CC_C | CC_O)) |
|
||||
(lshift(src ^ T0, 11 - (DATA_BITS - 1)) & CC_O) |
|
||||
((src >> (count - 1)) & CC_C);
|
||||
CC_OP = CC_OP_EFLAGS;
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_shl, MEM_SUFFIX), _T0_T1_cc)(void)
|
||||
{
|
||||
int count, src;
|
||||
count = T1 & 0x1f;
|
||||
if (count) {
|
||||
src = (DATA_TYPE)T0 << (count - 1);
|
||||
T0 = T0 << count;
|
||||
#ifdef MEM_WRITE
|
||||
glue(st, SUFFIX)((uint8_t *)A0, T0);
|
||||
#endif
|
||||
CC_SRC = src;
|
||||
CC_DST = T0;
|
||||
CC_OP = CC_OP_SHLB + SHIFT;
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_shr, MEM_SUFFIX), _T0_T1_cc)(void)
|
||||
{
|
||||
int count, src;
|
||||
count = T1 & 0x1f;
|
||||
if (count) {
|
||||
T0 &= DATA_MASK;
|
||||
src = T0 >> (count - 1);
|
||||
T0 = T0 >> count;
|
||||
#ifdef MEM_WRITE
|
||||
glue(st, SUFFIX)((uint8_t *)A0, T0);
|
||||
#endif
|
||||
CC_SRC = src;
|
||||
CC_DST = T0;
|
||||
CC_OP = CC_OP_SARB + SHIFT;
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_sar, MEM_SUFFIX), _T0_T1_cc)(void)
|
||||
{
|
||||
int count, src;
|
||||
count = T1 & 0x1f;
|
||||
if (count) {
|
||||
src = (DATA_STYPE)T0;
|
||||
T0 = src >> count;
|
||||
src = src >> (count - 1);
|
||||
#ifdef MEM_WRITE
|
||||
glue(st, SUFFIX)((uint8_t *)A0, T0);
|
||||
#endif
|
||||
CC_SRC = src;
|
||||
CC_DST = T0;
|
||||
CC_OP = CC_OP_SARB + SHIFT;
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
#if DATA_BITS == 16
|
||||
/* XXX: overflow flag might be incorrect in some cases in shldw */
|
||||
void OPPROTO glue(glue(op_shld, MEM_SUFFIX), _T0_T1_im_cc)(void)
|
||||
{
|
||||
int count;
|
||||
unsigned int res, tmp;
|
||||
count = PARAM1;
|
||||
T1 &= 0xffff;
|
||||
res = T1 | (T0 << 16);
|
||||
tmp = res >> (32 - count);
|
||||
res <<= count;
|
||||
if (count > 16)
|
||||
res |= T1 << (count - 16);
|
||||
T0 = res >> 16;
|
||||
#ifdef MEM_WRITE
|
||||
glue(st, SUFFIX)((uint8_t *)A0, T0);
|
||||
#endif
|
||||
CC_SRC = tmp;
|
||||
CC_DST = T0;
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_shld, MEM_SUFFIX), _T0_T1_ECX_cc)(void)
|
||||
{
|
||||
int count;
|
||||
unsigned int res, tmp;
|
||||
count = ECX & 0x1f;
|
||||
if (count) {
|
||||
T1 &= 0xffff;
|
||||
res = T1 | (T0 << 16);
|
||||
tmp = res >> (32 - count);
|
||||
res <<= count;
|
||||
if (count > 16)
|
||||
res |= T1 << (count - 16);
|
||||
T0 = res >> 16;
|
||||
#ifdef MEM_WRITE
|
||||
glue(st, SUFFIX)((uint8_t *)A0, T0);
|
||||
#endif
|
||||
CC_SRC = tmp;
|
||||
CC_DST = T0;
|
||||
CC_OP = CC_OP_SARB + SHIFT;
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_shrd, MEM_SUFFIX), _T0_T1_im_cc)(void)
|
||||
{
|
||||
int count;
|
||||
unsigned int res, tmp;
|
||||
|
||||
count = PARAM1;
|
||||
res = (T0 & 0xffff) | (T1 << 16);
|
||||
tmp = res >> (count - 1);
|
||||
res >>= count;
|
||||
if (count > 16)
|
||||
res |= T1 << (32 - count);
|
||||
T0 = res;
|
||||
#ifdef MEM_WRITE
|
||||
glue(st, SUFFIX)((uint8_t *)A0, T0);
|
||||
#endif
|
||||
CC_SRC = tmp;
|
||||
CC_DST = T0;
|
||||
}
|
||||
|
||||
|
||||
void OPPROTO glue(glue(op_shrd, MEM_SUFFIX), _T0_T1_ECX_cc)(void)
|
||||
{
|
||||
int count;
|
||||
unsigned int res, tmp;
|
||||
|
||||
count = ECX & 0x1f;
|
||||
if (count) {
|
||||
res = (T0 & 0xffff) | (T1 << 16);
|
||||
tmp = res >> (count - 1);
|
||||
res >>= count;
|
||||
if (count > 16)
|
||||
res |= T1 << (32 - count);
|
||||
T0 = res;
|
||||
#ifdef MEM_WRITE
|
||||
glue(st, SUFFIX)((uint8_t *)A0, T0);
|
||||
#endif
|
||||
CC_SRC = tmp;
|
||||
CC_DST = T0;
|
||||
CC_OP = CC_OP_SARB + SHIFT;
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
#endif
|
||||
|
||||
#if DATA_BITS == 32
|
||||
void OPPROTO glue(glue(op_shld, MEM_SUFFIX), _T0_T1_im_cc)(void)
|
||||
{
|
||||
int count, tmp;
|
||||
count = PARAM1;
|
||||
T0 &= DATA_MASK;
|
||||
T1 &= DATA_MASK;
|
||||
tmp = T0 << (count - 1);
|
||||
T0 = (T0 << count) | (T1 >> (DATA_BITS - count));
|
||||
#ifdef MEM_WRITE
|
||||
glue(st, SUFFIX)((uint8_t *)A0, T0);
|
||||
#endif
|
||||
CC_SRC = tmp;
|
||||
CC_DST = T0;
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_shld, MEM_SUFFIX), _T0_T1_ECX_cc)(void)
|
||||
{
|
||||
int count, tmp;
|
||||
count = ECX & 0x1f;
|
||||
if (count) {
|
||||
T0 &= DATA_MASK;
|
||||
T1 &= DATA_MASK;
|
||||
tmp = T0 << (count - 1);
|
||||
T0 = (T0 << count) | (T1 >> (DATA_BITS - count));
|
||||
#ifdef MEM_WRITE
|
||||
glue(st, SUFFIX)((uint8_t *)A0, T0);
|
||||
#endif
|
||||
CC_SRC = tmp;
|
||||
CC_DST = T0;
|
||||
CC_OP = CC_OP_SHLB + SHIFT;
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_shrd, MEM_SUFFIX), _T0_T1_im_cc)(void)
|
||||
{
|
||||
int count, tmp;
|
||||
count = PARAM1;
|
||||
T0 &= DATA_MASK;
|
||||
T1 &= DATA_MASK;
|
||||
tmp = T0 >> (count - 1);
|
||||
T0 = (T0 >> count) | (T1 << (DATA_BITS - count));
|
||||
#ifdef MEM_WRITE
|
||||
glue(st, SUFFIX)((uint8_t *)A0, T0);
|
||||
#endif
|
||||
CC_SRC = tmp;
|
||||
CC_DST = T0;
|
||||
}
|
||||
|
||||
|
||||
void OPPROTO glue(glue(op_shrd, MEM_SUFFIX), _T0_T1_ECX_cc)(void)
|
||||
{
|
||||
int count, tmp;
|
||||
count = ECX & 0x1f;
|
||||
if (count) {
|
||||
T0 &= DATA_MASK;
|
||||
T1 &= DATA_MASK;
|
||||
tmp = T0 >> (count - 1);
|
||||
T0 = (T0 >> count) | (T1 << (DATA_BITS - count));
|
||||
#ifdef MEM_WRITE
|
||||
glue(st, SUFFIX)((uint8_t *)A0, T0);
|
||||
#endif
|
||||
CC_SRC = tmp;
|
||||
CC_DST = T0;
|
||||
CC_OP = CC_OP_SARB + SHIFT;
|
||||
}
|
||||
FORCE_RET();
|
||||
}
|
||||
#endif
|
||||
|
||||
/* carry add/sub (we only need to set CC_OP differently) */
|
||||
|
||||
void OPPROTO glue(glue(op_adc, MEM_SUFFIX), _T0_T1_cc)(void)
|
||||
{
|
||||
int cf;
|
||||
cf = cc_table[CC_OP].compute_c();
|
||||
T0 = T0 + T1 + cf;
|
||||
#ifdef MEM_WRITE
|
||||
glue(st, SUFFIX)((uint8_t *)A0, T0);
|
||||
#endif
|
||||
CC_SRC = T1;
|
||||
CC_DST = T0;
|
||||
CC_OP = CC_OP_ADDB + SHIFT + cf * 3;
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_sbb, MEM_SUFFIX), _T0_T1_cc)(void)
|
||||
{
|
||||
int cf;
|
||||
cf = cc_table[CC_OP].compute_c();
|
||||
T0 = T0 - T1 - cf;
|
||||
#ifdef MEM_WRITE
|
||||
glue(st, SUFFIX)((uint8_t *)A0, T0);
|
||||
#endif
|
||||
CC_SRC = T1;
|
||||
CC_DST = T0;
|
||||
CC_OP = CC_OP_SUBB + SHIFT + cf * 3;
|
||||
}
|
||||
|
||||
void OPPROTO glue(glue(op_cmpxchg, MEM_SUFFIX), _T0_T1_EAX_cc)(void)
|
||||
{
|
||||
unsigned int src, dst;
|
||||
|
||||
src = T0;
|
||||
dst = EAX - T0;
|
||||
if ((DATA_TYPE)dst == 0) {
|
||||
T0 = T1;
|
||||
} else {
|
||||
EAX = (EAX & ~DATA_MASK) | (T0 & DATA_MASK);
|
||||
}
|
||||
#ifdef MEM_WRITE
|
||||
glue(st, SUFFIX)((uint8_t *)A0, T0);
|
||||
#endif
|
||||
CC_SRC = src;
|
||||
CC_DST = dst;
|
||||
FORCE_RET();
|
||||
}
|
||||
|
||||
#undef MEM_SUFFIX
|
||||
#undef MEM_WRITE
|
||||
@@ -3074,7 +3074,8 @@ static int print_insn_powerpc(FILE *, unsigned long insn, unsigned memaddr, int
|
||||
|
||||
int print_insn_ppc (bfd_vma pc, disassemble_info *info)
|
||||
{
|
||||
return print_insn_powerpc (info->stream, *(unsigned *)(long)pc, pc,
|
||||
return print_insn_powerpc (info->stream,
|
||||
(unsigned int)bfd_getb32((bfd_byte *)pc), pc,
|
||||
PPC_OPCODE_PPC | PPC_OPCODE_601);
|
||||
}
|
||||
|
||||
|
||||
+268
-35
@@ -47,7 +47,7 @@ QEMU generic features:
|
||||
|
||||
@item Self-modifying code support.
|
||||
|
||||
@item Precise exception support.
|
||||
@item Precise exceptions support.
|
||||
|
||||
@item The virtual CPU is a library (@code{libqemu}) which can be used
|
||||
in other projects.
|
||||
@@ -128,7 +128,7 @@ generic dynamic code generation architecture of QEMU.
|
||||
|
||||
@end itemize
|
||||
|
||||
@chapter QEMU User space emulation invocation
|
||||
@chapter QEMU User space emulator invocation
|
||||
|
||||
@section Quick Start
|
||||
|
||||
@@ -240,9 +240,9 @@ This section explains how to launch a Linux kernel inside QEMU.
|
||||
|
||||
@enumerate
|
||||
@item
|
||||
Download the archive @file{vl-test-xxx.tar.gz} containing a Linux kernel
|
||||
and an initrd (initial Ram Disk). The archive also contains a
|
||||
precompiled version of @file{vl}, the QEMU System emulator.
|
||||
Download the archive @file{vl-test-xxx.tar.gz} containing a Linux
|
||||
kernel and a disk image. The archive also contains a precompiled
|
||||
version of @file{vl}, the QEMU System emulator.
|
||||
|
||||
@item Optional: If you want network support (for example to launch X11 examples), you
|
||||
must copy the script @file{vl-ifup} in @file{/etc} and configure
|
||||
@@ -262,20 +262,25 @@ seen from the emulated kernel at IP address 172.20.0.1.
|
||||
> ./vl.sh
|
||||
connected to host network interface: tun0
|
||||
Uncompressing Linux... Ok, booting the kernel.
|
||||
Linux version 2.4.20 (bellard@voyager) (gcc version 2.95.2 20000220 (Debian GNU/Linux)) #42 Wed Jun 25 14:16:12 CEST 2003
|
||||
Linux version 2.4.20 (fabrice@localhost.localdomain) (gcc version 2.96 20000731 (Red Hat Linux 7.3 2.96-110)) #22 lun jui 7 13:37:41 CEST 2003
|
||||
BIOS-provided physical RAM map:
|
||||
BIOS-88: 0000000000000000 - 000000000009f000 (usable)
|
||||
BIOS-88: 0000000000100000 - 0000000002000000 (usable)
|
||||
BIOS-e801: 0000000000000000 - 000000000009f000 (usable)
|
||||
BIOS-e801: 0000000000100000 - 0000000002000000 (usable)
|
||||
32MB LOWMEM available.
|
||||
On node 0 totalpages: 8192
|
||||
zone(0): 4096 pages.
|
||||
zone(1): 4096 pages.
|
||||
zone(2): 0 pages.
|
||||
Kernel command line: root=/dev/ram ramdisk_size=6144
|
||||
Kernel command line: root=/dev/hda ide1=noprobe ide2=noprobe ide3=noprobe ide4=noprobe ide5=noprobe
|
||||
ide_setup: ide1=noprobe
|
||||
ide_setup: ide2=noprobe
|
||||
ide_setup: ide3=noprobe
|
||||
ide_setup: ide4=noprobe
|
||||
ide_setup: ide5=noprobe
|
||||
Initializing CPU#0
|
||||
Detected 501.785 MHz processor.
|
||||
Calibrating delay loop... 973.20 BogoMIPS
|
||||
Memory: 24776k/32768k available (725k kernel code, 7604k reserved, 151k data, 48k init, 0k highmem)
|
||||
Detected 501.285 MHz processor.
|
||||
Calibrating delay loop... 989.59 BogoMIPS
|
||||
Memory: 29268k/32768k available (907k kernel code, 3112k reserved, 212k data, 52k init, 0k highmem)
|
||||
Dentry cache hash table entries: 4096 (order: 3, 32768 bytes)
|
||||
Inode cache hash table entries: 2048 (order: 2, 16384 bytes)
|
||||
Mount-cache hash table entries: 512 (order: 0, 4096 bytes)
|
||||
@@ -289,24 +294,30 @@ Based upon Swansea University Computer Society NET3.039
|
||||
Initializing RT netlink socket
|
||||
apm: BIOS not found.
|
||||
Starting kswapd
|
||||
Journalled Block Device driver loaded
|
||||
pty: 256 Unix98 ptys configured
|
||||
Serial driver version 5.05c (2001-07-08) with no serial options enabled
|
||||
ttyS00 at 0x03f8 (irq = 4) is a 16450
|
||||
Uniform Multi-Platform E-IDE driver Revision: 6.31
|
||||
ide: Assuming 50MHz system bus speed for PIO modes; override with idebus=xx
|
||||
hda: QEMU HARDDISK, ATA DISK drive
|
||||
ide0 at 0x1f0-0x1f7,0x3f6 on irq 14
|
||||
hda: 12288 sectors (6 MB) w/256KiB Cache, CHS=12/16/63
|
||||
Partition check:
|
||||
hda: unknown partition table
|
||||
ne.c:v1.10 9/23/94 Donald Becker (becker@scyld.com)
|
||||
Last modified Nov 1, 2000 by Paul Gortmaker
|
||||
NE*000 ethercard probe at 0x300: 52 54 00 12 34 56
|
||||
eth0: NE2000 found at 0x300, using IRQ 9.
|
||||
RAMDISK driver initialized: 16 RAM disks of 6144K size 1024 blocksize
|
||||
RAMDISK driver initialized: 16 RAM disks of 4096K size 1024 blocksize
|
||||
NET4: Linux TCP/IP 1.0 for NET4.0
|
||||
IP Protocols: ICMP, UDP, TCP, IGMP
|
||||
IP: routing cache hash table of 512 buckets, 4Kbytes
|
||||
TCP: Hash tables configured (established 2048 bind 2048)
|
||||
TCP: Hash tables configured (established 2048 bind 4096)
|
||||
NET4: Unix domain sockets 1.0/SMP for Linux NET4.0.
|
||||
RAMDISK: ext2 filesystem found at block 0
|
||||
RAMDISK: Loading 6144 blocks [1 disk] into ram disk... done.
|
||||
Freeing initrd memory: 6144k freed
|
||||
EXT2-fs warning: mounting unchecked fs, running e2fsck is recommended
|
||||
VFS: Mounted root (ext2 filesystem).
|
||||
Freeing unused kernel memory: 48k freed
|
||||
Freeing unused kernel memory: 52k freed
|
||||
sh: can't access tty; job control turned off
|
||||
#
|
||||
@end example
|
||||
@@ -315,7 +326,8 @@ sh: can't access tty; job control turned off
|
||||
Then you can play with the kernel inside the virtual serial console. You
|
||||
can launch @code{ls} for example. Type @key{Ctrl-a h} to have an help
|
||||
about the keys you can type inside the virtual serial console. In
|
||||
particular @key{Ctrl-a b} is the Magic SysRq key.
|
||||
particular, use @key{Ctrl-a x} to exit QEMU and use @key{Ctrl-a b} as
|
||||
the Magic SysRq key.
|
||||
|
||||
@item
|
||||
If the network is enabled, launch the script @file{/etc/linuxrc} in the
|
||||
@@ -334,16 +346,175 @@ a real Virtual Linux system !
|
||||
|
||||
@end enumerate
|
||||
|
||||
NOTE: the example initrd is a modified version of the one made by Kevin
|
||||
NOTES:
|
||||
@enumerate
|
||||
@item
|
||||
A 2.5.74 kernel is also included in the vl-test archive. Just
|
||||
replace the bzImage in vl.sh to try it.
|
||||
|
||||
@item
|
||||
vl creates a temporary file in @var{$VLTMPDIR} (@file{/tmp} is the
|
||||
default) containing all the simulated PC memory. If possible, try to use
|
||||
a temporary directory using the tmpfs filesystem to avoid too many
|
||||
unnecessary disk accesses.
|
||||
|
||||
@item
|
||||
In order to exit cleanly for vl, you can do a @emph{shutdown} inside
|
||||
vl. vl will automatically exit when the Linux shutdown is done.
|
||||
|
||||
@item
|
||||
You can boot slightly faster by disabling the probe of non present IDE
|
||||
interfaces. To do so, add the following options on the kernel command
|
||||
line:
|
||||
@example
|
||||
ide1=noprobe ide2=noprobe ide3=noprobe ide4=noprobe ide5=noprobe
|
||||
@end example
|
||||
|
||||
@item
|
||||
The example disk image is a modified version of the one made by Kevin
|
||||
Lawton for the plex86 Project (@url{www.plex86.org}).
|
||||
|
||||
@section Kernel Compilation
|
||||
@end enumerate
|
||||
|
||||
You can use any Linux kernel within QEMU provided it is mapped at
|
||||
address 0x90000000 (the default is 0xc0000000). You must modify only two
|
||||
lines in the kernel source:
|
||||
@section Invocation
|
||||
|
||||
In asm/page.h, replace
|
||||
@example
|
||||
usage: vl [options] bzImage [kernel parameters...]
|
||||
@end example
|
||||
|
||||
@file{bzImage} is a Linux kernel image.
|
||||
|
||||
General options:
|
||||
@table @option
|
||||
@item -hda file
|
||||
@item -hdb file
|
||||
Use 'file' as hard disk 0 or 1 image (@xref{disk_images}).
|
||||
|
||||
@item -snapshot
|
||||
|
||||
Write to temporary files instead of disk image files. In this case,
|
||||
the raw disk image you use is not written back. You can however force
|
||||
the write back by pressing @key{C-a s} (@xref{disk_images}).
|
||||
|
||||
@item -m megs
|
||||
Set virtual RAM size to @var{megs} megabytes.
|
||||
|
||||
@item -n script
|
||||
Set network init script [default=/etc/vl-ifup]. This script is
|
||||
launched to configure the host network interface (usually tun0)
|
||||
corresponding to the virtual NE2000 card.
|
||||
|
||||
@item -initrd file
|
||||
Use 'file' as initial ram disk.
|
||||
@end table
|
||||
|
||||
Debug options:
|
||||
@table @option
|
||||
@item -s
|
||||
Wait gdb connection to port 1234.
|
||||
@item -p port
|
||||
Change gdb connection port.
|
||||
@item -d
|
||||
Output log in /tmp/vl.log
|
||||
@end table
|
||||
|
||||
During emulation, use @key{C-a h} to get terminal commands:
|
||||
|
||||
@table @key
|
||||
@item C-a h
|
||||
Print this help
|
||||
@item C-a x
|
||||
Exit emulatior
|
||||
@item C-a s
|
||||
Save disk data back to file (if -snapshot)
|
||||
@item C-a b
|
||||
Send break (magic sysrq)
|
||||
@item C-a C-a
|
||||
Send C-a
|
||||
@end table
|
||||
|
||||
@node disk_images
|
||||
@section Disk Images
|
||||
|
||||
@subsection Raw disk images
|
||||
|
||||
The disk images can simply be raw images of the hard disk. You can
|
||||
create them with the command:
|
||||
@example
|
||||
dd if=/dev/zero of=myimage bs=1024 count=mysize
|
||||
@end example
|
||||
where @var{myimage} is the image filename and @var{mysize} is its size
|
||||
in kilobytes.
|
||||
|
||||
@subsection Snapshot mode
|
||||
|
||||
If you use the option @option{-snapshot}, all disk images are
|
||||
considered as read only. When sectors in written, they are written in
|
||||
a temporary file created in @file{/tmp}. You can however force the
|
||||
write back to the raw disk images by pressing @key{C-a s}.
|
||||
|
||||
NOTE: The snapshot mode only works with raw disk images.
|
||||
|
||||
@subsection Copy On Write disk images
|
||||
|
||||
QEMU also supports user mode Linux
|
||||
(@url{http://user-mode-linux.sourceforge.net/}) Copy On Write (COW)
|
||||
disk images. The COW disk images are much smaller than normal images
|
||||
as they store only modified sectors. They also permit the use of the
|
||||
same disk image template for many users.
|
||||
|
||||
To create a COW disk images, use the command:
|
||||
|
||||
@example
|
||||
vlmkcow -f myrawimage.bin mycowimage.cow
|
||||
@end example
|
||||
|
||||
@file{myrawimage.bin} is a raw image you want to use as original disk
|
||||
image. It will never be written to.
|
||||
|
||||
@file{mycowimage.cow} is the COW disk image which is created by
|
||||
@code{vlmkcow}. You can use it directly with the @option{-hdx}
|
||||
options. You must not modify the original raw disk image if you use
|
||||
COW images, as COW images only store the modified sectors from the raw
|
||||
disk image. QEMU stores the original raw disk image name and its
|
||||
modified time in the COW disk image so that chances of mistakes are
|
||||
reduced.
|
||||
|
||||
If raw disk image is not read-only, by pressing @key{C-a s} you can
|
||||
flush the COW disk image back into the raw disk image, as in snapshot
|
||||
mode.
|
||||
|
||||
COW disk images can also be created without a corresponding raw disk
|
||||
image. It is useful to have a big initial virtual disk image without
|
||||
using much disk space. Use:
|
||||
|
||||
@example
|
||||
vlmkcow mycowimage.cow 1024
|
||||
@end example
|
||||
|
||||
to create a 1 gigabyte empty COW disk image.
|
||||
|
||||
NOTES:
|
||||
@enumerate
|
||||
@item
|
||||
COW disk images must be created on file systems supporting
|
||||
@emph{holes} such as ext2 or ext3.
|
||||
@item
|
||||
Since holes are used, the displayed size of the COW disk image is not
|
||||
the real one. To know it, use the @code{ls -ls} command.
|
||||
@end enumerate
|
||||
|
||||
@section Linux Kernel Compilation
|
||||
|
||||
You should be able to use any kernel with QEMU provided you make the
|
||||
following changes (only 2.4.x and 2.5.x were tested):
|
||||
|
||||
@enumerate
|
||||
@item
|
||||
The kernel must be mapped at 0x90000000 (the default is
|
||||
0xc0000000). You must modify only two lines in the kernel source:
|
||||
|
||||
In @file{include/asm/page.h}, replace
|
||||
@example
|
||||
#define __PAGE_OFFSET (0xc0000000)
|
||||
@end example
|
||||
@@ -352,7 +523,7 @@ by
|
||||
#define __PAGE_OFFSET (0x90000000)
|
||||
@end example
|
||||
|
||||
And in arch/i386/vmlinux.lds, replace
|
||||
And in @file{arch/i386/vmlinux.lds}, replace
|
||||
@example
|
||||
. = 0xc0000000 + 0x100000;
|
||||
@end example
|
||||
@@ -361,7 +532,37 @@ by
|
||||
. = 0x90000000 + 0x100000;
|
||||
@end example
|
||||
|
||||
The file config-2.4.20 gives the configuration of the example kernel.
|
||||
@item
|
||||
If you want to enable SMP (Symmetric Multi-Processing) support, you
|
||||
must make the following change in @file{include/asm/fixmap.h}. Replace
|
||||
@example
|
||||
#define FIXADDR_TOP (0xffffX000UL)
|
||||
@end example
|
||||
by
|
||||
@example
|
||||
#define FIXADDR_TOP (0xa7ffX000UL)
|
||||
@end example
|
||||
(X is 'e' or 'f' depending on the kernel version). Although you can
|
||||
use an SMP kernel with QEMU, it only supports one CPU.
|
||||
|
||||
@item
|
||||
If you are not using a 2.5 kernel as host kernel but if you use a target
|
||||
2.5 kernel, you must also ensure that the 'HZ' define is set to 100
|
||||
(1000 is the default) as QEMU cannot currently emulate timers at
|
||||
frequencies greater than 100 Hz on host Linux systems < 2.5. In
|
||||
@file{include/asm/param.h}, replace:
|
||||
|
||||
@example
|
||||
# define HZ 1000 /* Internal kernel timer frequency */
|
||||
@end example
|
||||
by
|
||||
@example
|
||||
# define HZ 100 /* Internal kernel timer frequency */
|
||||
@end example
|
||||
|
||||
@end enumerate
|
||||
|
||||
The file config-2.x.x gives the configuration of the example kernels.
|
||||
|
||||
Just type
|
||||
@example
|
||||
@@ -384,13 +585,45 @@ PIT (timers)
|
||||
@item
|
||||
CMOS memory
|
||||
@item
|
||||
Dumb VGA (to print the @code{Uncompressing Linux} message)
|
||||
@item
|
||||
Serial port (port=0x3f8, irq=4)
|
||||
@item
|
||||
NE2000 network adapter (port=0x300, irq=9)
|
||||
@item
|
||||
Dumb VGA (to print the @code{uncompressing Linux kernel} message)
|
||||
@item
|
||||
IDE disk interface (port=0x1f0, irq=14)
|
||||
@end itemize
|
||||
|
||||
@section GDB usage
|
||||
|
||||
QEMU has a primitive support to work with gdb, so that you can do
|
||||
'Ctrl-C' while the kernel is running and inspect its state.
|
||||
|
||||
In order to use gdb, launch vl with the '-s' option. It will wait for a
|
||||
gdb connection:
|
||||
@example
|
||||
> vl -s arch/i386/boot/bzImage initrd-2.4.20.img root=/dev/ram0 ramdisk_size=6144
|
||||
Connected to host network interface: tun0
|
||||
Waiting gdb connection on port 1234
|
||||
@end example
|
||||
|
||||
Then launch gdb on the 'vmlinux' executable:
|
||||
@example
|
||||
> gdb vmlinux
|
||||
@end example
|
||||
|
||||
In gdb, connect to QEMU:
|
||||
@example
|
||||
(gdb) target remote locahost:1234
|
||||
@end example
|
||||
|
||||
Then you can use gdb normally. For example, type 'c' to launch the kernel:
|
||||
@example
|
||||
(gdb) c
|
||||
@end example
|
||||
|
||||
WARNING: breakpoints and single stepping are not yet supported.
|
||||
|
||||
@chapter QEMU Internals
|
||||
|
||||
@section QEMU compared to other emulators
|
||||
@@ -405,9 +638,9 @@ Like Valgrind [2], QEMU does user space emulation and dynamic
|
||||
translation. Valgrind is mainly a memory debugger while QEMU has no
|
||||
support for it (QEMU could be used to detect out of bound memory
|
||||
accesses as Valgrind, but it has no support to track uninitialised data
|
||||
as Valgrind does). Valgrind dynamic translator generates better code
|
||||
as Valgrind does). The Valgrind dynamic translator generates better code
|
||||
than QEMU (in particular it does register allocation) but it is closely
|
||||
tied to an x86 host and target and has no support for precise exception
|
||||
tied to an x86 host and target and has no support for precise exceptions
|
||||
and system emulation.
|
||||
|
||||
EM86 [4] is the closest project to user space QEMU (and QEMU still uses
|
||||
@@ -433,8 +666,8 @@ system emulator. It requires a patched Linux kernel to work (you cannot
|
||||
launch the same kernel on your PC), but the patches are really small. As
|
||||
it is a PC virtualizer (no emulation is done except for some priveledged
|
||||
instructions), it has the potential of being faster than QEMU. The
|
||||
downside is that a complicated (and potentially unsafe) kernel patch is
|
||||
needed.
|
||||
downside is that a complicated (and potentially unsafe) host kernel
|
||||
patch is needed.
|
||||
|
||||
@section Portable dynamic translation
|
||||
|
||||
@@ -540,7 +773,7 @@ Correct translated code invalidation is done efficiently by maintaining
|
||||
a linked list of every translated block contained in a given page. Other
|
||||
linked lists are also maintained to undo direct block chaining.
|
||||
|
||||
Althought the overhead of doing @code{mprotect()} calls is important,
|
||||
Although the overhead of doing @code{mprotect()} calls is important,
|
||||
most MSDOS programs can be emulated at reasonnable speed with QEMU and
|
||||
DOSEMU.
|
||||
|
||||
@@ -609,7 +842,7 @@ reentrancy.
|
||||
|
||||
@section Self-virtualization
|
||||
|
||||
QEMU was conceived so that ultimately it can emulate itself. Althought
|
||||
QEMU was conceived so that ultimately it can emulate itself. Although
|
||||
it is not very useful, it is an important test to show the power of the
|
||||
emulator.
|
||||
|
||||
|
||||
@@ -236,6 +236,7 @@ void thunk_register_struct(int id, const char *name, const argtype *types);
|
||||
void thunk_register_struct_direct(int id, const char *name, StructEntry *se1);
|
||||
const argtype *thunk_convert(void *dst, const void *src,
|
||||
const argtype *type_ptr, int to_host);
|
||||
#ifndef NO_THUNK_TYPE_SIZE
|
||||
|
||||
extern StructEntry struct_entries[];
|
||||
|
||||
@@ -312,6 +313,8 @@ static inline int thunk_type_align(const argtype *type_ptr, int is_host)
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* NO_THUNK_TYPE_SIZE */
|
||||
|
||||
unsigned int target_to_host_bitmask(unsigned int x86_mask,
|
||||
bitmask_transtbl * trans_tbl);
|
||||
unsigned int host_to_target_bitmask(unsigned int alpha_mask,
|
||||
|
||||
+305
-96
@@ -365,14 +365,14 @@ static GenOpFunc *gen_op_cmov_reg_T1_T0[2][8] = {
|
||||
};
|
||||
|
||||
static GenOpFunc *gen_op_arith_T0_T1_cc[8] = {
|
||||
gen_op_addl_T0_T1_cc,
|
||||
gen_op_orl_T0_T1_cc,
|
||||
NULL,
|
||||
gen_op_orl_T0_T1,
|
||||
NULL,
|
||||
NULL,
|
||||
gen_op_andl_T0_T1_cc,
|
||||
gen_op_subl_T0_T1_cc,
|
||||
gen_op_xorl_T0_T1_cc,
|
||||
gen_op_cmpl_T0_T1_cc,
|
||||
gen_op_andl_T0_T1,
|
||||
NULL,
|
||||
gen_op_xorl_T0_T1,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static GenOpFunc *gen_op_arithc_T0_T1_cc[3][2] = {
|
||||
@@ -390,6 +390,21 @@ static GenOpFunc *gen_op_arithc_T0_T1_cc[3][2] = {
|
||||
},
|
||||
};
|
||||
|
||||
static GenOpFunc *gen_op_arithc_mem_T0_T1_cc[3][2] = {
|
||||
[OT_BYTE] = {
|
||||
gen_op_adcb_mem_T0_T1_cc,
|
||||
gen_op_sbbb_mem_T0_T1_cc,
|
||||
},
|
||||
[OT_WORD] = {
|
||||
gen_op_adcw_mem_T0_T1_cc,
|
||||
gen_op_sbbw_mem_T0_T1_cc,
|
||||
},
|
||||
[OT_LONG] = {
|
||||
gen_op_adcl_mem_T0_T1_cc,
|
||||
gen_op_sbbl_mem_T0_T1_cc,
|
||||
},
|
||||
};
|
||||
|
||||
static const int cc_op_arithb[8] = {
|
||||
CC_OP_ADDB,
|
||||
CC_OP_LOGICB,
|
||||
@@ -407,6 +422,12 @@ static GenOpFunc *gen_op_cmpxchg_T0_T1_EAX_cc[3] = {
|
||||
gen_op_cmpxchgl_T0_T1_EAX_cc,
|
||||
};
|
||||
|
||||
static GenOpFunc *gen_op_cmpxchg_mem_T0_T1_EAX_cc[3] = {
|
||||
gen_op_cmpxchgb_mem_T0_T1_EAX_cc,
|
||||
gen_op_cmpxchgw_mem_T0_T1_EAX_cc,
|
||||
gen_op_cmpxchgl_mem_T0_T1_EAX_cc,
|
||||
};
|
||||
|
||||
static GenOpFunc *gen_op_shift_T0_T1_cc[3][8] = {
|
||||
[OT_BYTE] = {
|
||||
gen_op_rolb_T0_T1_cc,
|
||||
@@ -440,6 +461,39 @@ static GenOpFunc *gen_op_shift_T0_T1_cc[3][8] = {
|
||||
},
|
||||
};
|
||||
|
||||
static GenOpFunc *gen_op_shift_mem_T0_T1_cc[3][8] = {
|
||||
[OT_BYTE] = {
|
||||
gen_op_rolb_mem_T0_T1_cc,
|
||||
gen_op_rorb_mem_T0_T1_cc,
|
||||
gen_op_rclb_mem_T0_T1_cc,
|
||||
gen_op_rcrb_mem_T0_T1_cc,
|
||||
gen_op_shlb_mem_T0_T1_cc,
|
||||
gen_op_shrb_mem_T0_T1_cc,
|
||||
gen_op_shlb_mem_T0_T1_cc,
|
||||
gen_op_sarb_mem_T0_T1_cc,
|
||||
},
|
||||
[OT_WORD] = {
|
||||
gen_op_rolw_mem_T0_T1_cc,
|
||||
gen_op_rorw_mem_T0_T1_cc,
|
||||
gen_op_rclw_mem_T0_T1_cc,
|
||||
gen_op_rcrw_mem_T0_T1_cc,
|
||||
gen_op_shlw_mem_T0_T1_cc,
|
||||
gen_op_shrw_mem_T0_T1_cc,
|
||||
gen_op_shlw_mem_T0_T1_cc,
|
||||
gen_op_sarw_mem_T0_T1_cc,
|
||||
},
|
||||
[OT_LONG] = {
|
||||
gen_op_roll_mem_T0_T1_cc,
|
||||
gen_op_rorl_mem_T0_T1_cc,
|
||||
gen_op_rcll_mem_T0_T1_cc,
|
||||
gen_op_rcrl_mem_T0_T1_cc,
|
||||
gen_op_shll_mem_T0_T1_cc,
|
||||
gen_op_shrl_mem_T0_T1_cc,
|
||||
gen_op_shll_mem_T0_T1_cc,
|
||||
gen_op_sarl_mem_T0_T1_cc,
|
||||
},
|
||||
};
|
||||
|
||||
static GenOpFunc1 *gen_op_shiftd_T0_T1_im_cc[2][2] = {
|
||||
[0] = {
|
||||
gen_op_shldw_T0_T1_im_cc,
|
||||
@@ -462,6 +516,28 @@ static GenOpFunc *gen_op_shiftd_T0_T1_ECX_cc[2][2] = {
|
||||
},
|
||||
};
|
||||
|
||||
static GenOpFunc1 *gen_op_shiftd_mem_T0_T1_im_cc[2][2] = {
|
||||
[0] = {
|
||||
gen_op_shldw_mem_T0_T1_im_cc,
|
||||
gen_op_shrdw_mem_T0_T1_im_cc,
|
||||
},
|
||||
[1] = {
|
||||
gen_op_shldl_mem_T0_T1_im_cc,
|
||||
gen_op_shrdl_mem_T0_T1_im_cc,
|
||||
},
|
||||
};
|
||||
|
||||
static GenOpFunc *gen_op_shiftd_mem_T0_T1_ECX_cc[2][2] = {
|
||||
[0] = {
|
||||
gen_op_shldw_mem_T0_T1_ECX_cc,
|
||||
gen_op_shrdw_mem_T0_T1_ECX_cc,
|
||||
},
|
||||
[1] = {
|
||||
gen_op_shldl_mem_T0_T1_ECX_cc,
|
||||
gen_op_shrdl_mem_T0_T1_ECX_cc,
|
||||
},
|
||||
};
|
||||
|
||||
static GenOpFunc *gen_op_btx_T0_T1_cc[2][4] = {
|
||||
[0] = {
|
||||
gen_op_btw_T0_T1_cc,
|
||||
@@ -748,60 +824,105 @@ static GenOpFunc1 *gen_op_fp_arith_STN_ST0[8] = {
|
||||
gen_op_fdiv_STN_ST0,
|
||||
};
|
||||
|
||||
static void gen_op(DisasContext *s1, int op, int ot, int d, int s)
|
||||
/* if d == OR_TMP0, it means memory operand (address in A0) */
|
||||
static void gen_op(DisasContext *s1, int op, int ot, int d)
|
||||
{
|
||||
if (d != OR_TMP0)
|
||||
GenOpFunc *gen_update_cc;
|
||||
|
||||
if (d != OR_TMP0) {
|
||||
gen_op_mov_TN_reg[ot][0][d]();
|
||||
if (s != OR_TMP1)
|
||||
gen_op_mov_TN_reg[ot][1][s]();
|
||||
if (op == OP_ADCL || op == OP_SBBL) {
|
||||
} else {
|
||||
gen_op_ld_T0_A0[ot]();
|
||||
}
|
||||
switch(op) {
|
||||
case OP_ADCL:
|
||||
case OP_SBBL:
|
||||
if (s1->cc_op != CC_OP_DYNAMIC)
|
||||
gen_op_set_cc_op(s1->cc_op);
|
||||
gen_op_arithc_T0_T1_cc[ot][op - OP_ADCL]();
|
||||
if (d != OR_TMP0) {
|
||||
gen_op_arithc_T0_T1_cc[ot][op - OP_ADCL]();
|
||||
gen_op_mov_reg_T0[ot][d]();
|
||||
} else {
|
||||
gen_op_arithc_mem_T0_T1_cc[ot][op - OP_ADCL]();
|
||||
}
|
||||
s1->cc_op = CC_OP_DYNAMIC;
|
||||
} else {
|
||||
goto the_end;
|
||||
case OP_ADDL:
|
||||
gen_op_addl_T0_T1();
|
||||
s1->cc_op = CC_OP_ADDB + ot;
|
||||
gen_update_cc = gen_op_update2_cc;
|
||||
break;
|
||||
case OP_SUBL:
|
||||
gen_op_subl_T0_T1();
|
||||
s1->cc_op = CC_OP_SUBB + ot;
|
||||
gen_update_cc = gen_op_update2_cc;
|
||||
break;
|
||||
default:
|
||||
case OP_ANDL:
|
||||
case OP_ORL:
|
||||
case OP_XORL:
|
||||
gen_op_arith_T0_T1_cc[op]();
|
||||
s1->cc_op = cc_op_arithb[op] + ot;
|
||||
s1->cc_op = CC_OP_LOGICB + ot;
|
||||
gen_update_cc = gen_op_update1_cc;
|
||||
break;
|
||||
case OP_CMPL:
|
||||
gen_op_cmpl_T0_T1_cc();
|
||||
s1->cc_op = CC_OP_SUBB + ot;
|
||||
gen_update_cc = NULL;
|
||||
break;
|
||||
}
|
||||
if (d != OR_TMP0 && op != OP_CMPL)
|
||||
gen_op_mov_reg_T0[ot][d]();
|
||||
}
|
||||
|
||||
static void gen_opi(DisasContext *s1, int op, int ot, int d, int c)
|
||||
{
|
||||
gen_op_movl_T1_im(c);
|
||||
gen_op(s1, op, ot, d, OR_TMP1);
|
||||
if (op != OP_CMPL) {
|
||||
if (d != OR_TMP0)
|
||||
gen_op_mov_reg_T0[ot][d]();
|
||||
else
|
||||
gen_op_st_T0_A0[ot]();
|
||||
}
|
||||
/* the flags update must happen after the memory write (precise
|
||||
exception support) */
|
||||
if (gen_update_cc)
|
||||
gen_update_cc();
|
||||
the_end: ;
|
||||
}
|
||||
|
||||
/* if d == OR_TMP0, it means memory operand (address in A0) */
|
||||
static void gen_inc(DisasContext *s1, int ot, int d, int c)
|
||||
{
|
||||
if (d != OR_TMP0)
|
||||
gen_op_mov_TN_reg[ot][0][d]();
|
||||
else
|
||||
gen_op_ld_T0_A0[ot]();
|
||||
if (s1->cc_op != CC_OP_DYNAMIC)
|
||||
gen_op_set_cc_op(s1->cc_op);
|
||||
if (c > 0) {
|
||||
gen_op_incl_T0_cc();
|
||||
gen_op_incl_T0();
|
||||
s1->cc_op = CC_OP_INCB + ot;
|
||||
} else {
|
||||
gen_op_decl_T0_cc();
|
||||
gen_op_decl_T0();
|
||||
s1->cc_op = CC_OP_DECB + ot;
|
||||
}
|
||||
if (d != OR_TMP0)
|
||||
gen_op_mov_reg_T0[ot][d]();
|
||||
else
|
||||
gen_op_st_T0_A0[ot]();
|
||||
gen_op_update_inc_cc();
|
||||
}
|
||||
|
||||
static void gen_shift(DisasContext *s1, int op, int ot, int d, int s)
|
||||
{
|
||||
if (d != OR_TMP0)
|
||||
gen_op_mov_TN_reg[ot][0][d]();
|
||||
else
|
||||
gen_op_ld_T0_A0[ot]();
|
||||
if (s != OR_TMP1)
|
||||
gen_op_mov_TN_reg[ot][1][s]();
|
||||
/* for zero counts, flags are not updated, so must do it dynamically */
|
||||
if (s1->cc_op != CC_OP_DYNAMIC)
|
||||
gen_op_set_cc_op(s1->cc_op);
|
||||
|
||||
gen_op_shift_T0_T1_cc[ot][op]();
|
||||
|
||||
|
||||
if (d != OR_TMP0)
|
||||
gen_op_shift_T0_T1_cc[ot][op]();
|
||||
else
|
||||
gen_op_shift_mem_T0_T1_cc[ot][op]();
|
||||
if (d != OR_TMP0)
|
||||
gen_op_mov_reg_T0[ot][d]();
|
||||
s1->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */
|
||||
@@ -1454,38 +1575,45 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
|
||||
switch(f) {
|
||||
case 0: /* OP Ev, Gv */
|
||||
modrm = ldub(s->pc++);
|
||||
reg = ((modrm >> 3) & 7) + OR_EAX;
|
||||
reg = ((modrm >> 3) & 7);
|
||||
mod = (modrm >> 6) & 3;
|
||||
rm = modrm & 7;
|
||||
if (mod != 3) {
|
||||
gen_lea_modrm(s, modrm, ®_addr, &offset_addr);
|
||||
gen_op_ld_T0_A0[ot]();
|
||||
opreg = OR_TMP0;
|
||||
} else if (op == OP_XORL && rm == reg) {
|
||||
xor_zero:
|
||||
/* xor reg, reg optimisation */
|
||||
gen_op_movl_T0_0();
|
||||
s->cc_op = CC_OP_LOGICB + ot;
|
||||
gen_op_mov_reg_T0[ot][reg]();
|
||||
gen_op_update1_cc();
|
||||
break;
|
||||
} else {
|
||||
opreg = OR_EAX + rm;
|
||||
}
|
||||
gen_op(s, op, ot, opreg, reg);
|
||||
if (mod != 3 && op != 7) {
|
||||
gen_op_st_T0_A0[ot]();
|
||||
opreg = rm;
|
||||
}
|
||||
gen_op_mov_TN_reg[ot][1][reg]();
|
||||
gen_op(s, op, ot, opreg);
|
||||
break;
|
||||
case 1: /* OP Gv, Ev */
|
||||
modrm = ldub(s->pc++);
|
||||
mod = (modrm >> 6) & 3;
|
||||
reg = ((modrm >> 3) & 7) + OR_EAX;
|
||||
reg = ((modrm >> 3) & 7);
|
||||
rm = modrm & 7;
|
||||
if (mod != 3) {
|
||||
gen_lea_modrm(s, modrm, ®_addr, &offset_addr);
|
||||
gen_op_ld_T1_A0[ot]();
|
||||
opreg = OR_TMP1;
|
||||
} else if (op == OP_XORL && rm == reg) {
|
||||
goto xor_zero;
|
||||
} else {
|
||||
opreg = OR_EAX + rm;
|
||||
gen_op_mov_TN_reg[ot][1][rm]();
|
||||
}
|
||||
gen_op(s, op, ot, reg, opreg);
|
||||
gen_op(s, op, ot, reg);
|
||||
break;
|
||||
case 2: /* OP A, Iv */
|
||||
val = insn_get(s, ot);
|
||||
gen_opi(s, op, ot, OR_EAX, val);
|
||||
gen_op_movl_T1_im(val);
|
||||
gen_op(s, op, ot, OR_EAX);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1509,7 +1637,6 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
|
||||
|
||||
if (mod != 3) {
|
||||
gen_lea_modrm(s, modrm, ®_addr, &offset_addr);
|
||||
gen_op_ld_T0_A0[ot]();
|
||||
opreg = OR_TMP0;
|
||||
} else {
|
||||
opreg = rm + OR_EAX;
|
||||
@@ -1525,11 +1652,8 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
|
||||
val = (int8_t)insn_get(s, OT_BYTE);
|
||||
break;
|
||||
}
|
||||
|
||||
gen_opi(s, op, ot, opreg, val);
|
||||
if (op != 7 && mod != 3) {
|
||||
gen_op_st_T0_A0[ot]();
|
||||
}
|
||||
gen_op_movl_T1_im(val);
|
||||
gen_op(s, op, ot, opreg);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -1577,12 +1701,13 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
|
||||
}
|
||||
break;
|
||||
case 3: /* neg */
|
||||
gen_op_negl_T0_cc();
|
||||
gen_op_negl_T0();
|
||||
if (mod != 3) {
|
||||
gen_op_st_T0_A0[ot]();
|
||||
} else {
|
||||
gen_op_mov_reg_T0[ot][rm]();
|
||||
}
|
||||
gen_op_update_neg_cc();
|
||||
s->cc_op = CC_OP_SUBB + ot;
|
||||
break;
|
||||
case 4: /* mul */
|
||||
@@ -1664,7 +1789,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
|
||||
}
|
||||
if (mod != 3) {
|
||||
gen_lea_modrm(s, modrm, ®_addr, &offset_addr);
|
||||
if (op != 3 && op != 5)
|
||||
if (op >= 2 && op != 3 && op != 5)
|
||||
gen_op_ld_T0_A0[ot]();
|
||||
} else {
|
||||
gen_op_mov_TN_reg[ot][0][rm]();
|
||||
@@ -1672,18 +1797,18 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
|
||||
|
||||
switch(op) {
|
||||
case 0: /* inc Ev */
|
||||
gen_inc(s, ot, OR_TMP0, 1);
|
||||
if (mod != 3)
|
||||
gen_op_st_T0_A0[ot]();
|
||||
opreg = OR_TMP0;
|
||||
else
|
||||
gen_op_mov_reg_T0[ot][rm]();
|
||||
opreg = rm;
|
||||
gen_inc(s, ot, opreg, 1);
|
||||
break;
|
||||
case 1: /* dec Ev */
|
||||
gen_inc(s, ot, OR_TMP0, -1);
|
||||
if (mod != 3)
|
||||
gen_op_st_T0_A0[ot]();
|
||||
opreg = OR_TMP0;
|
||||
else
|
||||
gen_op_mov_reg_T0[ot][rm]();
|
||||
opreg = rm;
|
||||
gen_inc(s, ot, opreg, -1);
|
||||
break;
|
||||
case 2: /* call Ev */
|
||||
/* XXX: optimize if memory (no and is necessary) */
|
||||
@@ -1822,17 +1947,18 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
|
||||
rm = modrm & 7;
|
||||
gen_op_mov_TN_reg[ot][0][reg]();
|
||||
gen_op_mov_TN_reg[ot][1][rm]();
|
||||
gen_op_addl_T0_T1_cc();
|
||||
gen_op_addl_T0_T1();
|
||||
gen_op_mov_reg_T0[ot][rm]();
|
||||
gen_op_mov_reg_T1[ot][reg]();
|
||||
} else {
|
||||
gen_lea_modrm(s, modrm, ®_addr, &offset_addr);
|
||||
gen_op_mov_TN_reg[ot][0][reg]();
|
||||
gen_op_ld_T1_A0[ot]();
|
||||
gen_op_addl_T0_T1_cc();
|
||||
gen_op_addl_T0_T1();
|
||||
gen_op_st_T0_A0[ot]();
|
||||
gen_op_mov_reg_T1[ot][reg]();
|
||||
}
|
||||
gen_op_update2_cc();
|
||||
s->cc_op = CC_OP_ADDB + ot;
|
||||
break;
|
||||
case 0x1b0:
|
||||
@@ -1853,8 +1979,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
|
||||
} else {
|
||||
gen_lea_modrm(s, modrm, ®_addr, &offset_addr);
|
||||
gen_op_ld_T0_A0[ot]();
|
||||
gen_op_cmpxchg_T0_T1_EAX_cc[ot]();
|
||||
gen_op_st_T0_A0[ot]();
|
||||
gen_op_cmpxchg_mem_T0_T1_EAX_cc[ot]();
|
||||
}
|
||||
s->cc_op = CC_OP_SUBB + ot;
|
||||
break;
|
||||
@@ -2232,7 +2357,6 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
|
||||
|
||||
if (mod != 3) {
|
||||
gen_lea_modrm(s, modrm, ®_addr, &offset_addr);
|
||||
gen_op_ld_T0_A0[ot]();
|
||||
opreg = OR_TMP0;
|
||||
} else {
|
||||
opreg = rm + OR_EAX;
|
||||
@@ -2247,10 +2371,6 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
|
||||
}
|
||||
gen_shifti(s, op, ot, opreg, shift);
|
||||
}
|
||||
|
||||
if (mod != 3) {
|
||||
gen_op_st_T0_A0[ot]();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0xd0:
|
||||
@@ -2298,7 +2418,10 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
|
||||
val = ldub(s->pc++);
|
||||
val &= 0x1f;
|
||||
if (val) {
|
||||
gen_op_shiftd_T0_T1_im_cc[ot - OT_WORD][op](val);
|
||||
if (mod == 3)
|
||||
gen_op_shiftd_T0_T1_im_cc[ot - OT_WORD][op](val);
|
||||
else
|
||||
gen_op_shiftd_mem_T0_T1_im_cc[ot - OT_WORD][op](val);
|
||||
if (op == 0 && ot != OT_WORD)
|
||||
s->cc_op = CC_OP_SHLB + ot;
|
||||
else
|
||||
@@ -2307,12 +2430,13 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
|
||||
} else {
|
||||
if (s->cc_op != CC_OP_DYNAMIC)
|
||||
gen_op_set_cc_op(s->cc_op);
|
||||
gen_op_shiftd_T0_T1_ECX_cc[ot - OT_WORD][op]();
|
||||
if (mod == 3)
|
||||
gen_op_shiftd_T0_T1_ECX_cc[ot - OT_WORD][op]();
|
||||
else
|
||||
gen_op_shiftd_mem_T0_T1_ECX_cc[ot - OT_WORD][op]();
|
||||
s->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */
|
||||
}
|
||||
if (mod != 3) {
|
||||
gen_op_st_T0_A0[ot]();
|
||||
} else {
|
||||
if (mod == 3) {
|
||||
gen_op_mov_reg_T0[ot][rm]();
|
||||
}
|
||||
break;
|
||||
@@ -2375,7 +2499,6 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
|
||||
|
||||
switch(op & 7) {
|
||||
case 0:
|
||||
gen_op_fpush();
|
||||
switch(op >> 4) {
|
||||
case 0:
|
||||
gen_op_flds_ST0_A0();
|
||||
@@ -2426,7 +2549,6 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
|
||||
gen_op_fnstcw_A0();
|
||||
break;
|
||||
case 0x1d: /* fldt mem */
|
||||
gen_op_fpush();
|
||||
gen_op_fldt_ST0_A0();
|
||||
break;
|
||||
case 0x1f: /* fstpt mem */
|
||||
@@ -2443,7 +2565,6 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
|
||||
gen_op_fnstsw_A0();
|
||||
break;
|
||||
case 0x3c: /* fbld */
|
||||
gen_op_fpush();
|
||||
gen_op_fbld_ST0_A0();
|
||||
break;
|
||||
case 0x3e: /* fbstp */
|
||||
@@ -2451,7 +2572,6 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
|
||||
gen_op_fpop();
|
||||
break;
|
||||
case 0x3d: /* fildll */
|
||||
gen_op_fpush();
|
||||
gen_op_fildll_ST0_A0();
|
||||
break;
|
||||
case 0x3f: /* fistpll */
|
||||
@@ -3170,6 +3290,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
|
||||
gen_op_st_T0_A0[ot]();
|
||||
else
|
||||
gen_op_mov_reg_T0[ot][rm]();
|
||||
gen_op_update_bt_cc();
|
||||
}
|
||||
break;
|
||||
case 0x1a3: /* bt Gv, Ev */
|
||||
@@ -3208,6 +3329,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
|
||||
gen_op_st_T0_A0[ot]();
|
||||
else
|
||||
gen_op_mov_reg_T0[ot][rm]();
|
||||
gen_op_update_bt_cc();
|
||||
}
|
||||
break;
|
||||
case 0x1bc: /* bsf */
|
||||
@@ -3299,12 +3421,14 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
|
||||
if (!s->vm86) {
|
||||
if (s->cpl <= s->iopl) {
|
||||
gen_op_sti();
|
||||
s->is_jmp = 2; /* give a chance to handle pending irqs */
|
||||
} else {
|
||||
gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
|
||||
}
|
||||
} else {
|
||||
if (s->iopl == 3) {
|
||||
gen_op_sti();
|
||||
s->is_jmp = 2; /* give a chance to handle pending irqs */
|
||||
} else {
|
||||
gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
|
||||
}
|
||||
@@ -3350,6 +3474,17 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
|
||||
gen_op_loop[s->aflag][b & 3](val, next_eip);
|
||||
s->is_jmp = 1;
|
||||
break;
|
||||
case 0x130: /* wrmsr */
|
||||
case 0x132: /* rdmsr */
|
||||
if (s->cpl != 0) {
|
||||
gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
|
||||
} else {
|
||||
if (b & 2)
|
||||
gen_op_rdmsr();
|
||||
else
|
||||
gen_op_wrmsr();
|
||||
}
|
||||
break;
|
||||
case 0x131: /* rdtsc */
|
||||
gen_op_rdtsc();
|
||||
break;
|
||||
@@ -3606,9 +3741,15 @@ static uint16_t opc_read_flags[NB_OPS] = {
|
||||
[INDEX_op_sbbw_T0_T1_cc] = CC_C,
|
||||
[INDEX_op_sbbl_T0_T1_cc] = CC_C,
|
||||
|
||||
[INDEX_op_adcb_mem_T0_T1_cc] = CC_C,
|
||||
[INDEX_op_adcw_mem_T0_T1_cc] = CC_C,
|
||||
[INDEX_op_adcl_mem_T0_T1_cc] = CC_C,
|
||||
[INDEX_op_sbbb_mem_T0_T1_cc] = CC_C,
|
||||
[INDEX_op_sbbw_mem_T0_T1_cc] = CC_C,
|
||||
[INDEX_op_sbbl_mem_T0_T1_cc] = CC_C,
|
||||
|
||||
/* subtle: due to the incl/decl implementation, C is used */
|
||||
[INDEX_op_incl_T0_cc] = CC_C,
|
||||
[INDEX_op_decl_T0_cc] = CC_C,
|
||||
[INDEX_op_update_inc_cc] = CC_C,
|
||||
|
||||
[INDEX_op_into] = CC_O,
|
||||
|
||||
@@ -3684,27 +3825,38 @@ static uint16_t opc_read_flags[NB_OPS] = {
|
||||
[INDEX_op_rcrb_T0_T1_cc] = CC_C,
|
||||
[INDEX_op_rcrw_T0_T1_cc] = CC_C,
|
||||
[INDEX_op_rcrl_T0_T1_cc] = CC_C,
|
||||
|
||||
[INDEX_op_rclb_mem_T0_T1_cc] = CC_C,
|
||||
[INDEX_op_rclw_mem_T0_T1_cc] = CC_C,
|
||||
[INDEX_op_rcll_mem_T0_T1_cc] = CC_C,
|
||||
[INDEX_op_rcrb_mem_T0_T1_cc] = CC_C,
|
||||
[INDEX_op_rcrw_mem_T0_T1_cc] = CC_C,
|
||||
[INDEX_op_rcrl_mem_T0_T1_cc] = CC_C,
|
||||
};
|
||||
|
||||
/* flags written by an operation */
|
||||
static uint16_t opc_write_flags[NB_OPS] = {
|
||||
[INDEX_op_addl_T0_T1_cc] = CC_OSZAPC,
|
||||
[INDEX_op_orl_T0_T1_cc] = CC_OSZAPC,
|
||||
[INDEX_op_update2_cc] = CC_OSZAPC,
|
||||
[INDEX_op_update1_cc] = CC_OSZAPC,
|
||||
[INDEX_op_cmpl_T0_T1_cc] = CC_OSZAPC,
|
||||
[INDEX_op_update_neg_cc] = CC_OSZAPC,
|
||||
/* subtle: due to the incl/decl implementation, C is used */
|
||||
[INDEX_op_update_inc_cc] = CC_OSZAPC,
|
||||
[INDEX_op_testl_T0_T1_cc] = CC_OSZAPC,
|
||||
|
||||
[INDEX_op_adcb_T0_T1_cc] = CC_OSZAPC,
|
||||
[INDEX_op_adcw_T0_T1_cc] = CC_OSZAPC,
|
||||
[INDEX_op_adcl_T0_T1_cc] = CC_OSZAPC,
|
||||
[INDEX_op_sbbb_T0_T1_cc] = CC_OSZAPC,
|
||||
[INDEX_op_sbbw_T0_T1_cc] = CC_OSZAPC,
|
||||
[INDEX_op_sbbl_T0_T1_cc] = CC_OSZAPC,
|
||||
[INDEX_op_andl_T0_T1_cc] = CC_OSZAPC,
|
||||
[INDEX_op_subl_T0_T1_cc] = CC_OSZAPC,
|
||||
[INDEX_op_xorl_T0_T1_cc] = CC_OSZAPC,
|
||||
[INDEX_op_cmpl_T0_T1_cc] = CC_OSZAPC,
|
||||
[INDEX_op_negl_T0_cc] = CC_OSZAPC,
|
||||
/* subtle: due to the incl/decl implementation, C is used */
|
||||
[INDEX_op_incl_T0_cc] = CC_OSZAPC,
|
||||
[INDEX_op_decl_T0_cc] = CC_OSZAPC,
|
||||
[INDEX_op_testl_T0_T1_cc] = CC_OSZAPC,
|
||||
|
||||
[INDEX_op_adcb_mem_T0_T1_cc] = CC_OSZAPC,
|
||||
[INDEX_op_adcw_mem_T0_T1_cc] = CC_OSZAPC,
|
||||
[INDEX_op_adcl_mem_T0_T1_cc] = CC_OSZAPC,
|
||||
[INDEX_op_sbbb_mem_T0_T1_cc] = CC_OSZAPC,
|
||||
[INDEX_op_sbbw_mem_T0_T1_cc] = CC_OSZAPC,
|
||||
[INDEX_op_sbbl_mem_T0_T1_cc] = CC_OSZAPC,
|
||||
|
||||
[INDEX_op_mulb_AL_T0] = CC_OSZAPC,
|
||||
[INDEX_op_imulb_AL_T0] = CC_OSZAPC,
|
||||
@@ -3766,6 +3918,42 @@ static uint16_t opc_write_flags[NB_OPS] = {
|
||||
[INDEX_op_shrdw_T0_T1_im_cc] = CC_OSZAPC,
|
||||
[INDEX_op_shrdl_T0_T1_im_cc] = CC_OSZAPC,
|
||||
|
||||
[INDEX_op_rolb_mem_T0_T1_cc] = CC_O | CC_C,
|
||||
[INDEX_op_rolw_mem_T0_T1_cc] = CC_O | CC_C,
|
||||
[INDEX_op_roll_mem_T0_T1_cc] = CC_O | CC_C,
|
||||
[INDEX_op_rorb_mem_T0_T1_cc] = CC_O | CC_C,
|
||||
[INDEX_op_rorw_mem_T0_T1_cc] = CC_O | CC_C,
|
||||
[INDEX_op_rorl_mem_T0_T1_cc] = CC_O | CC_C,
|
||||
|
||||
[INDEX_op_rclb_mem_T0_T1_cc] = CC_O | CC_C,
|
||||
[INDEX_op_rclw_mem_T0_T1_cc] = CC_O | CC_C,
|
||||
[INDEX_op_rcll_mem_T0_T1_cc] = CC_O | CC_C,
|
||||
[INDEX_op_rcrb_mem_T0_T1_cc] = CC_O | CC_C,
|
||||
[INDEX_op_rcrw_mem_T0_T1_cc] = CC_O | CC_C,
|
||||
[INDEX_op_rcrl_mem_T0_T1_cc] = CC_O | CC_C,
|
||||
|
||||
[INDEX_op_shlb_mem_T0_T1_cc] = CC_OSZAPC,
|
||||
[INDEX_op_shlw_mem_T0_T1_cc] = CC_OSZAPC,
|
||||
[INDEX_op_shll_mem_T0_T1_cc] = CC_OSZAPC,
|
||||
|
||||
[INDEX_op_shrb_mem_T0_T1_cc] = CC_OSZAPC,
|
||||
[INDEX_op_shrw_mem_T0_T1_cc] = CC_OSZAPC,
|
||||
[INDEX_op_shrl_mem_T0_T1_cc] = CC_OSZAPC,
|
||||
|
||||
[INDEX_op_sarb_mem_T0_T1_cc] = CC_OSZAPC,
|
||||
[INDEX_op_sarw_mem_T0_T1_cc] = CC_OSZAPC,
|
||||
[INDEX_op_sarl_mem_T0_T1_cc] = CC_OSZAPC,
|
||||
|
||||
[INDEX_op_shldw_mem_T0_T1_ECX_cc] = CC_OSZAPC,
|
||||
[INDEX_op_shldl_mem_T0_T1_ECX_cc] = CC_OSZAPC,
|
||||
[INDEX_op_shldw_mem_T0_T1_im_cc] = CC_OSZAPC,
|
||||
[INDEX_op_shldl_mem_T0_T1_im_cc] = CC_OSZAPC,
|
||||
|
||||
[INDEX_op_shrdw_mem_T0_T1_ECX_cc] = CC_OSZAPC,
|
||||
[INDEX_op_shrdl_mem_T0_T1_ECX_cc] = CC_OSZAPC,
|
||||
[INDEX_op_shrdw_mem_T0_T1_im_cc] = CC_OSZAPC,
|
||||
[INDEX_op_shrdl_mem_T0_T1_im_cc] = CC_OSZAPC,
|
||||
|
||||
[INDEX_op_btw_T0_T1_cc] = CC_OSZAPC,
|
||||
[INDEX_op_btl_T0_T1_cc] = CC_OSZAPC,
|
||||
[INDEX_op_btsw_T0_T1_cc] = CC_OSZAPC,
|
||||
@@ -3803,6 +3991,10 @@ static uint16_t opc_write_flags[NB_OPS] = {
|
||||
[INDEX_op_cmpxchgw_T0_T1_EAX_cc] = CC_OSZAPC,
|
||||
[INDEX_op_cmpxchgl_T0_T1_EAX_cc] = CC_OSZAPC,
|
||||
|
||||
[INDEX_op_cmpxchgb_mem_T0_T1_EAX_cc] = CC_OSZAPC,
|
||||
[INDEX_op_cmpxchgw_mem_T0_T1_EAX_cc] = CC_OSZAPC,
|
||||
[INDEX_op_cmpxchgl_mem_T0_T1_EAX_cc] = CC_OSZAPC,
|
||||
|
||||
[INDEX_op_cmpxchg8b] = CC_Z,
|
||||
[INDEX_op_lar] = CC_Z,
|
||||
[INDEX_op_lsl] = CC_Z,
|
||||
@@ -3812,15 +4004,13 @@ static uint16_t opc_write_flags[NB_OPS] = {
|
||||
|
||||
/* simpler form of an operation if no flags need to be generated */
|
||||
static uint16_t opc_simpler[NB_OPS] = {
|
||||
[INDEX_op_addl_T0_T1_cc] = INDEX_op_addl_T0_T1,
|
||||
[INDEX_op_orl_T0_T1_cc] = INDEX_op_orl_T0_T1,
|
||||
[INDEX_op_andl_T0_T1_cc] = INDEX_op_andl_T0_T1,
|
||||
[INDEX_op_subl_T0_T1_cc] = INDEX_op_subl_T0_T1,
|
||||
[INDEX_op_xorl_T0_T1_cc] = INDEX_op_xorl_T0_T1,
|
||||
[INDEX_op_negl_T0_cc] = INDEX_op_negl_T0,
|
||||
[INDEX_op_incl_T0_cc] = INDEX_op_incl_T0,
|
||||
[INDEX_op_decl_T0_cc] = INDEX_op_decl_T0,
|
||||
|
||||
[INDEX_op_update2_cc] = INDEX_op_nop,
|
||||
[INDEX_op_update1_cc] = INDEX_op_nop,
|
||||
[INDEX_op_update_neg_cc] = INDEX_op_nop,
|
||||
#if 0
|
||||
/* broken: CC_OP logic must be rewritten */
|
||||
[INDEX_op_update_inc_cc] = INDEX_op_nop,
|
||||
#endif
|
||||
[INDEX_op_rolb_T0_T1_cc] = INDEX_op_rolb_T0_T1,
|
||||
[INDEX_op_rolw_T0_T1_cc] = INDEX_op_rolw_T0_T1,
|
||||
[INDEX_op_roll_T0_T1_cc] = INDEX_op_roll_T0_T1,
|
||||
@@ -3829,6 +4019,14 @@ static uint16_t opc_simpler[NB_OPS] = {
|
||||
[INDEX_op_rorw_T0_T1_cc] = INDEX_op_rorw_T0_T1,
|
||||
[INDEX_op_rorl_T0_T1_cc] = INDEX_op_rorl_T0_T1,
|
||||
|
||||
[INDEX_op_rolb_mem_T0_T1_cc] = INDEX_op_rolb_mem_T0_T1,
|
||||
[INDEX_op_rolw_mem_T0_T1_cc] = INDEX_op_rolw_mem_T0_T1,
|
||||
[INDEX_op_roll_mem_T0_T1_cc] = INDEX_op_roll_mem_T0_T1,
|
||||
|
||||
[INDEX_op_rorb_mem_T0_T1_cc] = INDEX_op_rorb_mem_T0_T1,
|
||||
[INDEX_op_rorw_mem_T0_T1_cc] = INDEX_op_rorw_mem_T0_T1,
|
||||
[INDEX_op_rorl_mem_T0_T1_cc] = INDEX_op_rorl_mem_T0_T1,
|
||||
|
||||
[INDEX_op_shlb_T0_T1_cc] = INDEX_op_shlb_T0_T1,
|
||||
[INDEX_op_shlw_T0_T1_cc] = INDEX_op_shlw_T0_T1,
|
||||
[INDEX_op_shll_T0_T1_cc] = INDEX_op_shll_T0_T1,
|
||||
@@ -3946,6 +4144,10 @@ static inline int gen_intermediate_code_internal(TranslationBlock *tb, int searc
|
||||
break;
|
||||
} while (!dc->is_jmp && gen_opc_ptr < gen_opc_end &&
|
||||
(pc_ptr - pc_start) < (TARGET_PAGE_SIZE - 32));
|
||||
if (!dc->tf && dc->is_jmp == DISAS_NEXT) {
|
||||
gen_jmp(dc, ret - (unsigned long)dc->cs_base);
|
||||
}
|
||||
|
||||
/* we must store the eflags state if it is not already done */
|
||||
if (dc->is_jmp != DISAS_TB_JUMP) {
|
||||
if (dc->cc_op != CC_OP_DYNAMIC)
|
||||
@@ -3958,12 +4160,19 @@ static inline int gen_intermediate_code_internal(TranslationBlock *tb, int searc
|
||||
if (dc->tf) {
|
||||
gen_op_raise_exception(EXCP01_SSTP);
|
||||
}
|
||||
if (dc->is_jmp != 3) {
|
||||
if (dc->is_jmp != DISAS_TB_JUMP) {
|
||||
/* indicate that the hash table must be used to find the next TB */
|
||||
gen_op_movl_T0_0();
|
||||
}
|
||||
*gen_opc_ptr = INDEX_op_end;
|
||||
|
||||
/* we don't forget to fill the last values */
|
||||
if (search_pc) {
|
||||
j = gen_opc_ptr - gen_opc_buf;
|
||||
lj++;
|
||||
while (lj <= j)
|
||||
gen_opc_instr_start[lj++] = 0;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_DISAS
|
||||
if (loglevel) {
|
||||
fprintf(logfile, "----------------\n");
|
||||
@@ -4079,7 +4288,7 @@ void cpu_x86_update_cr0(CPUX86State *env)
|
||||
void cpu_x86_update_cr3(CPUX86State *env)
|
||||
{
|
||||
if (env->cr[0] & CR0_PG_MASK) {
|
||||
#ifdef DEBUG_MMU
|
||||
#if defined(DEBUG_MMU)
|
||||
printf("CR3 update: CR3=%08x\n", env->cr[3]);
|
||||
#endif
|
||||
page_unmap();
|
||||
|
||||
+12
-1
@@ -179,7 +179,18 @@ int cpu_restore_state(TranslationBlock *tb,
|
||||
#if defined(TARGET_I386)
|
||||
{
|
||||
int cc_op;
|
||||
|
||||
#ifdef DEBUG_DISAS
|
||||
if (loglevel) {
|
||||
int i;
|
||||
for(i=0;i<=j; i++) {
|
||||
if (gen_opc_instr_start[i]) {
|
||||
fprintf(logfile, "0x%04x: 0x%08x", i, gen_opc_pc[i]);
|
||||
}
|
||||
}
|
||||
fprintf(logfile, "j=0x%x eip=0x%lx cs_base=%lx\n",
|
||||
j, gen_opc_pc[j] - tb->cs_base, tb->cs_base);
|
||||
}
|
||||
#endif
|
||||
env->eip = gen_opc_pc[j] - tb->cs_base;
|
||||
cc_op = gen_opc_cc_op[j];
|
||||
if (cc_op != CC_OP_DYNAMIC)
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* QEMU System Emulator header
|
||||
*
|
||||
* Copyright (c) 2003 Fabrice Bellard
|
||||
*
|
||||
* 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 VL_H
|
||||
#define VL_H
|
||||
|
||||
/* vl.c */
|
||||
void *get_mmap_addr(unsigned long size);
|
||||
|
||||
/* block.c */
|
||||
typedef struct BlockDriverState BlockDriverState;
|
||||
|
||||
BlockDriverState *bdrv_open(const char *filename, int snapshot);
|
||||
void bdrv_close(BlockDriverState *bs);
|
||||
int bdrv_read(BlockDriverState *bs, int64_t sector_num,
|
||||
uint8_t *buf, int nb_sectors);
|
||||
int bdrv_write(BlockDriverState *bs, int64_t sector_num,
|
||||
const uint8_t *buf, int nb_sectors);
|
||||
void bdrv_get_geometry(BlockDriverState *bs, int64_t *nb_sectors_ptr);
|
||||
int bdrv_commit(BlockDriverState *bs);
|
||||
|
||||
/* user mode linux compatible COW file */
|
||||
#define COW_MAGIC 0x4f4f4f4d /* MOOO */
|
||||
#define COW_VERSION 2
|
||||
|
||||
struct cow_header_v2 {
|
||||
uint32_t magic;
|
||||
uint32_t long version;
|
||||
char backing_file[1024];
|
||||
int32_t mtime;
|
||||
uint64_t size;
|
||||
uint32_t sectorsize;
|
||||
};
|
||||
|
||||
#endif /* VL_H */
|
||||
@@ -0,0 +1,143 @@
|
||||
/*
|
||||
* create a COW disk image
|
||||
*
|
||||
* Copyright (c) 2003 Fabrice Bellard
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <getopt.h>
|
||||
#include <inttypes.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/mman.h>
|
||||
#include <fcntl.h>
|
||||
#include <signal.h>
|
||||
#include <time.h>
|
||||
#include <sys/time.h>
|
||||
#include <malloc.h>
|
||||
#include <termios.h>
|
||||
#include <sys/poll.h>
|
||||
#include <errno.h>
|
||||
#include <sys/wait.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
#include "vl.h"
|
||||
|
||||
#define NO_THUNK_TYPE_SIZE
|
||||
#include "thunk.h"
|
||||
|
||||
int cow_create(int cow_fd, const char *image_filename,
|
||||
int64_t image_sectors)
|
||||
{
|
||||
struct cow_header_v2 cow_header;
|
||||
int fd;
|
||||
struct stat st;
|
||||
|
||||
memset(&cow_header, 0, sizeof(cow_header));
|
||||
cow_header.magic = htonl(COW_MAGIC);
|
||||
cow_header.version = htonl(COW_VERSION);
|
||||
if (image_filename) {
|
||||
fd = open(image_filename, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
perror(image_filename);
|
||||
exit(1);
|
||||
}
|
||||
image_sectors = lseek64(fd, 0, SEEK_END);
|
||||
if (fstat(fd, &st) != 0) {
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
close(fd);
|
||||
image_sectors /= 512;
|
||||
cow_header.mtime = htonl(st.st_mtime);
|
||||
realpath(image_filename, cow_header.backing_file);
|
||||
}
|
||||
cow_header.sectorsize = htonl(512);
|
||||
cow_header.size = image_sectors * 512;
|
||||
#ifndef WORDS_BIGENDIAN
|
||||
cow_header.size = bswap64(cow_header.size);
|
||||
#endif
|
||||
write(cow_fd, &cow_header, sizeof(cow_header));
|
||||
/* resize to include at least all the bitmap */
|
||||
ftruncate(cow_fd, sizeof(cow_header) + ((image_sectors + 7) >> 3));
|
||||
lseek(cow_fd, 0, SEEK_SET);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void help(void)
|
||||
{
|
||||
printf("vlmkcow version " QEMU_VERSION ", Copyright (c) 2003 Fabrice Bellard\n"
|
||||
"usage: vlmkcow [-h] [-f disk_image] cow_image [cow_size]\n"
|
||||
"Create a Copy On Write disk image from an optional raw disk image\n"
|
||||
"\n"
|
||||
"-f disk_image set the raw disk image name\n"
|
||||
"cow_image the created cow_image\n"
|
||||
"cow_size the create cow_image size in MB if no raw disk image is used\n"
|
||||
"\n"
|
||||
"Once the cow_image is created from a raw disk image, you must not modify the original raw disk image\n"
|
||||
);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
const char *image_filename, *cow_filename;
|
||||
int cow_fd, c, nb_args;
|
||||
int64_t image_size;
|
||||
|
||||
image_filename = NULL;
|
||||
image_size = 0;
|
||||
for(;;) {
|
||||
c = getopt(argc, argv, "hf:");
|
||||
if (c == -1)
|
||||
break;
|
||||
switch(c) {
|
||||
case 'h':
|
||||
help();
|
||||
break;
|
||||
case 'f':
|
||||
image_filename = optarg;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!image_filename)
|
||||
nb_args = 2;
|
||||
else
|
||||
nb_args = 1;
|
||||
if (optind + nb_args != argc)
|
||||
help();
|
||||
|
||||
cow_filename = argv[optind];
|
||||
if (nb_args == 2) {
|
||||
image_size = (int64_t)atoi(argv[optind + 1]) * 2 * 1024;
|
||||
}
|
||||
|
||||
cow_fd = open(cow_filename, O_RDWR | O_CREAT | O_TRUNC, 0644);
|
||||
if (!cow_fd < 0)
|
||||
return -1;
|
||||
if (cow_create(cow_fd, image_filename, image_size) < 0) {
|
||||
fprintf(stderr, "%s: error while formating\n", cow_filename);
|
||||
exit(1);
|
||||
}
|
||||
close(cow_fd);
|
||||
return 0;
|
||||
}
|
||||
Reference in new issue
Block a user