vm86.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291
  1. /*
  2. * vm86 linux syscall support
  3. *
  4. * Copyright (c) 2003 Fabrice Bellard
  5. *
  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.
  10. *
  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.
  15. *
  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/>.
  18. */
  19. #include "qemu/osdep.h"
  20. #include "qemu.h"
  21. #include "user-internals.h"
  22. //#define DEBUG_VM86
  23. #ifdef DEBUG_VM86
  24. # define LOG_VM86(...) qemu_log(__VA_ARGS__);
  25. #else
  26. # define LOG_VM86(...) do { } while (0)
  27. #endif
  28. #define set_flags(X,new,mask) \
  29. ((X) = ((X) & ~(mask)) | ((new) & (mask)))
  30. #define SAFE_MASK (0xDD5)
  31. #define RETURN_MASK (0xDFF)
  32. static inline int is_revectored(int nr, struct target_revectored_struct *bitmap)
  33. {
  34. return (((uint8_t *)bitmap)[nr >> 3] >> (nr & 7)) & 1;
  35. }
  36. static inline void vm_putw(CPUX86State *env, uint32_t segptr,
  37. unsigned int reg16, unsigned int val)
  38. {
  39. cpu_stw_data(env, segptr + (reg16 & 0xffff), val);
  40. }
  41. void save_v86_state(CPUX86State *env)
  42. {
  43. CPUState *cs = env_cpu(env);
  44. TaskState *ts = get_task_state(cs);
  45. struct target_vm86plus_struct * target_v86;
  46. if (!lock_user_struct(VERIFY_WRITE, target_v86, ts->target_v86, 0))
  47. /* FIXME - should return an error */
  48. return;
  49. /* put the VM86 registers in the userspace register structure */
  50. target_v86->regs.eax = tswap32(env->regs[R_EAX]);
  51. target_v86->regs.ebx = tswap32(env->regs[R_EBX]);
  52. target_v86->regs.ecx = tswap32(env->regs[R_ECX]);
  53. target_v86->regs.edx = tswap32(env->regs[R_EDX]);
  54. target_v86->regs.esi = tswap32(env->regs[R_ESI]);
  55. target_v86->regs.edi = tswap32(env->regs[R_EDI]);
  56. target_v86->regs.ebp = tswap32(env->regs[R_EBP]);
  57. target_v86->regs.esp = tswap32(env->regs[R_ESP]);
  58. target_v86->regs.eip = tswap32(env->eip);
  59. target_v86->regs.cs = tswap16(env->segs[R_CS].selector);
  60. target_v86->regs.ss = tswap16(env->segs[R_SS].selector);
  61. target_v86->regs.ds = tswap16(env->segs[R_DS].selector);
  62. target_v86->regs.es = tswap16(env->segs[R_ES].selector);
  63. target_v86->regs.fs = tswap16(env->segs[R_FS].selector);
  64. target_v86->regs.gs = tswap16(env->segs[R_GS].selector);
  65. set_flags(env->eflags, ts->v86flags, VIF_MASK | ts->v86mask);
  66. target_v86->regs.eflags = tswap32(env->eflags);
  67. unlock_user_struct(target_v86, ts->target_v86, 1);
  68. LOG_VM86("save_v86_state: eflags=%08x cs:ip=%04x:%04x\n",
  69. env->eflags, env->segs[R_CS].selector, env->eip);
  70. /* restore 32 bit registers */
  71. env->regs[R_EAX] = ts->vm86_saved_regs.eax;
  72. env->regs[R_EBX] = ts->vm86_saved_regs.ebx;
  73. env->regs[R_ECX] = ts->vm86_saved_regs.ecx;
  74. env->regs[R_EDX] = ts->vm86_saved_regs.edx;
  75. env->regs[R_ESI] = ts->vm86_saved_regs.esi;
  76. env->regs[R_EDI] = ts->vm86_saved_regs.edi;
  77. env->regs[R_EBP] = ts->vm86_saved_regs.ebp;
  78. env->regs[R_ESP] = ts->vm86_saved_regs.esp;
  79. env->eflags = ts->vm86_saved_regs.eflags;
  80. env->eip = ts->vm86_saved_regs.eip;
  81. cpu_x86_load_seg(env, R_CS, ts->vm86_saved_regs.cs);
  82. cpu_x86_load_seg(env, R_SS, ts->vm86_saved_regs.ss);
  83. cpu_x86_load_seg(env, R_DS, ts->vm86_saved_regs.ds);
  84. cpu_x86_load_seg(env, R_ES, ts->vm86_saved_regs.es);
  85. cpu_x86_load_seg(env, R_FS, ts->vm86_saved_regs.fs);
  86. cpu_x86_load_seg(env, R_GS, ts->vm86_saved_regs.gs);
  87. }
  88. /* return from vm86 mode to 32 bit. The vm86() syscall will return
  89. 'retval' */
  90. static inline void return_to_32bit(CPUX86State *env, int retval)
  91. {
  92. LOG_VM86("return_to_32bit: ret=0x%x\n", retval);
  93. save_v86_state(env);
  94. env->regs[R_EAX] = retval;
  95. }
  96. static inline void clear_IF(CPUX86State *env)
  97. {
  98. CPUState *cs = env_cpu(env);
  99. TaskState *ts = get_task_state(cs);
  100. ts->v86flags &= ~VIF_MASK;
  101. }
  102. static inline void clear_TF(CPUX86State *env)
  103. {
  104. env->eflags &= ~TF_MASK;
  105. }
  106. static inline void clear_AC(CPUX86State *env)
  107. {
  108. env->eflags &= ~AC_MASK;
  109. }
  110. static inline unsigned int get_vflags(CPUX86State *env)
  111. {
  112. CPUState *cs = env_cpu(env);
  113. TaskState *ts = get_task_state(cs);
  114. unsigned int flags;
  115. flags = env->eflags & RETURN_MASK;
  116. if (ts->v86flags & VIF_MASK)
  117. flags |= IF_MASK;
  118. flags |= IOPL_MASK;
  119. return flags | (ts->v86flags & ts->v86mask);
  120. }
  121. #define ADD16(reg, val) reg = (reg & ~0xffff) | ((reg + (val)) & 0xffff)
  122. /* handle VM86 interrupt (NOTE: the CPU core currently does not
  123. support TSS interrupt revectoring, so this code is always executed) */
  124. static void do_int(CPUX86State *env, int intno)
  125. {
  126. CPUState *cs = env_cpu(env);
  127. TaskState *ts = get_task_state(cs);
  128. uint32_t int_addr, segoffs, ssp;
  129. unsigned int sp;
  130. if (env->segs[R_CS].selector == TARGET_BIOSSEG)
  131. goto cannot_handle;
  132. if (is_revectored(intno, &ts->vm86plus.int_revectored))
  133. goto cannot_handle;
  134. if (intno == 0x21 && is_revectored((env->regs[R_EAX] >> 8) & 0xff,
  135. &ts->vm86plus.int21_revectored))
  136. goto cannot_handle;
  137. int_addr = (intno << 2);
  138. segoffs = cpu_ldl_data(env, int_addr);
  139. if ((segoffs >> 16) == TARGET_BIOSSEG)
  140. goto cannot_handle;
  141. LOG_VM86("VM86: emulating int 0x%x. CS:IP=%04x:%04x\n",
  142. intno, segoffs >> 16, segoffs & 0xffff);
  143. /* save old state */
  144. ssp = env->segs[R_SS].selector << 4;
  145. sp = env->regs[R_ESP] & 0xffff;
  146. vm_putw(env, ssp, sp - 2, get_vflags(env));
  147. vm_putw(env, ssp, sp - 4, env->segs[R_CS].selector);
  148. vm_putw(env, ssp, sp - 6, env->eip);
  149. ADD16(env->regs[R_ESP], -6);
  150. /* goto interrupt handler */
  151. env->eip = segoffs & 0xffff;
  152. cpu_x86_load_seg(env, R_CS, segoffs >> 16);
  153. clear_TF(env);
  154. clear_IF(env);
  155. clear_AC(env);
  156. return;
  157. cannot_handle:
  158. LOG_VM86("VM86: return to 32 bits int 0x%x\n", intno);
  159. return_to_32bit(env, TARGET_VM86_INTx | (intno << 8));
  160. }
  161. void handle_vm86_trap(CPUX86State *env, int trapno)
  162. {
  163. if (trapno == 1 || trapno == 3) {
  164. return_to_32bit(env, TARGET_VM86_TRAP + (trapno << 8));
  165. } else {
  166. do_int(env, trapno);
  167. }
  168. }
  169. int do_vm86(CPUX86State *env, long subfunction, abi_ulong vm86_addr)
  170. {
  171. CPUState *cs = env_cpu(env);
  172. TaskState *ts = get_task_state(cs);
  173. struct target_vm86plus_struct * target_v86;
  174. int ret;
  175. switch (subfunction) {
  176. case TARGET_VM86_REQUEST_IRQ:
  177. case TARGET_VM86_FREE_IRQ:
  178. case TARGET_VM86_GET_IRQ_BITS:
  179. case TARGET_VM86_GET_AND_RESET_IRQ:
  180. qemu_log_mask(LOG_UNIMP, "qemu: unsupported vm86 subfunction (%ld)\n",
  181. subfunction);
  182. ret = -TARGET_EINVAL;
  183. goto out;
  184. case TARGET_VM86_PLUS_INSTALL_CHECK:
  185. /* NOTE: on old vm86 stuff this will return the error
  186. from verify_area(), because the subfunction is
  187. interpreted as (invalid) address to vm86_struct.
  188. So the installation check works.
  189. */
  190. ret = 0;
  191. goto out;
  192. }
  193. /* save current CPU regs */
  194. ts->vm86_saved_regs.eax = 0; /* default vm86 syscall return code */
  195. ts->vm86_saved_regs.ebx = env->regs[R_EBX];
  196. ts->vm86_saved_regs.ecx = env->regs[R_ECX];
  197. ts->vm86_saved_regs.edx = env->regs[R_EDX];
  198. ts->vm86_saved_regs.esi = env->regs[R_ESI];
  199. ts->vm86_saved_regs.edi = env->regs[R_EDI];
  200. ts->vm86_saved_regs.ebp = env->regs[R_EBP];
  201. ts->vm86_saved_regs.esp = env->regs[R_ESP];
  202. ts->vm86_saved_regs.eflags = env->eflags;
  203. ts->vm86_saved_regs.eip = env->eip;
  204. ts->vm86_saved_regs.cs = env->segs[R_CS].selector;
  205. ts->vm86_saved_regs.ss = env->segs[R_SS].selector;
  206. ts->vm86_saved_regs.ds = env->segs[R_DS].selector;
  207. ts->vm86_saved_regs.es = env->segs[R_ES].selector;
  208. ts->vm86_saved_regs.fs = env->segs[R_FS].selector;
  209. ts->vm86_saved_regs.gs = env->segs[R_GS].selector;
  210. ts->target_v86 = vm86_addr;
  211. if (!lock_user_struct(VERIFY_READ, target_v86, vm86_addr, 1))
  212. return -TARGET_EFAULT;
  213. /* build vm86 CPU state */
  214. ts->v86flags = tswap32(target_v86->regs.eflags);
  215. env->eflags = (env->eflags & ~SAFE_MASK) |
  216. (tswap32(target_v86->regs.eflags) & SAFE_MASK) | VM_MASK;
  217. ts->vm86plus.cpu_type = tswapal(target_v86->cpu_type);
  218. switch (ts->vm86plus.cpu_type) {
  219. case TARGET_CPU_286:
  220. ts->v86mask = 0;
  221. break;
  222. case TARGET_CPU_386:
  223. ts->v86mask = NT_MASK | IOPL_MASK;
  224. break;
  225. case TARGET_CPU_486:
  226. ts->v86mask = AC_MASK | NT_MASK | IOPL_MASK;
  227. break;
  228. default:
  229. ts->v86mask = ID_MASK | AC_MASK | NT_MASK | IOPL_MASK;
  230. break;
  231. }
  232. env->regs[R_EBX] = tswap32(target_v86->regs.ebx);
  233. env->regs[R_ECX] = tswap32(target_v86->regs.ecx);
  234. env->regs[R_EDX] = tswap32(target_v86->regs.edx);
  235. env->regs[R_ESI] = tswap32(target_v86->regs.esi);
  236. env->regs[R_EDI] = tswap32(target_v86->regs.edi);
  237. env->regs[R_EBP] = tswap32(target_v86->regs.ebp);
  238. env->regs[R_ESP] = tswap32(target_v86->regs.esp);
  239. env->eip = tswap32(target_v86->regs.eip);
  240. cpu_x86_load_seg(env, R_CS, tswap16(target_v86->regs.cs));
  241. cpu_x86_load_seg(env, R_SS, tswap16(target_v86->regs.ss));
  242. cpu_x86_load_seg(env, R_DS, tswap16(target_v86->regs.ds));
  243. cpu_x86_load_seg(env, R_ES, tswap16(target_v86->regs.es));
  244. cpu_x86_load_seg(env, R_FS, tswap16(target_v86->regs.fs));
  245. cpu_x86_load_seg(env, R_GS, tswap16(target_v86->regs.gs));
  246. ret = tswap32(target_v86->regs.eax); /* eax will be restored at
  247. the end of the syscall */
  248. memcpy(&ts->vm86plus.int_revectored,
  249. &target_v86->int_revectored, 32);
  250. memcpy(&ts->vm86plus.int21_revectored,
  251. &target_v86->int21_revectored, 32);
  252. ts->vm86plus.vm86plus.flags = tswapal(target_v86->vm86plus.flags);
  253. memcpy(&ts->vm86plus.vm86plus.vm86dbg_intxxtab,
  254. target_v86->vm86plus.vm86dbg_intxxtab, 32);
  255. unlock_user_struct(target_v86, vm86_addr, 0);
  256. LOG_VM86("do_vm86: cs:ip=%04x:%04x\n",
  257. env->segs[R_CS].selector, env->eip);
  258. /* now the virtual CPU is ready for vm86 execution ! */
  259. out:
  260. return ret;
  261. }