Compare commits

...
29 Commits
Author SHA1 Message Date
bellard 4690764bba update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@312 c046a42c-6fe2-441c-8c8c-71466251a162
2003-07-07 12:17:46 +00:00
bellard 3c1cf9fa86 dummy rdmsr and wrmsr support - xor reg, reg optimization
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@311 c046a42c-6fe2-441c-8c8c-71466251a162
2003-07-07 11:30:47 +00:00
bellard 1f47a9223e added disk image help
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@310 c046a42c-6fe2-441c-8c8c-71466251a162
2003-07-06 19:01:55 +00:00
bellard 33e3963e1b added user mode Linux Copy On Write disk image support - added -snapshot support (initial patch by Rusty Russell)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@309 c046a42c-6fe2-441c-8c8c-71466251a162
2003-07-06 17:15:21 +00:00
bellard cd4c3e888a added IDE WIN_READ_NATIVE_MAX command (2.5.xx fix) - added support for proper system shutdown
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@308 c046a42c-6fe2-441c-8c8c-71466251a162
2003-07-04 14:38:25 +00:00
bellard 7916e2245d allow up to 256 MB of ram
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@307 c046a42c-6fe2-441c-8c8c-71466251a162
2003-07-01 16:27:45 +00:00
bellard abd0aaff03 fixed date storage in CMOS
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@306 c046a42c-6fe2-441c-8c8c-71466251a162
2003-07-01 15:07:57 +00:00
bellard c39d5b78f6 make FPU load exception safe
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@305 c046a42c-6fe2-441c-8c8c-71466251a162
2003-07-01 15:07:14 +00:00
bellard 4d40895f2c more accurate bcd convert - fixed FPU exceptions
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@304 c046a42c-6fe2-441c-8c8c-71466251a162
2003-07-01 15:05:19 +00:00
bellard e477b8b81b correct eflags evaluation order for all operations - fixed important CPU state restoring bug in some exception cases - disabled unsafe inc flags optimisation
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@303 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-30 23:36:57 +00:00
bellard b118d61e55 added PIC debug
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@302 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-30 23:36:21 +00:00
bellard 2f62b397b5 dummy label to avoid gcc optimisations
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@301 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-30 23:18:59 +00:00
bellard 907a5b2690 fixed invalid irq jump chaining
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@300 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-30 23:18:22 +00:00
bellard 0849bf0821 allow read only images
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@299 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-30 23:17:31 +00:00
bellard 305034817d removed unused assignment
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@298 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-30 23:17:08 +00:00
bellard ec410fc9ce update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@297 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-30 23:16:33 +00:00
bellard 68a7931591 reduced irq latency
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@296 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-30 13:12:32 +00:00
bellard c9159e5321 added IDE mult support - reduced irq latency (IDE should have good performances now)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@295 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-30 13:06:39 +00:00
bellard 8c9b861e74 added block.c
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@294 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-30 10:12:19 +00:00
bellard 5797fa5d7e first step to fix precise eflags update in case of exception
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@293 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-30 10:11:50 +00:00
bellard 8ef9a8ece3 added nop operations
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@292 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-30 10:04:47 +00:00
bellard fc01f7e7f9 IDE emulation
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@291 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-30 10:03:06 +00:00
bellard 3b0dca51b0 gdb stub defines
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@290 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-27 18:52:23 +00:00
bellard da415d54bf gdb usage information
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@289 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-27 18:50:50 +00:00
bellard b4608c0455 added gdb support to vl
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@288 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-27 17:34:32 +00:00
bellard d5a0b50c6f update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@287 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-27 12:02:03 +00:00
bellard 87858c89ca more precise timer emulation - fixed NE2000 probe problems - added VLTMPDIR support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@286 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-27 12:01:39 +00:00
bellard a6f816d697 fixed endianness (Jocelyn Mayer)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@285 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-26 17:09:07 +00:00
bellard 0ad041d476 fixed inline pb
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@284 c046a42c-6fe2-441c-8c8c-71466251a162
2003-06-25 22:11:41 +00:00
29 changed files with 3400 additions and 824 deletions

No files matched your search

+16
View File
@@ -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
+11 -7
View File
@@ -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 \
+7 -6
View File
@@ -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
+1 -1
View File
@@ -1 +1 @@
0.4
0.4.2
+326
View File
@@ -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;
}
+11
View File
@@ -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 */
-1
View File
@@ -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
View File
@@ -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
View File
@@ -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);
+16
View File
@@ -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");
+2
View File
@@ -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);
+4 -3
View File
@@ -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;
+17
View File
@@ -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;
+390
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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);
}
}
+69 -51
View File
@@ -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
View File
@@ -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
View File
@@ -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 */
+423
View File
@@ -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
+2 -1
View File
@@ -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
View File
@@ -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.
+3
View File
@@ -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
View File
@@ -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, &reg_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, &reg_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, &reg_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, &reg_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, &reg_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, &reg_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, &reg_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
View File
@@ -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)
+1158 -192
View File
File diff suppressed because it is too large. Load diff
+55
View File
@@ -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 */
+143
View File
@@ -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;
}