Subversion Repositories Kolibri OS

Rev

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