vm86.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476
  1. /*
  2. * vm86.c
  3. *
  4. * Copyright (C) 2016 Aleksandar Andrejevic <theflash@sdf.lonestar.org>
  5. *
  6. * This program is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU Affero General Public License as
  8. * published by the Free Software Foundation, either version 3 of the
  9. * License, or (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 Affero General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Affero General Public License
  17. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. #include <vm86.h>
  20. #include <segments.h>
  21. #include <exception.h>
  22. #include <process.h>
  23. #include <thread.h>
  24. #include <memory.h>
  25. #define PREFIX_LOCK (1 << 0)
  26. #define PREFIX_OPSIZE (1 << 1)
  27. #define PREFIX_ADDRSIZE (1 << 2)
  28. #define PREFIX_REP (1 << 3)
  29. #define PREFIX_REPNZ (1 << 4)
  30. #define PREFIX_ES (1 << 5)
  31. #define PREFIX_SS (1 << 6)
  32. #define PREFIX_FS (1 << 7)
  33. #define PREFIX_GS (1 << 8)
  34. #define VM86_MEM_START 0x10000
  35. #define VM86_MEM_END 0x90000
  36. #define VM86_MEM_PARAGRAPHS ((VM86_MEM_END - VM86_MEM_START) >> 4)
  37. #define VM86_TRAMPOLINE_CS 0x0000
  38. #define VM86_TRAMPOLINE_IP 0xE000
  39. #define VM86_TRAMPOLINE_SS 0x0000
  40. #define VM86_TRAMPOLINE_SP 0xDFFA
  41. extern void vm86_start(vm86_registers_t input_regs, vm86_registers_t *output_regs);
  42. static bool_t vm86_interrupts = TRUE;
  43. static dword_t vm86_mem_bitmap[VM86_MEM_PARAGRAPHS / 32] = { 0 };
  44. static dword_t vm86_mem_last_alloc_bitmap[VM86_MEM_PARAGRAPHS / 32] = { 0 };
  45. static inline dword_t get_bios_interrupt(byte_t number)
  46. {
  47. return *((dword_t*)(number * sizeof(dword_t)));
  48. }
  49. static inline byte_t peekb(word_t segment, word_t offset)
  50. {
  51. return *((byte_t*)((segment << 4) + offset));
  52. }
  53. static inline void pokeb(word_t segment, word_t offset, byte_t value)
  54. {
  55. *((byte_t*)((segment << 4) + offset)) = value;
  56. }
  57. static inline word_t peekw(word_t segment, word_t offset)
  58. {
  59. return *((word_t*) ((segment << 4) + offset));
  60. }
  61. static inline void pokew(word_t segment, word_t offset, word_t value)
  62. {
  63. *((word_t*)((segment << 4) + offset)) = value;
  64. }
  65. static inline dword_t peekl(word_t segment, word_t offset)
  66. {
  67. return *((dword_t*)((segment << 4) + offset));
  68. }
  69. static inline void pokel(word_t segment, word_t offset, dword_t value)
  70. {
  71. *((dword_t*)((segment << 4) + offset)) = value;
  72. }
  73. word_t vm86_alloc(word_t size)
  74. {
  75. dword_t i;
  76. bool_t found = FALSE;
  77. dword_t first_free = VM86_MEM_PARAGRAPHS;
  78. for (i = 0; i < VM86_MEM_PARAGRAPHS; i++)
  79. {
  80. if (test_bit(vm86_mem_bitmap, i)) first_free = VM86_MEM_PARAGRAPHS;
  81. else if (first_free == VM86_MEM_PARAGRAPHS) first_free = i;
  82. if ((first_free != VM86_MEM_PARAGRAPHS) && ((i - first_free + 1) == size))
  83. {
  84. found = TRUE;
  85. break;
  86. }
  87. }
  88. if (!found) return 0;
  89. for (i = 0; i < size; i++)
  90. {
  91. set_bit(vm86_mem_bitmap, first_free + i);
  92. if (i != (size - 1)) clear_bit(vm86_mem_last_alloc_bitmap, first_free + i);
  93. else set_bit(vm86_mem_last_alloc_bitmap, first_free + i);
  94. }
  95. return (VM86_MEM_START >> 4) + first_free;
  96. }
  97. void vm86_free(word_t paragraph)
  98. {
  99. dword_t i;
  100. for (i = paragraph - (VM86_MEM_START >> 4); !test_bit(vm86_mem_last_alloc_bitmap, i); i++)
  101. {
  102. clear_bit(vm86_mem_bitmap, i);
  103. }
  104. }
  105. void vm86_handler(registers_ext_vm86_t *regs)
  106. {
  107. dword_t i, prefix = 0, count = 0, segment = 0, operand = 0;
  108. byte_t instruction;
  109. while (TRUE)
  110. {
  111. instruction = peekb(regs->cs, regs->eip);
  112. regs->eip++;
  113. if (instruction == 0x26) prefix |= PREFIX_ES;
  114. else if (instruction == 0x36) prefix |= PREFIX_SS;
  115. else if (instruction == 0x64) prefix |= PREFIX_FS;
  116. else if (instruction == 0x65) prefix |= PREFIX_GS;
  117. else if (instruction == 0x66) prefix |= PREFIX_OPSIZE;
  118. else if (instruction == 0x67) prefix |= PREFIX_ADDRSIZE;
  119. else if (instruction == 0xF0) prefix |= PREFIX_LOCK;
  120. else if (instruction == 0xF2) prefix |= PREFIX_REPNZ;
  121. else if (instruction == 0xF3) prefix |= PREFIX_REP;
  122. else break;
  123. }
  124. if (prefix & PREFIX_REP)
  125. {
  126. if (prefix & PREFIX_ADDRSIZE) count = regs->ecx;
  127. else count = regs->ecx & 0xFFFF;
  128. }
  129. else
  130. {
  131. count = 1;
  132. }
  133. if (prefix & PREFIX_ES) segment = regs->es;
  134. else if (prefix & PREFIX_SS) segment = regs->ss;
  135. else if (prefix & PREFIX_FS) segment = regs->fs;
  136. else if (prefix & PREFIX_GS) segment = regs->gs;
  137. else segment = regs->ds;
  138. switch (instruction)
  139. {
  140. case 0x6C: // insb byte ptr [es:di], dx
  141. {
  142. for (i = 0; i < count; i++)
  143. {
  144. pokeb(regs->es, regs->edi, cpu_read_port_byte(regs->edx));
  145. if (!(regs->eflags & CPU_STATUS_FLAG_DF)) regs->edi++;
  146. else regs->edi--;
  147. }
  148. break;
  149. }
  150. case 0x6D: // insw/insd (d)word ptr [es:di], dx
  151. {
  152. for (i = 0; i < count; i++)
  153. {
  154. if (!(prefix & PREFIX_OPSIZE))
  155. {
  156. pokew(regs->es, regs->edi, cpu_read_port_word(regs->edx));
  157. if (!(regs->eflags & CPU_STATUS_FLAG_DF)) regs->edi += 2;
  158. else regs->edi -= 2;
  159. }
  160. else
  161. {
  162. pokel(regs->es, regs->edi, cpu_read_port_dword(regs->edx));
  163. if (!(regs->eflags & CPU_STATUS_FLAG_DF)) regs->edi += 4;
  164. else regs->edi -= 4;
  165. }
  166. }
  167. break;
  168. }
  169. case 0x6E: // outsb dx, byte ptr [ds:si]
  170. {
  171. for (i = 0; i < count; i++)
  172. {
  173. cpu_write_port_byte(regs->edx, peekb(segment, regs->esi));
  174. if (!(regs->eflags & CPU_STATUS_FLAG_DF)) regs->esi++;
  175. else regs->esi--;
  176. }
  177. break;
  178. }
  179. case 0x6F: // outsw/outsd dx, (d)word ptr [ds:si]
  180. {
  181. for (i = 0; i < count; i++)
  182. {
  183. if (!(prefix & PREFIX_OPSIZE))
  184. {
  185. cpu_write_port_word(regs->edx, peekw(segment, regs->esi));
  186. if (!(regs->eflags & CPU_STATUS_FLAG_DF)) regs->esi += 2;
  187. else regs->esi -= 2;
  188. }
  189. else
  190. {
  191. cpu_write_port_dword(regs->edx, peekl(segment, regs->esi));
  192. if (!(regs->eflags & CPU_STATUS_FLAG_DF)) regs->esi += 4;
  193. else regs->esi -= 4;
  194. }
  195. }
  196. break;
  197. }
  198. case 0x9C: // pushf
  199. {
  200. operand = regs->eflags;
  201. operand &= ~CPU_STATUS_FLAG_VM;
  202. if (vm86_interrupts) operand |= CPU_STATUS_FLAG_IF;
  203. else operand &= ~CPU_STATUS_FLAG_IF;
  204. if (!(prefix & PREFIX_OPSIZE))
  205. {
  206. regs->esp3 -= 2;
  207. pokew(regs->ss, regs->esp3, operand & 0xFFFF);
  208. }
  209. else
  210. {
  211. regs->esp3 -= 4;
  212. pokel(regs->ss, regs->esp3, operand);
  213. }
  214. break;
  215. }
  216. case 0x9D: // popf
  217. {
  218. if (!(prefix & PREFIX_OPSIZE))
  219. {
  220. regs->eflags &= 0xFFFF0000;
  221. regs->eflags |= peekw(regs->ss, regs->esp3) | CPU_STATUS_FLAG_VM;
  222. regs->esp3 += 2;
  223. }
  224. else
  225. {
  226. regs->eflags = peekl(regs->ss, regs->esp3) | CPU_STATUS_FLAG_VM;
  227. regs->esp3 += 4;
  228. }
  229. vm86_interrupts = (regs->eflags & CPU_STATUS_FLAG_IF) ? TRUE : FALSE;
  230. regs->eflags |= CPU_STATUS_FLAG_IF;
  231. break;
  232. }
  233. case 0xCD: // int
  234. {
  235. operand = peekb(regs->cs, regs->eip);
  236. regs->eip++;
  237. regs->esp3 -= 2;
  238. pokew(regs->ss, regs->esp3, (regs->eflags & (~CPU_STATUS_FLAG_VM)) | (vm86_interrupts ? CPU_STATUS_FLAG_IF : 0));
  239. regs->esp3 -= 2;
  240. pokew(regs->ss, regs->esp3, regs->cs);
  241. regs->esp3 -= 2;
  242. pokew(regs->ss, regs->esp3, regs->eip);
  243. operand = get_bios_interrupt(operand);
  244. regs->cs = (operand >> 16) & 0xFFFF;
  245. regs->eip = operand & 0xFFFF;
  246. break;
  247. }
  248. case 0xCF: // iret
  249. {
  250. if (regs->cs == VM86_TRAMPOLINE_CS && regs->eip == VM86_TRAMPOLINE_IP + 1)
  251. {
  252. registers_t *stack_regs = (registers_t*)get_kernel_esp();
  253. stack_regs->esp += 20;
  254. set_kernel_esp(stack_regs->esp);
  255. vm86_registers_t *results = *(vm86_registers_t**)(stack_regs->esp + sizeof(vm86_registers_t));
  256. results->gs = regs->gs;
  257. results->fs = regs->fs;
  258. results->ds = regs->ds;
  259. results->es = regs->es;
  260. results->ss = regs->ss;
  261. results->esp = regs->esp;
  262. results->eflags = regs->eflags;
  263. results->cs = regs->cs;
  264. results->eip = regs->eip;
  265. results->eax = regs->eax;
  266. results->ecx = regs->ecx;
  267. results->edx = regs->edx;
  268. results->ebx = regs->ebx;
  269. results->ebp = regs->ebp;
  270. results->esi = regs->esi;
  271. results->edi = regs->edi;
  272. memcpy(regs, stack_regs, sizeof(registers_t));
  273. return;
  274. }
  275. regs->eip = peekw(regs->ss, regs->esp3);
  276. regs->esp3 += 2;
  277. regs->cs = peekw(regs->ss, regs->esp3);
  278. regs->esp3 += 2;
  279. regs->eflags = peekw(regs->ss, regs->esp3) | CPU_STATUS_FLAG_VM;
  280. regs->esp3 += 2;
  281. vm86_interrupts = (regs->eflags & CPU_STATUS_FLAG_IF) ? TRUE : FALSE;
  282. regs->eflags |= CPU_STATUS_FLAG_IF;
  283. break;
  284. }
  285. case 0xE4: // in al, <byte>
  286. {
  287. operand = peekb(regs->cs, regs->eip);
  288. regs->eip++;
  289. regs->eax &= 0xFFFFFF00;
  290. regs->eax |= cpu_read_port_byte(operand & 0xFF) & 0xFF;
  291. break;
  292. }
  293. case 0xE5: // in (e)ax, <byte>
  294. {
  295. operand = peekb(regs->cs, regs->eip);
  296. regs->eip++;
  297. if (!(prefix & PREFIX_OPSIZE))
  298. {
  299. regs->eax &= 0xFFFF0000;
  300. regs->eax |= cpu_read_port_word(operand & 0xFF) & 0xFFFF;
  301. }
  302. else regs->eax = cpu_read_port_dword(operand & 0xFF);
  303. break;
  304. }
  305. case 0xE6: // out <byte>, al
  306. {
  307. operand = peekb(regs->cs, regs->eip);
  308. regs->eip++;
  309. cpu_write_port_byte(operand & 0xFF, regs->eax & 0xFF);
  310. break;
  311. }
  312. case 0xE7: // out <byte>, (e)ax
  313. {
  314. operand = peekb(regs->cs, regs->eip);
  315. regs->eip++;
  316. if (!(prefix & PREFIX_OPSIZE)) cpu_write_port_word(operand & 0xFF, regs->eax & 0xFFFF);
  317. else cpu_write_port_dword(operand & 0xFF, regs->eax);
  318. break;
  319. }
  320. case 0xEC: // in al, dx
  321. {
  322. regs->eax &= 0xFFFFFF00;
  323. regs->eax |= cpu_read_port_byte(regs->edx & 0xFFFF) & 0xFF;
  324. break;
  325. }
  326. case 0xED: // in (e)ax, dx
  327. {
  328. if (!(prefix & PREFIX_OPSIZE))
  329. {
  330. regs->eax &= 0xFFFF0000;
  331. regs->eax |= cpu_read_port_word(regs->edx & 0xFFFF) & 0xFFFF;
  332. }
  333. else regs->eax = cpu_read_port_dword(regs->edx & 0xFFFF);
  334. break;
  335. }
  336. case 0xEE: // out dx, al
  337. {
  338. cpu_write_port_byte(regs->edx & 0xFFFF, regs->eax & 0xFF);
  339. break;
  340. }
  341. case 0xEF: // out dx, (e)ax
  342. {
  343. if (!(prefix & PREFIX_OPSIZE)) cpu_write_port_word(regs->edx & 0xFFFF, regs->eax & 0xFFFF);
  344. else cpu_write_port_dword(regs->edx & 0xFFFF, regs->eax);
  345. break;
  346. }
  347. case 0xFA: // cli
  348. {
  349. vm86_interrupts = FALSE;
  350. break;
  351. }
  352. case 0xFB: // sti
  353. {
  354. vm86_interrupts = TRUE;
  355. break;
  356. }
  357. default:
  358. {
  359. KERNEL_CRASH_WITH_REGS("General Protection Fault (VM86)", (registers_t*)regs);
  360. }
  361. }
  362. }
  363. dword_t vm86_interrupt(byte_t number, vm86_registers_t *regs)
  364. {
  365. critical_t critical;
  366. enter_critical(&critical);
  367. process_t *old_process = switch_process(kernel_process);
  368. dword_t ret = map_memory_internal(NULL, NULL, 0x100000, PAGE_PRESENT | PAGE_WRITABLE | PAGE_USERMODE);
  369. if (ret != ERR_SUCCESS) return ret;
  370. dword_t far_ptr = get_bios_interrupt(number);
  371. regs->cs = (far_ptr >> 16) & 0xFFFF;
  372. regs->eip = far_ptr & 0xFFFF;
  373. regs->ss = VM86_TRAMPOLINE_SS;
  374. regs->esp = VM86_TRAMPOLINE_SP;
  375. regs->eflags = 0x00020202;
  376. pokew(VM86_TRAMPOLINE_SS, VM86_TRAMPOLINE_SP, VM86_TRAMPOLINE_IP);
  377. pokew(VM86_TRAMPOLINE_SS, VM86_TRAMPOLINE_SP + 2, VM86_TRAMPOLINE_CS);
  378. pokew(VM86_TRAMPOLINE_SS, VM86_TRAMPOLINE_SP + 4, 0x0002);
  379. pokeb(VM86_TRAMPOLINE_CS, VM86_TRAMPOLINE_IP, 0xCF);
  380. vm86_start(*regs, regs);
  381. unmap_memory_internal(NULL, 0x100000);
  382. switch_process(old_process);
  383. leave_critical(&critical);
  384. return ERR_SUCCESS;
  385. }