Subversion Repositories Kolibri OS

Rev

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

  1. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  2. ;;                                                              ;;
  3. ;; Copyright (C) KolibriOS team 2004-2020. All rights reserved. ;;
  4. ;; Distributed under terms of the GNU General Public License    ;;
  5. ;;                                                              ;;
  6. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  7.  
  8. $Revision: 9048 $
  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.         or      eax, [esp+16]              ; flags
  131.         and     eax, [pte_valid_mask]
  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.         or      edx, [flags]
  195.         and     edx, [pte_valid_mask]
  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.         and     eax, [pte_valid_mask ]
  233.         mov     edi, ebx
  234.         shr     edi, 12
  235.         lea     edi, [page_tabs+edi*4]
  236. @@:
  237.         stosd
  238.         invlpg  [ebx]
  239.         add     eax, 0x1000
  240.         add     ebx, 0x1000
  241.         loop    @B
  242.  
  243.         pop     edi
  244.  
  245.         mov     ecx, pg_data.mutex
  246.         call    mutex_unlock
  247. .fail:
  248.         ret
  249.  
  250.  
  251. ; param
  252. ;  eax= base
  253. ;  ecx= count
  254.  
  255. align 4
  256. release_pages:
  257.  
  258.         push    ebp
  259.         push    esi
  260.         push    edi
  261.         push    ebx
  262.  
  263.         mov     esi, eax
  264.         mov     edi, eax
  265.  
  266.         shr     esi, 12
  267.         lea     esi, [page_tabs+esi*4]
  268.  
  269.         push    ecx
  270.         mov     ecx, pg_data.mutex
  271.         call    mutex_lock
  272.         pop     ecx
  273.  
  274.         mov     ebp, [pg_data.pages_free]
  275.         mov     ebx, [page_start]
  276.         mov     edx, sys_pgmap
  277. @@:
  278.         xor     eax, eax
  279.         xchg    eax, [esi]
  280.         invlpg  [edi]
  281.  
  282.         test    eax, 1
  283.         jz      .next
  284.  
  285.         shr     eax, 12
  286.         bts     [edx], eax
  287.         cmc
  288.         adc     ebp, 0
  289.         shr     eax, 3
  290.         and     eax, -4
  291.         add     eax, edx
  292.         cmp     eax, ebx
  293.         jae     .next
  294.  
  295.         mov     ebx, eax
  296. .next:
  297.         add     edi, 0x1000
  298.         add     esi, 4
  299.         loop    @B
  300.  
  301.         mov     [pg_data.pages_free], ebp
  302.         mov     ecx, pg_data.mutex
  303.         call    mutex_unlock
  304.  
  305.         pop     ebx
  306.         pop     edi
  307.         pop     esi
  308.         pop     ebp
  309.         ret
  310.  
  311. ; param
  312. ;  eax= base
  313. ;  ecx= count
  314.  
  315. align 4
  316. unmap_pages:
  317.  
  318.         push    edi
  319.  
  320.         mov     edi, eax
  321.         mov     edx, eax
  322.  
  323.         shr     edi, 10
  324.         add     edi, page_tabs
  325.  
  326.         xor     eax, eax
  327. @@:
  328.         stosd
  329.         invlpg  [edx]
  330.         add     edx, 0x1000
  331.         loop    @b
  332.  
  333.         pop     edi
  334.         ret
  335.  
  336.  
  337. align 4
  338. proc map_page_table stdcall, lin_addr:dword, phis_addr:dword
  339.         push    ebx
  340.         mov     ebx, [lin_addr]
  341.         shr     ebx, 22
  342.         mov     eax, [phis_addr]
  343.         and     eax, not 0xFFF
  344.         or      eax, PG_UWR
  345.         mov     dword [master_tab+ebx*4], eax
  346.         mov     eax, [lin_addr]
  347.         shr     eax, 10
  348.         add     eax, page_tabs
  349.         invlpg  [eax]
  350.         pop     ebx
  351.         ret
  352. endp
  353.  
  354. uglobal
  355. sb16_buffer_allocated db 0
  356. endg
  357.  
  358. ; Allocates [.size] bytes so that the target memory block
  359. ; is inside one 64K page for 24-bit DMA controller,
  360. ; that is, somewhere between 00xx0000h and 00xxFFFFh.
  361. proc alloc_dma24
  362. ; Implementation note.
  363. ; The only user of that function is SB16 driver,
  364. ; so just return a statically allocated buffer.
  365. virtual at esp
  366.                 dd      ? ; return address
  367. .size           dd      ?
  368. end virtual
  369.         cmp     [sb16_buffer_allocated], 0
  370.         jnz     .fail
  371.         inc     [sb16_buffer_allocated]
  372.         mov     eax, SB16Buffer
  373.         ret     4
  374. .fail:
  375.         xor     eax, eax
  376.         ret     4
  377. endp
  378.  
  379. ; Allocates a physical page for master page table
  380. ; that duplicates first Mb of OS_BASE at address 0;
  381. ; used for starting APs and for shutting down,
  382. ; where it is important to execute code in trivial-mapped pages.
  383. ; Returns eax = allocated physical page.
  384. proc create_trampoline_pgmap
  385. ; The only non-trivial moment:
  386. ; we need a linear address to fill information,
  387. ; but we don't need it outside of this function,
  388. ; so we're returning physical address.
  389. ; Therefore, allocate memory with kernel_alloc,
  390. ; this will allocate physical page and a linear address somewhere,
  391. ; and deallocate only linear address with free_kernel_space.
  392.         stdcall kernel_alloc, 0x1000
  393.         mov     edi, eax
  394.         mov     esi, master_tab
  395.         mov     ecx, 1024
  396.         rep movsd
  397.         mov     ecx, [master_tab+(OS_BASE shr 20)]
  398.         mov     [eax], ecx
  399.         mov     edi, eax
  400.         call    get_pg_addr
  401.         push    eax
  402.         stdcall free_kernel_space, edi
  403.         pop     eax
  404.         ret
  405. endp
  406.  
  407. align 4
  408. proc new_mem_resize stdcall, new_size:dword
  409.  
  410.         push    ebx
  411.         push    esi
  412.         push    edi
  413.  
  414.         mov     edx, [current_slot]
  415.         mov     ebx, [edx+APPDATA.process]
  416.  
  417.         cmp     [ebx+PROC.heap_base], 0
  418.         jne     .exit
  419.  
  420.         mov     edi, [new_size]
  421.         add     edi, 4095
  422.         and     edi, not 4095
  423.         mov     [new_size], edi
  424.  
  425.         mov     esi, [ebx+PROC.mem_used]
  426.         add     esi, 4095
  427.         and     esi, not 4095
  428.  
  429.         cmp     edi, esi
  430.         ja      .expand
  431.         je      .exit
  432.  
  433.         mov     ebx, edi
  434.         shr     edi, 12
  435.         shr     esi, 12
  436.  
  437.         mov     ecx, pg_data.mutex
  438.         call    mutex_lock
  439. @@:
  440.         mov     eax, [app_page_tabs+edi*4]
  441.         test    eax, 1
  442.         jz      .next
  443.  
  444.         mov     dword [app_page_tabs+edi*4], 0
  445.         invlpg  [ebx]
  446.         call    free_page
  447.  
  448. .next:
  449.         inc     edi
  450.         add     ebx, 0x1000
  451.         cmp     edi, esi
  452.         jb      @B
  453.  
  454.         mov     ecx, pg_data.mutex
  455.         call    mutex_unlock
  456.  
  457. .update_size:
  458.         mov     edx, [current_slot]
  459.         mov     ebx, [new_size]
  460.         mov     edx, [edx+APPDATA.process]
  461.         mov     [edx+PROC.mem_used], ebx
  462. .exit:
  463.         pop     edi
  464.         pop     esi
  465.         pop     ebx
  466.         xor     eax, eax
  467.         ret
  468.  
  469. .expand:
  470.  
  471.         mov     ecx, pg_data.mutex
  472.         call    mutex_lock
  473.  
  474.         xchg    esi, edi
  475.  
  476.         push    esi                   ;new size
  477.         push    edi                   ;old size
  478.  
  479.         add     edi, 0x3FFFFF
  480.         and     edi, not(0x3FFFFF)
  481.         add     esi, 0x3FFFFF
  482.         and     esi, not(0x3FFFFF)
  483.  
  484.         cmp     edi, esi
  485.         jae     .grow
  486.  @@:
  487.         call    alloc_page
  488.         test    eax, eax
  489.         jz      .exit_fail
  490.  
  491.         stdcall map_page_table, edi, eax
  492.  
  493.         push    edi
  494.         shr     edi, 10
  495.         add     edi, page_tabs
  496.         mov     ecx, 1024
  497.         xor     eax, eax
  498.         cld
  499.         rep stosd
  500.         pop     edi
  501.  
  502.         add     edi, 0x00400000
  503.         cmp     edi, esi
  504.         jb      @B
  505. .grow:
  506.         pop     edi                   ;old size
  507.         pop     ecx                   ;new size
  508.  
  509.         shr     edi, 10
  510.         shr     ecx, 10
  511.         sub     ecx, edi
  512.         shr     ecx, 2                ;pages count
  513.         mov     eax, 2
  514.  
  515.         add     edi, app_page_tabs
  516.         rep stosd
  517.  
  518.         mov     ecx, pg_data.mutex
  519.         call    mutex_unlock
  520.  
  521.         jmp     .update_size
  522.  
  523. .exit_fail:
  524.         mov     ecx, pg_data.mutex
  525.         call    mutex_unlock
  526.  
  527.         add     esp, 8
  528.         pop     edi
  529.         pop     esi
  530.         pop     ebx
  531.         xor     eax, eax
  532.         inc     eax
  533.         ret
  534. endp
  535.  
  536.  
  537. ; param
  538. ;  eax= linear address
  539. ;
  540. ; retval
  541. ;  eax= physical page address
  542.  
  543. align 4
  544. get_pg_addr:
  545.         sub     eax, OS_BASE
  546.         cmp     eax, 0x400000
  547.         jb      @f
  548.         shr     eax, 12
  549.         mov     eax, [page_tabs+(eax+(OS_BASE shr 12))*4]
  550. @@:
  551.         and     eax, 0xFFFFF000
  552.         ret
  553.  
  554.  
  555. align 4
  556. ; Now it is called from core/sys32::exc_c (see stack frame there)
  557. proc page_fault_handler
  558.  
  559.     .err_addr   equ ebp-4
  560.  
  561.         push    ebx               ;save exception number (#PF)
  562.         mov     ebp, esp
  563.         mov     ebx, cr2
  564.         push    ebx               ;that is locals: .err_addr = cr2
  565.         inc     [pg_data.pages_faults]
  566.  
  567.         mov     esi, [pf_err_code]
  568.  
  569.         cmp     ebx, OS_BASE      ;ebx == .err_addr
  570.         jb      .user_space       ;page in application memory
  571.  
  572.         cmp     ebx, page_tabs
  573.         jb      .kernel_space     ;page in kernel memory
  574.  
  575.         xor     eax, eax
  576.         cmp     ebx, kernel_tabs
  577.         jb      .alloc;.app_tabs  ;page tables of application ;
  578.                                   ;simply create one
  579. .core_tabs:
  580. .fail:  ;simply return to caller
  581.         mov     esp, ebp
  582.         pop     ebx               ;restore exception number (#PF)
  583.         ret
  584. .fail_maybe_unlock:
  585.         test    esi, esi
  586.         jz      .fail
  587. .fail_unlock:
  588.         mov     ecx, [current_process]
  589.         add     ecx, PROC.heap_lock
  590.         call    mutex_unlock
  591.         jmp     .fail
  592.  
  593. .user_space:
  594. ; PF entry in IDT is interrupt gate, so up to this moment
  595. ; atomicity was guaranteed by cleared IF.
  596. ; It is inpractical to guard all modifications in the page table by cli/sti,
  597. ; so enable interrupts and acquire the address space lock.
  598. ; Unfortunately, that enables the scenario when the fault of current thread
  599. ; is resolved by another thread when the current thread waits in mutex_lock,
  600. ; so watch out: in lock-protected section we can find out that
  601. ; there is no error already.
  602.         sti
  603.         mov     ecx, [current_process]
  604.         add     ecx, PROC.heap_lock
  605.         call    mutex_lock
  606.         test    esi, PG_READ
  607.         jnz     .err_access       ;Page is present
  608.                                   ;Access error ?
  609.  
  610.         shr     ebx, 12
  611.         mov     ecx, ebx
  612.         shr     ecx, 10
  613.         test    dword [master_tab+ecx*4], PG_READ
  614.         jz      .fail_unlock      ;page table is not created
  615.                                   ;incorrect address in program
  616.  
  617.         mov     eax, [page_tabs+ebx*4]
  618.         test    eax, PG_READ
  619.         jnz     .exit_unlock      ; already resolved by a parallel thread
  620.         test    eax, LAZY_ALLOC_PAGE
  621.         jz      .fail_unlock      ;address is not reserved for use, error
  622.         test    eax, LAZY_ALLOC_UNREADABLE
  623.         jnz     .fail_unlock
  624. .alloc:
  625.         mov     esi, eax
  626.         call    alloc_zero_page
  627.         test    eax, eax
  628.         jz      .fail_maybe_unlock
  629.  
  630.         mov     edx, PG_UWR
  631.         test    esi, LAZY_ALLOC_UNWRITABLE
  632.         jz      @f
  633.         mov     edx, PG_UR
  634. @@:
  635.         stdcall map_page, [.err_addr], eax, edx
  636.         mov     ecx, [current_process]
  637.         add     [ecx+PROC.mem_used], 0x1000
  638. .exit_unlock:
  639.         mov     ecx, [current_process]
  640.         add     ecx, PROC.heap_lock
  641.         call    mutex_unlock
  642. .exit:  ;iret with repeat fault instruction
  643.         add     esp, 12;clear in stack: locals(.err_addr) + #PF + ret_to_caller
  644.         restore_ring3_context
  645.         iretd
  646.  
  647. .err_access:
  648. ; access denied? this may be a result of copy-on-write protection
  649. ; Check whether the problem has already been resolved
  650. ; while we were waiting in mutex_lock.
  651.         mov     eax, ebx
  652.         shr     eax, 12
  653.         mov     eax, [page_tabs+eax*4]
  654.         test    eax, PG_READ
  655.         jz      .fail_unlock ; someone has free'd the page
  656.         test    eax, PG_USER
  657.         jz      .fail_unlock ; page is mprotect'ed without PROT_READ
  658.         test    eax, PG_WRITE
  659.         jnz     .exit_unlock ; someone has enabled write
  660.         test    eax, PG_SHARED
  661.         jz      .fail_unlock ; only shared pages can be copy-on-write
  662. ; check list of mapped data
  663.         and     ebx, not 0xFFF
  664.         call    find_smap_by_address
  665.         test    esi, esi
  666.         jz      .fail_unlock
  667. ; ignore children of SMEM, only children of PEDESCR can have copy-on-write data
  668.         cmp     [esi+SMAP.type], SMAP_TYPE_PE
  669.         jnz     .fail_unlock
  670.         shr     edi, 12
  671. ; lock page array in PEDESCR
  672.         mov     esi, [esi+SMAP.parent]
  673.         lea     ecx, [esi+PEDESCR.page_array_lock]
  674.         push    eax
  675.         call    mutex_lock
  676.         pop     eax
  677. ; check whether the page is shared
  678. ; PG_SHARED flag could be set by lock_and_map_page
  679.         xor     eax, [esi+sizeof.PEDESCR+edi*4]
  680.         test    eax, not 0xFFF
  681.         jnz     .fail_unlock2
  682. ; check whether write is allowed by section attributes
  683.         mov     eax, [esi+sizeof.PEDESCR+edi*4]
  684.         test    eax, IMAGE_SCN_MEM_WRITE shr 20
  685.         jz      .fail_unlock2
  686. ; if we're faulting on the page which was originally shareable writable,
  687. ; it means that someone has disabled writing with mprotect; fail
  688.         test    eax, IMAGE_SCN_MEM_SHARED shr 20
  689.         jnz     .fail_unlock2
  690.         stdcall pe_copy_on_write, PG_UWR
  691.         jc      .fail_unlock2
  692. .exit_unlock2:
  693.         lea     ecx, [esi+PEDESCR.page_array_lock]
  694.         call    mutex_unlock
  695.         jmp     .exit_unlock
  696. .fail_unlock2:
  697.         lea     ecx, [esi+PEDESCR.page_array_lock]
  698.         call    mutex_unlock
  699.         jmp     .fail_unlock
  700.  
  701. .kernel_space:
  702.         test    esi, PG_READ
  703.         jz      .fail   ;page does not present
  704.  
  705.         test    esi, 12 ;U/S (+below)
  706.         jnz     .fail   ;application requested kernel memory
  707.                        
  708.        ;test    esi, 8
  709.        ;jnz     .fail   ;the reserved bit is set in page tables
  710.                         ;added in P4/Xeon
  711.  
  712. ;an attempt to write to a protected kernel page
  713.  
  714.         cmp     ebx, tss._io_map_0
  715.         jb      .fail
  716.  
  717.         cmp     ebx, tss._io_map_0+8192
  718.         jae     .fail
  719.  
  720. ; io permission map
  721. ; copy-on-write protection
  722.  
  723.         call    alloc_page
  724.         test    eax, eax
  725.         jz      .fail
  726.  
  727.         push    eax
  728.         stdcall map_page, [.err_addr], eax, PG_SWR
  729.         pop     eax
  730.         mov     edi, [.err_addr]
  731.         and     edi, -4096
  732.         lea     esi, [edi+(not tss._io_map_0)+1]; -tss._io_map_0
  733.  
  734.         mov     ebx, esi
  735.         shr     ebx, 12
  736.         mov     edx, [current_slot]
  737.         or      eax, PG_SWR
  738.         mov     [edx+APPDATA.io_map+ebx*4], eax
  739.  
  740.         add     esi, [default_io_map]
  741.         mov     ecx, 4096/4
  742.        ;cld     ;caller is duty for this
  743.         rep movsd
  744.         jmp     .exit
  745. endp
  746.  
  747. ; Sometimes we can just allocate a page and let the caller fill it.
  748. ; Sometimes we need a zero-filled page, but we can zero it at the target.
  749. ; Sometimes we need a zero-filled page before mapping to the target.
  750. ; This function is for the last case.
  751. ; out: eax = physical page
  752. ; destroys: nothing
  753. proc alloc_zero_page
  754.         call    alloc_page
  755.         test    eax, eax
  756.         jz      .nothing
  757.         spin_lock_irqsave zero_page_spinlock
  758.         push    ecx edx edi eax
  759.         mov     edi, [zero_page_tab]
  760.         stdcall map_page, edi, [esp+4], PG_SWR
  761.         pushd   0 [esp+4] edi ; for map_page
  762.         mov     ecx, 0x1000/4
  763.         xor     eax, eax
  764.         rep stosd
  765.         call    map_page
  766.         pop     eax edi edx ecx
  767.         spin_unlock_irqrestore zero_page_spinlock
  768. .nothing:
  769.         ret
  770. endp
  771.  
  772. ; in: ebx = address
  773. ; out if SMAP exists for this address: esi -> SMAP, edi = ebx - SMAP.base
  774. ; out if SMAP does not exist: esi = 0
  775. proc find_smap_by_address
  776.         mov     edx, [current_process]
  777.         add     edx, PROC.smap_list
  778.         mov     esi, [edx+SMAP.fd]
  779. .scan:
  780.         cmp     esi, edx
  781.         jz      .fail
  782.         mov     edi, ebx
  783.         sub     edi, [esi+SMAP.base]
  784.         cmp     edi, [esi+SMAP.size]
  785.         jb      .exit
  786.         mov     esi, [esi+SMAP.fd]
  787.         jmp     .scan
  788. .fail:
  789.         xor     esi, esi
  790. .exit:
  791.         ret
  792. endp
  793.  
  794. ; Someone is about to write to copy-on-write page inside mapped PE.
  795. ; Provide a page that can be written to.
  796. ; in: esi -> PEDESCR
  797. ; in: edi = page number inside PE
  798. ; in: eax = [esi+sizeof.PEDESCR+edi*4]
  799. ; in: ebx = address in process, must be page-aligned
  800. ; in: [esp+4] = access rights for the new page
  801. ; out: CF=0 - ok, CF=1 - error, no memory
  802. proc pe_copy_on_write
  803. ; 1. Decrement reference counter unless it is 0xFF.
  804.         mov     edx, eax
  805.         and     edx, 0xFF
  806.         cmp     edx, 0xFF
  807.         jz      @f
  808.         dec     eax
  809. @@:
  810. ; 2. If reference counter is zero now, transfer ownership from PEDESCR to the process.
  811.         test    eax, 0xFF
  812.         jnz     .alloc_copy
  813.         mov     dword [esi+sizeof.PEDESCR+edi*4], 0
  814.         and     eax, not 0xFFF
  815. .remap:
  816.         stdcall map_page, ebx, eax, [esp+4]
  817.         clc
  818.         ret     4
  819. .alloc_copy:
  820. ; 3. Otherwise, store updated reference counter to PEDESCR,
  821. ; allocate new page, map it as rw and copy data.
  822.         mov     [esi+sizeof.PEDESCR+edi*4], eax
  823.         stdcall kernel_alloc, 0x1000
  824.         test    eax, eax
  825.         jz      .error
  826.         push    esi
  827.         mov     esi, ebx
  828.         mov     edi, eax
  829.         mov     ecx, 0x1000/4
  830.         rep movsd
  831.         mov     esi, eax
  832.         call    get_pg_addr
  833.         push    eax
  834.         stdcall free_kernel_space, esi
  835.         pop     eax
  836.         pop     esi
  837.         jmp     .remap
  838. .error:
  839.         stc
  840.         ret     4
  841. endp
  842.  
  843. PROT_READ = 1
  844. PROT_WRITE = 2
  845. PROT_EXEC = 4
  846. proc mprotect stdcall uses ebx esi edi, address:dword, size:dword, access:dword
  847. locals
  848. retval          dd      -1
  849. smap_ptr        dd      0
  850. endl
  851.         mov     ecx, [current_process]
  852.         add     ecx, PROC.heap_lock
  853.         call    mutex_lock
  854.         test    [access], not (PROT_READ+PROT_WRITE+PROT_EXEC)
  855.         jnz     .error
  856.         cmp     [size], 0
  857.         jz      .error
  858.         mov     eax, [address]
  859.         add     [size], eax
  860.         and     eax, not 0xFFF
  861. .addrloop:
  862.         mov     [address], eax
  863.         mov     ecx, eax
  864.         cmp     eax, OS_BASE
  865.         jae     .error
  866.         shr     eax, 22
  867.         test    byte [master_tab+eax*4], PG_READ
  868.         jz      .error
  869.         shr     ecx, 12
  870.         mov     eax, [page_tabs+ecx*4]
  871.         test    al, PG_READ
  872.         jnz     .page_present
  873.         test    al, LAZY_ALLOC_PAGE
  874.         jz      .error
  875.         cmp     [retval], -1
  876.         jnz     .skip_query
  877.         inc     [retval]
  878.         test    al, LAZY_ALLOC_UNREADABLE
  879.         jnz     @f
  880.         or      [retval], PROT_READ+PROT_EXEC
  881. @@:
  882.         test    al, LAZY_ALLOC_UNWRITABLE
  883.         jnz     @f
  884.         or      [retval], PROT_WRITE
  885. @@:
  886. .skip_query:
  887.         and     al, not (LAZY_ALLOC_UNREADABLE+LAZY_ALLOC_UNWRITABLE)
  888.         test    [access], PROT_READ
  889.         jnz     @f
  890.         or      al, LAZY_ALLOC_UNREADABLE
  891. @@:
  892.         test    [access], PROT_WRITE
  893.         jnz     @f
  894.         or      al, LAZY_ALLOC_UNWRITABLE
  895. @@:
  896.         mov     [page_tabs+ecx*4], eax
  897.         jmp     .nextpage
  898. .page_present:
  899.         test    eax, PG_SHARED
  900.         jnz     .page_shared
  901. .normal_page:
  902.         cmp     [retval], -1
  903.         jnz     .skip_query2
  904.         inc     [retval]
  905.         test    al, PG_USER
  906.         jz      @f
  907.         or      [retval], PROT_READ+PROT_EXEC
  908. @@:
  909.         test    al, PG_WRITE
  910.         jz      @f
  911.         or      [retval], PROT_WRITE
  912. @@:
  913. .skip_query2:
  914.         and     al, not (PG_USER+PG_WRITE)
  915.         test    [access], PROT_READ
  916.         jz      @f
  917.         or      al, PG_USER
  918. @@:
  919.         test    [access], PROT_WRITE
  920.         jz      @f
  921.         or      al, PG_WRITE
  922. @@:
  923.         mov     [page_tabs+ecx*4], eax
  924.         mov     eax, [address]
  925.         invlpg  [eax]
  926.         jmp     .nextpage
  927. .page_shared:
  928.         mov     esi, [smap_ptr]
  929.         test    esi, esi
  930.         jz      .find_smap
  931.         mov     edx, [address]
  932.         sub     edx, [esi+SMAP.base]
  933.         cmp     edx, [esi+SMAP.size]
  934.         jb      .found_smap
  935. .find_smap:
  936.         mov     ebx, [address]
  937.         call    find_smap_by_address
  938.         mov     [smap_ptr], esi
  939.         test    esi, esi
  940.         jz      .normal_page
  941. .found_smap:
  942.         cmp     [esi+SMAP.type], SMAP_TYPE_PE
  943.         jnz     .error
  944.         shr     edi, 12
  945.         mov     esi, [esi+SMAP.parent]
  946.         lea     ecx, [esi+PEDESCR.page_array_lock]
  947.         push    eax
  948.         call    mutex_lock
  949.         pop     eax
  950.         xor     eax, [esi+sizeof.PEDESCR+edi*4]
  951.         test    eax, not 0xFFF
  952.         jnz     .normal_page_unlock
  953.         mov     eax, [esi+sizeof.PEDESCR+edi*4]
  954.         test    eax, IMAGE_SCN_MEM_SHARED shr 20
  955.         jnz     .normal_page_unlock
  956.         cmp     [retval], -1
  957.         jnz     .skip_query3
  958.         mov     edx, [address]
  959.         shr     edx, 12
  960.         inc     [retval]
  961.         test    byte [page_tabs+edx*4], PG_USER
  962.         jz      @f
  963.         or      [retval], PROT_READ+PROT_EXEC
  964. @@:
  965.         test    eax, IMAGE_SCN_MEM_WRITE shr 20
  966.         jz      @f
  967.         or      [retval], PROT_WRITE
  968. @@:
  969. .skip_query3:
  970.         test    [access], PROT_WRITE
  971.         jz      .no_write
  972.         push    PG_SWR
  973.         test    [access], PROT_READ
  974.         jz      @f
  975.         pop     edx
  976.         push    PG_UWR
  977. @@:
  978.         call    pe_copy_on_write
  979.         lea     ecx, [esi+PEDESCR.page_array_lock]
  980.         call    mutex_unlock
  981.         jmp     .nextpage
  982. .normal_page_unlock:
  983.         lea     ecx, [esi+PEDESCR.page_array_lock]
  984.         call    mutex_unlock
  985.         mov     ecx, [address]
  986.         shr     ecx, 12
  987.         mov     eax, [page_tabs+ecx*4]
  988.         jmp     .normal_page
  989. .no_write:
  990.         lea     ecx, [esi+PEDESCR.page_array_lock]
  991.         call    mutex_unlock
  992.         mov     ecx, [address]
  993.         shr     ecx, 12
  994.         mov     eax, [page_tabs+ecx*4]
  995.         jmp     .skip_query2
  996. .nextpage:
  997.         mov     eax, [address]
  998.         add     eax, 0x1000
  999.         cmp     eax, [size]
  1000.         jb      .addrloop
  1001. .exit:
  1002.         mov     ecx, [current_process]
  1003.         add     ecx, PROC.heap_lock
  1004.         call    mutex_unlock
  1005.         mov     eax, [retval]
  1006.         ret
  1007. .error:
  1008.         or      [retval], -1
  1009.         jmp     .exit
  1010. endp
  1011.  
  1012. ; returns number of mapped bytes
  1013. proc map_memEx stdcall uses ebx esi edi, lin_addr:dword,slot:dword,\
  1014.                       ofs:dword,buf_size:dword,req_access:dword,where:dword
  1015.         locals
  1016.              count   dd ?
  1017.              process dd ?
  1018.         endl
  1019.  
  1020.         mov     [count], 0
  1021.         cmp     [buf_size], 0
  1022.         jz      .exit
  1023.  
  1024.         mov     eax, [slot]
  1025.         shl     eax, 8
  1026.         mov     ecx, [SLOT_BASE+eax+APPDATA.process]
  1027.         test    ecx, ecx
  1028.         jz      .exit
  1029.  
  1030.         mov     [process], ecx
  1031.         add     ecx, PROC.heap_lock
  1032.         call    mutex_lock
  1033.         mov     eax, [process]
  1034.         mov     ebx, [ofs]
  1035.         shr     ebx, 22
  1036.         mov     eax, [eax+PROC.pdt_0+ebx*4]                 ;get page table
  1037.         mov     esi, [where]
  1038.         and     eax, 0xFFFFF000
  1039.         jz      .unlock_exit
  1040.         stdcall map_page, esi, eax, PG_SWR
  1041. @@:
  1042.         mov     edi, [lin_addr]
  1043.         and     edi, 0xFFFFF000
  1044.         mov     ecx, [buf_size]
  1045.         add     ecx, 4095
  1046.         shr     ecx, 12
  1047.  
  1048.         mov     edx, [ofs]
  1049.         shr     edx, 12
  1050.         and     edx, 0x3FF
  1051. .map:
  1052.         stdcall lock_and_map_page, [slot], [req_access], [ofs]
  1053.         jnc     .unlock_exit
  1054.         add     [count], PAGE_SIZE
  1055.         add     [ofs], PAGE_SIZE
  1056.         dec     ecx
  1057.         jz      .unlock_exit
  1058.  
  1059.         add     edi, PAGE_SIZE
  1060.         inc     edx
  1061.         cmp     edx, 1024
  1062.         jnz     .map
  1063.  
  1064.         inc     ebx
  1065.         mov     eax, [process]
  1066.         mov     eax, [eax+PROC.pdt_0+ebx*4]
  1067.         and     eax, 0xFFFFF000
  1068.         jz      .unlock_exit
  1069.  
  1070.         stdcall map_page, esi, eax, PG_SWR
  1071.         xor     edx, edx
  1072.         jmp     .map
  1073. .unlock_exit:
  1074.         mov     ecx, [process]
  1075.         add     ecx, PROC.heap_lock
  1076.         call    mutex_unlock
  1077. .exit:
  1078.         mov     eax, [count]
  1079.         ret
  1080. endp
  1081.  
  1082. proc unmap_memEx stdcall uses ebx esi edi, lin_addr:dword,slot:dword,\
  1083.                       ofs:dword,mapped_size:dword,pagedir:dword
  1084.         locals
  1085.              process dd ?
  1086.         endl
  1087.  
  1088.         cmp     [mapped_size], 0
  1089.         jz      .exit
  1090.  
  1091.         mov     eax, [slot]
  1092.         shl     eax, 8
  1093.         mov     ecx, [SLOT_BASE+eax+APPDATA.process]
  1094.         mov     [process], ecx
  1095.         xor     eax, eax
  1096.         test    ecx, ecx
  1097.         jz      @f
  1098.         add     ecx, PROC.heap_lock
  1099.         call    mutex_lock
  1100.         mov     ebx, [ofs]
  1101.         shr     ebx, 22
  1102.         mov     eax, [process]
  1103.         mov     eax, [eax+PROC.pdt_0+ebx*4]                 ;get page table
  1104. @@:
  1105.         xor     esi, esi
  1106.         and     eax, 0xFFFFF000
  1107.         jz      @f
  1108.         mov     esi, [pagedir]
  1109.         stdcall map_page, esi, eax, PG_SWR
  1110. @@:
  1111.         mov     ecx, shared_locked_mutex
  1112.         call    mutex_lock
  1113.         mov     edi, [lin_addr]
  1114.         shr     edi, 12
  1115.         mov     ecx, [mapped_size]
  1116.         add     ecx, 4095
  1117.         shr     ecx, 12
  1118.         mov     [mapped_size], ecx
  1119.  
  1120.         mov     edx, [ofs]
  1121.         shr     edx, 12
  1122.         and     edx, 0x3FF
  1123.         lea     esi, [esi+edx*4]
  1124. .map:
  1125.         call    unlock_and_unmap_page
  1126.         dec     [mapped_size]
  1127.         jz      .done
  1128.  
  1129.         inc     edi
  1130.         add     esi, 4
  1131.         test    esi, 0xFFF
  1132.         jnz     .map
  1133.  
  1134.         inc     ebx
  1135.         xor     esi, esi
  1136.         cmp     [process], 0
  1137.         jz      .map
  1138.         mov     eax, [process]
  1139.         mov     eax, [eax+PROC.pdt_0+ebx*4]
  1140.         and     eax, 0xFFFFF000
  1141.         jz      .map
  1142.  
  1143.         mov     esi, [pagedir]
  1144.         stdcall map_page, esi, eax, PG_SWR
  1145.         jmp     .map
  1146. .done:
  1147.         mov     ecx, shared_locked_mutex
  1148.         call    mutex_unlock
  1149.         cmp     [process], 0
  1150.         jz      .exit
  1151.         mov     ecx, [process]
  1152.         add     ecx, PROC.heap_lock
  1153.         call    mutex_unlock
  1154. .exit:
  1155.         mov     eax, [pagedir]
  1156.         mov     ecx, eax
  1157.         shr     ecx, 12
  1158.         mov     dword [page_tabs+ecx*4], 0
  1159.         invlpg  [eax]
  1160.         ret
  1161. endp
  1162.  
  1163. ; in: esi+edx*4 = pointer to page table entry
  1164. ; in: [slot], [req_access], [ofs] on the stack
  1165. ; in: edi = linear address to map
  1166. ; in: address space lock must be held
  1167. ; out: CF cleared <=> failed
  1168. ; destroys: only eax
  1169. proc lock_and_map_page stdcall, slot:dword, req_access:dword, ofs:dword
  1170.     locals
  1171.         locked_descr dd ?
  1172.     endl
  1173.  
  1174.         mov     eax, [esi+edx*4]
  1175.         test    eax, PG_READ
  1176.         jz      .not_present
  1177.         test    eax, PG_SHARED
  1178.         jnz     .resolve_shared
  1179. ; normal case: not shared allocated page, mark as shared and map with requested access
  1180.         or      dword [esi+edx*4], PG_SHARED
  1181. .map:
  1182.         and     eax, not 0xFFF
  1183.         stdcall map_page, edi, eax, [req_access]
  1184.         stc
  1185. .fail:
  1186.         ret
  1187. .not_present:
  1188. ; check for alloc-on-demand page
  1189.         test    eax, LAZY_ALLOC_PAGE
  1190.         jz      .fail
  1191. ; allocate new page, save it to source page table
  1192.         push    ecx
  1193.         call    alloc_zero_page
  1194.         pop     ecx
  1195.         test    eax, eax
  1196.         jz      .fail
  1197.         or      eax, PG_READ+PG_SHARED
  1198.         test    dword [esi+edx*4], LAZY_ALLOC_UNREADABLE
  1199.         jnz     @f
  1200.         or      eax, PG_USER
  1201. @@:
  1202.         test    dword [esi+edx*4], LAZY_ALLOC_UNWRITABLE
  1203.         jnz     @f
  1204.         or      eax, PG_WRITE
  1205. @@:
  1206.         mov     [esi+edx*4], eax
  1207.         jmp     .map
  1208. .resolve_shared:
  1209.         push    ecx edx eax
  1210.         mov     eax, sizeof.SHARED_LOCKED_PAGE
  1211.         call    malloc
  1212.         mov     [locked_descr], eax
  1213.         test    eax, eax
  1214.         jz      .fail_pop
  1215.         mov     edx, [esp]
  1216.         and     edx, not 0xFFF
  1217.         mov     [eax+SHARED_LOCKED_PAGE.address], edx
  1218.         mov     eax, [slot]
  1219.         shl     eax, 8
  1220.         mov     eax, [SLOT_BASE+eax+APPDATA.process]
  1221.         mov     ecx, [eax+PROC.smap_list]
  1222.         add     eax, PROC.smap_list
  1223. .find_shared_parent:
  1224.         cmp     ecx, eax
  1225.         jz      .shared_orphan
  1226.         mov     edx, [ofs]
  1227.         sub     edx, [ecx+SMAP.base]
  1228.         cmp     edx, [ecx+SMAP.size]
  1229.         jb      .found_shared_parent
  1230.         mov     ecx, [ecx+SMAP.fd]
  1231.         jmp     .find_shared_parent
  1232. .shared_abandoned:
  1233.         call    mutex_unlock
  1234. .shared_orphan:
  1235. ; no copy-on-write for orphans
  1236.         test    dword [esp], PG_WRITE
  1237.         jnz     @f
  1238.         test    [req_access], PG_WRITE
  1239.         jnz     .shared_forbidden
  1240. @@:
  1241. ; locking the same normal page for second time:
  1242. ; the first lock_and_map_page has set PG_SHARED,
  1243. ; now we must cooperate with that other thread.
  1244.         mov     ecx, shared_locked_mutex
  1245.         call    mutex_lock
  1246.         mov     eax, [locked_descr]
  1247.         mov     [eax+SHARED_LOCKED_PAGE.parent], 0
  1248. .shared_common:
  1249.         mov     edx, [shared_locked_list+SHARED_LOCKED_PAGE.bk]
  1250.         mov     [eax+SHARED_LOCKED_PAGE.fd], shared_locked_list
  1251.         mov     [eax+SHARED_LOCKED_PAGE.bk], edx
  1252.         mov     [edx+SHARED_LOCKED_PAGE.fd], eax
  1253.         mov     [shared_locked_list+SHARED_LOCKED_PAGE.bk], edx
  1254.         call    mutex_unlock
  1255.         pop     eax edx ecx
  1256.         jmp     .map
  1257. .shared_forbidden_unlock:
  1258.         call    mutex_unlock
  1259. .shared_forbidden:
  1260.         mov     eax, [locked_descr]
  1261.         call    free
  1262. .fail_pop:
  1263.         pop     eax edx ecx
  1264.         clc
  1265.         ret
  1266. .found_shared_parent:
  1267.         shr     edx, 12
  1268.         mov     eax, [locked_descr]
  1269.         mov     [eax+SHARED_LOCKED_PAGE.offs], edx
  1270.         cmp     [ecx+SMAP.type], SMAP_TYPE_PE
  1271.         jnz     .parent_smap
  1272.         push    edx
  1273.         mov     ecx, [ecx+SMAP.parent]
  1274.         add     ecx, PEDESCR.page_array_lock
  1275.         call    mutex_lock
  1276.         pop     edx
  1277.         mov     eax, [esp]
  1278.         xor     eax, [ecx+sizeof.PEDESCR-PEDESCR.page_array_lock+edx*4]
  1279.         test    eax, not 0xFFF
  1280.         jnz     .shared_abandoned
  1281.         test    dword [esp], PG_WRITE
  1282.         jnz     @f
  1283.         test    [req_access], PG_WRITE
  1284.         jnz     .pedescr_try_cow
  1285. @@:
  1286.         mov     eax, [ecx+sizeof.PEDESCR-PEDESCR.page_array_lock+edx*4]
  1287.         inc     eax
  1288.         test    eax, 0xFF
  1289.         jnz     @f
  1290.         dec     eax
  1291. @@:
  1292.         mov     [ecx+sizeof.PEDESCR-PEDESCR.page_array_lock+edx*4], eax
  1293.         push    ecx
  1294.         mov     ecx, pe_list_mutex
  1295.         call    mutex_lock
  1296.         mov     eax, [esp]
  1297.         inc     dword [eax+PEDESCR.refcount-PEDESCR.page_array_lock]
  1298.         call    mutex_unlock
  1299.         pop     ecx
  1300.         call    mutex_unlock
  1301.         sub     ecx, PEDESCR.page_array_lock
  1302.         push    ecx
  1303. .shared_common2:
  1304.         mov     ecx, shared_locked_mutex
  1305.         call    mutex_lock
  1306.         mov     eax, [locked_descr]
  1307.         pop     [eax+SHARED_LOCKED_PAGE.parent]
  1308.         jmp     .shared_common
  1309. .pedescr_try_cow:
  1310.         mov     eax, [ecx+sizeof.PEDESCR-PEDESCR.page_array_lock+edx*4]
  1311.         test    eax, IMAGE_SCN_MEM_WRITE shr 20
  1312.         jz      @f
  1313.         or      dword [esp], PG_WRITE
  1314. @@:
  1315.         dec     eax
  1316.         test    eax, 0xFF
  1317.         jnz     .pedescr_alloc_copy
  1318.         mov     dword [ecx+sizeof.PEDESCR-PEDESCR.page_array_lock+edx*4], 0
  1319.         call    mutex_unlock
  1320.         mov     eax, [locked_descr]
  1321.         call    free
  1322.         pop     eax edx ecx
  1323.         or      eax, PG_SHARED
  1324.         mov     [esi+edx*4], eax
  1325.         jmp     .map
  1326. .pedescr_alloc_copy:
  1327.         push    ecx edx
  1328.         stdcall kernel_alloc, 0x1000
  1329.         pop     edx ecx
  1330.         test    eax, eax
  1331.         jz      .shared_forbidden_unlock
  1332.         dec     dword [ecx+sizeof.PEDESCR-PEDESCR.page_array_lock+edx*4]
  1333.         push    ecx esi edi
  1334.         mov     esi, edi
  1335.         mov     edi, eax
  1336.         stdcall map_page, esi, [ecx+sizeof.PEDESCR-PEDESCR.page_array_lock+edx*4], PG_READ
  1337.         mov     ecx, 0x1000/4
  1338.         rep movsd
  1339.         sub     esi, 0x1000
  1340.         sub     edi, 0x1000
  1341.         mov     eax, edi
  1342.         call    get_pg_addr
  1343.         and     dword [esp+12], 0xFFF
  1344.         or      dword [esp+12], eax
  1345.         stdcall map_page, esi, eax, [req_access]
  1346.         stdcall free_kernel_space, edi
  1347.         pop     edi esi ecx
  1348.         call    mutex_unlock
  1349.         mov     eax, [locked_descr]
  1350.         call    free
  1351.         pop     eax edx ecx
  1352.         or      eax, PG_SHARED
  1353.         mov     [esi+edx*4], eax
  1354.         stc
  1355.         ret
  1356. .parent_smap:
  1357.         test    dword [esp], PG_WRITE
  1358.         jnz     @f
  1359.         test    [req_access], PG_WRITE
  1360.         jz      .shared_forbidden
  1361. @@:
  1362.         push    [ecx+SMAP.parent]
  1363.         mov     ecx, shmem_list_mutex
  1364.         call    mutex_lock
  1365.         mov     eax, [esp]
  1366.         inc     dword [esp]
  1367.         inc     [eax+SMEM.refcount]
  1368.         call    mutex_unlock
  1369.         jmp     .shared_common2
  1370. endp
  1371.  
  1372. ; in: esi -> process page table entry or esi < 0x1000 if no page table entry
  1373. ; in: edi = page number for mapped copy
  1374. ; in: shared_locked_mutex is held
  1375. ; destroys eax, ecx, edx
  1376. proc unlock_and_unmap_page
  1377.         mov     edx, [page_tabs+edi*4]
  1378.         and     edx, not 0xFFF
  1379.         mov     dword [page_tabs+edi*4], 0
  1380.         mov     eax, edi
  1381.         shl     eax, 12
  1382.         invlpg  [eax]
  1383.         mov     eax, [shared_locked_list+SHARED_LOCKED_PAGE.fd]
  1384. .check_list:
  1385.         cmp     eax, shared_locked_list
  1386.         jz      .not_in_list
  1387.         cmp     edx, [eax+SHARED_LOCKED_PAGE.address]
  1388.         jz      .found_in_list
  1389.         mov     eax, [eax+SHARED_LOCKED_PAGE.fd]
  1390.         jmp     .check_list
  1391. .found_in_list:
  1392.         push    esi
  1393.         mov     esi, [eax+SHARED_LOCKED_PAGE.parent]
  1394.         mov     edx, [eax+SHARED_LOCKED_PAGE.fd]
  1395.         mov     ecx, [eax+SHARED_LOCKED_PAGE.bk]
  1396.         mov     [edx+SHARED_LOCKED_PAGE.bk], ecx
  1397.         mov     [ecx+SHARED_LOCKED_PAGE.fd], edx
  1398.         test    esi, esi
  1399.         jz      .orphan
  1400.         btr     esi, 0
  1401.         jc      .parent_smap
  1402.         push    eax
  1403.         lea     ecx, [esi+PEDESCR.page_array_lock]
  1404.         call    mutex_lock
  1405.         mov     edx, [esp]
  1406.         mov     edx, [edx+SHARED_LOCKED_PAGE.offs]
  1407.         mov     eax, [esi+sizeof.PEDESCR+edx*4]
  1408.         and     eax, 0xFF
  1409.         cmp     eax, 0xFF
  1410.         jz      .no_deref
  1411.         mov     eax, [esi+sizeof.PEDESCR+edx*4]
  1412.         dec     eax
  1413.         test    eax, 0xFF
  1414.         jnz     @f
  1415.         call    free_page
  1416.         xor     eax, eax
  1417. @@:
  1418.         mov     [esi+sizeof.PEDESCR+edx*4], eax
  1419. .no_deref:
  1420.         lea     ecx, [esi+PEDESCR.page_array_lock]
  1421.         call    mutex_unlock
  1422.         call    dereference_pe
  1423.         pop     eax
  1424.         call    free
  1425.         pop     esi
  1426.         ret
  1427. .parent_smap:
  1428.         call    free
  1429.         call    dereference_smem
  1430.         pop     esi
  1431.         ret
  1432. .orphan:
  1433.         call    free
  1434.         pop     esi
  1435.         ret
  1436. .not_in_list:
  1437.         cmp     esi, 0x1000
  1438.         jb      .just_free
  1439.         mov     eax, [esi]
  1440.         and     eax, not 0xFFF
  1441.         cmp     eax, edx
  1442.         jnz     .just_free
  1443.         and     dword [esi], not PG_SHARED
  1444.         ret
  1445. .just_free:
  1446.         mov     eax, edx
  1447.         call    free_page
  1448.         ret
  1449. endp
  1450.  
  1451. sys_IPC:
  1452. ;input:
  1453. ;  ebx=1 - set ipc buffer area
  1454. ;    ecx=address of buffer
  1455. ;    edx=size of buffer
  1456. ;  eax=2 - send message
  1457. ;    ebx=PID
  1458. ;    ecx=address of message
  1459. ;    edx=size of message
  1460.  
  1461.         dec     ebx
  1462.         jnz     @f
  1463.  
  1464.         mov     eax, [current_slot]
  1465.         pushf
  1466.         cli
  1467.         mov     [eax+APPDATA.ipc_start], ecx    ;set fields in extended information area
  1468.         mov     [eax+APPDATA.ipc_size], edx
  1469.  
  1470.         add     edx, ecx
  1471.         add     edx, 4095
  1472.         and     edx, not 4095
  1473.  
  1474. .touch:
  1475.         mov     eax, [ecx]
  1476.         add     ecx, 0x1000
  1477.         cmp     ecx, edx
  1478.         jb      .touch
  1479.  
  1480.         popf
  1481.         mov     [esp+32], ebx   ;ebx=0
  1482.         ret
  1483.  
  1484. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1485. ;2
  1486. @@:
  1487.         dec     ebx
  1488.         jnz     @f
  1489.  
  1490.         stdcall sys_ipc_send, ecx, edx, esi
  1491.         mov     [esp+32], eax
  1492.         ret
  1493. @@:
  1494.         or      eax, -1
  1495.         mov     [esp+32], eax
  1496.         ret
  1497.  
  1498. proc sys_ipc_send stdcall, PID:dword, msg_addr:dword, msg_size:dword
  1499.            locals
  1500.              dst_slot   dd ?
  1501.              dst_offset dd ?
  1502.              dst_ptr    dd ?
  1503.              buf_size   dd ?
  1504.              used_buf   dd ?
  1505.              mapped_size dd ?
  1506.              result     dd ?
  1507.            endl
  1508.  
  1509.         mov     ecx, ipc_mutex
  1510.         call    mutex_lock
  1511.  
  1512.         mov     eax, [PID]
  1513.         call    pid_to_slot
  1514.         test    eax, eax
  1515.         jz      .no_pid
  1516.  
  1517.         mov     [dst_slot], eax
  1518.         shl     eax, 8
  1519.         mov     edi, [eax+SLOT_BASE+APPDATA.ipc_start] ;is ipc area defined?
  1520.         test    edi, edi
  1521.         jz      .no_ipc_area
  1522.         mov     [dst_ptr], edi
  1523.  
  1524.         mov     ebx, edi
  1525.         and     ebx, 0xFFF
  1526.         mov     [dst_offset], ebx
  1527.  
  1528.         mov     esi, [eax+SLOT_BASE+APPDATA.ipc_size]
  1529.         mov     [buf_size], esi
  1530.  
  1531.         mov     ecx, [ipc_tmp]
  1532.         cmp     esi, 0x40000-0x1000; size of [ipc_tmp] minus one page
  1533.         jbe     @f
  1534.         push    esi edi
  1535.         add     esi, 0x1000
  1536.         stdcall alloc_kernel_space, esi
  1537.         mov     ecx, eax
  1538.         pop     edi esi
  1539. @@:
  1540.         mov     [used_buf], ecx
  1541.         stdcall map_memEx, ecx, [dst_slot], \
  1542.                 edi, esi, PG_SWR, [ipc_ptab]
  1543.         mov     [mapped_size], eax
  1544.         mov     [result], 3 ; buffer overflow
  1545.         sub     eax, [dst_offset]
  1546.         jc      .no_copy_data
  1547.         cmp     [buf_size], eax
  1548.         jb      @f
  1549.         mov     [buf_size], eax
  1550. @@:
  1551.         cmp     [buf_size], 8
  1552.         jb      .no_copy_data
  1553.  
  1554.         mov     [result], 2 ; ipc blocked
  1555.         mov     edi, [dst_offset]
  1556.         add     edi, [used_buf]
  1557.         cmp     dword [edi], 0
  1558.         jnz     .no_copy_data         ;if dword [buffer]<>0 - ipc blocked now
  1559.  
  1560.         mov     [result], 3 ; buffer overflow
  1561.         mov     edx, dword [edi+4]
  1562.         lea     ebx, [edx+8]
  1563.         add     ebx, [msg_size]
  1564.         cmp     ebx, [buf_size]
  1565.         ja      .no_copy_data          ;esi<0 - not enough memory in buffer
  1566.  
  1567.         mov     [result], 0
  1568.         mov     dword [edi+4], ebx
  1569.         mov     eax, [TASK_BASE]
  1570.         mov     eax, [eax+TASKDATA.pid]        ;eax - our PID
  1571.         add     edi, edx
  1572.         mov     [edi], eax
  1573.         mov     ecx, [msg_size]
  1574.  
  1575.         mov     [edi+4], ecx
  1576.         add     edi, 8
  1577.         mov     esi, [msg_addr]
  1578.        ;    add esi, new_app_base
  1579.         cld
  1580.         rep movsb
  1581. .no_copy_data:
  1582.         stdcall unmap_memEx, [used_buf], [dst_slot], [dst_ptr], [mapped_size], [ipc_ptab]
  1583.  
  1584.         cmp     [result], 0
  1585.         jnz     @f
  1586.         mov     eax, [dst_slot]
  1587.         shl     eax, BSF sizeof.APPDATA
  1588.         or      [eax+SLOT_BASE+APPDATA.occurred_events], EVENT_IPC
  1589. @@:
  1590.         mov     eax, [used_buf]
  1591.         cmp     eax, [ipc_tmp]
  1592.         je      @f
  1593.         stdcall free_kernel_space, eax
  1594. @@:
  1595.         mov     ecx, ipc_mutex
  1596.         call    mutex_unlock
  1597.         mov     eax, [result]
  1598.         ret
  1599. .no_pid:
  1600.         mov     ecx, ipc_mutex
  1601.         call    mutex_unlock
  1602.         mov     eax, 4
  1603.         ret
  1604. .no_ipc_area:
  1605.         mov     ecx, ipc_mutex
  1606.         call    mutex_unlock
  1607.         xor     eax, eax
  1608.         inc     eax
  1609.         ret
  1610. endp
  1611.  
  1612. align 4
  1613. sysfn_meminfo:
  1614.         cmp     ecx, OS_BASE
  1615.         jae     .fail
  1616.  
  1617.         mov     eax, [pg_data.pages_count]
  1618.         mov     [ecx], eax
  1619.         shl     eax, 12
  1620.         mov     [esp+32], eax
  1621.         mov     eax, [pg_data.pages_free]
  1622.         mov     [ecx+4], eax
  1623.         mov     eax, [pg_data.pages_faults]
  1624.         mov     [ecx+8], eax
  1625.         mov     eax, [heap_size]
  1626.         mov     [ecx+12], eax
  1627.         mov     eax, [heap_free]
  1628.         mov     [ecx+16], eax
  1629.         mov     eax, [heap_blocks]
  1630.         mov     [ecx+20], eax
  1631.         mov     eax, [free_blocks]
  1632.         mov     [ecx+24], eax
  1633.         ret
  1634. .fail:
  1635.         or      dword [esp+32], -1
  1636.         ret
  1637.  
  1638. align 4
  1639. f68:
  1640.         cmp     ebx, 4
  1641.         jbe     sys_sheduler
  1642.         cmp     ebx, 11
  1643.         jb      undefined_syscall
  1644.         cmp     ebx, 32
  1645.         ja      undefined_syscall
  1646.         xor     eax, eax
  1647.         jmp     dword [f68call+ebx*4-11*4]
  1648. .11:
  1649.         call    init_heap
  1650.         mov     [esp+SYSCALL_STACK._eax], eax
  1651.         ret
  1652. .12:
  1653.         stdcall user_alloc, ecx
  1654.         mov     [esp+SYSCALL_STACK._eax], eax
  1655.         ret
  1656. .13:
  1657.         stdcall user_free, ecx
  1658.         mov     [esp+SYSCALL_STACK._eax], eax
  1659.         ret
  1660. .14:
  1661.         cmp     ecx, OS_BASE
  1662.         jae     .fail
  1663.         mov     edi, ecx
  1664.         call    get_event_ex
  1665.         mov     [esp+SYSCALL_STACK._eax], eax
  1666.         ret
  1667. .16:
  1668.         test    ecx, ecx
  1669.         jz      .fail
  1670.         cmp     ecx, OS_BASE
  1671.         jae     .fail
  1672.         stdcall get_service, ecx
  1673.         mov     [esp+SYSCALL_STACK._eax], eax
  1674.         ret
  1675. .17:
  1676.         call    srv_handlerEx   ;ecx
  1677.         mov     [esp+SYSCALL_STACK._eax], eax
  1678.         ret
  1679. .18:
  1680.         mov     eax, edx
  1681. .19:
  1682.         cmp     ecx, OS_BASE
  1683.         jae     .fail
  1684.         stdcall load_library, ecx, eax
  1685.         mov     [esp+SYSCALL_STACK._eax], eax
  1686.         ret
  1687. .20:
  1688.         mov     eax, edx
  1689.         mov     ebx, ecx
  1690.         call    user_realloc            ;in: eax = pointer, ebx = new size
  1691.         mov     [esp+SYSCALL_STACK._eax], eax
  1692.         ret
  1693. .21:
  1694.         cmp     ecx, OS_BASE
  1695.         jae     .fail
  1696.         cmp     edx, OS_BASE
  1697.         jae     .fail
  1698.         stdcall load_pe_driver, ecx, edx
  1699.         mov     [esp+SYSCALL_STACK._eax], eax
  1700.         ret
  1701. .22:
  1702.         cmp     ecx, OS_BASE
  1703.         jae     .fail
  1704.         stdcall shmem_open, ecx, edx, esi
  1705.         mov     [esp+SYSCALL_STACK._edx], edx
  1706.         mov     [esp+SYSCALL_STACK._eax], eax
  1707.         ret
  1708. .23:
  1709.         cmp     ecx, OS_BASE
  1710.         jae     .fail
  1711.         stdcall shmem_close, ecx
  1712.         mov     [esp+SYSCALL_STACK._eax], eax
  1713.         ret
  1714. .24:
  1715.         mov     eax, [current_slot]
  1716.         xchg    ecx, [eax+APPDATA.exc_handler]
  1717.         xchg    edx, [eax+APPDATA.except_mask]
  1718.         mov     [esp+SYSCALL_STACK._ebx], edx
  1719.         mov     [esp+SYSCALL_STACK._eax], ecx
  1720.         ret
  1721. .25:
  1722.         cmp     ecx, 32
  1723.         jae     .fail
  1724.         mov     eax, [current_slot]
  1725.         btr     [eax+APPDATA.except_mask], ecx
  1726.         setc    byte[esp+SYSCALL_STACK._eax]
  1727.         jecxz   @f
  1728.         bts     [eax+APPDATA.except_mask], ecx
  1729. @@:
  1730.         ret
  1731. .26:
  1732.         stdcall user_unmap, ecx, edx, esi
  1733.         mov     [esp+SYSCALL_STACK._eax], eax
  1734.         ret
  1735. .27:
  1736.         cmp     ecx, OS_BASE
  1737.         jae     .fail
  1738.         stdcall load_file_umode, ecx
  1739.         mov     [esp+SYSCALL_STACK._edx], edx
  1740.         mov     [esp+SYSCALL_STACK._eax], eax
  1741.         ret
  1742. .28:
  1743.         cmp     ecx, OS_BASE
  1744.         jae     .fail
  1745.         push    ecx edx
  1746.         stdcall kernel_alloc, maxPathLength
  1747.         mov     edi, eax
  1748.         pop     eax esi
  1749.         push    edi
  1750.         call    getFullPath
  1751.         pop     ebp
  1752.         test    eax, eax
  1753.         jz      @f
  1754.         stdcall load_file_umode, ebp
  1755.         mov     [esp+SYSCALL_STACK._edx], edx
  1756. @@:
  1757.         mov     [esp+SYSCALL_STACK._eax], eax
  1758.         stdcall kernel_free, ebp
  1759.         ret
  1760.  
  1761. .29:
  1762.         stdcall user_ring, ecx
  1763.         mov     [esp+SYSCALL_STACK._eax], eax
  1764.         ret
  1765. .30:
  1766.         cmp     ecx, OS_BASE
  1767.         jae     .fail
  1768.         stdcall load_file_maybe_pe, ecx
  1769.         test    esi, esi
  1770.         jz      .30.not_pe
  1771.         stdcall map_pe_usermode, esi, eax, ebx
  1772.         mov     [esp+32], eax
  1773.         ret
  1774. .30.resolve_fail:
  1775.         movi    eax, -5
  1776.         jmp     .30.error
  1777. .30.not_pe:
  1778.         cmp     eax, -0x1000
  1779.         ja      .30.error
  1780.         stdcall kernel_free, eax
  1781.         movi    eax, -31
  1782. .30.error:
  1783.         mov     [esp+32], eax
  1784.         ret
  1785.  
  1786. .31:
  1787.         stdcall unmap_pe_usermode, ecx
  1788.         mov     [esp+32], eax
  1789.         ret
  1790.  
  1791. .32:
  1792.         stdcall mprotect, edx, esi, ecx
  1793.         mov     [esp+32], eax
  1794.         ret
  1795.  
  1796. .fail:
  1797.         mov     [esp+SYSCALL_STACK._eax], eax
  1798.         ret
  1799.  
  1800. align 4
  1801. f68call:   ; keep this table closer to main code
  1802.  
  1803.            dd f68.11   ; init_heap
  1804.            dd f68.12   ; user_alloc
  1805.            dd f68.13   ; user_free
  1806.            dd f68.14   ; get_event_ex
  1807.            dd f68.fail ; moved to f68.24
  1808.            dd f68.16   ; get_service
  1809.            dd f68.17   ; call_service
  1810.            dd f68.18   ; loadLibUnicode
  1811.            dd f68.19   ; load_dll
  1812.            dd f68.20   ; user_realloc
  1813.            dd f68.21   ; load_driver
  1814.            dd f68.22   ; shmem_open
  1815.            dd f68.23   ; shmem_close
  1816.            dd f68.24   ; set exception handler
  1817.            dd f68.25   ; unmask exception
  1818.            dd f68.26   ; user_unmap
  1819.            dd f68.27   ; load_file_umode
  1820.            dd f68.28   ; loadFileUnicode
  1821.            dd f68.29   ; user_ring
  1822.            dd f68.30   ; map_pe_usermode
  1823.            dd f68.31   ; unmap_pe_usermode
  1824.            dd f68.32   ; mprotect
  1825.  
  1826. align 4
  1827. proc load_pe_driver stdcall, file:dword, cmdline:dword
  1828.         push    esi
  1829.  
  1830.         stdcall load_PE, [file]
  1831.         test    eax, eax
  1832.         jz      .fail
  1833.  
  1834.         mov     esi, eax
  1835.         push    [cmdline]
  1836.         push    DRV_ENTRY
  1837.         call    eax
  1838.         pop     ecx
  1839.         pop     ecx
  1840.         test    eax, eax
  1841.         jz      .fail
  1842.  
  1843.         mov     [eax+SRV.entry], esi
  1844.         pop     esi
  1845.         ret
  1846.  
  1847. .fail:
  1848.         xor     eax, eax
  1849.         pop     esi
  1850.         ret
  1851. endp
  1852.  
  1853. align 4
  1854. proc create_ring_buffer stdcall, size:dword, flags:dword
  1855.            locals
  1856.              buf_ptr  dd ?
  1857.            endl
  1858.  
  1859.         mov     eax, [size]
  1860.         test    eax, eax
  1861.         jz      .fail
  1862.  
  1863.         add     eax, eax
  1864.         stdcall alloc_kernel_space, eax
  1865.         test    eax, eax
  1866.         jz      .fail
  1867.  
  1868.         push    ebx
  1869.  
  1870.         mov     [buf_ptr], eax
  1871.  
  1872.         mov     ebx, [size]
  1873.         shr     ebx, 12
  1874.         push    ebx
  1875.  
  1876.         stdcall alloc_pages, ebx
  1877.         pop     ecx
  1878.  
  1879.         test    eax, eax
  1880.         jz      .mm_fail
  1881.  
  1882.         push    edi
  1883.  
  1884.         or      eax, [flags]
  1885.         mov     edi, [buf_ptr]
  1886.         mov     ebx, [buf_ptr]
  1887.         mov     edx, ecx
  1888.         shl     edx, 2
  1889.         shr     edi, 10
  1890. @@:
  1891.         mov     [page_tabs+edi], eax
  1892.         mov     [page_tabs+edi+edx], eax
  1893.         invlpg  [ebx]
  1894.         invlpg  [ebx+0x10000]
  1895.         add     eax, 0x1000
  1896.         add     ebx, 0x1000
  1897.         add     edi, 4
  1898.         dec     ecx
  1899.         jnz     @B
  1900.  
  1901.         mov     eax, [buf_ptr]
  1902.         pop     edi
  1903.         pop     ebx
  1904.         ret
  1905. .mm_fail:
  1906.         stdcall free_kernel_space, [buf_ptr]
  1907.         xor     eax, eax
  1908.         pop     ebx
  1909. .fail:
  1910.         ret
  1911. endp
  1912.  
  1913.  
  1914. align 4
  1915. proc print_mem
  1916.         mov     edi, BOOT.memmap_blocks
  1917.         mov     ecx, [edi-4]
  1918.         test    ecx, ecx
  1919.         jz      .done
  1920.  
  1921. @@:
  1922.         mov     eax, [edi]
  1923.         mov     edx, [edi+4]
  1924.         add     eax, [edi+8]
  1925.         adc     edx, [edi+12]
  1926.  
  1927.         DEBUGF  1, "K : E820 %x%x - %x%x type %d\n", \
  1928.                     [edi+4], [edi],\
  1929.                     edx, eax, [edi+16]
  1930.         add     edi, 20
  1931.         dec     ecx
  1932.         jnz     @b
  1933. .done:
  1934.         ret
  1935. endp
  1936.