Subversion Repositories Kolibri OS

Rev

Rev 2465 | Rev 3908 | Go to most recent revision | Blame | Compare with Previous | 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: 3500 $
  9.  
  10.  
  11. struct  MEM_BLOCK
  12.         list            LHEAD
  13.         next_block      dd ? ;+8
  14.         prev_block      dd ? ;+4
  15.         base            dd ? ;+16
  16.         size            dd ? ;+20
  17.         flags           dd ? ;+24
  18.         handle          dd ? ;+28
  19. ends
  20.  
  21. FREE_BLOCK      equ  4
  22. USED_BLOCK      equ  8
  23. DONT_FREE_BLOCK equ  10h
  24.  
  25.  
  26. block_next   equ MEM_BLOCK.next_block
  27. block_prev   equ MEM_BLOCK.prev_block
  28. list_fd      equ MEM_BLOCK.list.next
  29. list_bk      equ MEM_BLOCK.list.prev
  30. block_base   equ MEM_BLOCK.base
  31. block_size   equ MEM_BLOCK.size
  32. block_flags  equ MEM_BLOCK.flags
  33.  
  34. macro calc_index op
  35. {          shr op, 12
  36.            dec op
  37.            cmp op, 63
  38.            jna @f
  39.            mov op, 63
  40. @@:
  41. }
  42.  
  43. align 4
  44. md:
  45. .add_to_used:
  46.            mov eax, [esi+block_base]
  47.            mov ebx, [esi+block_base]
  48.            shr ebx, 6
  49.            add eax, ebx
  50.            shr ebx, 6
  51.            add eax, ebx
  52.            shr eax, 12
  53.            and eax, 63
  54.            inc [mem_hash_cnt+eax*4]
  55.  
  56.            lea ecx, [mem_used_list+eax*8]
  57.            list_add esi, ecx
  58.            mov [esi+block_flags], USED_BLOCK
  59.            mov eax, [esi+block_size]
  60.            sub [heap_free], eax
  61.            ret
  62. align 4
  63. .find_used:
  64.            mov ecx, eax
  65.            mov ebx, eax
  66.            shr ebx, 6
  67.            add ecx, ebx
  68.            shr ebx, 6
  69.            add ecx, ebx
  70.            shr ecx, 12
  71.            and ecx, 63
  72.  
  73.            lea ebx, [mem_used_list+ecx*8]
  74.            mov esi, ebx
  75. .next:
  76.            mov esi, [esi+list_fd]
  77.            cmp esi, ebx
  78.            je .fail
  79.  
  80.            cmp eax, [esi+block_base]
  81.            jne .next
  82.  
  83.            ret
  84. .fail:
  85.            xor esi, esi
  86.            ret
  87.  
  88. align 4
  89. .del_from_used:
  90.            call .find_used
  91.            test esi, esi
  92.            jz .done
  93.  
  94.            cmp [esi+block_flags], USED_BLOCK
  95.            jne .fatal
  96.  
  97.            dec [mem_hash_cnt+ecx*4]
  98.            list_del esi
  99. .done:
  100.            ret
  101. .fatal:                            ;FIXME panic here
  102.            xor esi, esi
  103.            ret
  104.  
  105. ;Initial heap state
  106. ;
  107. ;+heap_size               terminator        USED_BLOCK
  108. ;+4096*MEM_BLOCK.sizeof   free space        FREE_BLOCK
  109. ;HEAP_BASE                heap_descriptors  USED_BLOCK
  110. ;
  111.  
  112. align 4
  113. proc init_kernel_heap
  114.  
  115.             mov ecx, 64
  116.             mov edi, mem_block_list
  117. @@:
  118.             mov eax, edi
  119.             stosd
  120.             stosd
  121.             loop @B
  122.  
  123.             mov ecx, 64
  124.             mov edi, mem_used_list
  125. @@:
  126.             mov eax, edi
  127.             stosd
  128.             stosd
  129.             loop @B
  130.  
  131.             stdcall alloc_pages, dword 32
  132.             mov ecx, 32
  133.             mov edx, eax
  134.             mov edi, HEAP_BASE
  135. .l1:
  136.         stdcall map_page, edi, edx, PG_SW
  137.             add edi, 0x1000
  138.             add edx, 0x1000
  139.             dec ecx
  140.             jnz .l1
  141.  
  142.             mov edi, HEAP_BASE                     ;descriptors
  143.         mov     ebx, HEAP_BASE+sizeof.MEM_BLOCK      ;free space
  144.         mov     ecx, HEAP_BASE+sizeof.MEM_BLOCK*2    ;terminator
  145.  
  146.             xor eax, eax
  147.             mov [edi+block_next], ebx
  148.             mov [edi+block_prev], eax
  149.             mov [edi+list_fd], eax
  150.             mov [edi+list_bk], eax
  151.             mov [edi+block_base], HEAP_BASE
  152.         mov     [edi+block_size], 4096*sizeof.MEM_BLOCK
  153.             mov [edi+block_flags], USED_BLOCK
  154.  
  155.             mov [ecx+block_next], eax
  156.             mov [ecx+block_prev], ebx
  157.         mov     [ecx+list_fd], eax
  158.         mov     [ecx+list_bk], eax
  159.         mov     [ecx+block_base], eax
  160.         mov     [ecx+block_size], eax
  161.         mov     [ecx+block_flags], USED_BLOCK
  162.  
  163.             mov [ebx+block_next], ecx
  164.             mov [ebx+block_prev], edi
  165.         mov     [ebx+block_base], HEAP_BASE+4096*sizeof.MEM_BLOCK
  166.  
  167.             mov ecx, [pg_data.kernel_pages]
  168.             shl ecx, 12
  169.         sub     ecx, HEAP_BASE-OS_BASE+4096*sizeof.MEM_BLOCK
  170.             mov [heap_size], ecx
  171.             mov [heap_free], ecx
  172.             mov [ebx+block_size], ecx
  173.             mov [ebx+block_flags], FREE_BLOCK
  174.  
  175.             mov [mem_block_mask], eax
  176.         mov     [mem_block_mask+4], 0x80000000
  177.  
  178.             mov ecx, mem_block_list+63*8
  179.             list_add ebx, ecx
  180.  
  181.             mov ecx, 4096-3-1
  182.         mov     eax, HEAP_BASE+sizeof.MEM_BLOCK*4
  183.  
  184.         mov     [next_memblock], HEAP_BASE+sizeof.MEM_BLOCK *3
  185. @@:
  186.         mov     [eax-sizeof.MEM_BLOCK], eax
  187.         add     eax, sizeof.MEM_BLOCK
  188.             loop @B
  189.  
  190.         mov     [eax-sizeof.MEM_BLOCK], dword 0
  191.  
  192.             mov ecx, heap_mutex
  193.             call mutex_init
  194.             mov [heap_blocks], 4094
  195.             mov [free_blocks], 4093
  196.             ret
  197. endp
  198.  
  199. ; param
  200. ;  eax= required size
  201. ;
  202. ; retval
  203. ;  edi= memory block descriptor
  204. ;  ebx= descriptor index
  205.  
  206. align 4
  207. get_small_block:
  208.            mov ecx, eax
  209.            shr ecx, 12
  210.            dec ecx
  211.            cmp ecx, 63
  212.            jle .get_index
  213.            mov ecx, 63
  214. .get_index:
  215.            lea esi, [mem_block_mask]
  216.            xor ebx, ebx
  217.            or edx, -1
  218.  
  219.            cmp ecx, 32
  220.            jb .bit_test
  221.  
  222.            sub ecx, 32
  223.            add ebx, 32
  224.            add esi, 4
  225. .bit_test:
  226.            shl edx, cl
  227.            and edx, [esi]
  228. .find:
  229.            bsf edi, edx
  230.            jz .high_mask
  231.            add ebx, edi
  232.            lea ecx, [mem_block_list+ebx*8]
  233.            mov edi, ecx
  234. .next:
  235.            mov edi, [edi+list_fd]
  236.            cmp edi, ecx
  237.            je .err
  238.            cmp eax, [edi+block_size]
  239.            ja .next
  240.            ret
  241. .err:
  242.            xor edi, edi
  243.            ret
  244.  
  245. .high_mask:
  246.            add esi, 4
  247.            cmp esi, mem_block_mask+8
  248.            jae .err
  249.            add ebx, 32
  250.            mov edx, [esi]
  251.            jmp .find
  252.  
  253.  
  254. align 4
  255. free_mem_block:
  256.            mov ebx, [next_memblock]
  257.            mov [eax], ebx
  258.            mov [next_memblock], eax
  259.            xor ebx, ebx
  260.  
  261.            mov dword [eax+4], ebx
  262.            mov dword [eax+8], ebx
  263.            mov dword [eax+12], ebx
  264.            mov dword [eax+16], ebx
  265. ;           mov dword [eax+20], 0     ;don't clear block size
  266.            mov dword [eax+24], ebx
  267.            mov dword [eax+28], ebx
  268.            inc [free_blocks]
  269.            ret
  270.  
  271. align 4
  272. proc alloc_kernel_space stdcall, size:dword
  273.            local block_ind:DWORD
  274.  
  275.            push ebx
  276.            push esi
  277.            push edi
  278.  
  279.            mov eax, [size]
  280.            add eax, 4095
  281.            and eax, not 4095
  282.            mov [size], eax
  283.  
  284.            cmp eax, [heap_free]
  285.            ja .error
  286.  
  287.            mov ecx, heap_mutex
  288.            call mutex_lock
  289.  
  290.            mov eax, [size]
  291.  
  292.            call get_small_block ; eax
  293.            test edi, edi
  294.            jz .error_unlock
  295.  
  296.            cmp [edi+block_flags], FREE_BLOCK
  297.            jne .error_unlock
  298.  
  299.            mov [block_ind], ebx         ;index of allocated block
  300.  
  301.            mov eax, [edi+block_size]
  302.            cmp eax, [size]
  303.            je .m_eq_size
  304.  
  305.            mov esi, [next_memblock]     ;new memory block
  306.            test esi, esi
  307.            jz .error_unlock
  308.  
  309.            dec [free_blocks]
  310.            mov eax, [esi]
  311.            mov [next_memblock], eax
  312.  
  313.            mov [esi+block_next], edi
  314.            mov eax, [edi+block_prev]
  315.            mov [esi+block_prev], eax
  316.            mov [edi+block_prev], esi
  317.            mov [esi+list_fd], 0
  318.            mov [esi+list_bk], 0
  319.            mov [eax+block_next], esi
  320.  
  321.            mov ebx, [edi+block_base]
  322.            mov [esi+block_base], ebx
  323.            mov edx, [size]
  324.            mov [esi+block_size], edx
  325.            add [edi+block_base], edx
  326.            sub [edi+block_size], edx
  327.  
  328.            mov eax, [edi+block_size]
  329.            calc_index eax
  330.            cmp eax, [block_ind]
  331.            je .add_used
  332.  
  333.            list_del edi
  334.  
  335.            mov ecx, [block_ind]
  336.            lea edx, [mem_block_list+ecx*8]
  337.            cmp edx, [edx]
  338.            jnz @f
  339.            btr [mem_block_mask], ecx
  340. @@:
  341.            bts [mem_block_mask], eax
  342.            lea edx, [mem_block_list+eax*8]   ;edx= list head
  343.            list_add edi, edx
  344. .add_used:
  345.  
  346.            call md.add_to_used
  347.  
  348.            mov ecx, heap_mutex
  349.            call mutex_unlock
  350.            mov eax, [esi+block_base]
  351.            pop edi
  352.            pop esi
  353.            pop ebx
  354.            ret
  355.  
  356. .m_eq_size:
  357.            list_del edi
  358.            lea edx, [mem_block_list+ebx*8]
  359.            cmp edx, [edx]
  360.            jnz @f
  361.            btr [mem_block_mask], ebx
  362. @@:
  363.            mov esi, edi
  364.            jmp .add_used
  365.  
  366. .error_unlock:
  367.            mov ecx, heap_mutex
  368.            call mutex_unlock
  369. .error:
  370.            xor eax, eax
  371.            pop edi
  372.            pop esi
  373.            pop ebx
  374.            ret
  375. endp
  376.  
  377. align 4
  378. proc free_kernel_space stdcall uses ebx ecx edx esi edi, base:dword
  379.  
  380.            mov ecx, heap_mutex
  381.            call mutex_lock
  382.  
  383.            mov eax, [base]
  384.  
  385.            call md.del_from_used
  386.            test esi, esi
  387.            jz .fail
  388.  
  389.            mov eax, [esi+block_size]
  390.            add [heap_free], eax
  391.  
  392.            mov edi, [esi+block_next]
  393.            cmp [edi+block_flags], FREE_BLOCK
  394.            jne .prev
  395.  
  396.            list_del edi
  397.  
  398.            mov edx, [edi+block_next]
  399.            mov [esi+block_next], edx
  400.            mov [edx+block_prev], esi
  401.            mov ecx, [edi+block_size]
  402.            add [esi+block_size], ecx
  403.  
  404.            calc_index ecx
  405.  
  406.            lea edx, [mem_block_list+ecx*8]
  407.            cmp edx, [edx]
  408.            jne @F
  409.            btr [mem_block_mask], ecx
  410. @@:
  411.            mov eax, edi
  412.            call free_mem_block
  413. .prev:
  414.            mov edi, [esi+block_prev]
  415.            cmp [edi+block_flags], FREE_BLOCK
  416.            jne .insert
  417.  
  418.            mov edx, [esi+block_next]
  419.            mov [edi+block_next], edx
  420.            mov [edx+block_prev], edi
  421.  
  422.            mov eax, esi
  423.            call free_mem_block
  424.  
  425.            mov ecx, [edi+block_size]
  426.            mov eax, [esi+block_size]
  427.            add eax, ecx
  428.            mov [edi+block_size], eax
  429.  
  430.            calc_index eax                     ;new index
  431.            calc_index ecx                     ;old index
  432.            cmp eax, ecx
  433.            je .m_eq
  434.  
  435.            push ecx
  436.            list_del edi
  437.            pop ecx
  438.  
  439.            lea edx, [mem_block_list+ecx*8]
  440.            cmp edx, [edx]
  441.            jne .add_block
  442.            btr [mem_block_mask], ecx
  443.  
  444. .add_block:
  445.            bts [mem_block_mask], eax
  446.            lea edx, [mem_block_list+eax*8]
  447.            list_add edi, edx
  448. .m_eq:
  449.            mov ecx, heap_mutex
  450.            call mutex_unlock
  451.            xor eax, eax
  452.            not eax
  453.            ret
  454. .insert:
  455.            mov [esi+block_flags], FREE_BLOCK
  456.            mov eax, [esi+block_size]
  457.            calc_index eax
  458.            mov edi, esi
  459.            jmp .add_block
  460.  
  461. .fail:
  462.            mov ecx, heap_mutex
  463.            call mutex_unlock
  464.            xor eax, eax
  465.            ret
  466. endp
  467.  
  468. align 4
  469. proc kernel_alloc stdcall, size:dword
  470.            locals
  471.              lin_addr    dd ?
  472.              pages_count dd ?
  473.            endl
  474.  
  475.            push ebx
  476.            push edi
  477.  
  478.            mov eax, [size]
  479.            add eax, 4095
  480.            and eax, not 4095;
  481.            mov [size], eax
  482.            and eax, eax
  483.            jz .err
  484.            mov ebx, eax
  485.            shr ebx, 12
  486.            mov [pages_count], ebx
  487.  
  488.            stdcall alloc_kernel_space, eax
  489.            test eax, eax
  490.            jz .err
  491.            mov [lin_addr], eax
  492.  
  493.            mov ecx, [pages_count]
  494.            mov edx, eax
  495.            mov ebx, ecx
  496.  
  497.            shr ecx, 3
  498.            jz .next
  499.  
  500.            and ebx, not 7
  501.            push ebx
  502.            stdcall alloc_pages, ebx
  503.            pop ecx                   ; yes ecx!!!
  504.            and eax, eax
  505.            jz .err
  506.  
  507.            mov edi, eax
  508.            mov edx, [lin_addr]
  509. @@:
  510.         stdcall map_page, edx, edi, dword PG_SW
  511.            add edx, 0x1000
  512.            add edi, 0x1000
  513.            dec ecx
  514.            jnz @B
  515. .next:
  516.            mov ecx, [pages_count]
  517.            and ecx, 7
  518.            jz .end
  519. @@:
  520.            push ecx
  521.            call alloc_page
  522.            pop ecx
  523.            test eax, eax
  524.            jz .err
  525.  
  526.         stdcall map_page, edx, eax, dword PG_SW
  527.            add edx, 0x1000
  528.            dec ecx
  529.            jnz @B
  530. .end:
  531.            mov eax, [lin_addr]
  532.            pop edi
  533.            pop ebx
  534.            ret
  535. .err:
  536.            xor eax, eax
  537.            pop edi
  538.            pop ebx
  539.            ret
  540. endp
  541.  
  542. align 4
  543. proc kernel_free stdcall, base:dword
  544.  
  545.            push ebx esi
  546.  
  547.            mov ecx, heap_mutex
  548.            call mutex_lock
  549.  
  550.            mov eax, [base]
  551.            call md.find_used
  552.  
  553.            mov ecx, heap_mutex
  554.            cmp [esi+block_flags], USED_BLOCK
  555.            jne .fail
  556.  
  557.            call mutex_unlock
  558.  
  559.            mov eax, [esi+block_base]
  560.            mov ecx, [esi+block_size]
  561.            shr ecx, 12
  562.            call release_pages   ;eax, ecx
  563.            stdcall free_kernel_space, [base]
  564.            pop esi ebx
  565.            ret
  566. .fail:
  567.            call mutex_unlock
  568.            xor eax, eax
  569.            pop esi ebx
  570.            ret
  571. endp
  572.  
  573. restore block_next
  574. restore block_prev
  575. restore block_list
  576. restore block_base
  577. restore block_size
  578. restore block_flags
  579.  
  580. ;;;;;;;;;;;;;;      USER     ;;;;;;;;;;;;;;;;;
  581.  
  582. HEAP_TOP  equ 0x80000000
  583.  
  584. align 4
  585. proc init_heap
  586.  
  587.         mov     ebx, [current_slot]
  588.            mov eax, [ebx+APPDATA.heap_top]
  589.            test eax, eax
  590.            jz @F
  591.         sub     eax, [ebx+APPDATA.heap_base]
  592.            sub eax, 4096
  593.            ret
  594. @@:
  595.            mov esi, [ebx+APPDATA.mem_size]
  596.            add esi, 4095
  597.            and esi, not 4095
  598.            mov [ebx+APPDATA.mem_size], esi
  599.            mov eax, HEAP_TOP
  600.            mov [ebx+APPDATA.heap_base], esi
  601.            mov [ebx+APPDATA.heap_top], eax
  602.  
  603.            sub eax, esi
  604.            shr esi, 10
  605.            mov ecx, eax
  606.            sub eax, 4096
  607.            or ecx, FREE_BLOCK
  608.            mov [page_tabs+esi], ecx
  609.            ret
  610. endp
  611.  
  612. align 4
  613. proc user_alloc stdcall, alloc_size:dword
  614.  
  615.            push ebx
  616.            push esi
  617.            push edi
  618.  
  619.            mov ecx, [alloc_size]
  620.            add ecx, (4095+4096)
  621.            and ecx, not 4095
  622.  
  623.            mov ebx, [current_slot]
  624.            mov esi, dword [ebx+APPDATA.heap_base]  ; heap_base
  625.            mov edi, dword [ebx+APPDATA.heap_top]   ; heap_top
  626. l_0:
  627.            cmp esi, edi
  628.            jae m_exit
  629.  
  630.            mov ebx, esi
  631.            shr ebx, 12
  632.            mov eax, [page_tabs+ebx*4]
  633.            test al, FREE_BLOCK
  634.            jz test_used
  635.            and eax, 0xFFFFF000
  636.            cmp eax, ecx    ;alloc_size
  637.            jb  m_next
  638.            jz  @f
  639.  
  640.            lea edx, [esi+ecx]
  641.            sub eax, ecx
  642.            or al, FREE_BLOCK
  643.            shr edx, 12
  644.            mov [page_tabs+edx*4], eax
  645. @@:
  646.            or ecx, USED_BLOCK
  647.            mov [page_tabs+ebx*4], ecx
  648.            shr ecx, 12
  649.            inc ebx
  650.            dec ecx
  651.            jz  .no
  652. @@:
  653.            mov dword [page_tabs+ebx*4], 2
  654.            inc ebx
  655.            dec ecx
  656.            jnz @B
  657. .no:
  658.  
  659.            mov     edx, [current_slot]
  660.            mov     ebx, [alloc_size]
  661.            add     ebx, 0xFFF
  662.            and     ebx, not 0xFFF
  663.            add     ebx, [edx+APPDATA.mem_size]
  664.            call    update_mem_size
  665.  
  666.            lea eax, [esi+4096]
  667.  
  668.            pop edi
  669.            pop esi
  670.            pop ebx
  671.            ret
  672. test_used:
  673.            test al, USED_BLOCK
  674.            jz m_exit
  675.  
  676.            and eax, 0xFFFFF000
  677. m_next:
  678.            add esi, eax
  679.            jmp l_0
  680. m_exit:
  681.            xor eax, eax
  682.            pop edi
  683.            pop esi
  684.            pop ebx
  685.            ret
  686. endp
  687.  
  688. align 4
  689. proc user_alloc_at stdcall, address:dword, alloc_size:dword
  690.  
  691.            push ebx
  692.            push esi
  693.            push edi
  694.  
  695.            mov ebx, [current_slot]
  696.            mov edx, [address]
  697.            and edx, not 0xFFF
  698.            mov [address], edx
  699.            sub edx, 0x1000
  700.            jb  .error
  701.            mov esi, [ebx+APPDATA.heap_base]
  702.            mov edi, [ebx+APPDATA.heap_top]
  703.            cmp edx, esi
  704.            jb  .error
  705. .scan:
  706.            cmp esi, edi
  707.            jae .error
  708.            mov ebx, esi
  709.            shr ebx, 12
  710.            mov eax, [page_tabs+ebx*4]
  711.            mov ecx, eax
  712.            and ecx, 0xFFFFF000
  713.            add ecx, esi
  714.            cmp edx, ecx
  715.            jb  .found
  716.            mov esi, ecx
  717.            jmp .scan
  718. .error:
  719.            xor eax, eax
  720.            pop edi
  721.            pop esi
  722.            pop ebx
  723.            ret
  724. .found:
  725.            test al, FREE_BLOCK
  726.            jz  .error
  727.            mov eax, ecx
  728.            sub eax, edx
  729.            sub eax, 0x1000
  730.            cmp eax, [alloc_size]
  731.            jb  .error
  732.  
  733. ; Here we have 1 big free block which includes requested area.
  734. ; In general, 3 other blocks must be created instead:
  735. ; free at [esi, edx);
  736. ; busy at [edx, edx+0x1000+ALIGN_UP(alloc_size,0x1000));
  737. ; free at [edx+0x1000+ALIGN_UP(alloc_size,0x1000), ecx)
  738. ; First or third block (or both) may be absent.
  739.            mov eax, edx
  740.            sub eax, esi
  741.            jz  .nofirst
  742.            or  al, FREE_BLOCK
  743.            mov [page_tabs+ebx*4], eax
  744. .nofirst:
  745.            mov eax, [alloc_size]
  746.            add eax, 0x1FFF
  747.            and eax, not 0xFFF
  748.            mov ebx, edx
  749.            add edx, eax
  750.            shr ebx, 12
  751.            or  al, USED_BLOCK
  752.            mov [page_tabs+ebx*4], eax
  753.            shr eax, 12
  754.            dec eax
  755.            jz  .second_nofill
  756.            inc ebx
  757. .fill:
  758.            mov dword [page_tabs+ebx*4], 2
  759.            inc ebx
  760.            dec eax
  761.            jnz .fill
  762.  
  763. .second_nofill:
  764.            sub ecx, edx
  765.            jz  .nothird
  766.            or  cl, FREE_BLOCK
  767.            mov [page_tabs+ebx*4], ecx
  768.  
  769. .nothird:
  770.  
  771.            mov     edx, [current_slot]
  772.            mov     ebx, [alloc_size]
  773.            add     ebx, 0xFFF
  774.            and     ebx, not 0xFFF
  775.            add     ebx, [edx+APPDATA.mem_size]
  776.            call    update_mem_size
  777.  
  778.            mov eax, [address]
  779.  
  780.            pop edi
  781.            pop esi
  782.            pop ebx
  783.            ret
  784. endp
  785.  
  786. align 4
  787. proc user_free stdcall, base:dword
  788.  
  789.            push esi
  790.  
  791.            mov esi, [base]
  792.            test esi, esi
  793.            jz .exit
  794.  
  795.            push ebx
  796.  
  797.            xor ebx, ebx
  798.            shr esi, 12
  799.            mov eax, [page_tabs+(esi-1)*4]
  800.            test al, USED_BLOCK
  801.            jz .cantfree
  802.            test al, DONT_FREE_BLOCK
  803.            jnz .cantfree
  804.  
  805.            and eax, not 4095
  806.            mov ecx, eax
  807.            or al, FREE_BLOCK
  808.            mov [page_tabs+(esi-1)*4], eax
  809.            sub ecx, 4096
  810.            mov ebx, ecx
  811.            shr ecx, 12
  812.            jz .released
  813. .release:
  814.            xor eax, eax
  815.            xchg eax, [page_tabs+esi*4]
  816.            test al, 1
  817.            jz @F
  818.            test eax, PG_SHARED
  819.            jnz @F
  820.            call free_page
  821.            mov eax, esi
  822.            shl eax, 12
  823.            invlpg [eax]
  824. @@:
  825.            inc esi
  826.            dec ecx
  827.            jnz .release
  828.  
  829. .released:
  830.            push edi
  831.  
  832.            mov edx, [current_slot]
  833.            mov esi, dword [edx+APPDATA.heap_base]
  834.            mov edi, dword [edx+APPDATA.heap_top]
  835.            sub ebx, [edx+APPDATA.mem_size]
  836.            neg ebx
  837.            call update_mem_size
  838.            call user_normalize
  839.            pop edi
  840.            pop ebx
  841.            pop esi
  842.            ret
  843. .exit:
  844.            xor eax, eax
  845.            inc eax
  846.            pop esi
  847.            ret
  848. .cantfree:
  849.            xor eax, eax
  850.            pop ebx
  851.            pop esi
  852.            ret
  853. endp
  854.  
  855.  
  856. align 4
  857. proc user_unmap stdcall, base:dword, offset:dword, size:dword
  858.  
  859.         push    ebx
  860.  
  861.         mov     ebx, [base]             ; must be valid pointer
  862.         test    ebx, ebx
  863.         jz      .error
  864.  
  865.         mov     edx, [offset]           ; check offset
  866.         add     edx, ebx                ; must be below 2Gb app limit
  867.         js      .error
  868.  
  869.         shr     ebx, 12                 ; chek block attributes
  870.         lea     ebx, [page_tabs+ebx*4]
  871.         mov     eax, [ebx-4]            ; block attributes
  872.         test    al, USED_BLOCK
  873.         jz      .error
  874.         test    al, DONT_FREE_BLOCK
  875.         jnz     .error
  876.  
  877.         shr     edx, 12
  878.         lea     edx, [page_tabs+edx*4]  ; unmap offset
  879.  
  880.         mov     ecx, [size]
  881.         add     ecx, 4095
  882.         shr     ecx, 12                 ; unmap size in pages
  883.  
  884.         shr     eax, 12                 ; block size + 1 page
  885.         lea     ebx, [ebx+eax*4-4]      ; block end ptr
  886.         lea     eax, [edx+ecx*4]        ; unmap end ptr
  887.  
  888.         cmp     eax, ebx                ; check for overflow
  889.         ja      .error
  890.  
  891.         mov     ebx, [offset]
  892.         and     ebx, not 4095           ; is it required ?
  893.  
  894. .unmap:
  895.         mov     eax, [edx]              ; get page addres
  896.         test    al, 1                   ; page mapped ?
  897.         jz      @F
  898.         test    eax, PG_SHARED          ; page shared ?
  899.         jnz     @F
  900.         mov     [page_tabs+edx*4], dword 2
  901.                                         ; mark page as reserved
  902.         invlpg  [ebx]                   ; when we start using
  903.         call    free_page               ; empty c-o-w page instead this ?
  904. @@:
  905.         add     ebx, 4096
  906.         add     edx, 4
  907.         dec     ecx
  908.         jnz     .unmap
  909.  
  910.         pop     ebx
  911.         or      al, 1                   ; return non zero on success
  912.         ret
  913. .error:
  914.         pop     ebx
  915.         xor     eax, eax                ; something wrong
  916.         ret
  917. endp
  918.  
  919. align 4
  920. user_normalize:
  921. ; in: esi=heap_base, edi=heap_top
  922. ; out: eax=0 <=> OK
  923. ; destroys: ebx,edx,esi,edi
  924.            shr esi, 12
  925.            shr edi, 12
  926. @@:
  927.            mov eax, [page_tabs+esi*4]
  928.            test al, USED_BLOCK
  929.            jz .test_free
  930.            shr eax, 12
  931.            add esi, eax
  932.            jmp @B
  933. .test_free:
  934.            test al, FREE_BLOCK
  935.            jz .err
  936.            mov edx, eax
  937.            shr edx, 12
  938.            add edx, esi
  939.            cmp edx, edi
  940.            jae .exit
  941.  
  942.            mov ebx, [page_tabs+edx*4]
  943.            test bl, USED_BLOCK
  944.            jz .next_free
  945.  
  946.            shr ebx, 12
  947.            add edx, ebx
  948.            mov esi, edx
  949.            jmp @B
  950. .next_free:
  951.            test bl, FREE_BLOCK
  952.            jz .err
  953.            and dword [page_tabs+edx*4], 0
  954.            add eax, ebx
  955.            and eax, not 4095
  956.            or eax, FREE_BLOCK
  957.            mov [page_tabs+esi*4], eax
  958.            jmp @B
  959. .exit:
  960.            xor eax, eax
  961.            inc eax
  962.            ret
  963. .err:
  964.            xor eax, eax
  965.            ret
  966.  
  967. user_realloc:
  968. ; in: eax = pointer, ebx = new size
  969. ; out: eax = new pointer or NULL
  970.         test    eax, eax
  971.         jnz     @f
  972. ; realloc(NULL,sz) - same as malloc(sz)
  973.         push    ebx
  974.         call    user_alloc
  975.         ret
  976. @@:
  977.         push    ecx edx
  978.         lea     ecx, [eax - 0x1000]
  979.         shr     ecx, 12
  980.         mov     edx, [page_tabs+ecx*4]
  981.         test    dl, USED_BLOCK
  982.         jnz     @f
  983. ; attempt to realloc invalid pointer
  984. .ret0:
  985.         pop     edx ecx
  986.         xor     eax, eax
  987.         ret
  988. @@:
  989.         test    dl, DONT_FREE_BLOCK
  990.         jnz     .ret0
  991.         add     ebx, 0x1FFF
  992.         shr     edx, 12
  993.         shr     ebx, 12
  994. ; edx = allocated size, ebx = new size
  995.         add     edx, ecx
  996.         add     ebx, ecx
  997.         cmp     edx, ebx
  998.         jb      .realloc_add
  999. ; release part of allocated memory
  1000. .loop:
  1001.         cmp     edx, ebx
  1002.         jz      .release_done
  1003.         dec     edx
  1004.         xor     eax, eax
  1005.         xchg    eax, [page_tabs+edx*4]
  1006.         test    al, 1
  1007.         jz      .loop
  1008.         call    free_page
  1009.         mov     eax, edx
  1010.         shl     eax, 12
  1011.         invlpg  [eax]
  1012.         jmp     .loop
  1013. .release_done:
  1014.         sub     ebx, ecx
  1015.         cmp     ebx, 1
  1016.         jnz     .nofreeall
  1017.         mov     eax, [page_tabs+ecx*4]
  1018.         and     eax, not 0xFFF
  1019.         mov     edx, [current_slot]
  1020.         mov     ebx, [APPDATA.mem_size+edx]
  1021.         sub     ebx, eax
  1022.         add     ebx, 0x1000
  1023.         or      al, FREE_BLOCK
  1024.         mov     [page_tabs+ecx*4], eax
  1025.         push    esi edi
  1026.         mov     esi, [APPDATA.heap_base+edx]
  1027.         mov     edi, [APPDATA.heap_top+edx]
  1028.         call    update_mem_size
  1029.         call    user_normalize
  1030.         pop     edi esi
  1031.         jmp     .ret0   ; all freed
  1032. .nofreeall:
  1033.         sub     edx, ecx
  1034.         shl     ebx, 12
  1035.         or      ebx, USED_BLOCK
  1036.         xchg    [page_tabs+ecx*4], ebx
  1037.         shr     ebx, 12
  1038.         sub     ebx, edx
  1039.         push    ebx ecx edx
  1040.         mov     edx, [current_slot]
  1041.         shl     ebx, 12
  1042.         sub     ebx, [APPDATA.mem_size+edx]
  1043.         neg     ebx
  1044.         call    update_mem_size
  1045.         pop     edx ecx ebx
  1046.         lea     eax, [ecx+1]
  1047.         shl     eax, 12
  1048.         push    eax
  1049.         add     ecx, edx
  1050.         lea     edx, [ecx+ebx]
  1051.         shl     ebx, 12
  1052.         jz      .ret
  1053.         push    esi
  1054.         mov     esi, [current_slot]
  1055.         mov     esi, [APPDATA.heap_top+esi]
  1056.         shr     esi, 12
  1057. @@:
  1058.         cmp     edx, esi
  1059.         jae     .merge_done
  1060.         mov     eax, [page_tabs+edx*4]
  1061.         test    al, USED_BLOCK
  1062.         jnz     .merge_done
  1063.         and     dword [page_tabs+edx*4], 0
  1064.         shr     eax, 12
  1065.         add     edx, eax
  1066.         shl     eax, 12
  1067.         add     ebx, eax
  1068.         jmp     @b
  1069. .merge_done:
  1070.         pop     esi
  1071.         or      ebx, FREE_BLOCK
  1072.         mov     [page_tabs+ecx*4], ebx
  1073. .ret:
  1074.         pop     eax edx ecx
  1075.         ret
  1076. .realloc_add:
  1077. ; get some additional memory
  1078.         mov     eax, [current_slot]
  1079.         mov     eax, [APPDATA.heap_top+eax]
  1080.         shr     eax, 12
  1081.         cmp     edx, eax
  1082.         jae     .cant_inplace
  1083.         mov     eax, [page_tabs+edx*4]
  1084.         test    al, FREE_BLOCK
  1085.         jz      .cant_inplace
  1086.         shr     eax, 12
  1087.         add     eax, edx
  1088.         sub     eax, ebx
  1089.         jb      .cant_inplace
  1090.         jz      @f
  1091.         shl     eax, 12
  1092.         or      al, FREE_BLOCK
  1093.         mov     [page_tabs+ebx*4], eax
  1094. @@:
  1095.         mov     eax, ebx
  1096.         sub     eax, ecx
  1097.         shl     eax, 12
  1098.         or      al, USED_BLOCK
  1099.         mov     [page_tabs+ecx*4], eax
  1100.         lea     eax, [ecx+1]
  1101.         shl     eax, 12
  1102.         push    eax
  1103.         push    edi
  1104.         lea     edi, [page_tabs+edx*4]
  1105.         mov     eax, 2
  1106.         sub     ebx, edx
  1107.         mov     ecx, ebx
  1108.         cld
  1109.         rep     stosd
  1110.         pop     edi
  1111.         mov     edx, [current_slot]
  1112.         shl     ebx, 12
  1113.         add     ebx, [APPDATA.mem_size+edx]
  1114.         call    update_mem_size
  1115.         pop     eax edx ecx
  1116.         ret
  1117. .cant_inplace:
  1118.         push    esi edi
  1119.         mov     eax, [current_slot]
  1120.         mov     esi, [APPDATA.heap_base+eax]
  1121.         mov     edi, [APPDATA.heap_top+eax]
  1122.         shr     esi, 12
  1123.         shr     edi, 12
  1124.         sub     ebx, ecx
  1125. .find_place:
  1126.         cmp     esi, edi
  1127.         jae     .place_not_found
  1128.         mov     eax, [page_tabs+esi*4]
  1129.         test    al, FREE_BLOCK
  1130.         jz      .next_place
  1131.         shr     eax, 12
  1132.         cmp     eax, ebx
  1133.         jae     .place_found
  1134.         add     esi, eax
  1135.         jmp     .find_place
  1136. .next_place:
  1137.         shr     eax, 12
  1138.         add     esi, eax
  1139.         jmp     .find_place
  1140. .place_not_found:
  1141.         pop     edi esi
  1142.         jmp     .ret0
  1143. .place_found:
  1144.         sub     eax, ebx
  1145.         jz      @f
  1146.         push    esi
  1147.         add     esi, ebx
  1148.         shl     eax, 12
  1149.         or      al, FREE_BLOCK
  1150.         mov     [page_tabs+esi*4], eax
  1151.         pop     esi
  1152. @@:
  1153.         mov     eax, ebx
  1154.         shl     eax, 12
  1155.         or      al, USED_BLOCK
  1156.         mov     [page_tabs+esi*4], eax
  1157.         inc     esi
  1158.         mov     eax, esi
  1159.         shl     eax, 12
  1160.         push    eax
  1161.         mov     eax, [page_tabs+ecx*4]
  1162.         and     eax, not 0xFFF
  1163.         or      al, FREE_BLOCK
  1164.         sub     edx, ecx
  1165.         mov     [page_tabs+ecx*4], eax
  1166.         inc     ecx
  1167.         dec     ebx
  1168.         dec     edx
  1169.         jz      .no
  1170. @@:
  1171.         xor     eax, eax
  1172.         xchg    eax, [page_tabs+ecx*4]
  1173.         mov     [page_tabs+esi*4], eax
  1174.         mov     eax, ecx
  1175.         shl     eax, 12
  1176.         invlpg  [eax]
  1177.         inc     esi
  1178.         inc     ecx
  1179.         dec     ebx
  1180.         dec     edx
  1181.         jnz     @b
  1182. .no:
  1183.         push    ebx
  1184.         mov     edx, [current_slot]
  1185.         shl     ebx, 12
  1186.         add     ebx, [APPDATA.mem_size+edx]
  1187.         call    update_mem_size
  1188.         pop     ebx
  1189. @@:
  1190.         mov     dword [page_tabs+esi*4], 2
  1191.         inc     esi
  1192.         dec     ebx
  1193.         jnz     @b
  1194.         pop     eax edi esi edx ecx
  1195.         ret
  1196.  
  1197. if 0
  1198. align 4
  1199. proc alloc_dll
  1200.            pushf
  1201.            cli
  1202.            bsf eax, [dll_map]
  1203.            jnz .find
  1204.            popf
  1205.            xor eax, eax
  1206.            ret
  1207. .find:
  1208.            btr [dll_map], eax
  1209.            popf
  1210.            shl eax, 5
  1211.            add eax, dll_tab
  1212.            ret
  1213. endp
  1214.  
  1215. align 4
  1216. proc alloc_service
  1217.            pushf
  1218.            cli
  1219.            bsf eax, [srv_map]
  1220.            jnz .find
  1221.            popf
  1222.            xor eax, eax
  1223.            ret
  1224. .find:
  1225.            btr [srv_map], eax
  1226.            popf
  1227.         shl     eax, 0x02
  1228.         lea     eax, [srv_tab+eax+eax*8] ;srv_tab+eax*36
  1229.            ret
  1230. endp
  1231.  
  1232. end if
  1233.  
  1234.  
  1235. ;;;;;;;;;;;;;;      SHARED      ;;;;;;;;;;;;;;;;;
  1236.  
  1237.  
  1238. ; param
  1239. ;  eax= shm_map object
  1240.  
  1241. align 4
  1242. destroy_smap:
  1243.  
  1244.            pushfd
  1245.            cli
  1246.  
  1247.            push esi
  1248.            push edi
  1249.  
  1250.            mov edi, eax
  1251.            mov esi, [eax+SMAP.parent]
  1252.            test esi, esi
  1253.            jz .done
  1254.  
  1255.            lock dec [esi+SMEM.refcount]
  1256.            jnz .done
  1257.  
  1258.            mov ecx, [esi+SMEM.bk]
  1259.            mov edx, [esi+SMEM.fd]
  1260.  
  1261.            mov [ecx+SMEM.fd], edx
  1262.            mov [edx+SMEM.bk], ecx
  1263.  
  1264.            stdcall kernel_free, [esi+SMEM.base]
  1265.            mov eax, esi
  1266.            call free
  1267. .done:
  1268.            mov eax, edi
  1269.            call destroy_kernel_object
  1270.  
  1271.            pop edi
  1272.            pop esi
  1273.            popfd
  1274.  
  1275.            ret
  1276.  
  1277. E_NOTFOUND      equ  5
  1278. E_ACCESS        equ 10
  1279. E_NOMEM         equ 30
  1280. E_PARAM         equ 33
  1281.  
  1282. SHM_READ        equ 0
  1283. SHM_WRITE       equ 1
  1284.  
  1285. SHM_ACCESS_MASK equ 3
  1286.  
  1287. SHM_OPEN        equ (0 shl 2)
  1288. SHM_OPEN_ALWAYS equ (1 shl 2)
  1289. SHM_CREATE      equ (2 shl 2)
  1290.  
  1291. SHM_OPEN_MASK   equ (3 shl 2)
  1292.  
  1293. align 4
  1294. proc shmem_open stdcall name:dword, size:dword, access:dword
  1295.            locals
  1296.               action         dd ?
  1297.               owner_access   dd ?
  1298.               mapped         dd ?
  1299.            endl
  1300.  
  1301.            push ebx
  1302.            push esi
  1303.            push edi
  1304.  
  1305.            mov [mapped], 0
  1306.            mov [owner_access], 0
  1307.  
  1308.            pushfd                      ;mutex required
  1309.            cli
  1310.  
  1311.            mov eax, [access]
  1312.            and eax, SHM_OPEN_MASK
  1313.            mov [action], eax
  1314.  
  1315.            mov ebx, [name]
  1316.            test ebx, ebx
  1317.            mov edx, E_PARAM
  1318.            jz .fail
  1319.  
  1320.            mov esi, [shmem_list.fd]
  1321. align 4
  1322. @@:
  1323.            cmp esi, shmem_list
  1324.            je .not_found
  1325.  
  1326.         lea     edx, [esi+SMEM.name]; link , base, size
  1327.            stdcall strncmp, edx, ebx, 32
  1328.            test eax, eax
  1329.            je .found
  1330.  
  1331.            mov esi, [esi+SMEM.fd]
  1332.            jmp @B
  1333.  
  1334. .not_found:
  1335.            mov eax, [action]
  1336.  
  1337.            cmp eax, SHM_OPEN
  1338.            mov edx, E_NOTFOUND
  1339.            je .fail
  1340.  
  1341.            cmp eax, SHM_CREATE
  1342.            mov edx, E_PARAM
  1343.            je .create_shm
  1344.  
  1345.            cmp eax, SHM_OPEN_ALWAYS
  1346.            jne .fail
  1347.  
  1348. .create_shm:
  1349.  
  1350.            mov ecx, [size]
  1351.            test ecx, ecx
  1352.            jz .fail
  1353.  
  1354.            add ecx, 4095
  1355.            and ecx, -4096
  1356.            mov [size], ecx
  1357.  
  1358.         mov     eax, sizeof.SMEM
  1359.            call malloc
  1360.            test eax, eax
  1361.            mov esi, eax
  1362.            mov edx, E_NOMEM
  1363.            jz .fail
  1364.  
  1365.            stdcall kernel_alloc, [size]
  1366.            test eax, eax
  1367.            mov [mapped], eax
  1368.            mov edx, E_NOMEM
  1369.            jz .cleanup
  1370.  
  1371.            mov ecx, [size]
  1372.            mov edx, [access]
  1373.            and edx, SHM_ACCESS_MASK
  1374.  
  1375.            mov [esi+SMEM.base], eax
  1376.            mov [esi+SMEM.size], ecx
  1377.            mov [esi+SMEM.access], edx
  1378.            mov [esi+SMEM.refcount], 0
  1379.            mov [esi+SMEM.name+28], 0
  1380.  
  1381.            lea eax, [esi+SMEM.name]
  1382.            stdcall strncpy, eax, [name], 31
  1383.  
  1384.            mov eax, [shmem_list.fd]
  1385.            mov [esi+SMEM.bk], shmem_list
  1386.            mov [esi+SMEM.fd], eax
  1387.  
  1388.            mov [eax+SMEM.bk], esi
  1389.            mov [shmem_list.fd], esi
  1390.  
  1391.            mov [action], SHM_OPEN
  1392.            mov [owner_access], SHM_WRITE
  1393.  
  1394. .found:
  1395.            mov eax, [action]
  1396.  
  1397.            cmp eax, SHM_CREATE
  1398.            mov edx, E_ACCESS
  1399.            je .exit
  1400.  
  1401.            cmp eax, SHM_OPEN
  1402.            mov edx, E_PARAM
  1403.            je .create_map
  1404.  
  1405.            cmp eax, SHM_OPEN_ALWAYS
  1406.            jne .fail
  1407.  
  1408. .create_map:
  1409.  
  1410.            mov eax, [access]
  1411.            and eax, SHM_ACCESS_MASK
  1412.            cmp eax, [esi+SMEM.access]
  1413.            mov [access], eax
  1414.            mov edx, E_ACCESS
  1415.            ja .fail
  1416.  
  1417.            mov ebx, [CURRENT_TASK]
  1418.            shl ebx, 5
  1419.            mov ebx, [CURRENT_TASK+ebx+4]
  1420.         mov     eax, sizeof.SMAP
  1421.  
  1422.            call create_kernel_object
  1423.            test eax, eax
  1424.            mov edi, eax
  1425.            mov edx, E_NOMEM
  1426.            jz .fail
  1427.  
  1428.            inc [esi+SMEM.refcount]
  1429.  
  1430.            mov [edi+SMAP.magic], 'SMAP'
  1431.            mov [edi+SMAP.destroy], destroy_smap
  1432.            mov [edi+SMAP.parent], esi
  1433.            mov [edi+SMAP.base], 0
  1434.  
  1435.            stdcall user_alloc, [esi+SMEM.size]
  1436.            test eax, eax
  1437.            mov [mapped], eax
  1438.            mov edx, E_NOMEM
  1439.            jz .cleanup2
  1440.  
  1441.            mov [edi+SMAP.base], eax
  1442.  
  1443.            mov ecx, [esi+SMEM.size]
  1444.            mov [size], ecx
  1445.  
  1446.            shr ecx, 12
  1447.            shr eax, 10
  1448.  
  1449.            mov esi, [esi+SMEM.base]
  1450.            shr esi, 10
  1451.            lea edi, [page_tabs+eax]
  1452.            add esi, page_tabs
  1453.  
  1454.            mov edx, [access]
  1455.            or edx, [owner_access]
  1456.            shl edx, 1
  1457.            or edx, PG_USER+PG_SHARED
  1458. @@:
  1459.            lodsd
  1460.            and eax, 0xFFFFF000
  1461.            or eax, edx
  1462.            stosd
  1463.            loop @B
  1464.  
  1465.            xor edx, edx
  1466.  
  1467.            cmp [owner_access], 0
  1468.            jne .fail
  1469. .exit:
  1470.            mov edx, [size]
  1471. .fail:
  1472.            mov eax, [mapped]
  1473.  
  1474.            popfd
  1475.            pop edi
  1476.            pop esi
  1477.            pop ebx
  1478.            ret
  1479. .cleanup:
  1480.            mov [size], edx
  1481.            mov eax, esi
  1482.            call free
  1483.            jmp .exit
  1484.  
  1485. .cleanup2:
  1486.            mov [size], edx
  1487.            mov eax, edi
  1488.            call destroy_smap
  1489.            jmp .exit
  1490. endp
  1491.  
  1492. align 4
  1493. proc shmem_close stdcall, name:dword
  1494.  
  1495.            mov eax, [name]
  1496.            test eax, eax
  1497.            jz .fail
  1498.  
  1499.            push esi
  1500.            push edi
  1501.            pushfd
  1502.            cli
  1503.  
  1504.            mov esi, [current_slot]
  1505.            add esi, APP_OBJ_OFFSET
  1506. .next:
  1507.            mov eax, [esi+APPOBJ.fd]
  1508.            test eax, eax
  1509.            jz @F
  1510.  
  1511.            cmp eax, esi
  1512.            mov esi, eax
  1513.            je @F
  1514.  
  1515.            cmp [eax+SMAP.magic], 'SMAP'
  1516.            jne .next
  1517.  
  1518.            mov edi, [eax+SMAP.parent]
  1519.            test edi, edi
  1520.            jz .next
  1521.  
  1522.            lea edi, [edi+SMEM.name]
  1523.            stdcall strncmp, [name], edi, 32
  1524.            test eax, eax
  1525.            jne .next
  1526.  
  1527.            stdcall user_free, [esi+SMAP.base]
  1528.  
  1529.         mov     eax, esi
  1530.            call [esi+APPOBJ.destroy]
  1531. @@:
  1532.            popfd
  1533.            pop edi
  1534.            pop esi
  1535. .fail:
  1536.            ret
  1537. endp
  1538.