mirror of
https://github.com/mborgerson/xemu.git
synced 2025-12-01 16:10:01 +00:00
added minimal segment support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@28 c046a42c-6fe2-441c-8c8c-71466251a162
This commit is contained in:
@ -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],
|
||||
|
||||
@ -48,7 +48,7 @@ int elf_exec(const char * filename, char ** argv, char ** envp,
|
||||
|
||||
void target_set_brk(char *new_brk);
|
||||
void syscall_init(void);
|
||||
long do_syscall(int num, long arg1, long arg2, long arg3,
|
||||
long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
|
||||
long arg4, long arg5, long arg6);
|
||||
void gemu_log(const char *fmt, ...) __attribute__((format(printf,1,2)));
|
||||
|
||||
|
||||
@ -69,6 +69,7 @@ struct dirent {
|
||||
#include "syscall_defs.h"
|
||||
|
||||
#ifdef TARGET_I386
|
||||
#include "cpu-i386.h"
|
||||
#include "syscall-i386.h"
|
||||
#endif
|
||||
|
||||
@ -607,6 +608,124 @@ StructEntry struct_termios_def = {
|
||||
.align = { __alignof__(struct target_termios), __alignof__(struct host_termios) },
|
||||
};
|
||||
|
||||
#ifdef TARGET_I386
|
||||
|
||||
/* NOTE: there is really one LDT for all the threads */
|
||||
uint8_t *ldt_table;
|
||||
|
||||
static int read_ldt(void *ptr, unsigned long bytecount)
|
||||
{
|
||||
int size;
|
||||
|
||||
if (!ldt_table)
|
||||
return 0;
|
||||
size = TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE;
|
||||
if (size > bytecount)
|
||||
size = bytecount;
|
||||
memcpy(ptr, ldt_table, size);
|
||||
return size;
|
||||
}
|
||||
|
||||
/* XXX: add locking support */
|
||||
static int write_ldt(CPUX86State *env,
|
||||
void *ptr, unsigned long bytecount, int oldmode)
|
||||
{
|
||||
struct target_modify_ldt_ldt_s ldt_info;
|
||||
int seg_32bit, contents, read_exec_only, limit_in_pages;
|
||||
int seg_not_present, useable;
|
||||
uint32_t *lp, entry_1, entry_2;
|
||||
|
||||
if (bytecount != sizeof(ldt_info))
|
||||
return -EINVAL;
|
||||
memcpy(&ldt_info, ptr, sizeof(ldt_info));
|
||||
tswap32s(&ldt_info.entry_number);
|
||||
tswapls((long *)&ldt_info.base_addr);
|
||||
tswap32s(&ldt_info.limit);
|
||||
tswap32s(&ldt_info.flags);
|
||||
|
||||
if (ldt_info.entry_number >= TARGET_LDT_ENTRIES)
|
||||
return -EINVAL;
|
||||
seg_32bit = ldt_info.flags & 1;
|
||||
contents = (ldt_info.flags >> 1) & 3;
|
||||
read_exec_only = (ldt_info.flags >> 3) & 1;
|
||||
limit_in_pages = (ldt_info.flags >> 4) & 1;
|
||||
seg_not_present = (ldt_info.flags >> 5) & 1;
|
||||
useable = (ldt_info.flags >> 6) & 1;
|
||||
|
||||
if (contents == 3) {
|
||||
if (oldmode)
|
||||
return -EINVAL;
|
||||
if (seg_not_present == 0)
|
||||
return -EINVAL;
|
||||
}
|
||||
/* allocate the LDT */
|
||||
if (!ldt_table) {
|
||||
ldt_table = malloc(TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE);
|
||||
if (!ldt_table)
|
||||
return -ENOMEM;
|
||||
memset(ldt_table, 0, TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE);
|
||||
env->ldt.base = ldt_table;
|
||||
env->ldt.limit = 0xffff;
|
||||
}
|
||||
|
||||
/* NOTE: same code as Linux kernel */
|
||||
/* Allow LDTs to be cleared by the user. */
|
||||
if (ldt_info.base_addr == 0 && ldt_info.limit == 0) {
|
||||
if (oldmode ||
|
||||
(contents == 0 &&
|
||||
read_exec_only == 1 &&
|
||||
seg_32bit == 0 &&
|
||||
limit_in_pages == 0 &&
|
||||
seg_not_present == 1 &&
|
||||
useable == 0 )) {
|
||||
entry_1 = 0;
|
||||
entry_2 = 0;
|
||||
goto install;
|
||||
}
|
||||
}
|
||||
|
||||
entry_1 = ((ldt_info.base_addr & 0x0000ffff) << 16) |
|
||||
(ldt_info.limit & 0x0ffff);
|
||||
entry_2 = (ldt_info.base_addr & 0xff000000) |
|
||||
((ldt_info.base_addr & 0x00ff0000) >> 16) |
|
||||
(ldt_info.limit & 0xf0000) |
|
||||
((read_exec_only ^ 1) << 9) |
|
||||
(contents << 10) |
|
||||
((seg_not_present ^ 1) << 15) |
|
||||
(seg_32bit << 22) |
|
||||
(limit_in_pages << 23) |
|
||||
0x7000;
|
||||
if (!oldmode)
|
||||
entry_2 |= (useable << 20);
|
||||
|
||||
/* Install the new entry ... */
|
||||
install:
|
||||
lp = (uint32_t *)(ldt_table + (ldt_info.entry_number << 3));
|
||||
lp[0] = tswap32(entry_1);
|
||||
lp[1] = tswap32(entry_2);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* specific and weird i386 syscalls */
|
||||
int gemu_modify_ldt(CPUX86State *env, int func, void *ptr, unsigned long bytecount)
|
||||
{
|
||||
int ret = -ENOSYS;
|
||||
|
||||
switch (func) {
|
||||
case 0:
|
||||
ret = read_ldt(ptr, bytecount);
|
||||
break;
|
||||
case 1:
|
||||
ret = write_ldt(env, ptr, bytecount, 1);
|
||||
break;
|
||||
case 0x11:
|
||||
ret = write_ldt(env, ptr, bytecount, 0);
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
void syscall_init(void)
|
||||
{
|
||||
#define STRUCT(name, list...) thunk_register_struct(STRUCT_ ## name, #name, struct_ ## name ## _def);
|
||||
@ -616,7 +735,7 @@ void syscall_init(void)
|
||||
#undef STRUCT_SPECIAL
|
||||
}
|
||||
|
||||
long do_syscall(int num, long arg1, long arg2, long arg3,
|
||||
long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
|
||||
long arg4, long arg5, long arg6)
|
||||
{
|
||||
long ret;
|
||||
@ -1095,8 +1214,11 @@ long do_syscall(int num, long arg1, long arg2, long arg3,
|
||||
/* no need to transcode because we use the linux syscall */
|
||||
ret = get_errno(sys_uname((struct new_utsname *)arg1));
|
||||
break;
|
||||
#ifdef TARGET_I386
|
||||
case TARGET_NR_modify_ldt:
|
||||
goto unimplemented;
|
||||
ret = get_errno(gemu_modify_ldt(cpu_env, arg1, (void *)arg2, arg3));
|
||||
break;
|
||||
#endif
|
||||
case TARGET_NR_adjtimex:
|
||||
goto unimplemented;
|
||||
case TARGET_NR_mprotect:
|
||||
|
||||
@ -61,4 +61,3 @@ STRUCT(cdrom_read_audio,
|
||||
|
||||
STRUCT(hd_geometry,
|
||||
TYPE_CHAR, TYPE_CHAR, TYPE_SHORT, TYPE_ULONG)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user