Subversion Repositories Kolibri OS

Rev

Rev 4429 | Go to most recent revision | Blame | Last modification | View Log | Download | RSS feed

  1. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  2. ;;                                                              ;;
  3. ;; Copyright (C) KolibriOS team 2004-2012. All rights reserved. ;;
  4. ;; Distributed under terms of the GNU General Public License    ;;
  5. ;;                                                              ;;
  6. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  7.  
  8. $Revision: 4424 $
  9.  
  10.  
  11. align 4
  12. proc alloc_page
  13.  
  14.         pushfd
  15.         cli
  16.         push    ebx
  17. ;//-
  18.         cmp     [pg_data.pages_free], 1
  19.         jle     .out_of_memory
  20. ;//-
  21.  
  22.         mov     ebx, [page_start]
  23.         mov     ecx, [page_end]
  24. .l1:
  25.         bsf     eax, [ebx];
  26.         jnz     .found
  27.         add     ebx, 4
  28.         cmp     ebx, ecx
  29.         jb      .l1
  30.         pop     ebx
  31.         popfd
  32.         xor     eax, eax
  33.         ret
  34. .found:
  35. ;//-
  36.         dec     [pg_data.pages_free]
  37.         jz      .out_of_memory
  38. ;//-
  39.         btr     [ebx], eax
  40.         mov     [page_start], ebx
  41.         sub     ebx, sys_pgmap
  42.         lea     eax, [eax+ebx*8]
  43.         shl     eax, 12
  44. ;//-       dec [pg_data.pages_free]
  45.         pop     ebx
  46.         popfd
  47.         ret
  48. ;//-
  49. .out_of_memory:
  50.         mov     [pg_data.pages_free], 1
  51.         xor     eax, eax
  52.         pop     ebx
  53.         popfd
  54.         ret
  55. ;//-
  56. endp
  57.  
  58. align 4
  59. proc alloc_pages stdcall, count:dword
  60.         pushfd
  61.         push    ebx
  62.         push    edi
  63.         cli
  64.         mov     eax, [count]
  65.         add     eax, 7
  66.         shr     eax, 3
  67.         mov     [count], eax
  68. ;//-
  69.         mov     ebx, [pg_data.pages_free]
  70.         sub     ebx, 9
  71.         js      .out_of_memory
  72.         shr     ebx, 3
  73.         cmp     eax, ebx
  74.         jg      .out_of_memory
  75. ;//-
  76.         mov     ecx, [page_start]
  77.         mov     ebx, [page_end]
  78. .find:
  79.         mov     edx, [count]
  80.         mov     edi, ecx
  81. .match:
  82.         cmp     byte [ecx], 0xFF
  83.         jne     .next
  84.         dec     edx
  85.         jz      .ok
  86.         inc     ecx
  87.         cmp     ecx, ebx
  88.         jb      .match
  89. .out_of_memory:
  90. .fail:
  91.         xor     eax, eax
  92.         pop     edi
  93.         pop     ebx
  94.         popfd
  95.         ret
  96. .next:
  97.         inc     ecx
  98.         cmp     ecx, ebx
  99.         jb      .find
  100.         pop     edi
  101.         pop     ebx
  102.         popfd
  103.         xor     eax, eax
  104.         ret
  105. .ok:
  106.         sub     ecx, edi
  107.         inc     ecx
  108.         push    esi
  109.         mov     esi, edi
  110.         xor     eax, eax
  111.         rep stosb
  112.         sub     esi, sys_pgmap
  113.         shl     esi, 3+12
  114.         mov     eax, esi
  115.         mov     ebx, [count]
  116.         shl     ebx, 3
  117.         sub     [pg_data.pages_free], ebx
  118.         pop     esi
  119.         pop     edi
  120.         pop     ebx
  121.         popfd
  122.         ret
  123. endp
  124.  
  125. align 4
  126. ;proc map_page stdcall,lin_addr:dword,phis_addr:dword,flags:dword
  127. map_page:
  128.         push    ebx
  129.         mov     eax, [esp+12]               ; phis_addr
  130.         and     eax, not 0xFFF
  131.         or      eax, [esp+16]              ; flags
  132.         mov     ebx, [esp+8]               ; lin_addr
  133.         shr     ebx, 12
  134.         mov     [page_tabs+ebx*4], eax
  135.         mov     eax, [esp+8]               ; lin_addr
  136.         pop     ebx
  137.         invlpg  [eax]
  138.         ret     12
  139.  
  140. align 4
  141. map_space:    ;not implemented
  142.  
  143.  
  144.         ret
  145.  
  146.  
  147. align 4
  148. proc free_page
  149. ;arg:  eax  page address
  150.         pushfd
  151.         cli
  152.         shr     eax, 12                       ;page index
  153.         bts     dword [sys_pgmap], eax        ;that's all!
  154.         cmc
  155.         adc     [pg_data.pages_free], 0
  156.         shr     eax, 3
  157.         and     eax, not 3                    ;dword offset from page_map
  158.         add     eax, sys_pgmap
  159.         cmp     [page_start], eax
  160.         ja      @f
  161.         popfd
  162.         ret
  163. @@:
  164.         mov     [page_start], eax
  165.         popfd
  166.         ret
  167. endp
  168.  
  169. align 4
  170. proc map_io_mem stdcall, base:dword, size:dword, flags:dword
  171.  
  172.         push    ebx
  173.         push    edi
  174.         mov     eax, [size]
  175.         add     eax, [base]
  176.         add     eax, 4095
  177.         and     eax, -4096
  178.         mov     ecx, [base]
  179.         and     ecx, -4096
  180.         sub     eax, ecx
  181.         mov     [size], eax
  182.  
  183.         stdcall alloc_kernel_space, eax
  184.         test    eax, eax
  185.         jz      .fail
  186.         push    eax
  187.  
  188.         mov     edi, 0x1000
  189.         mov     ebx, eax
  190.         mov     ecx, [size]
  191.         mov     edx, [base]
  192.         shr     eax, 12
  193.         shr     ecx, 12
  194.         and     edx, -4096
  195.         or      edx, [flags]
  196. @@:
  197.         mov     [page_tabs+eax*4], edx
  198.         invlpg  [ebx]
  199.         inc     eax
  200.         add     ebx, edi
  201.         add     edx, edi
  202.         loop    @B
  203.  
  204.         pop     eax
  205.         mov     edx, [base]
  206.         and     edx, 4095
  207.         add     eax, edx
  208. .fail:
  209.         pop     edi
  210.         pop     ebx
  211.         ret
  212. endp
  213.  
  214. ; param
  215. ;  eax= page base + page flags
  216. ;  ebx= linear address
  217. ;  ecx= count
  218.  
  219. align 4
  220. commit_pages:
  221.         test    ecx, ecx
  222.         jz      .fail
  223.  
  224.         push    edi
  225.         push    eax
  226.         push    ecx
  227.         mov     ecx, pg_data.mutex
  228.         call    mutex_lock
  229.         pop     ecx
  230.         pop     eax
  231.  
  232.         mov     edi, ebx
  233.         shr     edi, 12
  234.         lea     edi, [page_tabs+edi*4]
  235. @@:
  236.         stosd
  237.         invlpg  [ebx]
  238.         add     eax, 0x1000
  239.         add     ebx, 0x1000
  240.         loop    @B
  241.  
  242.         pop     edi
  243.  
  244.         mov     ecx, pg_data.mutex
  245.         call    mutex_unlock
  246. .fail:
  247.         ret
  248.  
  249.  
  250. ; param
  251. ;  eax= base
  252. ;  ecx= count
  253.  
  254. align 4
  255. release_pages:
  256.  
  257.         push    ebp
  258.         push    esi
  259.         push    edi
  260.         push    ebx
  261.  
  262.         mov     esi, eax
  263.         mov     edi, eax
  264.  
  265.         shr     esi, 12
  266.         lea     esi, [page_tabs+esi*4]
  267.  
  268.         push    ecx
  269.         mov     ecx, pg_data.mutex
  270.         call    mutex_lock
  271.         pop     ecx
  272.  
  273.         mov     ebp, [pg_data.pages_free]
  274.         mov     ebx, [page_start]
  275.         mov     edx, sys_pgmap
  276. @@:
  277.         xor     eax, eax
  278.         xchg    eax, [esi]
  279.         invlpg  [edi]
  280.  
  281.         test    eax, 1
  282.         jz      .next
  283.  
  284.         shr     eax, 12
  285.         bts     [edx], eax
  286.         cmc
  287.         adc     ebp, 0
  288.         shr     eax, 3
  289.         and     eax, -4
  290.         add     eax, edx
  291.         cmp     eax, ebx
  292.         jae     .next
  293.  
  294.         mov     ebx, eax
  295. .next:
  296.         add     edi, 0x1000
  297.         add     esi, 4
  298.         loop    @B
  299.  
  300.         mov     [pg_data.pages_free], ebp
  301.         mov     ecx, pg_data.mutex
  302.         call    mutex_unlock
  303.  
  304.         pop     ebx
  305.         pop     edi
  306.         pop     esi
  307.         pop     ebp
  308.         ret
  309.  
  310. ; param
  311. ;  eax= base
  312. ;  ecx= count
  313.  
  314. align 4
  315. unmap_pages:
  316.  
  317.         push    edi
  318.  
  319.         mov     edi, eax
  320.         mov     edx, eax
  321.  
  322.         shr     edi, 10
  323.         add     edi, page_tabs
  324.  
  325.         xor     eax, eax
  326. @@:
  327.         stosd
  328.         invlpg  [edx]
  329.         add     edx, 0x1000
  330.         loop    @b
  331.  
  332.         pop     edi
  333.         ret
  334.  
  335.  
  336. align 4
  337. proc map_page_table stdcall, lin_addr:dword, phis_addr:dword
  338.         push    ebx
  339.         mov     ebx, [lin_addr]
  340.         shr     ebx, 22
  341.         mov     eax, [phis_addr]
  342.         and     eax, not 0xFFF
  343.         or      eax, PG_UW        ;+PG_NOCACHE
  344.         mov     dword [master_tab+ebx*4], eax
  345.         mov     eax, [lin_addr]
  346.         shr     eax, 10
  347.         add     eax, page_tabs
  348.         invlpg  [eax]
  349.         pop     ebx
  350.         ret
  351. endp
  352.  
  353. align 4
  354. proc init_LFB
  355.            locals
  356.              pg_count dd ?
  357.            endl
  358.  
  359.         cmp     dword [LFBAddress], -1
  360.         jne     @f
  361.         mov     [BOOT_VARS+BOOT_MTRR], byte 2
  362. ; max VGA=640*480*4=1228800 bytes
  363. ; + 32*640*4=81920 bytes for mouse pointer
  364.         stdcall alloc_pages, ((1228800+81920)/4096)
  365.  
  366.         push    eax
  367.         call    alloc_page
  368.         stdcall map_page_table, LFB_BASE, eax
  369.         pop     eax
  370.         or      eax, PG_UW
  371.         mov     ebx, LFB_BASE
  372. ; max VGA=640*480*4=1228800 bytes
  373. ; + 32*640*4=81920 bytes for mouse pointer
  374.         mov     ecx, (1228800+81920)/4096
  375.         call    commit_pages
  376.         mov     [LFBAddress], dword LFB_BASE
  377.         ret
  378. @@:
  379.         test    [SCR_MODE], word 0100000000000000b
  380.         jnz     @f
  381.         mov     [BOOT_VARS+BOOT_MTRR], byte 2
  382.         ret
  383. @@:
  384.         call    init_mtrr
  385.  
  386.         mov     edx, LFB_BASE
  387.         mov     esi, [LFBAddress]
  388.         mov     edi, 0x00C00000
  389.         mov     dword [exp_lfb+4], edx
  390.  
  391.         shr     edi, 12
  392.         mov     [pg_count], edi
  393.         shr     edi, 10
  394.  
  395.         bt      [cpu_caps], CAPS_PSE
  396.         jnc     .map_page_tables
  397.         or      esi, PG_LARGE+PG_UW
  398.         mov     edx, sys_proc+PROC.pdt_0+(LFB_BASE shr 20)
  399. @@:
  400.         mov     [edx], esi
  401.         add     edx, 4
  402.         add     esi, 0x00400000
  403.         dec     edi
  404.         jnz     @B
  405.  
  406.         bt      [cpu_caps], CAPS_PGE
  407.         jnc     @F
  408.         or      dword [sys_proc+PROC.pdt_0+(LFB_BASE shr 20)], PG_GLOBAL
  409. @@:
  410.         mov     dword [LFBAddress], LFB_BASE
  411.         mov     eax, cr3      ;flush TLB
  412.         mov     cr3, eax
  413.         ret
  414.  
  415. .map_page_tables:
  416.  
  417. @@:
  418.         call    alloc_page
  419.         stdcall map_page_table, edx, eax
  420.         add     edx, 0x00400000
  421.         dec     edi
  422.         jnz     @B
  423.  
  424.         mov     eax, [LFBAddress]
  425.         mov     edi, page_tabs + (LFB_BASE shr 10)
  426.         or      eax, PG_UW
  427.         mov     ecx, [pg_count]
  428.         cld
  429. @@:
  430.         stosd
  431.         add     eax, 0x1000
  432.         dec     ecx
  433.         jnz     @B
  434.  
  435.         mov     dword [LFBAddress], LFB_BASE
  436.         mov     eax, cr3      ;flush TLB
  437.         mov     cr3, eax
  438.  
  439.         ret
  440. endp
  441.  
  442. align 4
  443. proc new_mem_resize stdcall, new_size:dword
  444.  
  445.         push    ebx
  446.         push    esi
  447.         push    edi
  448.  
  449.         mov     edx, [current_slot]
  450.         mov     ebx, [edx+APPDATA.process]
  451.  
  452.         cmp     [ebx+PROC.heap_base], 0
  453.         jne     .exit
  454.  
  455.         mov     edi, [new_size]
  456.         add     edi, 4095
  457.         and     edi, not 4095
  458.         mov     [new_size], edi
  459.  
  460.         mov     esi, [ebx+PROC.mem_used]
  461.         add     esi, 4095
  462.         and     esi, not 4095
  463.  
  464.         cmp     edi, esi
  465.         ja      .expand
  466.         je      .exit
  467.  
  468.         mov     ebx, edi
  469.         shr     edi, 12
  470.         shr     esi, 12
  471.  
  472.         mov     ecx, pg_data.mutex
  473.         call    mutex_lock
  474. @@:
  475.         mov     eax, [app_page_tabs+edi*4]
  476.         test    eax, 1
  477.         jz      .next
  478.  
  479.         mov     dword [app_page_tabs+edi*4], 0
  480.         invlpg  [ebx]
  481.         call    free_page
  482.  
  483. .next:
  484.         inc     edi
  485.         add     ebx, 0x1000
  486.         cmp     edi, esi
  487.         jb      @B
  488.  
  489.         mov     ecx, pg_data.mutex
  490.         call    mutex_unlock
  491.  
  492. .update_size:
  493.         mov     edx, [current_slot]
  494.         mov     ebx, [new_size]
  495.         mov     edx, [edx+APPDATA.process]
  496.         mov     [edx+PROC.mem_used], ebx
  497. .exit:
  498.         pop     edi
  499.         pop     esi
  500.         pop     ebx
  501.         xor     eax, eax
  502.         ret
  503.  
  504. .expand:
  505.  
  506.         mov     ecx, pg_data.mutex
  507.         call    mutex_lock
  508.  
  509.         xchg    esi, edi
  510.  
  511.         push    esi                   ;new size
  512.         push    edi                   ;old size
  513.  
  514.         add     edi, 0x3FFFFF
  515.         and     edi, not(0x3FFFFF)
  516.         add     esi, 0x3FFFFF
  517.         and     esi, not(0x3FFFFF)
  518.  
  519.         cmp     edi, esi
  520.         jae     .grow
  521.  @@:
  522.         call    alloc_page
  523.         test    eax, eax
  524.         jz      .exit_fail
  525.  
  526.         stdcall map_page_table, edi, eax
  527.  
  528.         push    edi
  529.         shr     edi, 10
  530.         add     edi, page_tabs
  531.         mov     ecx, 1024
  532.         xor     eax, eax
  533.         cld
  534.         rep stosd
  535.         pop     edi
  536.  
  537.         add     edi, 0x00400000
  538.         cmp     edi, esi
  539.         jb      @B
  540. .grow:
  541.         pop     edi                   ;old size
  542.         pop     ecx                   ;new size
  543.  
  544.         shr     edi, 10
  545.         shr     ecx, 10
  546.         sub     ecx, edi
  547.         shr     ecx, 2                ;pages count
  548.         mov     eax, 2
  549.  
  550.         add     edi, app_page_tabs
  551.         rep stosd
  552.  
  553.         mov     ecx, pg_data.mutex
  554.         call    mutex_unlock
  555.  
  556.         jmp     .update_size
  557.  
  558. .exit_fail:
  559.         mov     ecx, pg_data.mutex
  560.         call    mutex_unlock
  561.  
  562.         add     esp, 8
  563.         pop     edi
  564.         pop     esi
  565.         pop     ebx
  566.         xor     eax, eax
  567.         inc     eax
  568.         ret
  569. endp
  570.  
  571.  
  572. ; param
  573. ;  eax= linear address
  574. ;
  575. ; retval
  576. ;  eax= phisical page address
  577.  
  578. align 4
  579. get_pg_addr:
  580.         sub     eax, OS_BASE
  581.         cmp     eax, 0x400000
  582.         jb      @f
  583.         shr     eax, 12
  584.         mov     eax, [page_tabs+(eax+(OS_BASE shr 12))*4]
  585. @@:
  586.         and     eax, 0xFFFFF000
  587.         ret
  588.  
  589.  
  590. align 4
  591. ; Now it is called from core/sys32::exc_c (see stack frame there)
  592. proc page_fault_handler
  593.  
  594.     .err_addr   equ ebp-4
  595.  
  596.         push    ebx               ;save exception number (#PF)
  597.         mov     ebp, esp
  598.         mov     ebx, cr2
  599.         push    ebx               ;that is locals: .err_addr = cr2
  600.         inc     [pg_data.pages_faults]
  601.  
  602.         mov     eax, [pf_err_code]
  603.  
  604.         cmp     ebx, OS_BASE      ;ebx == .err_addr
  605.         jb      .user_space       ;страница в памяти приложения ;
  606.  
  607.         cmp     ebx, page_tabs
  608.         jb      .kernel_space     ;страница в памяти ядра
  609.  
  610.         cmp     ebx, kernel_tabs
  611.         jb      .alloc;.app_tabs  ;таблицы страниц приложения ;
  612.                                   ;просто создадим одну
  613. if 0 ;пока это просто лишнее
  614.         cmp     ebx, LFB_BASE
  615.         jb      .core_tabs        ;таблицы страниц ядра
  616.                                   ;Ошибка
  617.   .lfb:
  618.                                   ;область LFB
  619.                                   ;Ошибка
  620.         jmp     .fail
  621. end if
  622. .core_tabs:
  623. .fail:  ;simply return to caller
  624.         mov     esp, ebp
  625.         pop     ebx               ;restore exception number (#PF)
  626.         ret
  627.  
  628. ;        xchg bx, bx
  629. ;        add     esp,12 ;clear in stack: locals(.err_addr) + #PF + ret_to_caller
  630. ;        restore_ring3_context
  631. ;        iretd
  632.  
  633. .user_space:
  634.         test    eax, PG_MAP
  635.         jnz     .err_access       ;Страница присутствует
  636.                                   ;Ошибка доступа ?
  637.  
  638.         shr     ebx, 12
  639.         mov     ecx, ebx
  640.         shr     ecx, 10
  641.         mov     edx, [master_tab+ecx*4]
  642.         test    edx, PG_MAP
  643.         jz      .fail             ;таблица страниц не создана
  644.                                   ;неверный адрес в программе
  645.  
  646.         mov     eax, [page_tabs+ebx*4]
  647.         test    eax, 2
  648.         jz      .fail             ;адрес не зарезервирован для ;
  649.                                   ;использования. Ошибка
  650. .alloc:
  651.         call    alloc_page
  652.         test    eax, eax
  653.         jz      .fail
  654.  
  655.         stdcall map_page, [.err_addr], eax, PG_UW
  656.  
  657.         mov     edi, [.err_addr]
  658.         and     edi, 0xFFFFF000
  659.         mov     ecx, 1024
  660.         xor     eax, eax
  661.        ;cld     ;caller is duty for this
  662.         rep stosd
  663. .exit:  ;iret with repeat fault instruction
  664.         add     esp, 12;clear in stack: locals(.err_addr) + #PF + ret_to_caller
  665.         restore_ring3_context
  666.         iretd
  667.  
  668. .err_access:
  669. ; access denied? this may be a result of copy-on-write protection for DLL
  670. ; check list of HDLLs
  671.         and     ebx, not 0xFFF
  672.         mov     eax, [CURRENT_TASK]
  673.         shl     eax, 8
  674.         mov     eax, [SLOT_BASE+eax+APPDATA.dlls_list_ptr]
  675.         test    eax, eax
  676.         jz      .fail
  677.         mov     esi, [eax+HDLL.fd]
  678. .scan_hdll:
  679.         cmp     esi, eax
  680.         jz      .fail
  681.         mov     edx, ebx
  682.         sub     edx, [esi+HDLL.base]
  683.         cmp     edx, [esi+HDLL.size]
  684.         jb      .fault_in_hdll
  685. .scan_hdll.next:
  686.         mov     esi, [esi+HDLL.fd]
  687.         jmp     .scan_hdll
  688. .fault_in_hdll:
  689. ; allocate new page, map it as rw and copy data
  690.         call    alloc_page
  691.         test    eax, eax
  692.         jz      .fail
  693.         stdcall map_page, ebx, eax, PG_UW
  694.         mov     edi, ebx
  695.         mov     ecx, 1024
  696.         sub     ebx, [esi+HDLL.base]
  697.         mov     esi, [esi+HDLL.parent]
  698.         mov     esi, [esi+DLLDESCR.data]
  699.         add     esi, ebx
  700.         rep movsd
  701.         jmp     .exit
  702.  
  703. .kernel_space:
  704.         test    eax, PG_MAP
  705.         jz      .fail   ;страница не присутствует
  706.  
  707.         test    eax, 12 ;U/S (+below)
  708.         jnz     .fail   ;приложение обратилось к памяти
  709.                         ;ядра
  710.        ;test    eax, 8
  711.        ;jnz     .fail   ;установлен зарезервированный бит
  712.                         ;в таблицах страниц. добавлено в P4/Xeon
  713.  
  714. ;попытка записи в защищённую страницу ядра
  715.  
  716.         cmp     ebx, tss._io_map_0
  717.         jb      .fail
  718.  
  719.         cmp     ebx, tss._io_map_0+8192
  720.         jae     .fail
  721.  
  722. ; io permission map
  723. ; copy-on-write protection
  724.  
  725.         call    alloc_page
  726.         test    eax, eax
  727.         jz      .fail
  728.  
  729.         push    eax
  730.         stdcall map_page, [.err_addr], eax, dword PG_SW
  731.         pop     eax
  732.         mov     edi, [.err_addr]
  733.         and     edi, -4096
  734.         lea     esi, [edi+(not tss._io_map_0)+1]; -tss._io_map_0
  735.  
  736.         mov     ebx, esi
  737.         shr     ebx, 12
  738.         mov     edx, [current_slot]
  739.         or      eax, PG_SW
  740.         mov     [edx+APPDATA.io_map+ebx*4], eax
  741.  
  742.         add     esi, [default_io_map]
  743.         mov     ecx, 4096/4
  744.        ;cld     ;caller is duty for this
  745.         rep movsd
  746.         jmp     .exit
  747. endp
  748.  
  749. ; returns number of mapped bytes
  750. proc map_mem_ipc stdcall, lin_addr:dword,slot:dword,\
  751.                       ofs:dword,buf_size:dword,req_access:dword
  752.         locals
  753.              count   dd ?
  754.              process dd ?
  755.         endl
  756.  
  757.         mov     [count], 0
  758.         cmp     [buf_size], 0
  759.         jz      .exit
  760.  
  761.         mov     eax, [slot]
  762.         shl     eax, 8
  763.         mov     eax, [SLOT_BASE+eax+APPDATA.process]
  764.         test    eax, eax
  765.         jz      .exit
  766.  
  767.         mov     [process], eax
  768.         mov     ebx, [ofs]
  769.         shr     ebx, 22
  770.         mov     eax, [eax+PROC.pdt_0+ebx*4]                 ;get page table
  771.         mov     esi, [ipc_ptab]
  772.         and     eax, 0xFFFFF000
  773.         jz      .exit
  774.         stdcall map_page, esi, eax, PG_SW
  775. @@:
  776.         mov     edi, [lin_addr]
  777.         and     edi, 0xFFFFF000
  778.         mov     ecx, [buf_size]
  779.         add     ecx, 4095
  780.         shr     ecx, 12
  781.         inc     ecx                  ; ???????????
  782.  
  783.         mov     edx, [ofs]
  784.         shr     edx, 12
  785.         and     edx, 0x3FF
  786. .map:
  787.         stdcall safe_map_page, [slot], [req_access], [ofs]
  788.         jnc     .exit
  789.         add     dword [ebp-4], PAGE_SIZE
  790.         add     [ofs], PAGE_SIZE
  791.         dec     ecx
  792.         jz      .exit
  793.  
  794.         add     edi, PAGE_SIZE
  795.         inc     edx
  796.         cmp     edx, 1024
  797.         jnz     .map
  798.  
  799.         inc     ebx
  800.         mov     eax, [process]
  801.         mov     eax, [eax+PROC.pdt_0+ebx*4]
  802.         and     eax, 0xFFFFF000
  803.         jz      .exit
  804.  
  805.         stdcall map_page, esi, eax, PG_SW
  806.         xor     edx, edx
  807.         jmp     .map
  808.  
  809. .exit:
  810.         pop     eax
  811.         ret
  812. endp
  813.  
  814. proc map_memEx stdcall, lin_addr:dword,slot:dword,\
  815.                         ofs:dword,buf_size:dword,req_access:dword
  816.         push    0 ; initialize number of mapped bytes
  817.  
  818.         cmp     [buf_size], 0
  819.         jz      .exit
  820.  
  821.         mov     eax, [slot]
  822.         shl     eax, 8
  823.         mov     eax, [SLOT_BASE+eax+APPDATA.process]
  824.         mov     eax, [eax+PROC.pdt_0_phys]
  825.         and     eax, 0xFFFFF000
  826.  
  827.         stdcall map_page, [proc_mem_pdir], eax, PG_UW
  828.         mov     ebx, [ofs]
  829.         shr     ebx, 22
  830.         mov     esi, [proc_mem_pdir]
  831.         mov     edi, [proc_mem_tab]
  832.         mov     eax, [esi+ebx*4]
  833.         and     eax, 0xFFFFF000
  834.         test    eax, eax
  835.         jz      .exit
  836.         stdcall map_page, edi, eax, PG_UW
  837.  
  838. @@:
  839.         mov     edi, [lin_addr]
  840.         and     edi, 0xFFFFF000
  841.         mov     ecx, [buf_size]
  842.         add     ecx, 4095
  843.         shr     ecx, 12
  844.         inc     ecx
  845.  
  846.         mov     edx, [ofs]
  847.         shr     edx, 12
  848.         and     edx, 0x3FF
  849.         mov     esi, [proc_mem_tab]
  850.  
  851. .map:
  852.         stdcall safe_map_page, [slot], [req_access], [ofs]
  853.         jnc     .exit
  854.         add     dword [ebp-4], 0x1000
  855.         add     edi, 0x1000
  856.         add     [ofs], 0x1000
  857.         inc     edx
  858.         dec     ecx
  859.         jnz     .map
  860. .exit:
  861.         pop     eax
  862.         ret
  863. endp
  864.  
  865. ; in: esi+edx*4 = pointer to page table entry
  866. ; in: [slot], [req_access], [ofs] on the stack
  867. ; in: edi = linear address to map
  868. ; out: CF cleared <=> failed
  869. ; destroys: only eax
  870. proc safe_map_page stdcall, slot:dword, req_access:dword, ofs:dword
  871.         mov     eax, [esi+edx*4]
  872.         test    al, PG_MAP
  873.         jz      .not_present
  874.         test    al, PG_WRITE
  875.         jz      .resolve_readonly
  876. ; normal case: writable page, just map with requested access
  877. .map:
  878.         stdcall map_page, edi, eax, [req_access]
  879.         stc
  880. .fail:
  881.         ret
  882. .not_present:
  883. ; check for alloc-on-demand page
  884.         test    al, 2
  885.         jz      .fail
  886. ; allocate new page, save it to source page table
  887.         push    ecx
  888.         call    alloc_page
  889.         pop     ecx
  890.         test    eax, eax
  891.         jz      .fail
  892.         or      al, PG_UW
  893.         mov     [esi+edx*4], eax
  894.         jmp     .map
  895. .resolve_readonly:
  896. ; readonly page, probably copy-on-write
  897. ; check: readonly request of readonly page is ok
  898.         test    [req_access], PG_WRITE
  899.         jz      .map
  900. ; find control structure for this page
  901.         pushf
  902.         cli
  903.         cld
  904.         push    ebx ecx
  905.         mov     eax, [slot]
  906.         shl     eax, 8
  907.         mov     eax, [SLOT_BASE+eax+APPDATA.dlls_list_ptr]
  908.         test    eax, eax
  909.         jz      .no_hdll
  910.         mov     ecx, [eax+HDLL.fd]
  911. .scan_hdll:
  912.         cmp     ecx, eax
  913.         jz      .no_hdll
  914.         mov     ebx, [ofs]
  915.         and     ebx, not 0xFFF
  916.         sub     ebx, [ecx+HDLL.base]
  917.         cmp     ebx, [ecx+HDLL.size]
  918.         jb      .hdll_found
  919.         mov     ecx, [ecx+HDLL.fd]
  920.         jmp     .scan_hdll
  921. .no_hdll:
  922.         pop     ecx ebx
  923.         popf
  924.         clc
  925.         ret
  926. .hdll_found:
  927. ; allocate page, save it in page table, map it, copy contents from base
  928.         mov     eax, [ecx+HDLL.parent]
  929.         add     ebx, [eax+DLLDESCR.data]
  930.         call    alloc_page
  931.         test    eax, eax
  932.         jz      .no_hdll
  933.         or      al, PG_UW
  934.         mov     [esi+edx*4], eax
  935.         stdcall map_page, edi, eax, [req_access]
  936.         push    esi edi
  937.         mov     esi, ebx
  938.         mov     ecx, 4096/4
  939.         rep movsd
  940.         pop     edi esi
  941.         pop     ecx ebx
  942.         popf
  943.         stc
  944.         ret
  945. endp
  946.  
  947. sys_IPC:
  948. ;input:
  949. ;  ebx=1 - set ipc buffer area
  950. ;    ecx=address of buffer
  951. ;    edx=size of buffer
  952. ;  eax=2 - send message
  953. ;    ebx=PID
  954. ;    ecx=address of message
  955. ;    edx=size of message
  956.  
  957.         dec     ebx
  958.         jnz     @f
  959.  
  960.         mov     eax, [current_slot]
  961.         pushf
  962.         cli
  963.         mov     [eax+APPDATA.ipc_start], ecx    ;set fields in extended information area
  964.         mov     [eax+APPDATA.ipc_size], edx
  965.  
  966.         add     edx, ecx
  967.         add     edx, 4095
  968.         and     edx, not 4095
  969.  
  970. .touch:
  971.         mov     eax, [ecx]
  972.         add     ecx, 0x1000
  973.         cmp     ecx, edx
  974.         jb      .touch
  975.  
  976.         popf
  977.         mov     [esp+32], ebx   ;ebx=0
  978.         ret
  979.  
  980. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  981. ;2
  982. @@:
  983.         dec     ebx
  984.         jnz     @f
  985.  
  986.         stdcall sys_ipc_send, ecx, edx, esi
  987.         mov     [esp+32], eax
  988.         ret
  989. @@:
  990.         or      eax, -1
  991.         mov     [esp+32], eax
  992.         ret
  993.  
  994. proc sys_ipc_send stdcall, PID:dword, msg_addr:dword, msg_size:dword
  995.            locals
  996.              dst_slot   dd ?
  997.              dst_offset dd ?
  998.              buf_size   dd ?
  999.              used_buf   dd ?
  1000.            endl
  1001.  
  1002.         pushf
  1003.         cli
  1004.  
  1005.         mov     eax, [PID]
  1006.         call    pid_to_slot
  1007.         test    eax, eax
  1008.         jz      .no_pid
  1009.  
  1010.         mov     [dst_slot], eax
  1011.         shl     eax, 8
  1012.         mov     edi, [eax+SLOT_BASE+APPDATA.ipc_start] ;is ipc area defined?
  1013.         test    edi, edi
  1014.         jz      .no_ipc_area
  1015.  
  1016.         mov     ebx, edi
  1017.         and     ebx, 0xFFF
  1018.         mov     [dst_offset], ebx
  1019.  
  1020.         mov     esi, [eax+SLOT_BASE+APPDATA.ipc_size]
  1021.         mov     [buf_size], esi
  1022.  
  1023.         mov     ecx, [ipc_tmp]
  1024.         cmp     esi, 0x40000-0x1000; size of [ipc_tmp] minus one page
  1025.         jbe     @f
  1026.         push    esi edi
  1027.         add     esi, 0x1000
  1028.         stdcall alloc_kernel_space, esi
  1029.         mov     ecx, eax
  1030.         pop     edi esi
  1031. @@:
  1032.         mov     [used_buf], ecx
  1033.         stdcall map_mem_ipc, ecx, [dst_slot], \
  1034.                 edi, esi, PG_SW
  1035.  
  1036.         mov     edi, [dst_offset]
  1037.         add     edi, [used_buf]
  1038.         cmp     dword [edi], 0
  1039.         jnz     .ipc_blocked          ;if dword [buffer]<>0 - ipc blocked now
  1040.  
  1041.         mov     edx, dword [edi+4]
  1042.         lea     ebx, [edx+8]
  1043.         add     ebx, [msg_size]
  1044.         cmp     ebx, [buf_size]
  1045.         ja      .buffer_overflow       ;esi<0 - not enough memory in buffer
  1046.  
  1047.         mov     dword [edi+4], ebx
  1048.         mov     eax, [TASK_BASE]
  1049.         mov     eax, [eax+0x04]        ;eax - our PID
  1050.         add     edi, edx
  1051.         mov     [edi], eax
  1052.         mov     ecx, [msg_size]
  1053.  
  1054.         mov     [edi+4], ecx
  1055.         add     edi, 8
  1056.         mov     esi, [msg_addr]
  1057.        ;    add esi, new_app_base
  1058.         cld
  1059.         rep movsb
  1060.  
  1061.         mov     ebx, [ipc_tmp]
  1062.         mov     edx, ebx
  1063.         shr     ebx, 12
  1064.         xor     eax, eax
  1065.         mov     [page_tabs+ebx*4], eax
  1066.         invlpg  [edx]
  1067.  
  1068.         mov     ebx, [ipc_pdir]
  1069.         mov     edx, ebx
  1070.         shr     ebx, 12
  1071.         xor     eax, eax
  1072.         mov     [page_tabs+ebx*4], eax
  1073.         invlpg  [edx]
  1074.  
  1075.         mov     ebx, [ipc_ptab]
  1076.         mov     edx, ebx
  1077.         shr     ebx, 12
  1078.         xor     eax, eax
  1079.         mov     [page_tabs+ebx*4], eax
  1080.         invlpg  [edx]
  1081.  
  1082.         mov     eax, [dst_slot]
  1083.         shl     eax, 8
  1084.         or      [eax+SLOT_BASE+0xA8], dword 0x40
  1085.         push    0
  1086.         jmp     .ret
  1087. .no_pid:
  1088.         popf
  1089.         mov     eax, 4
  1090.         ret
  1091. .no_ipc_area:
  1092.         popf
  1093.         xor     eax, eax
  1094.         inc     eax
  1095.         ret
  1096. .ipc_blocked:
  1097.         push    2
  1098.         jmp     .ret
  1099. .buffer_overflow:
  1100.         push    3
  1101. .ret:
  1102.         mov     eax, [used_buf]
  1103.         cmp     eax, [ipc_tmp]
  1104.         je      @f
  1105.         stdcall free_kernel_space, eax
  1106. @@:
  1107.         pop     eax
  1108.         popf
  1109.         ret
  1110. endp
  1111.  
  1112. align 4
  1113. sysfn_meminfo:
  1114.  
  1115.         ;   add ecx, new_app_base
  1116.         cmp     ecx, OS_BASE
  1117.         jae     .fail
  1118.  
  1119.         mov     eax, [pg_data.pages_count]
  1120.         mov     [ecx], eax
  1121.         shl     eax, 12
  1122.         mov     [esp+32], eax
  1123.         mov     eax, [pg_data.pages_free]
  1124.         mov     [ecx+4], eax
  1125.         mov     eax, [pg_data.pages_faults]
  1126.         mov     [ecx+8], eax
  1127.         mov     eax, [heap_size]
  1128.         mov     [ecx+12], eax
  1129.         mov     eax, [heap_free]
  1130.         mov     [ecx+16], eax
  1131.         mov     eax, [heap_blocks]
  1132.         mov     [ecx+20], eax
  1133.         mov     eax, [free_blocks]
  1134.         mov     [ecx+24], eax
  1135.         ret
  1136. .fail:
  1137.         or      dword [esp+32], -1
  1138.         ret
  1139.  
  1140. align 4
  1141. f68:
  1142.         cmp     ebx, 4
  1143.         jbe     sys_sheduler
  1144.  
  1145.         cmp     ebx, 11
  1146.         jb      .fail
  1147.  
  1148.         cmp     ebx, 27
  1149.         ja      .fail
  1150.  
  1151.         jmp     dword [f68call+ebx*4-11*4]
  1152. .11:
  1153.         call    init_heap
  1154.         mov     [esp+32], eax
  1155.         ret
  1156. .12:
  1157.         stdcall user_alloc, ecx
  1158.         mov     [esp+32], eax
  1159.         ret
  1160. .13:
  1161.         stdcall user_free, ecx
  1162.         mov     [esp+32], eax
  1163.         ret
  1164. .14:
  1165.         cmp     ecx, OS_BASE
  1166.         jae     .fail
  1167.         mov     edi, ecx
  1168.         call    get_event_ex
  1169.         mov     [esp+32], eax
  1170.         ret
  1171. .16:
  1172.         test    ecx, ecx
  1173.         jz      .fail
  1174.         cmp     ecx, OS_BASE
  1175.         jae     .fail
  1176.         stdcall get_service, ecx
  1177.         mov     [esp+32], eax
  1178.         ret
  1179. .17:
  1180.         call    srv_handlerEx   ;ecx
  1181.         mov     [esp+32], eax
  1182.         ret
  1183. .19:
  1184.         cmp     ecx, OS_BASE
  1185.         jae     .fail
  1186.         stdcall load_library, ecx
  1187.         mov     [esp+32], eax
  1188.         ret
  1189. .20:
  1190.         mov     eax, edx
  1191.         mov     ebx, ecx
  1192.         call    user_realloc            ;in: eax = pointer, ebx = new size
  1193.         mov     [esp+32], eax
  1194.         ret
  1195. .21:
  1196.         cmp     ecx, OS_BASE
  1197.         jae     .fail
  1198.  
  1199.         cmp     edx, OS_BASE
  1200.         jae     .fail
  1201.  
  1202.         stdcall load_pe_driver, ecx, edx
  1203.         mov     [esp+32], eax
  1204.         ret
  1205. .22:
  1206.         cmp     ecx, OS_BASE
  1207.         jae     .fail
  1208.  
  1209.         stdcall shmem_open, ecx, edx, esi
  1210.         mov     [esp+24], edx
  1211.         mov     [esp+32], eax
  1212.         ret
  1213.  
  1214. .23:
  1215.         cmp     ecx, OS_BASE
  1216.         jae     .fail
  1217.  
  1218.         stdcall shmem_close, ecx
  1219.         mov     [esp+32], eax
  1220.         ret
  1221. .24:
  1222.         mov     eax, [current_slot]
  1223.         xchg    ecx, [eax+APPDATA.exc_handler]
  1224.         xchg    edx, [eax+APPDATA.except_mask]
  1225.         mov     [esp+32], ecx ; reg_eax+8
  1226.         mov     [esp+20], edx ; reg_ebx+8
  1227.         ret
  1228. .25:
  1229.         cmp     ecx, 32
  1230.         jae     .fail
  1231.         mov     eax, [current_slot]
  1232.         btr     [eax+APPDATA.except_mask], ecx
  1233.         setc    byte[esp+32]
  1234.         jecxz   @f
  1235.         bts     [eax+APPDATA.except_mask], ecx
  1236. @@:
  1237.         ret
  1238.  
  1239. .26:
  1240.         stdcall user_unmap, ecx, edx, esi
  1241.         mov     [esp+32], eax
  1242.         ret
  1243.  
  1244. .27:
  1245.         cmp     ecx, OS_BASE
  1246.         jae     .fail
  1247.  
  1248.         stdcall load_file_umode, ecx
  1249.         mov     [esp+24], edx
  1250.         mov     [esp+32], eax
  1251.         ret
  1252.  
  1253. .fail:
  1254.         xor     eax, eax
  1255.         mov     [esp+32], eax
  1256.         ret
  1257.  
  1258.  
  1259. align 4
  1260. f68call:   ; keep this table closer to main code
  1261.  
  1262.            dd f68.11   ; init_heap
  1263.            dd f68.12   ; user_alloc
  1264.            dd f68.13   ; user_free
  1265.            dd f68.14   ; get_event_ex
  1266.            dd f68.fail ; moved to f68.24
  1267.            dd f68.16   ; get_service
  1268.            dd f68.17   ; call_service
  1269.            dd f68.fail ; moved to f68.25
  1270.            dd f68.19   ; load_dll
  1271.            dd f68.20   ; user_realloc
  1272.            dd f68.21   ; load_driver
  1273.            dd f68.22   ; shmem_open
  1274.            dd f68.23   ; shmem_close
  1275.            dd f68.24   ; set exception handler
  1276.            dd f68.25   ; unmask exception
  1277.            dd f68.26   ; user_unmap
  1278.            dd f68.27   ; load_file_umode
  1279.  
  1280.  
  1281. align 4
  1282. proc load_pe_driver stdcall, file:dword, cmdline:dword
  1283.         push    esi
  1284.  
  1285.         stdcall load_PE, [file]
  1286.         test    eax, eax
  1287.         jz      .fail
  1288.  
  1289.         mov     esi, eax
  1290.         push    [cmdline]
  1291.         push    DRV_ENTRY
  1292.         call    eax
  1293.         pop     ecx
  1294.         pop     ecx
  1295.         test    eax, eax
  1296.         jz      .fail
  1297.  
  1298.         mov     [eax+SRV.entry], esi
  1299.         pop     esi
  1300.         ret
  1301.  
  1302. .fail:
  1303.         xor     eax, eax
  1304.         pop     esi
  1305.         ret
  1306. endp
  1307.  
  1308. align 4
  1309. proc init_mtrr
  1310.  
  1311.         cmp     [BOOT_VARS+BOOT_MTRR], byte 2
  1312.         je      .exit
  1313.  
  1314.         bt      [cpu_caps], CAPS_MTRR
  1315.         jnc     .exit
  1316.  
  1317.         mov     eax, cr0
  1318.         or      eax, 0x60000000 ;disable caching
  1319.         mov     cr0, eax
  1320.         wbinvd                  ;invalidate cache
  1321.  
  1322.         mov     ecx, 0x2FF
  1323.         rdmsr                   ;
  1324. ; has BIOS already initialized MTRRs?
  1325.         test    ah, 8
  1326.         jnz     .skip_init
  1327. ; rarely needed, so mainly placeholder
  1328. ; main memory - cached
  1329.         push    eax
  1330.  
  1331.         mov     eax, [MEM_AMOUNT]
  1332. ; round eax up to next power of 2
  1333.         dec     eax
  1334.         bsr     ecx, eax
  1335.         mov     ebx, 2
  1336.         shl     ebx, cl
  1337.         dec     ebx
  1338. ; base of memory range = 0, type of memory range = MEM_WB
  1339.         xor     edx, edx
  1340.         mov     eax, MEM_WB
  1341.         mov     ecx, 0x200
  1342.         wrmsr
  1343. ; mask of memory range = 0xFFFFFFFFF - (size - 1), ebx = size - 1
  1344.         mov     eax, 0xFFFFFFFF
  1345.         mov     edx, 0x0000000F
  1346.         sub     eax, ebx
  1347.         sbb     edx, 0
  1348.         or      eax, 0x800
  1349.         inc     ecx
  1350.         wrmsr
  1351. ; clear unused MTRRs
  1352.         xor     eax, eax
  1353.         xor     edx, edx
  1354. @@:
  1355.         inc     ecx
  1356.         wrmsr
  1357.         cmp     ecx, 0x20F
  1358.         jb      @b
  1359. ; enable MTRRs
  1360.         pop     eax
  1361.         or      ah, 8
  1362.         and     al, 0xF0; default memtype = UC
  1363.         mov     ecx, 0x2FF
  1364.         wrmsr
  1365. .skip_init:
  1366.         stdcall set_mtrr, [LFBAddress], [LFBSize], MEM_WC
  1367.  
  1368.         wbinvd                  ;again invalidate
  1369.  
  1370.         mov     eax, cr0
  1371.         and     eax, not 0x60000000
  1372.         mov     cr0, eax        ; enable caching
  1373. .exit:
  1374.         ret
  1375. endp
  1376.  
  1377. align 4
  1378. proc set_mtrr stdcall, base:dword,size:dword,mem_type:dword
  1379. ; find unused register
  1380.         mov     ecx, 0x201
  1381. @@:
  1382.         rdmsr
  1383.         dec     ecx
  1384.         test    ah, 8
  1385.         jz      .found
  1386.         rdmsr
  1387.         mov     al, 0; clear memory type field
  1388.         cmp     eax, [base]
  1389.         jz      .ret
  1390.         add     ecx, 3
  1391.         cmp     ecx, 0x210
  1392.         jb      @b
  1393. ; no free registers, ignore the call
  1394. .ret:
  1395.         ret
  1396. .found:
  1397. ; found, write values
  1398.         xor     edx, edx
  1399.         mov     eax, [base]
  1400.         or      eax, [mem_type]
  1401.         wrmsr
  1402.  
  1403.         mov     ebx, [size]
  1404.         dec     ebx
  1405.         mov     eax, 0xFFFFFFFF
  1406.         mov     edx, 0x00000000
  1407.         sub     eax, ebx
  1408.         sbb     edx, 0
  1409.         or      eax, 0x800
  1410.         inc     ecx
  1411.         wrmsr
  1412.         ret
  1413. endp
  1414.  
  1415. align 4
  1416. proc create_ring_buffer stdcall, size:dword, flags:dword
  1417.            locals
  1418.              buf_ptr  dd ?
  1419.            endl
  1420.  
  1421.         mov     eax, [size]
  1422.         test    eax, eax
  1423.         jz      .fail
  1424.  
  1425.         add     eax, eax
  1426.         stdcall alloc_kernel_space, eax
  1427.         test    eax, eax
  1428.         jz      .fail
  1429.  
  1430.         push    ebx
  1431.  
  1432.         mov     [buf_ptr], eax
  1433.  
  1434.         mov     ebx, [size]
  1435.         shr     ebx, 12
  1436.         push    ebx
  1437.  
  1438.         stdcall alloc_pages, ebx
  1439.         pop     ecx
  1440.  
  1441.         test    eax, eax
  1442.         jz      .mm_fail
  1443.  
  1444.         push    edi
  1445.  
  1446.         or      eax, [flags]
  1447.         mov     edi, [buf_ptr]
  1448.         mov     ebx, [buf_ptr]
  1449.         mov     edx, ecx
  1450.         shl     edx, 2
  1451.         shr     edi, 10
  1452. @@:
  1453.         mov     [page_tabs+edi], eax
  1454.         mov     [page_tabs+edi+edx], eax
  1455.         invlpg  [ebx]
  1456.         invlpg  [ebx+0x10000]
  1457.         add     eax, 0x1000
  1458.         add     ebx, 0x1000
  1459.         add     edi, 4
  1460.         dec     ecx
  1461.         jnz     @B
  1462.  
  1463.         mov     eax, [buf_ptr]
  1464.         pop     edi
  1465.         pop     ebx
  1466.         ret
  1467. .mm_fail:
  1468.         stdcall free_kernel_space, [buf_ptr]
  1469.         xor     eax, eax
  1470.         pop     ebx
  1471. .fail:
  1472.         ret
  1473. endp
  1474.  
  1475.  
  1476. align 4
  1477. proc print_mem
  1478.         mov     edi, BOOT_VAR + 0x9104
  1479.         mov     ecx, [edi-4]
  1480.         test    ecx, ecx
  1481.         jz      .done
  1482.  
  1483. @@:
  1484.         mov     eax, [edi]
  1485.         mov     edx, [edi+4]
  1486.         add     eax, [edi+8]
  1487.         adc     edx, [edi+12]
  1488.  
  1489.         DEBUGF  1, "K : E820 %x%x - %x%x type %d\n", \
  1490.                     [edi+4], [edi],\
  1491.                     edx, eax, [edi+16]
  1492.         add     edi, 20
  1493.         dec     ecx
  1494.         jnz     @b
  1495. .done:
  1496.         ret
  1497. endp
  1498.