2 * vm86 linux syscall support
4 * Copyright (c) 2003 Fabrice Bellard
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, see <http://www.gnu.org/licenses/>.
19 #include "qemu/osdep.h"
22 #include "user-internals.h"
27 # define LOG_VM86(...) qemu_log(__VA_ARGS__);
29 # define LOG_VM86(...) do { } while (0)
33 #define set_flags(X,new,mask) \
34 ((X) = ((X) & ~(mask)) | ((new) & (mask)))
36 #define SAFE_MASK (0xDD5)
37 #define RETURN_MASK (0xDFF)
39 static inline int is_revectored(int nr
, struct target_revectored_struct
*bitmap
)
41 return (((uint8_t *)bitmap
)[nr
>> 3] >> (nr
& 7)) & 1;
44 static inline void vm_putw(CPUX86State
*env
, uint32_t segptr
,
45 unsigned int reg16
, unsigned int val
)
47 cpu_stw_data(env
, segptr
+ (reg16
& 0xffff), val
);
50 static inline void vm_putl(CPUX86State
*env
, uint32_t segptr
,
51 unsigned int reg16
, unsigned int val
)
53 cpu_stl_data(env
, segptr
+ (reg16
& 0xffff), val
);
56 static inline unsigned int vm_getb(CPUX86State
*env
,
57 uint32_t segptr
, unsigned int reg16
)
59 return cpu_ldub_data(env
, segptr
+ (reg16
& 0xffff));
62 static inline unsigned int vm_getw(CPUX86State
*env
,
63 uint32_t segptr
, unsigned int reg16
)
65 return cpu_lduw_data(env
, segptr
+ (reg16
& 0xffff));
68 static inline unsigned int vm_getl(CPUX86State
*env
,
69 uint32_t segptr
, unsigned int reg16
)
71 return cpu_ldl_data(env
, segptr
+ (reg16
& 0xffff));
74 void save_v86_state(CPUX86State
*env
)
76 CPUState
*cs
= env_cpu(env
);
77 TaskState
*ts
= cs
->opaque
;
78 struct target_vm86plus_struct
* target_v86
;
80 if (!lock_user_struct(VERIFY_WRITE
, target_v86
, ts
->target_v86
, 0))
81 /* FIXME - should return an error */
83 /* put the VM86 registers in the userspace register structure */
84 target_v86
->regs
.eax
= tswap32(env
->regs
[R_EAX
]);
85 target_v86
->regs
.ebx
= tswap32(env
->regs
[R_EBX
]);
86 target_v86
->regs
.ecx
= tswap32(env
->regs
[R_ECX
]);
87 target_v86
->regs
.edx
= tswap32(env
->regs
[R_EDX
]);
88 target_v86
->regs
.esi
= tswap32(env
->regs
[R_ESI
]);
89 target_v86
->regs
.edi
= tswap32(env
->regs
[R_EDI
]);
90 target_v86
->regs
.ebp
= tswap32(env
->regs
[R_EBP
]);
91 target_v86
->regs
.esp
= tswap32(env
->regs
[R_ESP
]);
92 target_v86
->regs
.eip
= tswap32(env
->eip
);
93 target_v86
->regs
.cs
= tswap16(env
->segs
[R_CS
].selector
);
94 target_v86
->regs
.ss
= tswap16(env
->segs
[R_SS
].selector
);
95 target_v86
->regs
.ds
= tswap16(env
->segs
[R_DS
].selector
);
96 target_v86
->regs
.es
= tswap16(env
->segs
[R_ES
].selector
);
97 target_v86
->regs
.fs
= tswap16(env
->segs
[R_FS
].selector
);
98 target_v86
->regs
.gs
= tswap16(env
->segs
[R_GS
].selector
);
99 set_flags(env
->eflags
, ts
->v86flags
, VIF_MASK
| ts
->v86mask
);
100 target_v86
->regs
.eflags
= tswap32(env
->eflags
);
101 unlock_user_struct(target_v86
, ts
->target_v86
, 1);
102 LOG_VM86("save_v86_state: eflags=%08x cs:ip=%04x:%04x\n",
103 env
->eflags
, env
->segs
[R_CS
].selector
, env
->eip
);
105 /* restore 32 bit registers */
106 env
->regs
[R_EAX
] = ts
->vm86_saved_regs
.eax
;
107 env
->regs
[R_EBX
] = ts
->vm86_saved_regs
.ebx
;
108 env
->regs
[R_ECX
] = ts
->vm86_saved_regs
.ecx
;
109 env
->regs
[R_EDX
] = ts
->vm86_saved_regs
.edx
;
110 env
->regs
[R_ESI
] = ts
->vm86_saved_regs
.esi
;
111 env
->regs
[R_EDI
] = ts
->vm86_saved_regs
.edi
;
112 env
->regs
[R_EBP
] = ts
->vm86_saved_regs
.ebp
;
113 env
->regs
[R_ESP
] = ts
->vm86_saved_regs
.esp
;
114 env
->eflags
= ts
->vm86_saved_regs
.eflags
;
115 env
->eip
= ts
->vm86_saved_regs
.eip
;
117 cpu_x86_load_seg(env
, R_CS
, ts
->vm86_saved_regs
.cs
);
118 cpu_x86_load_seg(env
, R_SS
, ts
->vm86_saved_regs
.ss
);
119 cpu_x86_load_seg(env
, R_DS
, ts
->vm86_saved_regs
.ds
);
120 cpu_x86_load_seg(env
, R_ES
, ts
->vm86_saved_regs
.es
);
121 cpu_x86_load_seg(env
, R_FS
, ts
->vm86_saved_regs
.fs
);
122 cpu_x86_load_seg(env
, R_GS
, ts
->vm86_saved_regs
.gs
);
125 /* return from vm86 mode to 32 bit. The vm86() syscall will return
127 static inline void return_to_32bit(CPUX86State
*env
, int retval
)
129 LOG_VM86("return_to_32bit: ret=0x%x\n", retval
);
131 env
->regs
[R_EAX
] = retval
;
134 static inline int set_IF(CPUX86State
*env
)
136 CPUState
*cs
= env_cpu(env
);
137 TaskState
*ts
= cs
->opaque
;
139 ts
->v86flags
|= VIF_MASK
;
140 if (ts
->v86flags
& VIP_MASK
) {
141 return_to_32bit(env
, TARGET_VM86_STI
);
147 static inline void clear_IF(CPUX86State
*env
)
149 CPUState
*cs
= env_cpu(env
);
150 TaskState
*ts
= cs
->opaque
;
152 ts
->v86flags
&= ~VIF_MASK
;
155 static inline void clear_TF(CPUX86State
*env
)
157 env
->eflags
&= ~TF_MASK
;
160 static inline void clear_AC(CPUX86State
*env
)
162 env
->eflags
&= ~AC_MASK
;
165 static inline int set_vflags_long(unsigned long eflags
, CPUX86State
*env
)
167 CPUState
*cs
= env_cpu(env
);
168 TaskState
*ts
= cs
->opaque
;
170 set_flags(ts
->v86flags
, eflags
, ts
->v86mask
);
171 set_flags(env
->eflags
, eflags
, SAFE_MASK
);
172 if (eflags
& IF_MASK
)
179 static inline int set_vflags_short(unsigned short flags
, CPUX86State
*env
)
181 CPUState
*cs
= env_cpu(env
);
182 TaskState
*ts
= cs
->opaque
;
184 set_flags(ts
->v86flags
, flags
, ts
->v86mask
& 0xffff);
185 set_flags(env
->eflags
, flags
, SAFE_MASK
);
193 static inline unsigned int get_vflags(CPUX86State
*env
)
195 CPUState
*cs
= env_cpu(env
);
196 TaskState
*ts
= cs
->opaque
;
199 flags
= env
->eflags
& RETURN_MASK
;
200 if (ts
->v86flags
& VIF_MASK
)
203 return flags
| (ts
->v86flags
& ts
->v86mask
);
206 #define ADD16(reg, val) reg = (reg & ~0xffff) | ((reg + (val)) & 0xffff)
208 /* handle VM86 interrupt (NOTE: the CPU core currently does not
209 support TSS interrupt revectoring, so this code is always executed) */
210 static void do_int(CPUX86State
*env
, int intno
)
212 CPUState
*cs
= env_cpu(env
);
213 TaskState
*ts
= cs
->opaque
;
214 uint32_t int_addr
, segoffs
, ssp
;
217 if (env
->segs
[R_CS
].selector
== TARGET_BIOSSEG
)
219 if (is_revectored(intno
, &ts
->vm86plus
.int_revectored
))
221 if (intno
== 0x21 && is_revectored((env
->regs
[R_EAX
] >> 8) & 0xff,
222 &ts
->vm86plus
.int21_revectored
))
224 int_addr
= (intno
<< 2);
225 segoffs
= cpu_ldl_data(env
, int_addr
);
226 if ((segoffs
>> 16) == TARGET_BIOSSEG
)
228 LOG_VM86("VM86: emulating int 0x%x. CS:IP=%04x:%04x\n",
229 intno
, segoffs
>> 16, segoffs
& 0xffff);
231 ssp
= env
->segs
[R_SS
].selector
<< 4;
232 sp
= env
->regs
[R_ESP
] & 0xffff;
233 vm_putw(env
, ssp
, sp
- 2, get_vflags(env
));
234 vm_putw(env
, ssp
, sp
- 4, env
->segs
[R_CS
].selector
);
235 vm_putw(env
, ssp
, sp
- 6, env
->eip
);
236 ADD16(env
->regs
[R_ESP
], -6);
237 /* goto interrupt handler */
238 env
->eip
= segoffs
& 0xffff;
239 cpu_x86_load_seg(env
, R_CS
, segoffs
>> 16);
245 LOG_VM86("VM86: return to 32 bits int 0x%x\n", intno
);
246 return_to_32bit(env
, TARGET_VM86_INTx
| (intno
<< 8));
249 void handle_vm86_trap(CPUX86State
*env
, int trapno
)
251 if (trapno
== 1 || trapno
== 3) {
252 return_to_32bit(env
, TARGET_VM86_TRAP
+ (trapno
<< 8));
258 #define CHECK_IF_IN_TRAP() \
259 if ((ts->vm86plus.vm86plus.flags & TARGET_vm86dbg_active) && \
260 (ts->vm86plus.vm86plus.flags & TARGET_vm86dbg_TFpendig)) \
263 #define VM86_FAULT_RETURN \
264 if ((ts->vm86plus.vm86plus.flags & TARGET_force_return_for_pic) && \
265 (ts->v86flags & (IF_MASK | VIF_MASK))) \
266 return_to_32bit(env, TARGET_VM86_PICRETURN); \
269 void handle_vm86_fault(CPUX86State
*env
)
271 CPUState
*cs
= env_cpu(env
);
272 TaskState
*ts
= cs
->opaque
;
274 unsigned int ip
, sp
, newflags
, newip
, newcs
, opcode
, intno
;
275 int data32
, pref_done
;
277 csp
= env
->segs
[R_CS
].selector
<< 4;
278 ip
= env
->eip
& 0xffff;
280 ssp
= env
->segs
[R_SS
].selector
<< 4;
281 sp
= env
->regs
[R_ESP
] & 0xffff;
283 LOG_VM86("VM86 exception %04x:%08x\n",
284 env
->segs
[R_CS
].selector
, env
->eip
);
289 opcode
= vm_getb(env
, csp
, ip
);
292 case 0x66: /* 32-bit data */ data32
=1; break;
293 case 0x67: /* 32-bit address */ break;
294 case 0x2e: /* CS */ break;
295 case 0x3e: /* DS */ break;
296 case 0x26: /* ES */ break;
297 case 0x36: /* SS */ break;
298 case 0x65: /* GS */ break;
299 case 0x64: /* FS */ break;
300 case 0xf2: /* repnz */ break;
301 case 0xf3: /* rep */ break;
302 default: pref_done
= 1;
304 } while (!pref_done
);
308 case 0x9c: /* pushf */
310 vm_putl(env
, ssp
, sp
- 4, get_vflags(env
));
311 ADD16(env
->regs
[R_ESP
], -4);
313 vm_putw(env
, ssp
, sp
- 2, get_vflags(env
));
314 ADD16(env
->regs
[R_ESP
], -2);
319 case 0x9d: /* popf */
321 newflags
= vm_getl(env
, ssp
, sp
);
322 ADD16(env
->regs
[R_ESP
], 4);
324 newflags
= vm_getw(env
, ssp
, sp
);
325 ADD16(env
->regs
[R_ESP
], 2);
330 if (set_vflags_long(newflags
, env
))
333 if (set_vflags_short(newflags
, env
))
339 intno
= vm_getb(env
, csp
, ip
);
342 if (ts
->vm86plus
.vm86plus
.flags
& TARGET_vm86dbg_active
) {
343 if ( (ts
->vm86plus
.vm86plus
.vm86dbg_intxxtab
[intno
>> 3] >>
345 return_to_32bit(env
, TARGET_VM86_INTx
+ (intno
<< 8));
352 case 0xcf: /* iret */
354 newip
= vm_getl(env
, ssp
, sp
) & 0xffff;
355 newcs
= vm_getl(env
, ssp
, sp
+ 4) & 0xffff;
356 newflags
= vm_getl(env
, ssp
, sp
+ 8);
357 ADD16(env
->regs
[R_ESP
], 12);
359 newip
= vm_getw(env
, ssp
, sp
);
360 newcs
= vm_getw(env
, ssp
, sp
+ 2);
361 newflags
= vm_getw(env
, ssp
, sp
+ 4);
362 ADD16(env
->regs
[R_ESP
], 6);
365 cpu_x86_load_seg(env
, R_CS
, newcs
);
368 if (set_vflags_long(newflags
, env
))
371 if (set_vflags_short(newflags
, env
))
388 /* real VM86 GPF exception */
389 return_to_32bit(env
, TARGET_VM86_UNKNOWN
);
394 int do_vm86(CPUX86State
*env
, long subfunction
, abi_ulong vm86_addr
)
396 CPUState
*cs
= env_cpu(env
);
397 TaskState
*ts
= cs
->opaque
;
398 struct target_vm86plus_struct
* target_v86
;
401 switch (subfunction
) {
402 case TARGET_VM86_REQUEST_IRQ
:
403 case TARGET_VM86_FREE_IRQ
:
404 case TARGET_VM86_GET_IRQ_BITS
:
405 case TARGET_VM86_GET_AND_RESET_IRQ
:
406 qemu_log_mask(LOG_UNIMP
, "qemu: unsupported vm86 subfunction (%ld)\n",
408 ret
= -TARGET_EINVAL
;
410 case TARGET_VM86_PLUS_INSTALL_CHECK
:
411 /* NOTE: on old vm86 stuff this will return the error
412 from verify_area(), because the subfunction is
413 interpreted as (invalid) address to vm86_struct.
414 So the installation check works.
420 /* save current CPU regs */
421 ts
->vm86_saved_regs
.eax
= 0; /* default vm86 syscall return code */
422 ts
->vm86_saved_regs
.ebx
= env
->regs
[R_EBX
];
423 ts
->vm86_saved_regs
.ecx
= env
->regs
[R_ECX
];
424 ts
->vm86_saved_regs
.edx
= env
->regs
[R_EDX
];
425 ts
->vm86_saved_regs
.esi
= env
->regs
[R_ESI
];
426 ts
->vm86_saved_regs
.edi
= env
->regs
[R_EDI
];
427 ts
->vm86_saved_regs
.ebp
= env
->regs
[R_EBP
];
428 ts
->vm86_saved_regs
.esp
= env
->regs
[R_ESP
];
429 ts
->vm86_saved_regs
.eflags
= env
->eflags
;
430 ts
->vm86_saved_regs
.eip
= env
->eip
;
431 ts
->vm86_saved_regs
.cs
= env
->segs
[R_CS
].selector
;
432 ts
->vm86_saved_regs
.ss
= env
->segs
[R_SS
].selector
;
433 ts
->vm86_saved_regs
.ds
= env
->segs
[R_DS
].selector
;
434 ts
->vm86_saved_regs
.es
= env
->segs
[R_ES
].selector
;
435 ts
->vm86_saved_regs
.fs
= env
->segs
[R_FS
].selector
;
436 ts
->vm86_saved_regs
.gs
= env
->segs
[R_GS
].selector
;
438 ts
->target_v86
= vm86_addr
;
439 if (!lock_user_struct(VERIFY_READ
, target_v86
, vm86_addr
, 1))
440 return -TARGET_EFAULT
;
441 /* build vm86 CPU state */
442 ts
->v86flags
= tswap32(target_v86
->regs
.eflags
);
443 env
->eflags
= (env
->eflags
& ~SAFE_MASK
) |
444 (tswap32(target_v86
->regs
.eflags
) & SAFE_MASK
) | VM_MASK
;
446 ts
->vm86plus
.cpu_type
= tswapal(target_v86
->cpu_type
);
447 switch (ts
->vm86plus
.cpu_type
) {
452 ts
->v86mask
= NT_MASK
| IOPL_MASK
;
455 ts
->v86mask
= AC_MASK
| NT_MASK
| IOPL_MASK
;
458 ts
->v86mask
= ID_MASK
| AC_MASK
| NT_MASK
| IOPL_MASK
;
462 env
->regs
[R_EBX
] = tswap32(target_v86
->regs
.ebx
);
463 env
->regs
[R_ECX
] = tswap32(target_v86
->regs
.ecx
);
464 env
->regs
[R_EDX
] = tswap32(target_v86
->regs
.edx
);
465 env
->regs
[R_ESI
] = tswap32(target_v86
->regs
.esi
);
466 env
->regs
[R_EDI
] = tswap32(target_v86
->regs
.edi
);
467 env
->regs
[R_EBP
] = tswap32(target_v86
->regs
.ebp
);
468 env
->regs
[R_ESP
] = tswap32(target_v86
->regs
.esp
);
469 env
->eip
= tswap32(target_v86
->regs
.eip
);
470 cpu_x86_load_seg(env
, R_CS
, tswap16(target_v86
->regs
.cs
));
471 cpu_x86_load_seg(env
, R_SS
, tswap16(target_v86
->regs
.ss
));
472 cpu_x86_load_seg(env
, R_DS
, tswap16(target_v86
->regs
.ds
));
473 cpu_x86_load_seg(env
, R_ES
, tswap16(target_v86
->regs
.es
));
474 cpu_x86_load_seg(env
, R_FS
, tswap16(target_v86
->regs
.fs
));
475 cpu_x86_load_seg(env
, R_GS
, tswap16(target_v86
->regs
.gs
));
476 ret
= tswap32(target_v86
->regs
.eax
); /* eax will be restored at
477 the end of the syscall */
478 memcpy(&ts
->vm86plus
.int_revectored
,
479 &target_v86
->int_revectored
, 32);
480 memcpy(&ts
->vm86plus
.int21_revectored
,
481 &target_v86
->int21_revectored
, 32);
482 ts
->vm86plus
.vm86plus
.flags
= tswapal(target_v86
->vm86plus
.flags
);
483 memcpy(&ts
->vm86plus
.vm86plus
.vm86dbg_intxxtab
,
484 target_v86
->vm86plus
.vm86dbg_intxxtab
, 32);
485 unlock_user_struct(target_v86
, vm86_addr
, 0);
487 LOG_VM86("do_vm86: cs:ip=%04x:%04x\n",
488 env
->segs
[R_CS
].selector
, env
->eip
);
489 /* now the virtual CPU is ready for vm86 execution ! */