diff options
author | bellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162> | 2003-03-16 18:05:05 +0000 |
---|---|---|
committer | bellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162> | 2003-03-16 18:05:05 +0000 |
commit | 6dbad63eef5947c6c8750e44f408138779b6d0bb (patch) | |
tree | e96572a87e9adb75efde4cd9213472f1903ec742 /linux-user/main.c | |
parent | 27362c82e9df7770554943ceda36ec4e5638c49d (diff) |
added minimal segment support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@28 c046a42c-6fe2-441c-8c8c-71466251a162
Diffstat (limited to 'linux-user/main.c')
-rw-r--r-- | linux-user/main.c | 58 |
1 files changed, 38 insertions, 20 deletions
diff --git a/linux-user/main.c b/linux-user/main.c index 6aefe3afb6..b59c85d9c5 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -1,5 +1,5 @@ /* - * emu main + * gemu main * * Copyright (c) 2003 Fabrice Bellard * @@ -80,10 +80,28 @@ int cpu_x86_inl(int addr) return 0; } +/* default linux values for the selectors */ +#define __USER_CS (0x23) +#define __USER_DS (0x2B) -/* XXX: currently we use LDT entries */ -#define __USER_CS (0x23|4) -#define __USER_DS (0x2B|4) +void write_dt(void *ptr, unsigned long addr, unsigned long limit, + int seg32_bit) +{ + unsigned int e1, e2, limit_in_pages; + limit_in_pages = 0; + if (limit > 0xffff) { + limit = limit >> 12; + limit_in_pages = 1; + } + e1 = (addr << 16) | (limit & 0xffff); + e2 = ((addr >> 16) & 0xff) | (addr & 0xff000000) | (limit & 0x000f0000); + e2 |= limit_in_pages << 23; /* byte granularity */ + e2 |= seg32_bit << 22; /* 32 bit segment */ + stl((uint8_t *)ptr, e1); + stl((uint8_t *)ptr + 4, e2); +} + +uint64_t gdt_table[6]; void usage(void) { @@ -94,6 +112,8 @@ void usage(void) exit(1); } + + int main(int argc, char **argv) { const char *filename; @@ -149,6 +169,7 @@ int main(int argc, char **argv) env = cpu_x86_init(); + /* linux register setup */ env->regs[R_EAX] = regs->eax; env->regs[R_EBX] = regs->ebx; env->regs[R_ECX] = regs->ecx; @@ -157,23 +178,19 @@ 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->segs[R_CS] = __USER_CS; - env->segs[R_DS] = __USER_DS; - env->segs[R_ES] = __USER_DS; - env->segs[R_SS] = __USER_DS; - env->segs[R_FS] = __USER_DS; - env->segs[R_GS] = __USER_DS; env->pc = regs->eip; -#if 0 - LDT[__USER_CS >> 3].w86Flags = DF_PRESENT | DF_PAGES | DF_32; - LDT[__USER_CS >> 3].dwSelLimit = 0xfffff; - LDT[__USER_CS >> 3].lpSelBase = NULL; - - LDT[__USER_DS >> 3].w86Flags = DF_PRESENT | DF_PAGES | DF_32; - LDT[__USER_DS >> 3].dwSelLimit = 0xfffff; - LDT[__USER_DS >> 3].lpSelBase = NULL; -#endif + /* linux segment setup */ + env->gdt.base = (void *)gdt_table; + env->gdt.limit = sizeof(gdt_table) - 1; + write_dt(&gdt_table[__USER_CS >> 3], 0, 0xffffffff, 1); + write_dt(&gdt_table[__USER_DS >> 3], 0, 0xffffffff, 1); + cpu_x86_load_seg(env, R_CS, __USER_CS); + cpu_x86_load_seg(env, R_DS, __USER_DS); + cpu_x86_load_seg(env, R_ES, __USER_DS); + cpu_x86_load_seg(env, R_SS, __USER_DS); + cpu_x86_load_seg(env, R_FS, __USER_DS); + cpu_x86_load_seg(env, R_GS, __USER_DS); for(;;) { int err; @@ -186,7 +203,8 @@ int main(int argc, char **argv) if (pc[0] == 0xcd && pc[1] == 0x80) { /* syscall */ env->pc += 2; - env->regs[R_EAX] = do_syscall(env->regs[R_EAX], + env->regs[R_EAX] = do_syscall(env, + env->regs[R_EAX], env->regs[R_EBX], env->regs[R_ECX], env->regs[R_EDX], |