Commit 851e67a1b46ff7999a7585d682f8add983e82fc9
1 parent
fc2b4c48
primitive vm86 support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@57 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
2 changed files
with
117 additions
and
18 deletions
linux-user/main.c
... | ... | @@ -104,35 +104,99 @@ void write_dt(void *ptr, unsigned long addr, unsigned long limit, |
104 | 104 | |
105 | 105 | uint64_t gdt_table[6]; |
106 | 106 | |
107 | +//#define DEBUG_VM86 | |
108 | + | |
107 | 109 | void cpu_loop(struct CPUX86State *env) |
108 | 110 | { |
109 | 111 | int err; |
110 | 112 | uint8_t *pc; |
111 | 113 | target_siginfo_t info; |
112 | - | |
114 | + | |
113 | 115 | for(;;) { |
114 | 116 | err = cpu_x86_exec(env); |
115 | 117 | pc = env->seg_cache[R_CS].base + env->eip; |
116 | 118 | switch(err) { |
117 | 119 | case EXCP0D_GPF: |
118 | - if (pc[0] == 0xcd && pc[1] == 0x80) { | |
119 | - /* syscall */ | |
120 | - env->eip += 2; | |
121 | - env->regs[R_EAX] = do_syscall(env, | |
122 | - env->regs[R_EAX], | |
123 | - env->regs[R_EBX], | |
124 | - env->regs[R_ECX], | |
125 | - env->regs[R_EDX], | |
126 | - env->regs[R_ESI], | |
127 | - env->regs[R_EDI], | |
128 | - env->regs[R_EBP]); | |
120 | + if (env->eflags & VM_MASK) { | |
121 | + TaskState *ts; | |
122 | + int ret; | |
123 | +#ifdef DEBUG_VM86 | |
124 | + printf("VM86 exception %04x:%08x %02x\n", | |
125 | + env->segs[R_CS], env->eip, pc[0]); | |
126 | +#endif | |
127 | + /* VM86 mode */ | |
128 | + ts = env->opaque; | |
129 | + | |
130 | + /* XXX: add all cases */ | |
131 | + switch(pc[0]) { | |
132 | + case 0xcd: /* int */ | |
133 | + env->eip += 2; | |
134 | + ret = TARGET_VM86_INTx | (pc[1] << 8); | |
135 | + break; | |
136 | + default: | |
137 | + /* real VM86 GPF exception */ | |
138 | + ret = TARGET_VM86_UNKNOWN; | |
139 | + break; | |
140 | + } | |
141 | +#ifdef DEBUG_VM86 | |
142 | + printf("ret=0x%x\n", ret); | |
143 | +#endif | |
144 | + /* put the VM86 registers in the userspace register structure */ | |
145 | + ts->target_v86->regs.eax = tswap32(env->regs[R_EAX]); | |
146 | + ts->target_v86->regs.ebx = tswap32(env->regs[R_EBX]); | |
147 | + ts->target_v86->regs.ecx = tswap32(env->regs[R_ECX]); | |
148 | + ts->target_v86->regs.edx = tswap32(env->regs[R_EDX]); | |
149 | + ts->target_v86->regs.esi = tswap32(env->regs[R_ESI]); | |
150 | + ts->target_v86->regs.edi = tswap32(env->regs[R_EDI]); | |
151 | + ts->target_v86->regs.ebp = tswap32(env->regs[R_EBP]); | |
152 | + ts->target_v86->regs.esp = tswap32(env->regs[R_ESP]); | |
153 | + ts->target_v86->regs.eip = tswap32(env->eip); | |
154 | + ts->target_v86->regs.cs = tswap16(env->segs[R_CS]); | |
155 | + ts->target_v86->regs.ss = tswap16(env->segs[R_SS]); | |
156 | + ts->target_v86->regs.ds = tswap16(env->segs[R_DS]); | |
157 | + ts->target_v86->regs.es = tswap16(env->segs[R_ES]); | |
158 | + ts->target_v86->regs.fs = tswap16(env->segs[R_FS]); | |
159 | + ts->target_v86->regs.gs = tswap16(env->segs[R_GS]); | |
160 | + | |
161 | + /* restore 32 bit registers */ | |
162 | + env->regs[R_EBX] = ts->vm86_saved_regs.ebx; | |
163 | + env->regs[R_ECX] = ts->vm86_saved_regs.ecx; | |
164 | + env->regs[R_EDX] = ts->vm86_saved_regs.edx; | |
165 | + env->regs[R_ESI] = ts->vm86_saved_regs.esi; | |
166 | + env->regs[R_EDI] = ts->vm86_saved_regs.edi; | |
167 | + env->regs[R_EBP] = ts->vm86_saved_regs.ebp; | |
168 | + env->regs[R_ESP] = ts->vm86_saved_regs.esp; | |
169 | + env->eflags = ts->vm86_saved_regs.eflags; | |
170 | + env->eip = ts->vm86_saved_regs.eip; | |
171 | + | |
172 | + cpu_x86_load_seg(env, R_CS, ts->vm86_saved_regs.cs); | |
173 | + cpu_x86_load_seg(env, R_SS, ts->vm86_saved_regs.ss); | |
174 | + cpu_x86_load_seg(env, R_DS, ts->vm86_saved_regs.ds); | |
175 | + cpu_x86_load_seg(env, R_ES, ts->vm86_saved_regs.es); | |
176 | + cpu_x86_load_seg(env, R_FS, ts->vm86_saved_regs.fs); | |
177 | + cpu_x86_load_seg(env, R_GS, ts->vm86_saved_regs.gs); | |
178 | + | |
179 | + env->regs[R_EAX] = ret; | |
129 | 180 | } else { |
130 | - /* XXX: more precise info */ | |
131 | - info.si_signo = SIGSEGV; | |
132 | - info.si_errno = 0; | |
133 | - info.si_code = 0; | |
134 | - info._sifields._sigfault._addr = 0; | |
135 | - queue_signal(info.si_signo, &info); | |
181 | + if (pc[0] == 0xcd && pc[1] == 0x80) { | |
182 | + /* syscall */ | |
183 | + env->eip += 2; | |
184 | + env->regs[R_EAX] = do_syscall(env, | |
185 | + env->regs[R_EAX], | |
186 | + env->regs[R_EBX], | |
187 | + env->regs[R_ECX], | |
188 | + env->regs[R_EDX], | |
189 | + env->regs[R_ESI], | |
190 | + env->regs[R_EDI], | |
191 | + env->regs[R_EBP]); | |
192 | + } else { | |
193 | + /* XXX: more precise info */ | |
194 | + info.si_signo = SIGSEGV; | |
195 | + info.si_errno = 0; | |
196 | + info.si_code = 0; | |
197 | + info._sifields._sigfault._addr = 0; | |
198 | + queue_signal(info.si_signo, &info); | |
199 | + } | |
136 | 200 | } |
137 | 201 | break; |
138 | 202 | case EXCP00_DIVZ: |
... | ... | @@ -188,12 +252,15 @@ void usage(void) |
188 | 252 | |
189 | 253 | /* XXX: currently only used for async signals (see signal.c) */ |
190 | 254 | CPUX86State *global_env; |
255 | +/* used to free thread contexts */ | |
256 | +TaskState *first_task_state; | |
191 | 257 | |
192 | 258 | int main(int argc, char **argv) |
193 | 259 | { |
194 | 260 | const char *filename; |
195 | 261 | struct target_pt_regs regs1, *regs = ®s1; |
196 | 262 | struct image_info info1, *info = &info1; |
263 | + TaskState ts1, *ts = &ts1; | |
197 | 264 | CPUX86State *env; |
198 | 265 | int optind; |
199 | 266 | const char *r; |
... | ... | @@ -272,6 +339,11 @@ int main(int argc, char **argv) |
272 | 339 | env = cpu_x86_init(); |
273 | 340 | global_env = env; |
274 | 341 | |
342 | + /* build Task State */ | |
343 | + memset(ts, 0, sizeof(TaskState)); | |
344 | + env->opaque = ts; | |
345 | + ts->used = 1; | |
346 | + | |
275 | 347 | /* linux register setup */ |
276 | 348 | env->regs[R_EAX] = regs->eax; |
277 | 349 | env->regs[R_EBX] = regs->ebx; | ... | ... |
linux-user/qemu.h
... | ... | @@ -33,6 +33,33 @@ struct image_info { |
33 | 33 | int personality; |
34 | 34 | }; |
35 | 35 | |
36 | +/* Information about the current linux thread */ | |
37 | +struct vm86_saved_state { | |
38 | + uint32_t eax; /* return code */ | |
39 | + uint32_t ebx; | |
40 | + uint32_t ecx; | |
41 | + uint32_t edx; | |
42 | + uint32_t esi; | |
43 | + uint32_t edi; | |
44 | + uint32_t ebp; | |
45 | + uint32_t esp; | |
46 | + uint32_t eflags; | |
47 | + uint32_t eip; | |
48 | + uint16_t cs, ss, ds, es, fs, gs; | |
49 | +}; | |
50 | + | |
51 | +/* NOTE: we force a big alignment so that the stack stored after is | |
52 | + aligned too */ | |
53 | +typedef struct TaskState { | |
54 | + struct TaskState *next; | |
55 | + struct target_vm86plus_struct *target_v86; | |
56 | + struct vm86_saved_state vm86_saved_regs; | |
57 | + int used; /* non zero if used */ | |
58 | + uint8_t stack[0]; | |
59 | +} __attribute__((aligned(16))) TaskState; | |
60 | + | |
61 | +extern TaskState *first_task_state; | |
62 | + | |
36 | 63 | int elf_exec(const char *interp_prefix, |
37 | 64 | const char * filename, char ** argv, char ** envp, |
38 | 65 | struct target_pt_regs * regs, struct image_info *infop); | ... | ... |