Skip to content

Commit

Permalink
better 16 bit code support
Browse files Browse the repository at this point in the history
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@38 c046a42c-6fe2-441c-8c8c-71466251a162
  • Loading branch information
bellard committed Mar 22, 2003
1 parent e591824 commit dab2ed9
Show file tree
Hide file tree
Showing 11 changed files with 595 additions and 216 deletions.
1 change: 1 addition & 0 deletions TODO
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
- overrides/16bit for string ops
- optimize translated cache chaining (DLL PLT-like system)
- 64 bit syscalls
- signals
Expand Down
10 changes: 6 additions & 4 deletions cpu-i386.h
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ typedef struct SegmentDescriptorTable {
typedef struct CPUX86State {
/* standard registers */
uint32_t regs[8];
uint32_t pc; /* cs_case + eip value */
uint32_t eip;
uint32_t eflags;

/* emulator internal eflags handling */
Expand Down Expand Up @@ -392,10 +392,12 @@ void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector);

#define GEN_FLAG_CODE32_SHIFT 0
#define GEN_FLAG_ADDSEG_SHIFT 1
#define GEN_FLAG_ST_SHIFT 2
#define GEN_FLAG_SS32_SHIFT 2
#define GEN_FLAG_ST_SHIFT 3

int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size,
int *gen_code_size_ptr, uint8_t *pc_start,
int flags);
int *gen_code_size_ptr,
uint8_t *pc_start, uint8_t *cs_base, int flags);
void cpu_x86_tblocks_init(void);

#endif /* CPU_I386_H */
17 changes: 12 additions & 5 deletions exec-i386.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@
#define CODE_GEN_HASH_SIZE (1 << CODE_GEN_HASH_BITS)

typedef struct TranslationBlock {
unsigned long pc; /* simulated PC corresponding to this block */
unsigned long pc; /* simulated PC corresponding to this block (EIP + CS base) */
unsigned long cs_base; /* CS base for this block */
unsigned int flags; /* flags defining in which context the code was generated */
uint8_t *tc_ptr; /* pointer to the translated code */
struct TranslationBlock *hash_next; /* next matching block */
Expand Down Expand Up @@ -140,6 +141,7 @@ static void tb_flush(void)
/* find a translation block in the translation cache. If not found,
allocate a new one */
static inline TranslationBlock *tb_find_and_alloc(unsigned long pc,
unsigned long cs_base,
unsigned int flags)
{
TranslationBlock **ptb, *tb;
Expand All @@ -151,7 +153,7 @@ static inline TranslationBlock *tb_find_and_alloc(unsigned long pc,
tb = *ptb;
if (!tb)
break;
if (tb->pc == pc && tb->flags == flags)
if (tb->pc == pc && tb->cs_base == cs_base && tb->flags == flags)
return tb;
ptb = &tb->hash_next;
}
Expand All @@ -161,6 +163,7 @@ static inline TranslationBlock *tb_find_and_alloc(unsigned long pc,
tb = &tbs[nb_tbs++];
*ptb = tb;
tb->pc = pc;
tb->cs_base = cs_base;
tb->flags = flags;
tb->tc_ptr = NULL;
tb->hash_next = NULL;
Expand Down Expand Up @@ -198,7 +201,7 @@ int cpu_x86_exec(CPUX86State *env1)
int code_gen_size, ret;
void (*gen_func)(void);
TranslationBlock *tb;
uint8_t *tc_ptr;
uint8_t *tc_ptr, *cs_base, *pc;
unsigned int flags;

/* first we save global registers */
Expand Down Expand Up @@ -251,17 +254,21 @@ int cpu_x86_exec(CPUX86State *env1)
/* we compute the CPU state. We assume it will not
change during the whole generated block. */
flags = env->seg_cache[R_CS].seg_32bit << GEN_FLAG_CODE32_SHIFT;
flags |= env->seg_cache[R_SS].seg_32bit << GEN_FLAG_SS32_SHIFT;
flags |= (((unsigned long)env->seg_cache[R_DS].base |
(unsigned long)env->seg_cache[R_ES].base |
(unsigned long)env->seg_cache[R_SS].base) != 0) <<
GEN_FLAG_ADDSEG_SHIFT;
tb = tb_find_and_alloc((unsigned long)env->pc, flags);
cs_base = env->seg_cache[R_CS].base;
pc = cs_base + env->eip;
tb = tb_find_and_alloc((unsigned long)pc, (unsigned long)cs_base,
flags);
tc_ptr = tb->tc_ptr;
if (!tb->tc_ptr) {
/* if no translated code available, then translate it now */
tc_ptr = code_gen_ptr;
cpu_x86_gen_code(code_gen_ptr, CODE_GEN_MAX_SIZE,
&code_gen_size, (uint8_t *)env->pc, flags);
&code_gen_size, pc, cs_base, flags);
tb->tc_ptr = tc_ptr;
code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1));
}
Expand Down
2 changes: 1 addition & 1 deletion exec-i386.h
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ register struct CPUX86State *env asm("l3");
#ifndef reg_EDI
#define EDI (env->regs[R_EDI])
#endif
#define PC (env->pc)
#define EIP (env->eip)
#define DF (env->df)

#define CC_SRC (env->cc_src)
Expand Down
8 changes: 4 additions & 4 deletions linux-user/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ int main(int argc, char **argv)
env->regs[R_EDI] = regs->edi;
env->regs[R_EBP] = regs->ebp;
env->regs[R_ESP] = regs->esp;
env->pc = regs->eip;
env->eip = regs->eip;

/* linux segment setup */
env->gdt.base = (void *)gdt_table;
Expand All @@ -198,12 +198,12 @@ int main(int argc, char **argv)
uint8_t *pc;

err = cpu_x86_exec(env);
pc = env->seg_cache[R_CS].base + env->eip;
switch(err) {
case EXCP0D_GPF:
pc = (uint8_t *)env->pc;
if (pc[0] == 0xcd && pc[1] == 0x80) {
/* syscall */
env->pc += 2;
env->eip += 2;
env->regs[R_EAX] = do_syscall(env,
env->regs[R_EAX],
env->regs[R_EBX],
Expand All @@ -219,7 +219,7 @@ int main(int argc, char **argv)
default:
trap_error:
fprintf(stderr, "0x%08lx: Unknown exception %d, aborting\n",
(long)env->pc, err);
(long)pc, err);
abort();
}
}
Expand Down
37 changes: 28 additions & 9 deletions linux-user/syscall.c
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
#include <linux/cdrom.h>
#include <linux/hdreg.h>
#include <linux/soundcard.h>
#include <linux/dirent.h>

#include "gemu.h"

Expand All @@ -63,13 +64,6 @@
#define PAGE_MASK ~(PAGE_SIZE - 1)
#endif

struct dirent {
long d_ino;
long d_off;
unsigned short d_reclen;
char d_name[256]; /* We must not include limits.h! */
};

//#include <linux/msdos_fs.h>
#define VFAT_IOCTL_READDIR_BOTH _IOR('r', 1, struct dirent [2])
#define VFAT_IOCTL_READDIR_SHORT _IOR('r', 2, struct dirent [2])
Expand All @@ -86,6 +80,7 @@ struct dirent {
#define __NR_sys_statfs __NR_statfs
#define __NR_sys_fstatfs __NR_fstatfs
#define __NR_sys_getdents __NR_getdents
#define __NR_sys_getdents64 __NR_getdents64

#ifdef __NR_gettid
_syscall0(int, gettid)
Expand All @@ -97,6 +92,7 @@ static int gettid(void) {
_syscall1(int,sys_uname,struct new_utsname *,buf)
_syscall2(int,sys_getcwd1,char *,buf,size_t,size)
_syscall3(int, sys_getdents, uint, fd, struct dirent *, dirp, uint, count);
_syscall3(int, sys_getdents64, uint, fd, struct dirent64 *, dirp, uint, count);
_syscall5(int, _llseek, uint, fd, ulong, hi, ulong, lo,
loff_t *, res, uint, wh);
_syscall2(int,sys_statfs,const char *,path,struct kernel_statfs *,buf)
Expand Down Expand Up @@ -1005,7 +1001,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
ret = get_errno(setsid());
break;
case TARGET_NR_sigaction:
#if 0
#if 1
{
ret = 0;
}
Expand Down Expand Up @@ -1336,6 +1332,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
{
struct dirent *dirp = (void *)arg2;
long count = arg3;

ret = get_errno(sys_getdents(arg1, dirp, count));
if (!is_error(ret)) {
struct dirent *de;
Expand All @@ -1355,6 +1352,29 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
}
}
break;
case TARGET_NR_getdents64:
{
struct dirent64 *dirp = (void *)arg2;
long count = arg3;
ret = get_errno(sys_getdents64(arg1, dirp, count));
if (!is_error(ret)) {
struct dirent64 *de;
int len = ret;
int reclen;
de = dirp;
while (len > 0) {
reclen = tswap16(de->d_reclen);
if (reclen > len)
break;
de->d_reclen = reclen;
tswap64s(&de->d_ino);
tswap64s(&de->d_off);
de = (struct dirent64 *)((char *)de + reclen);
len -= reclen;
}
}
}
break;
case TARGET_NR__newselect:
ret = do_select(arg1, (void *)arg2, (void *)arg3, (void *)arg4,
(void *)arg5);
Expand Down Expand Up @@ -1519,7 +1539,6 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
case TARGET_NR_pivot_root:
case TARGET_NR_mincore:
case TARGET_NR_madvise:
case TARGET_NR_getdents64:
goto unimplemented;
#if TARGET_LONG_BITS == 32
case TARGET_NR_fcntl64:
Expand Down
16 changes: 16 additions & 0 deletions linux-user/syscall_defs.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,22 @@ struct kernel_statfs {
int f_spare[6];
};

struct target_dirent {
target_long d_ino;
target_long d_off;
unsigned short d_reclen;
char d_name[256]; /* We must not include limits.h! */
};

struct target_dirent64 {
uint64_t d_ino;
int64_t d_off;
unsigned short d_reclen;
unsigned char d_type;
char d_name[256];
};


/* mostly generic signal stuff */
#define TARGET_SIG_DFL ((target_long)0) /* default signal handling */
#define TARGET_SIG_IGN ((target_long)1) /* ignore signal */
Expand Down
Loading

0 comments on commit dab2ed9

Please sign in to comment.