Subversion Repositories Kolibri OS

Rev

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