Subversion Repositories Kolibri OS

Rev

Rev 928 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  2. ;;                                                              ;;
  3. ;; Copyright (C) KolibriOS team 2007-2008. All rights reserved. ;;
  4. ;; Distributed under terms of the GNU General Public License    ;;
  5. ;;                                                              ;;
  6. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  7.  
  8. $Revision: 996 $
  9.  
  10. ; Virtual-8086 mode manager
  11. ; diamond, 2007, 2008
  12.  
  13. DEBUG_SHOW_IO = 0
  14.  
  15. struc V86_machine
  16. {
  17. ; page directory
  18.         .pagedir dd     ?
  19. ; translation table: V86 address -> flat linear address
  20.         .pages  dd      ?
  21. ; mutex to protect all data from writing by multiple threads at one time
  22.         .mutex  dd      ?
  23. ; i/o permission map
  24.         .iopm   dd      ?
  25. .size = $
  26. }
  27. virtual at 0
  28. V86_machine V86_machine
  29. end virtual
  30.  
  31. ; Create V86 machine
  32. ; in: nothing
  33. ; out: eax = handle (pointer to struc V86_machine)
  34. ;      eax = NULL => failure
  35. ; destroys: ebx, ecx, edx (due to malloc)
  36. v86_create:
  37. ; allocate V86_machine structure
  38.         mov     eax, V86_machine.size
  39.         call    malloc
  40.         test    eax, eax
  41.         jz      .fail
  42. ; initialize mutex
  43.         and     dword [eax+V86_machine.mutex], 0
  44. ; allocate tables
  45.         mov     ebx, eax
  46. ; We allocate 4 pages.
  47. ; First is main page directory for V86 mode.
  48. ; Second page:
  49. ; first half (0x800 bytes) is page table for addresses 0 - 0x100000,
  50. ; second half is for V86-to-linear translation.
  51. ; Third and fourth are for I/O permission map.
  52.  
  53.         mov ecx, 0x4000
  54.         mov edx, PG_SW
  55.         call    @mem_alloc@8
  56.         test    eax, eax
  57.         jz      .fail2
  58.         mov     [ebx+V86_machine.pagedir], eax
  59.         push    edi eax
  60.         mov     edi, eax
  61.         add     eax, 1800h
  62.         mov     [ebx+V86_machine.pages], eax
  63. ; initialize tables
  64.         mov     ecx, 2000h/4
  65.         xor     eax, eax
  66.         rep     stosd
  67.         mov     [ebx+V86_machine.iopm], edi
  68.         dec     eax
  69.         mov     ecx, 2000h/4
  70.         rep     stosd
  71.         pop     eax
  72. ; page directory: first entry is page table...
  73.         mov     edi, eax
  74.         add     eax, 1000h
  75.         push    eax
  76.         call    get_pg_addr
  77.         or      al, PG_UW
  78.         stosd
  79. ; ...and also copy system page tables
  80. ; thx to Serge, system is located at high addresses
  81.         add     edi, (HEAP_BASE shr 20) - 4
  82.         push    esi
  83.         mov     esi, (HEAP_BASE shr 20) + _sys_pdbr
  84.         mov     ecx, 0x80000000 shr 22
  85.         rep     movsd
  86.  
  87.         mov     eax, [ebx+V86_machine.pagedir]   ;root dir also is
  88.         call    get_pg_addr                      ;used as page table
  89.         or      al, PG_SW
  90.         mov [edi-4096+(page_tabs shr 20)], eax
  91.  
  92.         pop     esi
  93. ; now V86 specific: initialize known addresses in first Mb
  94.         pop     eax
  95. ; first page - BIOS data (shared between all machines!)
  96. ; physical address = 0x1f0000
  97. ; linear address = 0
  98.         mov     dword [eax], 111b
  99.         mov     dword [eax+800h], OS_BASE
  100. ; page before 0xA0000 - Extended BIOS Data Area (shared between all machines!)
  101. ; physical address = 0x9C000
  102. ; linear address = 0x8009C000
  103. ; (I have seen one computer with EBDA segment = 0x9D80,
  104. ; all other computers use less memory)
  105.         mov     ecx, 4
  106.         mov     edx, 0x9C000
  107.         push    eax
  108.         lea     edi, [eax+0x9C*4]
  109. @@:
  110.         lea     eax, [edx + OS_BASE]
  111.         mov     [edi+800h], eax
  112.         lea     eax, [edx + 111b]
  113.         stosd
  114.         add     edx, 0x1000
  115.         loop    @b
  116.         pop     eax
  117.         pop     edi
  118. ; addresses 0xC0000 - 0xFFFFF - BIOS code (shared between all machines!)
  119. ; physical address = 0xC0000
  120. ; linear address = 0x800C0000
  121.         mov     ecx, 0xC0
  122. @@:
  123.         mov     edx, ecx
  124.         shl     edx, 12
  125.         push    edx
  126.         or      edx, 101b
  127.         mov     [eax+ecx*4], edx
  128.         pop     edx
  129.         add     edx, OS_BASE
  130.         mov     [eax+ecx*4+0x800], edx
  131.         inc     cl
  132.         jnz     @b
  133.         mov     eax, ebx
  134.         ret
  135. .fail2:
  136.         mov     eax, ebx
  137.         call    free
  138. .fail:
  139.         xor     eax, eax
  140.         ret
  141.  
  142. ; Destroy V86 machine
  143. ; in: eax = handle
  144. ; out: nothing
  145. ; destroys: eax, ebx, ecx, edx (due to free)
  146. v86_destroy:
  147.         push    eax
  148.  
  149.         mov ecx, [eax+V86_machine.pagedir]
  150.         call @mem_free@4
  151.  
  152.         pop     eax
  153.         jmp     free
  154.  
  155. ; Translate V86-address to linear address
  156. ; in: eax=V86 address
  157. ;     esi=handle
  158. ; out: eax=linear address
  159. ; destroys: nothing
  160. v86_get_lin_addr:
  161.         push    ecx edx
  162.         mov     ecx, eax
  163.         mov     edx, [esi+V86_machine.pages]
  164.         shr     ecx, 12
  165.         and     eax, 0xFFF
  166.         add     eax, [edx+ecx*4]        ; atomic operation, no mutex needed
  167.         pop     edx ecx
  168.         ret
  169.  
  170. ; Sets linear address for V86-page
  171. ; in: eax=linear address (must be page-aligned)
  172. ;     ecx=V86 page (NOT address!)
  173. ;     esi=handle
  174. ; out: nothing
  175. ; destroys: nothing
  176. v86_set_page:
  177.         push    eax ebx
  178.         mov     ebx, [esi+V86_machine.pagedir]
  179.         mov     [ebx+ecx*4+0x1800], eax
  180.         call    get_pg_addr
  181.         or      al, 111b
  182.         mov     [ebx+ecx*4+0x1000], eax
  183.         pop     ebx eax
  184.         ret
  185.  
  186. ; Allocate memory in V86 machine
  187. ; in: eax=size (in bytes)
  188. ;     esi=handle
  189. ; out: eax=V86 address, para-aligned (0x10 multiple)
  190. ; destroys: nothing
  191. ; ­¥¤®¯¨á ­ !!!
  192. ;v86_alloc:
  193. ;        push    ebx ecx edx edi
  194. ;        lea     ebx, [esi+V86_machine.mutex]
  195. ;        call    wait_mutex
  196. ;        add     eax, 0x1F
  197. ;        shr     eax, 4
  198. ;        mov     ebx, 0x1000  ; start with address 0x1000 (second page)
  199. ;        mov     edi, [esi+V86_machine.tables]
  200. ;.l:
  201. ;        mov     ecx, ebx
  202. ;        shr     ecx, 12
  203. ;        mov     edx, [edi+0x1000+ecx*4] ; get linear address
  204. ;        test    edx, edx                ; page allocated?
  205. ;        jz      .unalloc
  206. ;        mov     ecx, ebx
  207. ;        and     ecx, 0xFFF
  208. ;        add     edx, ecx
  209. ;        cmp     dword [edx], 0          ; free block?
  210. ;        jnz     .n
  211. ;        cmp     dword [edx+4],
  212. ;        and     [esi+V86_machine.mutex], 0
  213. ;        pop     edi edx ecx ebx
  214. ;        ret
  215.  
  216. uglobal
  217. sys_v86_machine dd      ?
  218. endg
  219.  
  220. ; Called from kernel.asm at first stages of loading
  221. ; Initialize system V86 machine (used to simulate BIOS int 13h)
  222. init_sys_v86:
  223.         call    v86_create
  224.         mov     [sys_v86_machine], eax
  225.         test    eax, eax
  226.         jz      .ret
  227.         mov     byte [BOOT_VAR + 0x500], 0xCD
  228.         mov     byte [BOOT_VAR + 0x501], 0x13
  229.         mov     byte [BOOT_VAR + 0x502], 0xF4
  230.         mov     byte [BOOT_VAR + 0x503], 0xCD
  231.         mov     byte [BOOT_VAR + 0x504], 0x10
  232.         mov     byte [BOOT_VAR + 0x505], 0xF4
  233.         mov     esi, eax
  234.         mov     ebx, [eax+V86_machine.pagedir]
  235. ; one page for stack, two pages for results (0x2000 bytes = 16 sectors)
  236.         mov     dword [ebx+0x99*4+0x1000], 0x99000 or 111b
  237.         mov     dword [ebx+0x99*4+0x1800], OS_BASE + 0x99000
  238.         mov     dword [ebx+0x9A*4+0x1000], 0x9A000 or 111b
  239.         mov     dword [ebx+0x9A*4+0x1800], OS_BASE + 0x9A000
  240.         mov     dword [ebx+0x9B*4+0x1000], 0x9B000 or 111b
  241.         mov     dword [ebx+0x9B*4+0x1800], OS_BASE + 0x9B000
  242. if ~DEBUG_SHOW_IO
  243. ; allow access to all ports
  244.         mov     ecx, [esi+V86_machine.iopm]
  245.         xor     eax, eax
  246.         mov     edi, ecx
  247.         mov     ecx, 10000h/8/4
  248.         rep     stosd
  249. end if
  250. .ret:
  251.         ret
  252.  
  253. struc v86_regs
  254. {
  255. ; don't change the order, it is important
  256.         .edi    dd      ?
  257.         .esi    dd      ?
  258.         .ebp    dd      ?
  259.                 dd      ?       ; ignored
  260.         .ebx    dd      ?
  261.         .edx    dd      ?
  262.         .ecx    dd      ?
  263.         .eax    dd      ?
  264.         .eip    dd      ?
  265.         .cs     dd      ?
  266.         .eflags dd      ?       ; VM flag must be set!
  267.         .esp    dd      ?
  268.         .ss     dd      ?
  269.         .es     dd      ?
  270.         .ds     dd      ?
  271.         .fs     dd      ?
  272.         .gs     dd      ?
  273. .size = $
  274. }
  275. virtual at 0
  276. v86_regs v86_regs
  277. end virtual
  278.  
  279. ; Run V86 machine
  280. ; in: ebx -> registers for V86 (two structures: in and out)
  281. ;     esi = handle
  282. ;     ecx = expected end address (CS:IP)
  283. ;     edx = IRQ to hook or -1 if not required
  284. ; out: structure pointed to by ebx is filled with new values
  285. ;     eax = 1 - exception has occured, cl contains code
  286. ;     eax = 2 - access to disabled i/o port, ecx contains port address
  287. ;     eax = 3 - IRQ is already hooked by another VM
  288. ; destroys: nothing
  289. v86_start:
  290.         pushad
  291.  
  292.         cli
  293.  
  294.         mov     ecx, [CURRENT_TASK]
  295.         shl     ecx, 8
  296.         add     ecx, SLOT_BASE
  297.  
  298.         mov     eax, [esi+V86_machine.iopm]
  299.         call    get_pg_addr
  300.         inc     eax
  301.         push    dword [ecx+APPDATA.io_map]
  302.         push    dword [ecx+APPDATA.io_map+4]
  303.         mov     dword [ecx+APPDATA.io_map], eax
  304.     ;    mov     dword [page_tabs + (tss._io_map_0 shr 10)], eax
  305.         add     eax, 0x1000
  306.         mov     dword [ecx+APPDATA.io_map+4], eax
  307.     ;    mov     dword [page_tabs + (tss._io_map_1 shr 10)], eax
  308.  
  309.         push    [ecx+APPDATA.dir_table]
  310.         push    [ecx+APPDATA.saved_esp0]
  311.         mov     [ecx+APPDATA.saved_esp0], esp
  312.         mov     [tss._esp0], esp
  313.  
  314.         mov     eax, [esi+V86_machine.pagedir]
  315.         call    get_pg_addr
  316.         mov     [ecx+APPDATA.dir_table], eax
  317.         mov     cr3, eax
  318.  
  319. ;        mov     [irq_tab+5*4], my05
  320.  
  321. ; We do not enable interrupts, because V86 IRQ redirector assumes that
  322. ; machine is running
  323. ; They will be enabled by IRET.
  324. ;        sti
  325.  
  326.         mov     eax, esi
  327.         sub     esp, v86_regs.size
  328.         mov     esi, ebx
  329.         mov     edi, esp
  330.         mov     ecx, v86_regs.size/4
  331.         rep     movsd
  332.  
  333.         cmp     edx, -1
  334.         jz      .noirqhook
  335. uglobal
  336. v86_irqhooks    rd      16*2
  337. endg
  338.         cmp     [v86_irqhooks+edx*8], 0
  339.         jz      @f
  340.         cmp     [v86_irqhooks+edx*8], eax
  341.         jz      @f
  342.         mov     esi, v86_irqerr
  343.         call    sys_msg_board_str
  344.         inc     [v86_irqhooks+edx*8+4]
  345.         mov     eax, 3
  346.         jmp     v86_exc_c.exit
  347. @@:
  348.         mov     [v86_irqhooks+edx*8], eax
  349.         inc     [v86_irqhooks+edx*8+4]
  350. .noirqhook:
  351.  
  352.         popad
  353.         iretd
  354.  
  355. ; It is only possible to leave virtual-8086 mode by faulting to
  356. ; a protected-mode interrupt handler (typically the general-protection
  357. ; exception handler, which in turn calls the virtual 8086-mode monitor).
  358.  
  359. v86_debug_exc:
  360.         pushad
  361.         xor     eax, eax
  362.         mov     dr6, eax
  363.         mov     bl, 1
  364.         jmp     v86_exc_c
  365.  
  366. v86_page_fault:
  367.         add     esp, 4
  368.         pushad
  369.         mov     bl, 14
  370.         jmp     v86_exc_c
  371.  
  372. v86_except_16:
  373.         pushad
  374.         mov     bl, 16
  375.         jmp     v86_exc_c
  376. v86_except_19:
  377.         pushad
  378.         mov     bl, 19
  379.  
  380. iglobal
  381. v86_exc_str1    db      'V86 : unexpected exception ',0
  382. v86_exc_str2    db      ' at ',0
  383. v86_exc_str3    db      ':',0
  384. v86_exc_str4    db      13,10,'V86 : faulted code:',0
  385. v86_exc_str5    db      ' (unavailable)',0
  386. v86_newline     db      13,10,0
  387. v86_io_str1     db      'V86 : access to disabled i/o port ',0
  388. v86_io_byte     db      ' (byte)',13,10,0
  389. v86_io_word     db      ' (word)',13,10,0
  390. v86_io_dword    db      ' (dword)',13,10,0
  391. v86_irqerr      db      'V86 : IRQ already hooked',13,10,0
  392. endg
  393.  
  394. v86_exc_c:
  395.         mov     ax, sel_app_data
  396.         mov     ds, ax
  397.         mov     es, ax
  398. ; Did we all that we have wanted to do?
  399.         mov     eax, [esp+v86_regs.size+10h+18h]
  400.         cmp     word [esp+v86_regs.eip], ax
  401.         jnz     @f
  402.         shr     eax, 16
  403.         cmp     word [esp+v86_regs.cs], ax
  404.         jz      .done
  405. @@:
  406. ; Various system events, which must be handled, result in #GP
  407.         cmp     bl, 13
  408.         jnz     .nogp
  409. ; If faulted EIP exceeds 0xFFFF, we have #GP and it is an error
  410.         cmp     word [esp+v86_regs.eip+2], 0
  411.         jnz     .nogp
  412. ; Otherwise we can safely access byte at CS:IP
  413. ; (because it is #GP, not #PF handler)
  414. ; …᫨ ¡ë ¬ë ¬®£«¨ áå«®¯®â âì ¨áª«î祭¨¥ ⮫쪮 ¨§-§  ç⥭¨ï ¡ ©â®¢ ª®¤ ,
  415. ; ¬ë ¡ë ¥£® 㦥 áå«®¯®â «¨ ¨ íâ® ¡ë«® ¡ë ­¥ #GP
  416.         movzx   esi, word [esp+v86_regs.cs]
  417.         shl     esi, 4
  418.         add     esi, [esp+v86_regs.eip]
  419.         lodsb
  420.         cmp     al, 0xCD        ; int xx command = CD xx
  421.         jz      .handle_int
  422.         cmp     al, 0xCF
  423.         jz      .handle_iret
  424.         cmp     al, 0xF3
  425.         jz      .handle_rep
  426.         cmp     al, 0xEC
  427.         jz      .handle_in
  428.         cmp     al, 0xED
  429.         jz      .handle_in_word
  430.         cmp     al, 0xEE
  431.         jz      .handle_out
  432.         cmp     al, 0xEF
  433.         jz      .handle_out_word
  434.         cmp     al, 0xE4
  435.         jz      .handle_in_imm
  436.         cmp     al, 0xE6
  437.         jz      .handle_out_imm
  438.         cmp     al, 0x9C
  439.         jz      .handle_pushf
  440.         cmp     al, 0x9D
  441.         jz      .handle_popf
  442.         cmp     al, 0xFA
  443.         jz      .handle_cli
  444.         cmp     al, 0xFB
  445.         jz      .handle_sti
  446.         cmp     al, 0x66
  447.         jz      .handle_66
  448.         jmp     .nogp
  449. .handle_int:
  450.         cmp     word [esp+v86_regs.eip], 0xFFFF
  451.         jae     .nogp
  452.         xor     eax, eax
  453.         lodsb
  454. ;        call    sys_msg_board_byte
  455. ; simulate INT command
  456. ; N.B. It is possible that some checks need to be corrected,
  457. ;      but at least in case of normal execution the code works.
  458. .simulate_int:
  459.         cmp     word [esp+v86_regs.esp], 6
  460.         jae     @f
  461.         mov     bl, 12          ; #SS exception
  462.         jmp     .nogp
  463. @@:
  464.         movzx   edx, word [esp+v86_regs.ss]
  465.         shl     edx, 4
  466.         push    eax
  467.         movzx   eax, word [esp+4+v86_regs.esp]
  468.         sub     eax, 6
  469.         add     edx, eax
  470.         mov     eax, edx
  471.         mov     esi, [esp+4+v86_regs.size+10h+4]
  472.         call    v86_get_lin_addr
  473.         cmp     eax, 0x1000
  474.         jae     @f
  475.         mov     bl, 14          ; #PF exception
  476.         jmp     .nogp
  477. @@:
  478.         lea     eax, [edx+5]
  479.         call    v86_get_lin_addr
  480.         cmp     eax, 0x1000
  481.         jae     @f
  482.         mov     bl, 14          ; #PF exception
  483.         jmp     .nogp
  484. @@:
  485.         sub     word [esp+4+v86_regs.esp], 6
  486.         mov     eax, [esp+4+v86_regs.eip]
  487.         inc     eax
  488.         inc     eax
  489.         mov     word [edx], ax
  490.         mov     eax, [esp+4+v86_regs.cs]
  491.         mov     word [edx+2], ax
  492.         mov     eax, [esp+4+v86_regs.eflags]
  493.         mov     word [edx+4], ax
  494.         pop     eax
  495.         mov     cx, [eax*4]
  496.         mov     word [esp+v86_regs.eip], cx
  497.         mov     cx, [eax*4+2]
  498.         mov     word [esp+v86_regs.cs], cx
  499. ; note that interrupts will be disabled globally at IRET
  500.         and     byte [esp+v86_regs.eflags+1], not 3 ; clear IF and TF flags
  501. ; continue V86 execution
  502.         popad
  503.         iretd
  504. .handle_iret:
  505.         cmp     word [esp+v86_regs.esp], 0x10000 - 6
  506.         jbe     @f
  507.         mov     bl, 12
  508.         jmp     .nogp
  509. @@:
  510.         movzx   edx, word [esp+v86_regs.ss]
  511.         shl     edx, 4
  512.         movzx   eax, word [esp+v86_regs.esp]
  513.         add     edx, eax
  514.         mov     eax, edx
  515.         mov     esi, [esp+v86_regs.size+10h+4]
  516.         call    v86_get_lin_addr
  517.         cmp     eax, 0x1000
  518.         jae     @f
  519.         mov     bl, 14
  520.         jmp     .nogp
  521. @@:
  522.         lea     eax, [edx+5]
  523.         call    v86_get_lin_addr
  524.         cmp     eax, 0x1000
  525.         jae     @f
  526.         mov     bl, 14
  527.         jmp     .nogp
  528. @@:
  529.         mov     ax, [edx]
  530.         mov     word [esp+v86_regs.eip], ax
  531.         mov     ax, [edx+2]
  532.         mov     word [esp+v86_regs.cs], ax
  533.         mov     ax, [edx+4]
  534.         mov     word [esp+v86_regs.eflags], ax
  535.         add     word [esp+v86_regs.esp], 6
  536.         popad
  537.         iretd
  538. .handle_pushf:
  539.         cmp     word [esp+v86_regs.esp], 1
  540.         jnz     @f
  541.         mov     bl, 12
  542.         jmp     .nogp
  543. @@:
  544.         movzx   edx, word [esp+v86_regs.ss]
  545.         shl     edx, 4
  546.         mov     eax, [esp+v86_regs.esp]
  547.         sub     eax, 2
  548.         movzx   eax, ax
  549.         add     edx, eax
  550.         mov     eax, edx
  551.         mov     esi, [esp+v86_regs.size+10h+4]
  552.         call    v86_get_lin_addr
  553.         cmp     eax, 0x1000
  554.         jae     @f
  555.         mov     bl, 14          ; #PF exception
  556.         jmp     .nogp
  557. @@:
  558.         lea     eax, [edx+1]
  559.         call    v86_get_lin_addr
  560.         cmp     eax, 0x1000
  561.         jae     @f
  562.         mov     bl, 14
  563.         jmp     .nogp
  564. @@:
  565.         sub     word [esp+v86_regs.esp], 2
  566.         mov     eax, [esp+v86_regs.eflags]
  567.         mov     [edx], ax
  568.         inc     word [esp+v86_regs.eip]
  569.         popad
  570.         iretd
  571. .handle_pushfd:
  572.         cmp     word [esp+v86_regs.esp], 4
  573.         jae     @f
  574.         mov     bl, 12          ; #SS exception
  575.         jmp     .nogp
  576. @@:
  577.         movzx   edx, word [esp+v86_regs.ss]
  578.         shl     edx, 4
  579.         movzx   eax, word [esp+v86_regs.esp]
  580.         sub     eax, 4
  581.         add     edx, eax
  582.         mov     eax, edx
  583.         mov     esi, [esp+v86_regs.size+10h+4]
  584.         call    v86_get_lin_addr
  585.         cmp     eax, 0x1000
  586.         jae     @f
  587.         mov     bl, 14          ; #PF exception
  588.         jmp     .nogp
  589. @@:
  590.         lea     eax, [edx+3]
  591.         call    v86_get_lin_addr
  592.         cmp     eax, 0x1000
  593.         jae     @f
  594.         mov     bl, 14          ; #PF exception
  595.         jmp     .nogp
  596. @@:
  597.         sub     word [esp+v86_regs.esp], 4
  598.         movzx   eax, word [esp+v86_regs.eflags]
  599.         mov     [edx], eax
  600.         add     word [esp+v86_regs.eip], 2
  601.         popad
  602.         iretd
  603. .handle_popf:
  604.         cmp     word [esp+v86_regs.esp], 0xFFFF
  605.         jnz     @f
  606.         mov     bl, 12
  607.         jmp     .nogp
  608. @@:
  609.         movzx   edx, word [esp+v86_regs.ss]
  610.         shl     edx, 4
  611.         movzx   eax, word [esp+v86_regs.esp]
  612.         add     edx, eax
  613.         mov     eax, edx
  614.         mov     esi, [esp+v86_regs.size+10h+4]
  615.         call    v86_get_lin_addr
  616.         cmp     eax, 0x1000
  617.         jae     @f
  618.         mov     bl, 14          ; #PF exception
  619.         jmp     .nogp
  620. @@:
  621.         lea     eax, [edx+1]
  622.         call    v86_get_lin_addr
  623.         cmp     eax, 0x1000
  624.         jae     @f
  625.         mov     bl, 14
  626.         jmp     .nogp
  627. @@:
  628.         mov     ax, [edx]
  629.         mov     word [esp+v86_regs.eflags], ax
  630.         add     word [esp+v86_regs.esp], 2
  631.         inc     word [esp+v86_regs.eip]
  632.         popad
  633.         iretd
  634. .handle_popfd:
  635.         cmp     word [esp+v86_regs.esp], 0x10000 - 4
  636.         jbe     @f
  637.         mov     bl, 12
  638.         jmp     .nogp
  639. @@:
  640.         movzx   edx, word [esp+v86_regs.ss]
  641.         shl     edx, 4
  642.         movzx   eax, word [esp+v86_regs.esp]
  643.         add     edx, eax
  644.         mov     eax, edx
  645.         mov     esi, [esp+v86_regs.size+10h+4]
  646.         call    v86_get_lin_addr
  647.         cmp     eax, 0x1000
  648.         jae     @f
  649.         mov     bl, 14
  650.         jmp     .nogp
  651. @@:
  652.         lea     eax, [edx+3]
  653.         call    v86_get_lin_addr
  654.         cmp     eax, 0x1000
  655.         jae     @f
  656.         mov     bl, 14
  657.         jmp     .nogp
  658. @@:
  659.         mov     eax, [edx]
  660.         mov     word [esp+v86_regs.eflags], ax
  661.         add     word [esp+v86_regs.esp], 4
  662.         add     word [esp+v86_regs.eip], 2
  663.         popad
  664.         iretd
  665. .handle_cli:
  666.         and     byte [esp+v86_regs.eflags+1], not 2
  667.         inc     word [esp+v86_regs.eip]
  668.         popad
  669.         iretd
  670. .handle_sti:
  671.         or      byte [esp+v86_regs.eflags+1], 2
  672.         inc     word [esp+v86_regs.eip]
  673.         popad
  674.         iretd
  675. .handle_rep:
  676.         cmp     word [esp+v86_regs.eip], 0xFFFF
  677.         jae     .nogp
  678.         lodsb
  679.         cmp     al, 6Eh
  680.         jz      .handle_rep_outsb
  681.         jmp     .nogp
  682. .handle_rep_outsb:
  683. .handle_in:
  684. .handle_out:
  685. .invalid_io_byte:
  686.         movzx   ebx, word [esp+v86_regs.edx]
  687.         mov     ecx, 1
  688.         jmp     .invalid_io
  689. .handle_in_imm:
  690. .handle_out_imm:
  691.         cmp     word [esp+v86_regs.eip], 0xFFFF
  692.         jae     .nogp
  693.         lodsb
  694.         movzx   ebx, al
  695.         mov     ecx, 1
  696.         jmp     .invalid_io
  697. .handle_66:
  698.         cmp     word [esp+v86_regs.eip], 0xFFFF
  699.         jae     .nogp
  700.         lodsb
  701.         cmp     al, 0x9C
  702.         jz      .handle_pushfd
  703.         cmp     al, 0x9D
  704.         jz      .handle_popfd
  705.         cmp     al, 0xEF
  706.         jz      .handle_out_dword
  707.         cmp     al, 0xED
  708.         jz      .handle_in_dword
  709.         jmp     .nogp
  710. .handle_in_word:
  711. .handle_out_word:
  712.         movzx   ebx, word [esp+v86_regs.edx]
  713.         mov     ecx, 2
  714.         jmp     .invalid_io
  715. .handle_in_dword:
  716. .handle_out_dword:
  717. .invalid_io_dword:
  718.         movzx   ebx, word [esp+v86_regs.edx]
  719.         mov     ecx, 4
  720. .invalid_io:
  721.         mov     esi, v86_io_str1
  722.         call    sys_msg_board_str
  723.         mov     eax, ebx
  724.         call    sys_msg_board_dword
  725.         mov     esi, v86_io_byte
  726.         cmp     ecx, 1
  727.         jz      @f
  728.         mov     esi, v86_io_word
  729.         cmp     ecx, 2
  730.         jz      @f
  731.         mov     esi, v86_io_dword
  732. @@:
  733.         call    sys_msg_board_str
  734. if DEBUG_SHOW_IO
  735.         mov     edx, ebx
  736.         mov     ebx, 200
  737.         call    delay_hs
  738.         mov     esi, [esp+v86_regs.size+10h+4]
  739.         mov     eax, [esi+V86_machine.iopm]
  740. @@:
  741.         btr     [eax], edx
  742.         inc     edx
  743.         loop    @b
  744.         popad
  745.         iretd
  746. else
  747.         mov     eax, 2
  748.         jmp     .exit
  749. end if
  750. .nogp:
  751.  
  752.         mov     esi, v86_exc_str1
  753.         call    sys_msg_board_str
  754.         mov     al, bl
  755.         call    sys_msg_board_byte
  756.         mov     esi, v86_exc_str2
  757.         call    sys_msg_board_str
  758.         mov     ax, [esp+32+4]
  759.         call    sys_msg_board_word
  760.         mov     esi, v86_exc_str3
  761.         call    sys_msg_board_str
  762.         mov     ax, [esp+32]
  763.         call    sys_msg_board_word
  764.         mov     esi, v86_exc_str4
  765.         call    sys_msg_board_str
  766.         mov     ecx, 8
  767.         movzx   edx, word [esp+32+4]
  768.         shl     edx, 4
  769.         add     edx, [esp+32]
  770. @@:
  771.         mov     esi, [esp+v86_regs.size+10h+4]
  772.         mov     eax, edx
  773.         call    v86_get_lin_addr
  774.         cmp     eax, 0x1000
  775.         jb      .nopage
  776.         mov     esi, v86_exc_str3-2
  777.         call    sys_msg_board_str
  778.         mov     al, [edx]
  779.         call    sys_msg_board_byte
  780.         inc     edx
  781.         loop    @b
  782.         jmp     @f
  783. .nopage:
  784.         mov     esi, v86_exc_str5
  785.         call    sys_msg_board_str
  786. @@:
  787.         mov     esi, v86_newline
  788.         call    sys_msg_board_str
  789.         mov     eax, 1
  790.         jmp     .exit
  791.  
  792. .done:
  793.         xor     eax, eax
  794.  
  795. .exit:
  796.         mov     [esp+v86_regs.size+10h+1Ch], eax
  797.         mov     [esp+v86_regs.size+10h+18h], ebx
  798.  
  799.         mov     edx, [esp+v86_regs.size+10h+14h]
  800.         cmp     edx, -1
  801.         jz      @f
  802.         dec     [v86_irqhooks+edx*8+4]
  803.         jnz     @f
  804.         and     [v86_irqhooks+edx*8], 0
  805. @@:
  806.  
  807.         mov     esi, esp
  808.         mov     edi, [esi+v86_regs.size+10h+10h]
  809.         add     edi, v86_regs.size
  810.         mov     ecx, v86_regs.size/4
  811.         rep     movsd
  812.         mov     esp, esi
  813.  
  814.         cli
  815.         mov     ecx, [CURRENT_TASK]
  816.         shl     ecx, 8
  817.         pop     eax
  818.         mov     [SLOT_BASE+ecx+APPDATA.saved_esp0], eax
  819.         mov     [tss._esp0], eax
  820.         pop     eax
  821.         mov     [SLOT_BASE+ecx+APPDATA.dir_table], eax
  822.         pop     ebx
  823.         mov     dword [SLOT_BASE+ecx+APPDATA.io_map+4], ebx
  824.       ;  mov     dword [page_tabs + (tss._io_map_1 shr 10)], ebx
  825.         pop     ebx
  826.         mov     dword [SLOT_BASE+ecx+APPDATA.io_map], ebx
  827.       ;  mov     dword [page_tabs + (tss._io_map_0 shr 10)], ebx
  828.         mov     cr3, eax
  829. ;        mov     [irq_tab+5*4], 0
  830.         sti
  831.  
  832.         popad
  833.         ret
  834.  
  835. ;my05:
  836. ;        mov     dx, 30C2h
  837. ;        mov     cx, 4
  838. ;.0:
  839. ;        in      al, dx
  840. ;        cmp     al, 0FFh
  841. ;        jz      @f
  842. ;        test    al, 4
  843. ;        jnz     .1
  844. ;@@:
  845. ;        add     dx, 8
  846. ;        in      al, dx
  847. ;        cmp     al, 0FFh
  848. ;        jz      @f
  849. ;        test    al, 4
  850. ;        jnz     .1
  851. ;@@:
  852. ;        loop    .0
  853. ;        ret
  854. ;.1:
  855. ;        or      al, 84h
  856. ;        out     dx, al
  857. ;.2:
  858. ;        mov     dx, 30F7h
  859. ;        in      al, dx
  860. ;        mov     byte [BOOT_VAR + 48Eh], 0FFh
  861. ;        ret
  862.  
  863. v86_irq:
  864. ; push irq/pushad/jmp v86_irq
  865. ; eax = irq
  866.         lea     esi, [esp+1Ch]
  867.         lea     edi, [esi+4]
  868.         mov     ecx, 8
  869.         std
  870.         rep     movsd
  871.         cld
  872.         mov     edi, eax
  873.         pop     eax
  874.         mov     esi, [v86_irqhooks+edi*8]       ; get VM handle
  875.         mov     eax, [esi+V86_machine.pagedir]
  876.         call    get_pg_addr
  877.         mov     ecx, [CURRENT_TASK]
  878.         shl     ecx, 8
  879.         cmp     [SLOT_BASE+ecx+APPDATA.dir_table], eax
  880.         jnz     .notcurrent
  881.         lea     eax, [edi+8]
  882.         cmp     al, 10h
  883.         jb      @f
  884.         add     al, 60h
  885. @@:
  886.         jmp     v86_exc_c.simulate_int
  887. .notcurrent:
  888.         mov     ebx, SLOT_BASE + 0x100
  889.         mov     ecx, [TASK_COUNT]
  890. .scan:
  891.         cmp     [ebx+APPDATA.dir_table], eax
  892.         jnz     .cont
  893.         push    ecx
  894.         mov     ecx, [ebx+APPDATA.saved_esp0]
  895.         cmp     word [ecx-v86_regs.size+v86_regs.esp], 6
  896.         jb      .cont2
  897.         movzx   edx, word [ecx-v86_regs.size+v86_regs.ss]
  898.         shl     edx, 4
  899.         push    eax
  900.         movzx   eax, word [ecx-v86_regs.size+v86_regs.esp]
  901.         sub     eax, 6
  902.         add     edx, eax
  903.         mov     eax, edx
  904.         call    v86_get_lin_addr
  905.         cmp     eax, 0x1000
  906.         jb      .cont3
  907.         lea     eax, [edx+5]
  908.         call    v86_get_lin_addr
  909.         cmp     eax, 0x1000
  910.         jb      .cont3
  911.         pop     eax
  912.         pop     ecx
  913.         jmp     .found
  914. .cont3:
  915.         pop     eax
  916. .cont2:
  917.         pop     ecx
  918. .cont:
  919.         loop    .scan
  920.         mov     al, 20h
  921.         out     20h, al
  922.         cmp     edi, 8
  923.         jb      @f
  924.         out     0A0h, al
  925. @@:
  926.         popad
  927.         iretd
  928. .found:
  929.         mov     cr3, eax
  930.         sub     word [esi-v86_regs.size+v86_regs.esp], 6
  931.         mov     ecx, [esi-v86_regs.size+v86_regs.eip]
  932.         mov     word [edx], cx
  933.         mov     ecx, [esi-v86_regs.size+v86_regs.cs]
  934.         mov     word [edx+2], cx
  935.         mov     ecx, [esi-v86_regs.size+v86_regs.eflags]
  936.         mov     word [edx+4], cx
  937.         lea     eax, [edi+8]
  938.         cmp     al, 10h
  939.         jb      @f
  940.         add     al, 60h
  941. @@:
  942.         mov     cx, [eax*4]
  943.         mov     word [esi-v86_regs.size+v86_regs.eip], cx
  944.         mov     cx, [eax*4+2]
  945.         mov     word [esi-v86_regs.size+v86_regs.cs], cx
  946.         and     byte [esi-v86_regs.size+v86_regs.eflags+1], not 3
  947.         push    ebx
  948.         call    update_counters
  949.         pop     ebx
  950.         sub     ebx, SLOT_BASE
  951.         shr     ebx, 8
  952.         mov     esi, [CURRENT_TASK]
  953.         call    do_change_task
  954.         popad
  955.         iretd
  956.