Index: kernel/trunk/const.inc
===================================================================
--- kernel/trunk/const.inc	(revision 6766)
+++ kernel/trunk/const.inc	(working copy)
@@ -414,11 +414,11 @@
 struct  PROC
         list            LHEAD
         thr_list        LHEAD
+        smap_list       LHEAD
         heap_lock       MUTEX
         heap_base       rd 1
         heap_top        rd 1
         mem_used        rd 1
-        dlls_list_ptr   rd 1
         pdt_0_phys      rd 1
         pdt_1_phys      rd 1
         io_map_0        rd 1
@@ -614,37 +614,16 @@
         name            rb 32   ;+24
 ends
 
-struct  SMAP            APPOBJ
+struct  SMAP
+        fd              dd ?   ;next in mmapped list
+        bk              dd ?   ;prev in mmapped list
         base            dd ?   ;mapped base
-        parent          dd ?   ;SMEM
-ends
-
-struct  DLLDESCR
-        bk              dd ?
-        fd              dd ?    ;+4
-        data            dd ?    ;+8
-        size            dd ?    ;+12
-        timestamp       dq ?
-        refcount        dd ?
-        defaultbase     dd ?
-        coff_hdr        dd ?
-        symbols_ptr     dd ?
-        symbols_num     dd ?
-        symbols_lim     dd ?
-        exports         dd ?   ;export table
-        name            rb 260
-ends
-
-struct  HDLL
-        fd              dd ?   ;next object in list
-        bk              dd ?   ;prev object in list
-        pid             dd ?   ;owner id
-
-        base            dd ?   ;mapped base
         size            dd ?   ;mapped size
-        refcount        dd ?   ;reference counter for this process and this lib
-        parent          dd ?   ;DLLDESCR
+        type            dd ?   ;SMAP_TYPE_SMEM or SMAP_TYPE_PE
+        parent          dd ?   ;SMEM or PEDESCR
 ends
+SMAP_TYPE_SMEM = 1
+SMAP_TYPE_PE = 2
 
 
 struct  BOOT_DATA
@@ -737,6 +716,55 @@
         owner           dd ? ; pointer to SRV or 0
 ends
 
+struct  PEDESCR
+        bk              dd ?
+        fd              dd ?
+        size            dd ?    ; in pages
+        timestamp       dq ?
+        refcount        dd ?
+        defaultbase     dd ?
+        name            dd ?
+        entry           dd ?
+        stacksize       dd ?
+        page_array_lock MUTEX
+; After those fields the array follows, one dword per every of [size] pages.
+; The value of every field has 3 parts:
+; - upper 20 bits are page number or zero;
+; - next 4 bits are access rights shareable/executable/readable/writable
+;   in the same order as IMAGE_SCN_MEM_xxx shifted appropriately;
+; - lower 8 bits are reference counter.
+; The exact meaning depends on page type.
+; * For a page with data in non-shareable section
+;   which has at least one unmodified copy:
+;   - upper 20 bits are page number for unmodified copy,
+;   - reference counter = number of unmodified copies is nonzero up to 0xFF.
+;   If reference counter reaches 0xFF, it becomes locked at this value.
+;   If reference counter reaches zero, the last copy changes ownership
+;   to the last process,
+;   and the page is converted to the following state.
+; * For a page with data in non-shareable section
+;   with no unmodified copies:
+;   - all fields are reset to zero.
+;   The original content is lost; map_pe_usermode would reload from file.
+; * For a page with zeroes in non-shareable section:
+;   - upper 20 bits are zero,
+;   - lower 8 bits are 0xFF.
+; * For a page in shareable section with data or with zeroes:
+;   - upper 20 bits are page number for all copies,
+;   - lower 8 bits are reference counter from 1 to 0xFF.
+;   Reference counter does not actually matter here,
+;   it equals [refcount] unless 0xFF was once reached,
+;   but is kept for consistency.
+ends
+
+struct  SHARED_LOCKED_PAGE
+        fd              dd ?
+        bk              dd ?
+        address         dd ?
+        parent          dd ?
+        offs            dd ?
+ends
+
 struct  IDE_DATA
         ProgrammingInterface dd ?
         Interrupt            dw ?
@@ -859,7 +887,20 @@
         NumLinenum      dw ?
         Characteristics dd ?
 ends
+IMAGE_SCN_MEM_SHARED  = 10000000h
+IMAGE_SCN_MEM_EXECUTE = 20000000h
+IMAGE_SCN_MEM_READ    = 40000000h
+IMAGE_SCN_MEM_WRITE   = 80000000h
 
+struct  STRIPPED_PE_SECTION
+        Name            rb 8
+        VirtualSize     dd ?
+        VirtualAddress  dd ?
+        SizeOfRawData   dd ?
+        PtrRawData      dd ?
+        Characteristics dd ?
+ends
+
 struct  COFF_RELOC
         VirtualAddress  dd ?
         SymIndex        dd ?
@@ -897,6 +938,62 @@
 SPE_DIRECTORY_EXPORT    = 1
 SPE_DIRECTORY_BASERELOC = 2
 
+struct IMAGE_DATA_DIRECTORY
+        VirtualAddress dd  ?
+        isize          dd  ?
+ends
+
+struct IMAGE_OPTIONAL_HEADER32
+        Magic                   dw  ?
+        MajorLinkerVersion      db  ?
+        MinorLinkerVersion      db  ?
+        SizeOfCode              dd  ?
+        SizeOfInitializedData   dd  ?
+        SizeOfUninitializedData dd  ?
+        AddressOfEntryPoint     dd  ?
+        BaseOfCode              dd  ?
+        BaseOfData              dd  ?
+        ImageBase               dd  ?
+        SectionAlignment        dd  ?
+        FileAlignment           dd  ?
+        MajorOperatingSystemVersion     dw  ?
+        MinorOperatingSystemVersion     dw  ?
+        MajorImageVersion       dw  ?
+        MinorImageVersion       dw  ?
+        MajorSubsystemVersion   dw  ?
+        MinorSubsystemVersion   dw  ?
+        Win32VersionValue       dd  ?
+        SizeOfImage             dd  ?
+        SizeOfHeaders           dd  ?
+        CheckSum                dd  ?
+        Subsystem               dw  ?
+        DllCharacteristics      dw  ?
+        SizeOfStackReserve      dd  ?
+        SizeOfStackCommit       dd  ?
+        SizeOfHeapReserve       dd  ?
+        SizeOfHeapCommit        dd  ?
+        LoaderFlags             dd  ?
+        NumberOfDirectories     dd  ?
+        DataDirectory           IMAGE_DATA_DIRECTORY ?
+        Directories             rb  sizeof.IMAGE_DATA_DIRECTORY*15
+ends
+
+struct IMAGE_FILE_HEADER
+        Machine                 dw ?
+        NumberOfSections        dw ?
+        TimeDateStamp           dd ?
+        PointerToSymbolTable    dd ?
+        NumberOfSymbols         dd ?
+        SizeOfOptionalHeader    dw ?
+        Characteristics         dw ?
+ends
+
+struct IMAGE_NT_HEADERS
+        Signature       dd ?
+        FileHeader      IMAGE_FILE_HEADER
+        OptionalHeader  IMAGE_OPTIONAL_HEADER32
+ends
+
 struct  IOCTL
         handle          dd ?
         io_code         dd ?
Index: kernel/trunk/core/dll.inc
===================================================================
--- kernel/trunk/core/dll.inc	(revision 6766)
+++ kernel/trunk/core/dll.inc	(working copy)
@@ -902,9 +902,13 @@
 proc load_library stdcall, file_name:dword
     locals
         fullname    dd  ?
-        fileinfo    rb  40
+        filesize    dd  ?
         coff        dd  ?
         img_base    dd  ?
+        img_size    dd  ?
+        symbols_ptr dd  ?
+        symbols_lim dd  ?
+        exports     dd  ?
     endl
 
 ; resolve file name
@@ -914,105 +918,19 @@
         stdcall get_full_file_name, eax, maxPathLength
         test    eax, eax
         jz      .fail
-; scan for required DLL in list of already loaded for this process,
-; ignore timestamp
-        cli
-        mov     esi, [current_process]
-        mov     edi, [fullname]
-        mov     ebx, [esi+PROC.dlls_list_ptr]
-        test    ebx, ebx
-        jz      .not_in_process
-        mov     esi, [ebx+HDLL.fd]
-.scan_in_process:
-        cmp     esi, ebx
-        jz      .not_in_process
-        mov     eax, [esi+HDLL.parent]
-        add     eax, DLLDESCR.name
-        stdcall strncmp, eax, edi, -1
-        test    eax, eax
-        jnz     .next_in_process
-; simple variant: load DLL which is already loaded in this process
-; just increment reference counters and return address of exports table
-        inc     [esi+HDLL.refcount]
-        mov     ecx, [esi+HDLL.parent]
-        inc     [ecx+DLLDESCR.refcount]
-        mov     eax, [ecx+DLLDESCR.exports]
-        sub     eax, [ecx+DLLDESCR.defaultbase]
-        add     eax, [esi+HDLL.base]
-        sti
-        push    eax
-        stdcall kernel_free, [fullname]
-        pop     eax
-        ret
 
-.next_in_process:
-        mov     esi, [esi+HDLL.fd]
-        jmp     .scan_in_process
-
-.not_in_process:
-; scan in full list, compare timestamp
-        sti
-        lea     eax, [fileinfo]
-        stdcall get_fileinfo, edi, eax
-        test    eax, eax
-        jnz     .fail
-        cli
-        mov     esi, [dll_list.fd]
-.scan_for_dlls:
-        cmp     esi, dll_list
-        jz      .load_new
-        lea     eax, [esi+DLLDESCR.name]
-        stdcall strncmp, eax, edi, -1
-        test    eax, eax
-        jnz     .continue_scan
-.test_prev_dll:
-        mov     eax, dword [fileinfo+24]; last modified time
-        mov     edx, dword [fileinfo+28]; last modified date
-        cmp     dword [esi+DLLDESCR.timestamp], eax
-        jnz     .continue_scan
-        cmp     dword [esi+DLLDESCR.timestamp+4], edx
-        jz      .dll_already_loaded
-.continue_scan:
-        mov     esi, [esi+DLLDESCR.fd]
-        jmp     .scan_for_dlls
-
-; new DLL
-.load_new:
-        sti
 ; load file
-        stdcall load_file, edi
+        stdcall load_file, [fullname]
         test    eax, eax
         jz      .fail
         mov     [coff], eax
-        mov     dword [fileinfo+32], ebx
+        mov     [filesize], ebx
 
-; allocate DLLDESCR struct; size is DLLDESCR.sizeof plus size of DLL name
-        mov     esi, edi
-        mov     ecx, -1
-        xor     eax, eax
-        repnz scasb
-        not     ecx
-        lea     eax, [ecx+sizeof.DLLDESCR]
-        push    ecx
-        call    malloc
-        pop     ecx
-        test    eax, eax
-        jz      .fail_and_free_coff
-; save timestamp
-        lea     edi, [eax+DLLDESCR.name]
-        rep movsb
-        mov     esi, eax
-        mov     eax, dword [fileinfo+24]
-        mov     dword [esi+DLLDESCR.timestamp], eax
-        mov     eax, dword [fileinfo+28]
-        mov     dword [esi+DLLDESCR.timestamp+4], eax
-
 ; calculate size of loaded DLL
-        mov     edx, [coff]
-        movzx   ecx, [edx+COFF_HEADER.nSections]
+        movzx   ecx, [eax+COFF_HEADER.nSections]
         xor     ebx, ebx
 
-        add     edx, 20
+        lea     edx, [eax+20]
 @@:
         call    coff_get_align
         add     ebx, eax
@@ -1023,31 +941,19 @@
         dec     ecx
         jnz     @B
 ; it must be nonzero and not too big
-        mov     [esi+DLLDESCR.size], ebx
+        mov     [img_size], ebx
         test    ebx, ebx
-        jz      .fail_and_free_dll
-        cmp     ebx, MAX_DEFAULT_DLL_ADDR-MIN_DEFAULT_DLL_ADDR
-        ja      .fail_and_free_dll
-; allocate memory for kernel-side image
-        stdcall kernel_alloc, ebx
+        jz      .fail_and_free_coff
+        cmp     ebx, 0x10000000
+        ja      .fail_and_free_coff
+; allocate memory
+        call    init_heap
+        stdcall user_alloc, [img_size]
         test    eax, eax
-        jz      .fail_and_free_dll
-        mov     [esi+DLLDESCR.data], eax
-; calculate preferred base address
-        add     ebx, 0x1FFF
-        and     ebx, not 0xFFF
-        mov     ecx, [dll_cur_addr]
-        lea     edx, [ecx+ebx]
-        cmp     edx, MAX_DEFAULT_DLL_ADDR
-        jb      @f
-        mov     ecx, MIN_DEFAULT_DLL_ADDR
-        lea     edx, [ecx+ebx]
-@@:
-        mov     [esi+DLLDESCR.defaultbase], ecx
-        mov     [dll_cur_addr], edx
+        jz      .fail_and_free_coff
+        mov	[img_base], eax
 
 ; copy sections and set correct values for VirtualAddress'es in headers
-        push    esi
         mov     edx, [coff]
         movzx   ebx, [edx+COFF_HEADER.nSections]
         mov     edi, eax
@@ -1055,15 +961,11 @@
         cld
 @@:
         call    coff_get_align
-        add     ecx, eax
         add     edi, eax
         not     eax
-        and     ecx, eax
         and     edi, eax
-        mov     [edx+COFF_SECTION.VirtualAddress], ecx
-        add     ecx, [edx+COFF_SECTION.SizeOfRawData]
+        mov     [edx+COFF_SECTION.VirtualAddress], edi
         mov     esi, [edx+COFF_SECTION.PtrRawData]
-        push    ecx
         mov     ecx, [edx+COFF_SECTION.SizeOfRawData]
         test    esi, esi
         jnz     .copy
@@ -1074,84 +976,30 @@
         add     esi, [coff]
         rep movsb
 .next:
-        pop     ecx
         add     edx, sizeof.COFF_SECTION
         dec     ebx
         jnz     @B
-        pop     esi
 
-; save some additional data from COFF file
-; later we will use COFF header, headers for sections and symbol table
-; and also relocations table for all sections
         mov     edx, [coff]
         mov     ebx, [edx+COFF_HEADER.pSymTable]
-        mov     edi, dword [fileinfo+32]
+        mov     edi, [filesize]
         sub     edi, ebx
         jc      .fail_and_free_data
-        mov     [esi+DLLDESCR.symbols_lim], edi
+        mov     [symbols_lim], edi
         add     ebx, edx
-        movzx   ecx, [edx+COFF_HEADER.nSections]
-        lea     ecx, [ecx*5]
-        lea     edi, [edi+ecx*8+20]
-        add     edx, 20
-@@:
-        movzx   eax, [edx+COFF_SECTION.NumReloc]
-        lea     eax, [eax*5]
-        lea     edi, [edi+eax*2]
-        add     edx, sizeof.COFF_SECTION
-        sub     ecx, 5
-        jnz     @b
-        stdcall kernel_alloc, edi
-        test    eax, eax
-        jz      .fail_and_free_data
-        mov     edx, [coff]
-        movzx   ecx, [edx+COFF_HEADER.nSections]
-        lea     ecx, [ecx*5]
-        lea     ecx, [ecx*2+5]
-        mov     [esi+DLLDESCR.coff_hdr], eax
-        push    esi
-        mov     esi, edx
-        mov     edi, eax
-        rep movsd
-        pop     esi
-        mov     [esi+DLLDESCR.symbols_ptr], edi
-        push    esi
-        mov     ecx, [edx+COFF_HEADER.nSymbols]
-        mov     [esi+DLLDESCR.symbols_num], ecx
-        mov     ecx, [esi+DLLDESCR.symbols_lim]
-        mov     esi, ebx
-        rep movsb
-        pop     esi
-        mov     ebx, [esi+DLLDESCR.coff_hdr]
-        push    esi
-        movzx   eax, [edx+COFF_HEADER.nSections]
-        lea     edx, [ebx+20]
-@@:
-        movzx   ecx, [edx+COFF_SECTION.NumReloc]
-        lea     ecx, [ecx*5]
-        mov     esi, [edx+COFF_SECTION.PtrReloc]
-        mov     [edx+COFF_SECTION.PtrReloc], edi
-        sub     [edx+COFF_SECTION.PtrReloc], ebx
-        add     esi, [coff]
-        shr     ecx, 1
-        rep movsd
-        adc     ecx, ecx
-        rep movsw
-        add     edx, sizeof.COFF_SECTION
-        dec     eax
-        jnz     @b
-        pop     esi
+; coff_hdr = coff
+; symbols_num = coff.nSymbols
+	mov	[symbols_ptr], ebx
+        mov     ebx, edx
 
 ; fixup symbols
-        mov     edx, ebx
-        mov     eax, [ebx+COFF_HEADER.nSymbols]
+        mov     eax, [edx+COFF_HEADER.nSymbols]
         add     edx, 20
-        mov     ecx, [esi+DLLDESCR.symbols_num]
-        lea     ecx, [ecx*9]
+        lea     ecx, [eax*9]
         add     ecx, ecx
-        add     ecx, [esi+DLLDESCR.symbols_ptr]
+        add     ecx, [symbols_ptr]
 
-        stdcall fix_coff_symbols, edx, [esi+DLLDESCR.symbols_ptr], eax, \
+        stdcall fix_coff_symbols, edx, [symbols_ptr], eax, \
                 ecx, 0
 ;          test eax, eax
 ;          jnz @F
@@ -1158,111 +1006,25 @@
 ;
 ;@@:
 
-        stdcall get_coff_sym, [esi+DLLDESCR.symbols_ptr], [ebx+COFF_HEADER.nSymbols], szEXPORTS
+        stdcall get_coff_sym, [symbols_ptr], [ebx+COFF_HEADER.nSymbols], szEXPORTS
         test    eax, eax
         jnz     @F
 
-        stdcall get_coff_sym, [esi+DLLDESCR.symbols_ptr], [ebx+COFF_HEADER.nSymbols], sz_EXPORTS
+        stdcall get_coff_sym, [symbols_ptr], [ebx+COFF_HEADER.nSymbols], sz_EXPORTS
 @@:
-        mov     [esi+DLLDESCR.exports], eax
+        mov     [exports], eax
 
-; fix relocs in the hidden copy in kernel memory to default address
-; it is first fix; usually this will be enough, but second fix
-; can be necessary if real load address will not equal assumption
-        mov     eax, [esi+DLLDESCR.data]
-        sub     eax, [esi+DLLDESCR.defaultbase]
-        stdcall fix_coff_relocs, ebx, [esi+DLLDESCR.symbols_ptr], eax
+        stdcall fix_coff_relocs, ebx, [symbols_ptr], 0
 
         stdcall kernel_free, [coff]
 
-        cli
-; initialize DLLDESCR struct
-        and     dword [esi+DLLDESCR.refcount], 0; no HDLLs yet; later it will be incremented
-        mov     [esi+DLLDESCR.fd], dll_list
-        mov     eax, [dll_list.bk]
-        mov     [dll_list.bk], esi
-        mov     [esi+DLLDESCR.bk], eax
-        mov     [eax+DLLDESCR.fd], esi
-.dll_already_loaded:
         stdcall kernel_free, [fullname]
-        inc     [esi+DLLDESCR.refcount]
-        push    esi
-        call    init_heap
-        pop     esi
-        mov     edi, [esi+DLLDESCR.size]
-        stdcall user_alloc_at, [esi+DLLDESCR.defaultbase], edi
-        test    eax, eax
-        jnz     @f
-        stdcall user_alloc, edi
-        test    eax, eax
-        jz      .fail_and_dereference
-@@:
-        mov     [img_base], eax
-        mov     eax, sizeof.HDLL
-        call    malloc
-        test    eax, eax
-        jz      .fail_and_free_user
-        mov     ebx, [CURRENT_TASK]
-        shl     ebx, 5
-        mov     edx, [CURRENT_TASK+ebx+TASKDATA.pid]
-        mov     [eax+HDLL.pid], edx
-        push    eax
-        call    init_dlls_in_thread
-        pop     ebx
-        test    eax, eax
-        jz      .fail_and_free_user
-        mov     edx, [eax+HDLL.fd]
-        mov     [ebx+HDLL.fd], edx
-        mov     [ebx+HDLL.bk], eax
-        mov     [eax+HDLL.fd], ebx
-        mov     [edx+HDLL.bk], ebx
-        mov     eax, ebx
-        mov     ebx, [img_base]
-        mov     [eax+HDLL.base], ebx
-        mov     [eax+HDLL.size], edi
-        mov     [eax+HDLL.refcount], 1
-        mov     [eax+HDLL.parent], esi
-        mov     edx, ebx
-        shr     edx, 12
-        or      dword [page_tabs+(edx-1)*4], DONT_FREE_BLOCK
-; copy entries of page table from kernel-side image to usermode
-; use copy-on-write for user-mode image, so map as readonly
-        xor     edi, edi
-        mov     ecx, [esi+DLLDESCR.data]
-        shr     ecx, 12
-.map_pages_loop:
-        mov     eax, [page_tabs+ecx*4]
-        and     eax, not 0xFFF
-        or      al, PG_UR
-        xchg    eax, [page_tabs+edx*4]
-        test    al, 1
-        jz      @f
-        call    free_page
-@@:
-        invlpg  [ebx+edi]
-        inc     ecx
-        inc     edx
-        add     edi, 0x1000
-        cmp     edi, [esi+DLLDESCR.size]
-        jb      .map_pages_loop
 
-; if real user-mode base is not equal to preferred base, relocate image
-        sub     ebx, [esi+DLLDESCR.defaultbase]
-        jz      @f
-        stdcall rebase_coff, [esi+DLLDESCR.coff_hdr], [esi+DLLDESCR.symbols_ptr], ebx
-@@:
-
-        mov     eax, [esi+DLLDESCR.exports]
-        sub     eax, [esi+DLLDESCR.defaultbase]
-        add     eax, [img_base]
-        sti
+        mov     eax, [exports]
         ret
 
 .fail_and_free_data:
-        stdcall kernel_free, [esi+DLLDESCR.data]
-.fail_and_free_dll:
-        mov     eax, esi
-        call    free
+	stdcall	user_free, [img_base]
 .fail_and_free_coff:
         stdcall kernel_free, [coff]
 .fail:
@@ -1269,88 +1031,24 @@
         stdcall kernel_free, [fullname]
         xor     eax, eax
         ret
-
-.fail_and_free_user:
-        stdcall user_free, [img_base]
-.fail_and_dereference:
-        mov     eax, 1  ; delete 1 reference
-        call    dereference_dll
-        sti
-        xor     eax, eax
-        ret
 endp
 
-; initialize [APPDATA.dlls_list_ptr] for given thread
-; DLL is per-process object, so APPDATA.dlls_list_ptr must be
-; kept in sync for all threads of one process.
-; out: eax = APPDATA.dlls_list_ptr if all is OK,
-; NULL if memory allocation failed
-init_dlls_in_thread:
-        mov     ebx, [current_process]
-        mov     eax, [ebx+PROC.dlls_list_ptr]
-        test    eax, eax
-        jnz     .ret
-
-        mov     eax, 8
-        call    malloc                               ; FIXME
-        test    eax, eax
-        jz      .ret
-
-        mov     [eax], eax
-        mov     [eax+4], eax
-
-        mov     ebx, [current_process]
-        mov     [ebx+PROC.dlls_list_ptr], eax
-.ret:
-        ret
-
-; in: eax = number of references to delete, esi -> DLLDESCR struc
-dereference_dll:
-        sub     [esi+DLLDESCR.refcount], eax
-        jnz     .ret
-        mov     eax, [esi+DLLDESCR.fd]
-        mov     edx, [esi+DLLDESCR.bk]
-        mov     [eax+DLLDESCR.bk], edx
-        mov     [edx+DLLDESCR.fd], eax
-        stdcall kernel_free, [esi+DLLDESCR.coff_hdr]
-        stdcall kernel_free, [esi+DLLDESCR.data]
+; in: esi -> PEDESCR struct
+proc dereference_pe
+        mov     ecx, pe_list_mutex
+        call    mutex_lock
+        dec     [esi+PEDESCR.refcount]
+        jnz     mutex_unlock
+        mov     eax, [esi+PEDESCR.fd]
+        mov     edx, [esi+PEDESCR.bk]
+        mov     [eax+PEDESCR.bk], edx
+        mov     [edx+PEDESCR.fd], eax
+        call    mutex_unlock
         mov     eax, esi
         call    free
-.ret:
         ret
+endp
 
-destroy_hdll:
-        push    ebx ecx esi edi
-        mov     ebx, [eax+HDLL.base]
-        mov     esi, [eax+HDLL.parent]
-        mov     edx, [esi+DLLDESCR.size]
-
-        push    eax
-        mov     esi, [eax+HDLL.parent]
-        mov     eax, [eax+HDLL.refcount]
-        call    dereference_dll
-        pop     eax
-        mov     edx, [eax+HDLL.bk]
-        mov     ebx, [eax+HDLL.fd]
-        mov     [ebx+HDLL.bk], edx
-        mov     [edx+HDLL.fd], ebx
-        call    free
-        pop     edi esi ecx ebx
-        ret
-
-; ecx -> APPDATA for slot, esi = dlls_list_ptr
-destroy_all_hdlls:
-        test    esi, esi
-        jz      .ret
-.loop:
-        mov     eax, [esi+HDLL.fd]
-        cmp     eax, esi
-        jz      free
-        call    destroy_hdll
-        jmp     .loop
-.ret:
-        ret
-
 align 4
 stop_all_services:
         push    ebp
Index: kernel/trunk/core/heap.inc
===================================================================
--- kernel/trunk/core/heap.inc	(revision 6766)
+++ kernel/trunk/core/heap.inc	(working copy)
@@ -22,6 +22,9 @@
 USED_BLOCK      equ  8
 DONT_FREE_BLOCK equ  10h
 
+LAZY_ALLOC_PAGE = 2
+LAZY_ALLOC_UNREADABLE = 20h
+LAZY_ALLOC_UNWRITABLE = 40h
 
 block_next   equ MEM_BLOCK.next_block
 block_prev   equ MEM_BLOCK.prev_block
@@ -32,7 +35,8 @@
 block_flags  equ MEM_BLOCK.flags
 
 macro calc_index op
-{          shr op, 12
+{
+        shr     op, 12
         dec     op
         cmp     op, 63
         jna     @f
@@ -573,36 +577,44 @@
         sub     eax, PAGE_SIZE
         ret
 @@:
-        lea     ecx, [ebx+PROC.heap_lock]
-        call    mutex_init
 
-        mov     esi, [ebx+PROC.mem_used]
-        add     esi, 4095
-        and     esi, not 4095
-        mov     [ebx+PROC.mem_used], esi
+        mov     edx, [ebx+PROC.mem_used]
+        add     edx, 4095
+        and     edx, not 4095
+        mov     [ebx+PROC.mem_used], edx
         mov     eax, HEAP_TOP
-        mov     [ebx+PROC.heap_base], esi
+        mov     [ebx+PROC.heap_base], edx
         mov     [ebx+PROC.heap_top], eax
 
-        sub     eax, esi
-        shr     esi, 10
+        sub     eax, edx
+        shr     edx, 10
         mov     ecx, eax
         sub     eax, PAGE_SIZE
         or      ecx, FREE_BLOCK
-        mov     [page_tabs+esi], ecx
+        mov     [page_tabs+edx], ecx
         ret
 endp
 
 align 4
-proc user_alloc stdcall, alloc_size:dword
+proc user_alloc ;stdcall, alloc_size:dword
+        mov     ecx, [current_process]
+        add     ecx, PROC.heap_lock
+        call    mutex_lock
+        stdcall user_alloc_nolock, [esp+4]
+        push    eax
+        mov     ecx, [current_process]
+        add     ecx, PROC.heap_lock
+        call    mutex_unlock
+        pop     eax
+        ret     4
+endp
 
+proc user_alloc_nolock stdcall, alloc_size:dword
         push    ebx
         push    esi
         push    edi
 
         mov     ebx, [current_process]
-        lea     ecx, [ebx+PROC.heap_lock]
-        call    mutex_lock
 
         mov     ecx, [alloc_size]
         add     ecx, (4095+PAGE_SIZE)
@@ -643,15 +655,6 @@
         jnz     @B
 .no:
 
-        mov     edx, [current_process]
-        mov     ebx, [alloc_size]
-        add     ebx, 0xFFF
-        and     ebx, not 0xFFF
-        add     [edx+PROC.mem_used], ebx
-
-        lea     ecx, [edx+PROC.heap_lock]
-        call    mutex_unlock
-
         lea     eax, [esi+4096]
 
         pop     edi
@@ -667,9 +670,6 @@
         add     esi, eax
         jmp     .scan
 .m_exit:
-        mov     ecx, [current_process]
-        lea     ecx, [ecx+PROC.heap_lock]
-        call    mutex_unlock
 
         xor     eax, eax
         pop     edi
@@ -679,15 +679,25 @@
 endp
 
 align 4
-proc user_alloc_at stdcall, address:dword, alloc_size:dword
+proc user_alloc_at ;stdcall, address:dword, alloc_size:dword
+        mov     ecx, [current_process]
+        add     ecx, PROC.heap_lock
+        call    mutex_lock
+        stdcall user_alloc_at_nolock, [esp+8], [esp+8]
+        push    eax
+        mov     ecx, [current_process]
+        add     ecx, PROC.heap_lock
+        call    mutex_unlock
+        pop     eax
+        ret     8
+endp
 
+proc user_alloc_at_nolock stdcall, address:dword, alloc_size:dword
         push    ebx
         push    esi
         push    edi
 
         mov     ebx, [current_process]
-        lea     ecx, [ebx+PROC.heap_lock]
-        call    mutex_lock
 
         mov     edx, [address]
         and     edx, not 0xFFF
@@ -712,9 +722,6 @@
         mov     esi, ecx
         jmp     .scan
 .error:
-        mov     ecx, [current_process]
-        lea     ecx, [ecx+PROC.heap_lock]
-        call    mutex_unlock
 
         xor     eax, eax
         pop     edi
@@ -767,15 +774,6 @@
         mov     [page_tabs+ebx*4], ecx
 
 .nothird:
-        mov     edx, [current_process]
-        mov     ebx, [alloc_size]
-        add     ebx, 0xFFF
-        and     ebx, not 0xFFF
-        add     [edx+PROC.mem_used], ebx
-
-        lea     ecx, [edx+PROC.heap_lock]
-        call    mutex_unlock
-
         mov     eax, [address]
 
         pop     edi
@@ -790,8 +788,6 @@
         push    esi
 
         mov     esi, [base]
-        test    esi, esi
-        jz      .fail
 
         push    ebx
 
@@ -801,6 +797,7 @@
 
         xor     ebx, ebx
         shr     esi, 12
+        jz      .cantfree
         mov     eax, [page_tabs+(esi-1)*4]
         test    al, USED_BLOCK
         jz      .cantfree
@@ -807,6 +804,11 @@
         test    al, DONT_FREE_BLOCK
         jnz     .cantfree
 
+        push    0
+virtual at esp
+.num_released_pages dd ?
+end virtual
+
         and     eax, not 4095
         mov     ecx, eax
         or      al, FREE_BLOCK
@@ -816,16 +818,18 @@
         shr     ecx, 12
         jz      .released
 .release:
-        xor     eax, eax
-        xchg    eax, [page_tabs+esi*4]
-        test    al, 1
-        jz      @F
-        test    eax, PG_SHARED
-        jnz     @F
-        call    free_page
+        mov     edx, [page_tabs+esi*4]
+        mov     dword [page_tabs+esi*4], 0
         mov     eax, esi
         shl     eax, 12
         invlpg  [eax]
+        test    dl, 1
+        jz      @F
+        inc     [.num_released_pages]
+        test    edx, PG_SHARED
+        jnz     @f
+        mov     eax, edx
+        call    free_page
 @@:
         inc     esi
         dec     ecx
@@ -832,17 +836,13 @@
         jnz     .release
 
 .released:
-        push    edi
 
+        pop     eax ; .num_released_pages
+        shl     eax, 12
         mov     edx, [current_process]
         lea     ecx, [edx+PROC.heap_lock]
-        mov     esi, dword [edx+PROC.heap_base]
-        mov     edi, dword [edx+PROC.heap_top]
-        sub     ebx, [edx+PROC.mem_used]
-        neg     ebx
-        mov     [edx+PROC.mem_used], ebx
+        sub     [edx+PROC.mem_used], eax
         call    user_normalize
-        pop     edi
 .exit:
         call    mutex_unlock
 
@@ -865,18 +865,21 @@
 
 align 4
 proc user_unmap stdcall, base:dword, offset:dword, size:dword
+        mov     ecx, [current_process]
+        add     ecx, PROC.heap_lock
+        call    mutex_lock
 
         push    ebx
 
         mov     ebx, [base]             ; must be valid pointer
-        test    ebx, ebx
-        jz      .error
 
         mov     edx, [offset]           ; check offset
         add     edx, ebx                ; must be below 2Gb app limit
+        jc      .error
         js      .error
 
         shr     ebx, 12                 ; chek block attributes
+        jz      .error
         lea     ebx, [page_tabs+ebx*4]
         mov     eax, [ebx-4]            ; block attributes
         test    al, USED_BLOCK
@@ -902,36 +905,63 @@
         and     ebx, not 4095           ; is it required ?
         add     ebx, [base]
 
+        push    0
+virtual at esp
+.num_released_pages dd ?
+end virtual
+
 .unmap:
         mov     eax, [edx]              ; get page addres
         test    al, 1                   ; page mapped ?
-        jz      @F
+        jz      .next
         test    eax, PG_SHARED          ; page shared ?
-        jnz     @F
-        mov     [edx], dword 2
+        jnz     .next
+        inc     [.num_released_pages]
+        mov     dword [edx], LAZY_ALLOC_PAGE
                                         ; mark page as reserved
+        test    eax, PG_READ
+        jnz     @f
+        or      dword [edx], LAZY_ALLOC_UNREADABLE
+@@:
+        test    eax, PG_WRITE
+        jnz     @f
+        or      dword [edx], LAZY_ALLOC_UNWRITABLE
+@@:
         invlpg  [ebx]                   ; when we start using
         call    free_page               ; empty c-o-w page instead this ?
-@@:
+.next:
         add     ebx, 4096
         add     edx, 4
         dec     ecx
         jnz     .unmap
 
+        pop     eax ; .num_released_pages
         pop     ebx
-        or      al, 1                   ; return non zero on success
+        shl     eax, 12
+        mov     ecx, [current_process]
+        sub     [ecx+PROC.mem_used], eax
+        push    eax
+        add     ecx, PROC.heap_lock
+        call    mutex_unlock
+        pop     eax                     ; return number of released bytes
         ret
 .error:
         pop     ebx
+        mov     ecx, [current_process]
+        add     ecx, PROC.heap_lock
+        call    mutex_unlock
         xor     eax, eax                ; something wrong
+        dec     eax
         ret
 endp
 
 align 4
-user_normalize:
-; in: esi=heap_base, edi=heap_top
+proc user_normalize uses esi edi
+; in: edx->PROC
 ; out: eax=0 <=> OK
-; destroys: ebx,edx,esi,edi
+; destroys: ebx,edx
+        mov     esi, dword [edx+PROC.heap_base]
+        mov     edi, dword [edx+PROC.heap_top]
         shr     esi, 12
         shr     edi, 12
 @@:
@@ -974,6 +1004,7 @@
 .err:
         xor     eax, eax
         ret
+endp
 
 user_realloc:
 ; in: eax = pointer, ebx = new size
@@ -1019,37 +1050,43 @@
         cmp     edx, ebx
         jb      .realloc_add
 ; release part of allocated memory
+        push    edx
+        push    0
+virtual at esp
+.num_released_pages dd ?
+end virtual
 .loop:
         cmp     edx, ebx
         jz      .release_done
         dec     edx
-        xor     eax, eax
-        xchg    eax, [page_tabs+edx*4]
+        push    dword [page_tabs+edx*4]
+        mov     dword [page_tabs+edx*4], 0
+        mov     eax, edx
+        shl     eax, 12
+        invlpg  [eax]
+        pop     eax
         test    al, 1
         jz      .loop
+        inc     [.num_released_pages]
+        test    eax, PG_SHARED
+        jnz     .loop
         call    free_page
-        mov     eax, edx
-        shl     eax, 12
-        invlpg  [eax]
         jmp     .loop
 .release_done:
+        pop     eax ; .num_released_pages
+        mov     edx, [current_process]
+        shl     eax, 12
+        sub     [edx+PROC.mem_used], eax
+        pop     edx
         sub     ebx, ecx
         cmp     ebx, 1
         jnz     .nofreeall
         mov     eax, [page_tabs+ecx*4]
         and     eax, not 0xFFF
-        mov     edx, [current_process]
-        mov     ebx, [edx+PROC.mem_used]
-        sub     ebx, eax
-        add     ebx, 0x1000
         or      al, FREE_BLOCK
         mov     [page_tabs+ecx*4], eax
-        push    esi edi
-        mov     esi, [edx+PROC.heap_base]
-        mov     edi, [edx+PROC.heap_top]
-        mov     [edx+PROC.mem_used], ebx
+        mov     edx, [current_process]
         call    user_normalize
-        pop     edi esi
         jmp     .ret0   ; all freed
 .nofreeall:
         sub     edx, ecx
@@ -1058,13 +1095,6 @@
         xchg    [page_tabs+ecx*4], ebx
         shr     ebx, 12
         sub     ebx, edx
-        push    ebx ecx edx
-        mov     edx, [current_process]
-        shl     ebx, 12
-        sub     ebx, [edx+PROC.mem_used]
-        neg     ebx
-        mov     [edx+PROC.mem_used], ebx
-        pop     edx ecx ebx
         lea     eax, [ecx+1]
         shl     eax, 12
         push    eax
@@ -1134,9 +1164,6 @@
         cld
         rep stosd
         pop     edi
-        mov     edx, [current_process]
-        shl     ebx, 12
-        add     [edx+PROC.mem_used], ebx
 
         mov     ecx, [current_process]
         lea     ecx, [ecx+PROC.heap_lock]
@@ -1210,11 +1237,6 @@
         dec     edx
         jnz     @b
 .no:
-        push    ebx
-        mov     edx, [current_process]
-        shl     ebx, 12
-        add     [edx+PROC.mem_used], ebx
-        pop     ebx
 @@:
         mov     dword [page_tabs+esi*4], 2
         inc     esi
@@ -1233,25 +1255,48 @@
 
 
 ; param
-;  eax= shm_map object
+;  edi= shm_map object
+;  [esp+4] = process
 
-align 4
-destroy_smap:
-
-        pushfd
-        cli
-
+proc destroy_smap ;stdcall, process:dword
         push    esi
-        push    edi
+        mov     esi, [edi+SMAP.parent]
+        cmp     [edi+SMAP.type], SMAP_TYPE_SMEM
+        jz      .smem
+        mov     ecx, [esp+8]
+        add     ecx, PROC.heap_lock
+        call    mutex_lock
+        stdcall release_pemap, [esp+8]
+        mov     ecx, [esp+8]
+        add     ecx, PROC.heap_lock
+        call    mutex_unlock
+        sub     ecx, PROC.heap_lock
+        cmp     ecx, [current_process]
+        jnz     @f
+        stdcall user_free, [edi+SMAP.base]
+@@:
+        call    dereference_pe
+        jmp     .common
+.smem:
+        mov     eax, [current_process]
+        cmp     [esp+8], eax
+        jnz     @f
+        stdcall user_free, [edi+SMAP.base]
+@@:
+        call    dereference_smem
+.common:
+        mov     eax, edi
+        call    free
+        pop     esi
+        ret     4
+endp
 
-        mov     edi, eax
-        mov     esi, [eax+SMAP.parent]
-        test    esi, esi
-        jz      .done
+proc dereference_smem
+        mov     ecx, shmem_list_mutex
+        call    mutex_lock
+        dec     [esi+SMEM.refcount]
+        jnz     mutex_unlock
 
-        lock dec [esi+SMEM.refcount]
-        jnz     .done
-
         mov     ecx, [esi+SMEM.bk]
         mov     edx, [esi+SMEM.fd]
 
@@ -1258,18 +1303,14 @@
         mov     [ecx+SMEM.fd], edx
         mov     [edx+SMEM.bk], ecx
 
+        mov     ecx, shmem_list_mutex
+        call    mutex_unlock
+
         stdcall kernel_free, [esi+SMEM.base]
         mov     eax, esi
         call    free
-.done:
-        mov     eax, edi
-        call    destroy_kernel_object
-
-        pop     edi
-        pop     esi
-        popfd
-
         ret
+endp
 
 E_NOTFOUND      equ  5
 E_ACCESS        equ 10
@@ -1288,23 +1329,17 @@
 SHM_OPEN_MASK   equ (3 shl 2)
 
 align 4
-proc shmem_open stdcall name:dword, size:dword, access:dword
+proc shmem_open stdcall uses ebx esi edi, name:dword, size:dword, access:dword
         locals
            action         dd ?
            owner_access   dd ?
            mapped         dd ?
+           edx_ret        dd ?
         endl
 
-        push    ebx
-        push    esi
-        push    edi
-
         mov     [mapped], 0
         mov     [owner_access], 0
 
-        pushfd                         ;mutex required
-        cli
-
         mov     eax, [access]
         and     eax, SHM_OPEN_MASK
         mov     [action], eax
@@ -1311,9 +1346,12 @@
 
         mov     ebx, [name]
         test    ebx, ebx
-        mov     edx, E_PARAM
-        jz      .fail
+        mov     [edx_ret], E_PARAM
+        jz      .exit
 
+        mov     ecx, shmem_list_mutex
+        call    mutex_lock
+
         mov     esi, [shmem_list.fd]
 align 4
 @@:
@@ -1331,22 +1369,22 @@
 .not_found:
         mov     eax, [action]
 
+        mov     [edx_ret], E_NOTFOUND
         cmp     eax, SHM_OPEN
-        mov     edx, E_NOTFOUND
-        je      .fail
+        je      .exit_unlock
 
+        mov     [edx_ret], E_PARAM
         cmp     eax, SHM_CREATE
-        mov     edx, E_PARAM
         je      .create_shm
 
         cmp     eax, SHM_OPEN_ALWAYS
-        jne     .fail
+        jne     .exit_unlock
 
 .create_shm:
 
         mov     ecx, [size]
         test    ecx, ecx
-        jz      .fail
+        jz      .exit_unlock
 
         add     ecx, 4095
         and     ecx, -4096
@@ -1356,13 +1394,11 @@
         call    malloc
         test    eax, eax
         mov     esi, eax
-        mov     edx, E_NOMEM
-        jz      .fail
+        mov     [edx_ret], E_NOMEM
+        jz      .exit_unlock
 
         stdcall kernel_alloc, [size]
         test    eax, eax
-        mov     [mapped], eax
-        mov     edx, E_NOMEM
         jz      .cleanup
 
         mov     ecx, [size]
@@ -1391,16 +1427,16 @@
 .found:
         mov     eax, [action]
 
+        mov     [edx_ret], E_ACCESS
         cmp     eax, SHM_CREATE
-        mov     edx, E_ACCESS
-        je      .exit
+        je      .exit_unlock
 
+        mov     [edx_ret], E_PARAM
         cmp     eax, SHM_OPEN
-        mov     edx, E_PARAM
         je      .create_map
 
         cmp     eax, SHM_OPEN_ALWAYS
-        jne     .fail
+        jne     .exit_unlock
 
 .create_map:
 
@@ -1408,37 +1444,44 @@
         and     eax, SHM_ACCESS_MASK
         cmp     eax, [esi+SMEM.access]
         mov     [access], eax
-        mov     edx, E_ACCESS
-        ja      .fail
+        mov     [edx_ret], E_ACCESS
+        ja      .exit_unlock
 
-        mov     ebx, [CURRENT_TASK]
-        shl     ebx, 5
-        mov     ebx, [CURRENT_TASK+ebx+4]
+        inc     [esi+SMEM.refcount]
+        mov     ecx, shmem_list_mutex
+        call    mutex_unlock
+
         mov     eax, sizeof.SMAP
-
-        call    create_kernel_object
+        call    malloc
         test    eax, eax
         mov     edi, eax
-        mov     edx, E_NOMEM
-        jz      .fail
+        mov     [edx_ret], E_NOMEM
+        jz      .cleanup2
 
-        inc     [esi+SMEM.refcount]
-
-        mov     [edi+SMAP.magic], 'SMAP'
-        mov     [edi+SMAP.destroy], destroy_smap
+        mov     [edi+SMAP.type], SMAP_TYPE_SMEM
         mov     [edi+SMAP.parent], esi
-        mov     [edi+SMAP.base], 0
 
-        stdcall user_alloc, [esi+SMEM.size]
+        mov     ecx, [current_process]
+        add     ecx, PROC.heap_lock
+        call    mutex_lock
+
+        stdcall user_alloc_nolock, [esi+SMEM.size]
         test    eax, eax
         mov     [mapped], eax
-        mov     edx, E_NOMEM
-        jz      .cleanup2
+        jz      .cleanup3
 
         mov     [edi+SMAP.base], eax
+        mov     ecx, [current_process]
+        mov     edx, [ecx+PROC.smap_list+SMAP.bk]
+        add     ecx, PROC.smap_list
+        mov     [edi+SMAP.fd], ecx
+        mov     [edi+SMAP.bk], edx
+        mov     [ecx+SMAP.bk], edi
+        mov     [edx+SMAP.fd], edi
 
         mov     ecx, [esi+SMEM.size]
-        mov     [size], ecx
+        mov     [edi+SMAP.size], ecx
+        mov     [edx_ret], ecx
 
         shr     ecx, 12
         shr     eax, 10
@@ -1445,44 +1488,51 @@
 
         mov     esi, [esi+SMEM.base]
         shr     esi, 10
-        lea     edi, [page_tabs+eax]
-        add     esi, page_tabs
 
+        xor     ebx, ebx
         mov     edx, [access]
         or      edx, [owner_access]
         shl     edx, 1
         or      edx, PG_SHARED+PG_UR
 @@:
-        lodsd
-        and     eax, 0xFFFFF000
-        or      eax, edx
-        stosd
-        loop    @B
+        mov     edi, [page_tabs+esi+ebx*4]
+        and     edi, 0xFFFFF000
+        or      edi, edx
+        mov     [page_tabs+eax+ebx*4], edi
+        inc     ebx
+        dec     ecx
+        jnz     @B
 
-        xor     edx, edx
+        mov     ecx, [current_process]
+        shl     ebx, 12
+        add     [ecx+PROC.mem_used], ebx
+        add     ecx, PROC.heap_lock
+        call    mutex_unlock
 
         cmp     [owner_access], 0
-        jne     .fail
+        jz      .exit
+        mov     [edx_ret], 0
+
 .exit:
-        mov     edx, [size]
-.fail:
         mov     eax, [mapped]
-
-        popfd
-        pop     edi
-        pop     esi
-        pop     ebx
+        mov     edx, [edx_ret]
         ret
 .cleanup:
-        mov     [size], edx
         mov     eax, esi
         call    free
+.exit_unlock:
+        mov     ecx, shmem_list_mutex
+        call    mutex_unlock
         jmp     .exit
 
+.cleanup3:
+        mov     ecx, [current_process]
+        add     ecx, PROC.heap_lock
+        call    mutex_unlock
+        mov     eax, edi
+        call    free
 .cleanup2:
-        mov     [size], edx
-        mov     eax, edi
-        call    destroy_smap
+        call    dereference_smem
         jmp     .exit
 endp
 
@@ -1489,46 +1539,52 @@
 align 4
 proc shmem_close stdcall, name:dword
 
-        mov     eax, [name]
-        test    eax, eax
+        cmp     [name], 0
         jz      .fail
 
         push    esi
         push    edi
-        pushfd
-        cli
 
-        mov     esi, [current_slot]
-        add     esi, APP_OBJ_OFFSET
+        mov     ecx, [current_process]
+        lea     edi, [ecx+PROC.smap_list]
+        add     ecx, PROC.heap_lock
+        call    mutex_lock
+        mov     esi, edi
+
 .next:
-        mov     eax, [esi+APPOBJ.fd]
-        test    eax, eax
-        jz      @F
+        mov     edi, [edi+SMAP.fd]
+        cmp     edi, esi
+        je      .notfound
 
-        cmp     eax, esi
-        mov     esi, eax
-        je      @F
-
-        cmp     [eax+SMAP.magic], 'SMAP'
+        cmp     [edi+SMAP.type], SMAP_TYPE_SMEM
         jne     .next
 
-        mov     edi, [eax+SMAP.parent]
-        test    edi, edi
-        jz      .next
+        mov     eax, [edi+SMAP.parent]
+        add     eax, SMEM.name
 
-        lea     edi, [edi+SMEM.name]
-        stdcall strncmp, [name], edi, 32
+        stdcall strncmp, [name], eax, 32
         test    eax, eax
         jne     .next
 
-        stdcall user_free, [esi+SMAP.base]
+        mov     eax, [edi+SMAP.fd]
+        mov     edx, [edi+SMAP.bk]
+        mov     [eax+SMAP.bk], edx
+        mov     [edx+SMAP.fd], eax
 
-        mov     eax, esi
-        call    [esi+APPOBJ.destroy]
-@@:
-        popfd
+        mov     ecx, [current_process]
+        add     ecx, PROC.heap_lock
+        call    mutex_unlock
+
+        stdcall destroy_smap, [current_process]
+
+.exit:
         pop     edi
         pop     esi
 .fail:
         ret
+.notfound:
+        mov     ecx, [current_process]
+        add     ecx, PROC.heap_lock
+        call    mutex_unlock
+        jmp     .exit
 endp
Index: kernel/trunk/core/memory.inc
===================================================================
--- kernel/trunk/core/memory.inc	(revision 6766)
+++ kernel/trunk/core/memory.inc	(working copy)
@@ -564,7 +564,7 @@
         push    ebx               ;that is locals: .err_addr = cr2
         inc     [pg_data.pages_faults]
 
-        mov     eax, [pf_err_code]
+        mov     esi, [pf_err_code]
 
         cmp     ebx, OS_BASE      ;ebx == .err_addr
         jb      .user_space       ;страница в памяти приложения ;
@@ -572,6 +572,7 @@
         cmp     ebx, page_tabs
         jb      .kernel_space     ;страница в памяти ядра
 
+        xor     eax, eax
         cmp     ebx, kernel_tabs
         jb      .alloc;.app_tabs  ;таблицы страниц приложения ;
                                   ;просто создадим одну
@@ -580,9 +581,29 @@
         mov     esp, ebp
         pop     ebx               ;restore exception number (#PF)
         ret
+.fail_maybe_unlock:
+        test    esi, esi
+        jz      .fail
+.fail_unlock:
+        mov     ecx, [current_process]
+        add     ecx, PROC.heap_lock
+        call    mutex_unlock
+        jmp     .fail
 
 .user_space:
-        test    eax, PG_READ
+; PF entry in IDT is interrupt gate, so up to this moment
+; atomicity was guaranteed by cleared IF.
+; It is inpractical to guard all modifications in the page table by cli/sti,
+; so enable interrupts and acquire the address space lock.
+; Unfortunately, that enables the scenario when the fault of current thread
+; is resolved by another thread when the current thread waits in mutex_lock,
+; so watch out: in lock-protected section we can find out that
+; there is no error already.
+        sti
+        mov     ecx, [current_process]
+        add     ecx, PROC.heap_lock
+        call    mutex_lock
+        test    esi, PG_READ
         jnz     .err_access       ;Страница присутствует
                                   ;Ошибка доступа ?
 
@@ -589,28 +610,36 @@
         shr     ebx, 12
         mov     ecx, ebx
         shr     ecx, 10
-        mov     edx, [master_tab+ecx*4]
-        test    edx, PG_READ
-        jz      .fail             ;таблица страниц не создана
+        test    dword [master_tab+ecx*4], PG_READ
+        jz      .fail_unlock      ;таблица страниц не создана
                                   ;неверный адрес в программе
 
         mov     eax, [page_tabs+ebx*4]
-        test    eax, 2
-        jz      .fail             ;адрес не зарезервирован для ;
+        test    eax, PG_READ
+        jnz     .exit_unlock ; already resolved by a parallel thread
+        test    eax, LAZY_ALLOC_PAGE
+        jz      .fail_unlock      ;адрес не зарезервирован для ;
                                   ;использования. Ошибка
+        test    eax, LAZY_ALLOC_UNREADABLE
+        jnz     .fail_unlock
 .alloc:
-        call    alloc_page
+        mov     esi, eax
+        call    alloc_zero_page
         test    eax, eax
-        jz      .fail
+        jz      .fail_maybe_unlock
 
-        stdcall map_page, [.err_addr], eax, PG_UWR
-
-        mov     edi, [.err_addr]
-        and     edi, 0xFFFFF000
-        mov     ecx, 1024
-        xor     eax, eax
-       ;cld     ;caller is duty for this
-        rep stosd
+        mov     edx, PG_UWR
+        test    esi, LAZY_ALLOC_UNWRITABLE
+        jz      @f
+        mov     edx, PG_UR
+@@:
+        stdcall map_page, [.err_addr], eax, edx
+        mov     ecx, [current_process]
+        add     [ecx+PROC.mem_used], 0x1000
+.exit_unlock:
+        mov     ecx, [current_process]
+        add     ecx, PROC.heap_lock
+        call    mutex_unlock
 .exit:  ;iret with repeat fault instruction
         add     esp, 12;clear in stack: locals(.err_addr) + #PF + ret_to_caller
         restore_ring3_context
@@ -617,47 +646,67 @@
         iretd
 
 .err_access:
-; access denied? this may be a result of copy-on-write protection for DLL
-; check list of HDLLs
+; access denied? this may be a result of copy-on-write protection
+; Check whether the problem has already been resolved
+; while we were waiting in mutex_lock.
+        mov     eax, ebx
+        shr     eax, 12
+        mov     eax, [page_tabs+eax*4]
+        test    eax, PG_READ
+        jz      .fail_unlock ; someone has free'd the page
+        test    eax, PG_USER
+        jz      .fail_unlock ; page is mprotect'ed without PROT_READ
+        test    eax, PG_WRITE
+        jnz     .exit_unlock ; someone has enabled write
+        test    eax, PG_SHARED
+        jz      .fail_unlock ; only shared pages can be copy-on-write
+; check list of mapped data
         and     ebx, not 0xFFF
-        mov     eax, [current_process]
-        mov     eax, [eax+PROC.dlls_list_ptr]
-        test    eax, eax
-        jz      .fail
-        mov     esi, [eax+HDLL.fd]
-.scan_hdll:
-        cmp     esi, eax
-        jz      .fail
-        mov     edx, ebx
-        sub     edx, [esi+HDLL.base]
-        cmp     edx, [esi+HDLL.size]
-        jb      .fault_in_hdll
-.scan_hdll.next:
-        mov     esi, [esi+HDLL.fd]
-        jmp     .scan_hdll
-.fault_in_hdll:
-; allocate new page, map it as rw and copy data
-        call    alloc_page
-        test    eax, eax
-        jz      .fail
-        stdcall map_page, ebx, eax, PG_UWR
-        mov     edi, ebx
-        mov     ecx, 1024
-        sub     ebx, [esi+HDLL.base]
-        mov     esi, [esi+HDLL.parent]
-        mov     esi, [esi+DLLDESCR.data]
-        add     esi, ebx
-        rep movsd
-        jmp     .exit
+        call    find_smap_by_address
+        test    esi, esi
+        jz      .fail_unlock
+; ignore children of SMEM, only children of PEDESCR can have copy-on-write data
+        cmp     [esi+SMAP.type], SMAP_TYPE_PE
+        jnz     .fail_unlock
+        shr     edi, 12
+; lock page array in PEDESCR
+        mov     esi, [esi+SMAP.parent]
+        lea     ecx, [esi+PEDESCR.page_array_lock]
+        push    eax
+        call    mutex_lock
+        pop     eax
+; check whether the page is shared
+; PG_SHARED flag could be set by lock_and_map_page
+        xor     eax, [esi+sizeof.PEDESCR+edi*4]
+        test    eax, not 0xFFF
+        jnz     .fail_unlock2
+; check whether write is allowed by section attributes
+        mov     eax, [esi+sizeof.PEDESCR+edi*4]
+        test    eax, IMAGE_SCN_MEM_WRITE shr 20
+        jz      .fail_unlock2
+; if we're faulting on the page which was originally shareable writable,
+; it means that someone has disabled writing with mprotect; fail
+        test    eax, IMAGE_SCN_MEM_SHARED shr 20
+        jnz     .fail_unlock2
+        stdcall pe_copy_on_write, PG_UWR
+        jc	.fail_unlock2
+.exit_unlock2:
+        lea     ecx, [esi+PEDESCR.page_array_lock]
+        call    mutex_unlock
+        jmp     .exit_unlock
+.fail_unlock2:
+        lea     ecx, [esi+PEDESCR.page_array_lock]
+        call    mutex_unlock
+        jmp     .fail_unlock
 
 .kernel_space:
-        test    eax, PG_READ
+        test    esi, PG_READ
         jz      .fail   ;страница не присутствует
 
-        test    eax, 12 ;U/S (+below)
+        test    esi, 12 ;U/S (+below)
         jnz     .fail   ;приложение обратилось к памяти
                         ;ядра
-       ;test    eax, 8
+       ;test    esi, 8
        ;jnz     .fail   ;установлен зарезервированный бит
                         ;в таблицах страниц. добавлено в P4/Xeon
 
@@ -677,7 +726,7 @@
         jz      .fail
 
         push    eax
-        stdcall map_page, [.err_addr], eax, dword PG_SWR
+        stdcall map_page, [.err_addr], eax, PG_SWR
         pop     eax
         mov     edi, [.err_addr]
         and     edi, -4096
@@ -696,9 +745,274 @@
         jmp     .exit
 endp
 
+; Sometimes we can just allocate a page and let the caller fill it.
+; Sometimes we need a zero-filled page, but we can zero it at the target.
+; Sometimes we need a zero-filled page before mapping to the target.
+; This function is for the last case.
+; out: eax = physical page
+; destroys: nothing
+proc alloc_zero_page
+	call	alloc_page
+	test	eax, eax
+	jz	.nothing
+	spin_lock_irqsave zero_page_spinlock
+	push	ecx edx edi eax
+	mov	edi, [zero_page_tab]
+	stdcall	map_page, edi, [esp+4], PG_SWR
+	pushd	0 [esp+4] edi ; for map_page
+	mov	ecx, 0x1000/4
+	xor	eax, eax
+	rep stosd
+	call	map_page
+	pop	eax edi edx ecx
+	spin_unlock_irqrestore zero_page_spinlock
+.nothing:
+	ret
+endp
+
+; in: ebx = address
+; out if SMAP exists for this address: esi -> SMAP, edi = ebx - SMAP.base
+; out if SMAP does not exist: esi = 0
+proc find_smap_by_address
+        mov     edx, [current_process]
+        add     edx, PROC.smap_list
+        mov     esi, [edx+SMAP.fd]
+.scan:
+        cmp     esi, edx
+        jz      .fail
+        mov     edi, ebx
+        sub     edi, [esi+SMAP.base]
+        cmp     edi, [esi+SMAP.size]
+        jb      .exit
+        mov     esi, [esi+SMAP.fd]
+        jmp     .scan
+.fail:
+        xor     esi, esi
+.exit:
+        ret
+endp
+
+; Someone is about to write to copy-on-write page inside mapped PE.
+; Provide a page that can be written to.
+; in: esi -> PEDESCR
+; in: edi = page number inside PE
+; in: eax = [esi+sizeof.PEDESCR+edi*4]
+; in: ebx = address in process, must be page-aligned
+; in: [esp+4] = access rights for the new page
+; out: CF=0 - ok, CF=1 - error, no memory
+proc pe_copy_on_write
+; 1. Decrement reference counter unless it is 0xFF.
+        mov     edx, eax
+        and     edx, 0xFF
+        cmp     edx, 0xFF
+        jz      @f
+        dec     eax
+@@:
+; 2. If reference counter is zero now, transfer ownership from PEDESCR to the process.
+        test    eax, 0xFF
+        jnz     .alloc_copy
+        mov     dword [esi+sizeof.PEDESCR+edi*4], 0
+        and     eax, not 0xFFF
+.remap:
+        stdcall map_page, ebx, eax, [esp+4]
+        clc
+        ret     4
+.alloc_copy:
+; 3. Otherwise, store updated reference counter to PEDESCR,
+; allocate new page, map it as rw and copy data.
+        mov     [esi+sizeof.PEDESCR+edi*4], eax
+        stdcall kernel_alloc, 0x1000
+        test    eax, eax
+        jz      .error
+        push    esi
+        mov     esi, ebx
+        mov     edi, eax
+        mov     ecx, 0x1000/4
+        rep movsd
+        mov     esi, eax
+        call    get_pg_addr
+        push    eax
+        stdcall free_kernel_space, esi
+        pop     eax
+        pop     esi
+        jmp     .remap
+.error:
+        stc
+        ret     4
+endp
+
+PROT_READ = 1
+PROT_WRITE = 2
+PROT_EXEC = 4
+proc mprotect stdcall uses ebx esi edi, address:dword, size:dword, access:dword
+locals
+retval		dd	-1
+smap_ptr	dd	0
+endl
+	mov	ecx, [current_process]
+	add	ecx, PROC.heap_lock
+	call	mutex_lock
+	test	[access], not (PROT_READ+PROT_WRITE+PROT_EXEC)
+	jnz	.error
+	cmp	[size], 0
+	jz	.error
+	mov	eax, [address]
+	add	[size], eax
+	and	eax, not 0xFFF
+.addrloop:
+	mov	[address], eax
+	mov	ecx, eax
+	cmp	eax, OS_BASE
+	jae	.error
+	shr     eax, 22
+	test    byte [master_tab+eax*4], PG_READ
+	jz      .error
+	shr	ecx, 12
+	mov	eax, [page_tabs+ecx*4]
+	test	al, PG_READ
+	jnz	.page_present
+	test	al, LAZY_ALLOC_PAGE
+	jz	.error
+	cmp	[retval], -1
+	jnz	.skip_query
+	inc	[retval]
+	test	al, LAZY_ALLOC_UNREADABLE
+	jnz	@f
+	or	[retval], PROT_READ+PROT_EXEC
+@@:
+	test	al, LAZY_ALLOC_UNWRITABLE
+	jnz	@f
+	or	[retval], PROT_WRITE
+@@:
+.skip_query:
+	and	al, not (LAZY_ALLOC_UNREADABLE+LAZY_ALLOC_UNWRITABLE)
+	test	[access], PROT_READ
+	jnz	@f
+	or	al, LAZY_ALLOC_UNREADABLE
+@@:
+	test	[access], PROT_WRITE
+	jnz	@f
+	or	al, LAZY_ALLOC_UNWRITABLE
+@@:
+	mov	[page_tabs+ecx*4], eax
+	jmp	.nextpage
+.page_present:
+	test	eax, PG_SHARED
+	jnz	.page_shared
+.normal_page:
+	cmp	[retval], -1
+	jnz	.skip_query2
+	inc	[retval]
+	test	al, PG_USER
+	jz	@f
+	or	[retval], PROT_READ+PROT_EXEC
+@@:
+	test	al, PG_WRITE
+	jz	@f
+	or	[retval], PROT_WRITE
+@@:
+.skip_query2:
+	and	al, not (PG_USER+PG_WRITE)
+	test	[access], PROT_READ
+	jz	@f
+	or	al, PG_USER
+@@:
+	test	[access], PROT_WRITE
+	jz	@f
+	or	al, PG_WRITE
+@@:
+	mov	[page_tabs+ecx*4], eax
+	mov	eax, [address]
+	invlpg	[eax]
+	jmp	.nextpage
+.page_shared:
+	mov	esi, [smap_ptr]
+	test	esi, esi
+	jz	.find_smap
+	mov	edx, [address]
+	sub	edx, [esi+SMAP.base]
+	cmp	edx, [esi+SMAP.size]
+	jb	.found_smap
+.find_smap:
+	mov	ebx, [address]
+	call	find_smap_by_address
+	mov	[smap_ptr], esi
+	test	esi, esi
+	jz	.normal_page
+.found_smap:
+	cmp	[esi+SMAP.type], SMAP_TYPE_PE
+	jnz	.error
+	shr	edi, 12
+	mov	esi, [esi+SMAP.parent]
+	lea	ecx, [esi+PEDESCR.page_array_lock]
+	push	eax
+	call	mutex_lock
+	pop	eax
+	xor	eax, [esi+sizeof.PEDESCR+edi*4]
+	test	eax, not 0xFFF
+	jnz	.normal_page_unlock
+	mov	eax, [esi+sizeof.PEDESCR+edi*4]
+	test	eax, IMAGE_SCN_MEM_SHARED shr 20
+	jnz	.normal_page_unlock
+	cmp	[retval], -1
+	jnz	.skip_query3
+	mov	edx, [address]
+	shr	edx, 12
+	inc	[retval]
+	test	byte [page_tabs+edx*4], PG_USER
+	jz	@f
+	or	[retval], PROT_READ+PROT_EXEC
+@@:
+	test	eax, IMAGE_SCN_MEM_WRITE shr 20
+	jz	@f
+	or	[retval], PROT_WRITE
+@@:
+.skip_query3:
+	test	[access], PROT_WRITE
+	jz	.no_write
+	push	PG_SWR
+	test	[access], PROT_READ
+	jz	@f
+	pop	edx
+	push	PG_UWR
+@@:
+	call	pe_copy_on_write
+	lea	ecx, [esi+PEDESCR.page_array_lock]
+	call	mutex_unlock
+	jmp	.nextpage
+.normal_page_unlock:
+	lea	ecx, [esi+PEDESCR.page_array_lock]
+	call	mutex_unlock
+	mov	ecx, [address]
+	shr	ecx, 12
+	mov	eax, [page_tabs+ecx*4]
+	jmp	.normal_page
+.no_write:
+	lea	ecx, [esi+PEDESCR.page_array_lock]
+	call	mutex_unlock
+	mov	ecx, [address]
+	shr	ecx, 12
+	mov	eax, [page_tabs+ecx*4]
+	jmp	.skip_query2
+.nextpage:
+	mov	eax, [address]
+	add	eax, 0x1000
+	cmp	eax, [size]
+	jb	.addrloop
+.exit:
+	mov	ecx, [current_process]
+	add	ecx, PROC.heap_lock
+	call	mutex_unlock
+	mov	eax, [retval]
+	ret
+.error:
+	or	[retval], -1
+	jmp	.exit
+endp
+
 ; returns number of mapped bytes
-proc map_mem_ipc stdcall, lin_addr:dword,slot:dword,\
-                      ofs:dword,buf_size:dword,req_access:dword
+proc map_memEx stdcall uses ebx esi edi, lin_addr:dword,slot:dword,\
+                      ofs:dword,buf_size:dword,req_access:dword,where:dword
         locals
              count   dd ?
              process dd ?
@@ -710,17 +1024,20 @@
 
         mov     eax, [slot]
         shl     eax, 8
-        mov     eax, [SLOT_BASE+eax+APPDATA.process]
-        test    eax, eax
+        mov     ecx, [SLOT_BASE+eax+APPDATA.process]
+        test    ecx, ecx
         jz      .exit
 
-        mov     [process], eax
+        mov     [process], ecx
+        add     ecx, PROC.heap_lock
+        call    mutex_lock
+        mov     eax, [process]
         mov     ebx, [ofs]
         shr     ebx, 22
         mov     eax, [eax+PROC.pdt_0+ebx*4]                 ;get page table
-        mov     esi, [ipc_ptab]
+        mov     esi, [where]
         and     eax, 0xFFFFF000
-        jz      .exit
+        jz      .unlock_exit
         stdcall map_page, esi, eax, PG_SWR
 @@:
         mov     edi, [lin_addr]
@@ -728,18 +1045,17 @@
         mov     ecx, [buf_size]
         add     ecx, 4095
         shr     ecx, 12
-        inc     ecx                  ; ???????????
 
         mov     edx, [ofs]
         shr     edx, 12
         and     edx, 0x3FF
 .map:
-        stdcall safe_map_page, [slot], [req_access], [ofs]
-        jnc     .exit
+        stdcall lock_and_map_page, [slot], [req_access], [ofs]
+        jnc     .unlock_exit
         add     [count], PAGE_SIZE
         add     [ofs], PAGE_SIZE
         dec     ecx
-        jz      .exit
+        jz      .unlock_exit
 
         add     edi, PAGE_SIZE
         inc     edx
@@ -750,76 +1066,98 @@
         mov     eax, [process]
         mov     eax, [eax+PROC.pdt_0+ebx*4]
         and     eax, 0xFFFFF000
-        jz      .exit
+        jz      .unlock_exit
 
         stdcall map_page, esi, eax, PG_SWR
         xor     edx, edx
         jmp     .map
+.unlock_exit:
+        mov     ecx, [process]
+        add     ecx, PROC.heap_lock
+        call    mutex_unlock
 .exit:
         mov     eax, [count]
         ret
 endp
 
-proc map_memEx stdcall, lin_addr:dword,slot:dword,\
-                        ofs:dword,buf_size:dword,req_access:dword
+proc unmap_memEx stdcall uses ebx esi edi, lin_addr:dword,slot:dword,\
+                      ofs:dword,mapped_size:dword,pagedir:dword
         locals
-             count   dd ?
              process dd ?
         endl
 
-        mov     [count], 0
-        cmp     [buf_size], 0
+        cmp     [mapped_size], 0
         jz      .exit
 
         mov     eax, [slot]
         shl     eax, 8
-        mov     eax, [SLOT_BASE+eax+APPDATA.process]
-        test    eax, eax
-        jz      .exit
-
-        mov     [process], eax
+        mov     ecx, [SLOT_BASE+eax+APPDATA.process]
+        mov     [process], ecx
+        xor     eax, eax
+        test    ecx, ecx
+        jz      @f
+        add     ecx, PROC.heap_lock
+        call    mutex_lock
         mov     ebx, [ofs]
         shr     ebx, 22
+        mov     eax, [process]
         mov     eax, [eax+PROC.pdt_0+ebx*4]                 ;get page table
-        mov     esi, [proc_mem_tab]
+@@:
+        xor     esi, esi
         and     eax, 0xFFFFF000
-        jz      .exit
+        jz      @f
+        mov     esi, [pagedir]
         stdcall map_page, esi, eax, PG_SWR
 @@:
+        mov     ecx, shared_locked_mutex
+        call    mutex_lock
         mov     edi, [lin_addr]
-        and     edi, 0xFFFFF000
-        mov     ecx, [buf_size]
+        shr     edi, 12
+        mov     ecx, [mapped_size]
         add     ecx, 4095
         shr     ecx, 12
-        inc     ecx                  ; ???????????
+        mov     [mapped_size], ecx
 
         mov     edx, [ofs]
         shr     edx, 12
         and     edx, 0x3FF
+        lea     esi, [esi+edx*4]
 .map:
-        stdcall safe_map_page, [slot], [req_access], [ofs]
-        jnc     .exit
-        add     [count], PAGE_SIZE
-        add     [ofs], PAGE_SIZE
-        dec     ecx
-        jz      .exit
+        call    unlock_and_unmap_page
+        dec     [mapped_size]
+        jz      .done
 
-        add     edi, PAGE_SIZE
-        inc     edx
-        cmp     edx, 1024
+        inc     edi
+        add     esi, 4
+        test    esi, 0xFFF
         jnz     .map
 
         inc     ebx
+        xor     esi, esi
+        cmp     [process], 0
+        jz      .map
         mov     eax, [process]
         mov     eax, [eax+PROC.pdt_0+ebx*4]
         and     eax, 0xFFFFF000
-        jz      .exit
+        jz      .map
 
+        mov     esi, [pagedir]
         stdcall map_page, esi, eax, PG_SWR
-        xor     edx, edx
         jmp     .map
+.done:
+        mov     ecx, shared_locked_mutex
+        call    mutex_unlock
+        cmp     [process], 0
+        jz      .exit
+        mov     ecx, [process]
+        add     ecx, PROC.heap_lock
+        call    mutex_unlock
 .exit:
-        mov     eax, [count]
+        mov     eax, [pagedir]
+        mov     ecx, eax
+        shr     ecx, 12
+        mov     dword [page_tabs+ecx*4], 0
+        invlpg  [eax]
         ret
 endp
 
@@ -826,16 +1164,23 @@
 ; in: esi+edx*4 = pointer to page table entry
 ; in: [slot], [req_access], [ofs] on the stack
 ; in: edi = linear address to map
+; in: address space lock must be held
 ; out: CF cleared <=> failed
 ; destroys: only eax
-proc safe_map_page stdcall, slot:dword, req_access:dword, ofs:dword
+proc lock_and_map_page stdcall, slot:dword, req_access:dword, ofs:dword
+    locals
+        locked_descr dd ?
+    endl
+
         mov     eax, [esi+edx*4]
-        test    al, PG_READ
+        test    eax, PG_READ
         jz      .not_present
-        test    al, PG_WRITE
-        jz      .resolve_readonly
-; normal case: writable page, just map with requested access
+        test    eax, PG_SHARED
+        jnz     .resolve_shared
+; normal case: not shared allocated page, mark as shared and map with requested access
+        or      dword [esi+edx*4], PG_SHARED
 .map:
+        and     eax, not 0xFFF
         stdcall map_page, edi, eax, [req_access]
         stc
 .fail:
@@ -842,70 +1187,268 @@
         ret
 .not_present:
 ; check for alloc-on-demand page
-        test    al, 2
+        test    eax, LAZY_ALLOC_PAGE
         jz      .fail
 ; allocate new page, save it to source page table
         push    ecx
-        call    alloc_page
+        call    alloc_zero_page
         pop     ecx
         test    eax, eax
         jz      .fail
-        or      al, PG_UWR
+        or      eax, PG_READ+PG_SHARED
+        test    dword [esi+edx*4], LAZY_ALLOC_UNREADABLE
+        jnz     @f
+        or      eax, PG_USER
+@@:
+        test    dword [esi+edx*4], LAZY_ALLOC_UNWRITABLE
+        jnz     @f
+        or      eax, PG_WRITE
+@@:
         mov     [esi+edx*4], eax
         jmp     .map
-.resolve_readonly:
-; readonly page, probably copy-on-write
-; check: readonly request of readonly page is ok
-        test    [req_access], PG_WRITE
-        jz      .map
-; find control structure for this page
-        pushf
-        cli
-        cld
-        push    ebx ecx
+.resolve_shared:
+        push    ecx edx eax
+        mov     eax, sizeof.SHARED_LOCKED_PAGE
+        call    malloc
+        mov     [locked_descr], eax
+        test    eax, eax
+        jz      .fail_pop
+        mov     edx, [esp]
+        and     edx, not 0xFFF
+        mov     [eax+SHARED_LOCKED_PAGE.address], edx
         mov     eax, [slot]
         shl     eax, 8
         mov     eax, [SLOT_BASE+eax+APPDATA.process]
-        mov     eax, [eax+PROC.dlls_list_ptr]
-        test    eax, eax
-        jz      .no_hdll
-        mov     ecx, [eax+HDLL.fd]
-.scan_hdll:
+        mov     ecx, [eax+PROC.smap_list]
+        add     eax, PROC.smap_list
+.find_shared_parent:
         cmp     ecx, eax
-        jz      .no_hdll
-        mov     ebx, [ofs]
-        and     ebx, not 0xFFF
-        sub     ebx, [ecx+HDLL.base]
-        cmp     ebx, [ecx+HDLL.size]
-        jb      .hdll_found
-        mov     ecx, [ecx+HDLL.fd]
-        jmp     .scan_hdll
-.no_hdll:
-        pop     ecx ebx
-        popf
+        jz      .shared_orphan
+        mov     edx, [ofs]
+        sub     edx, [ecx+SMAP.base]
+        cmp     edx, [ecx+SMAP.size]
+        jb      .found_shared_parent
+        mov     ecx, [ecx+SMAP.fd]
+        jmp     .find_shared_parent
+.shared_abandoned:
+        call    mutex_unlock
+.shared_orphan:
+; no copy-on-write for orphans
+        test    dword [esp], PG_WRITE
+        jnz     @f
+        test    [req_access], PG_WRITE
+        jnz     .shared_forbidden
+@@:
+; locking the same normal page for second time:
+; the first lock_and_map_page has set PG_SHARED,
+; now we must cooperate with that other thread.
+        mov     ecx, shared_locked_mutex
+        call    mutex_lock
+        mov     eax, [locked_descr]
+        mov     [eax+SHARED_LOCKED_PAGE.parent], 0
+.shared_common:
+        mov     edx, [shared_locked_list+SHARED_LOCKED_PAGE.bk]
+        mov     [eax+SHARED_LOCKED_PAGE.fd], shared_locked_list
+        mov     [eax+SHARED_LOCKED_PAGE.bk], edx
+        mov     [edx+SHARED_LOCKED_PAGE.fd], eax
+        mov     [shared_locked_list+SHARED_LOCKED_PAGE.bk], edx
+        call    mutex_unlock
+        pop     eax edx ecx
+        jmp     .map
+.shared_forbidden_unlock:
+        call    mutex_unlock
+.shared_forbidden:
+        mov     eax, [locked_descr]
+        call    free
+.fail_pop:
+        pop     eax edx ecx
         clc
         ret
-.hdll_found:
-; allocate page, save it in page table, map it, copy contents from base
-        mov     eax, [ecx+HDLL.parent]
-        add     ebx, [eax+DLLDESCR.data]
-        call    alloc_page
+.found_shared_parent:
+        shr     edx, 12
+        mov     eax, [locked_descr]
+        mov     [eax+SHARED_LOCKED_PAGE.offs], edx
+        cmp     [ecx+SMAP.type], SMAP_TYPE_PE
+        jnz     .parent_smap
+        push    edx
+        mov     ecx, [ecx+SMAP.parent]
+        add     ecx, PEDESCR.page_array_lock
+        call    mutex_lock
+        pop     edx
+        mov     eax, [esp]
+        xor     eax, [ecx+sizeof.PEDESCR-PEDESCR.page_array_lock+edx*4]
+        test    eax, not 0xFFF
+        jnz     .shared_abandoned
+        test    dword [esp], PG_WRITE
+        jnz     @f
+        test    [req_access], PG_WRITE
+        jnz     .pedescr_try_cow
+@@:
+        mov     eax, [ecx+sizeof.PEDESCR-PEDESCR.page_array_lock+edx*4]
+        inc     eax
+        test    eax, 0xFF
+        jnz     @f
+        dec     eax
+@@:
+        mov     [ecx+sizeof.PEDESCR-PEDESCR.page_array_lock+edx*4], eax
+        push    ecx
+        mov     ecx, pe_list_mutex
+        call    mutex_lock
+        mov     eax, [esp]
+        inc     dword [eax+PEDESCR.refcount-PEDESCR.page_array_lock]
+        call    mutex_unlock
+        pop     ecx
+        call    mutex_unlock
+        sub     ecx, PEDESCR.page_array_lock
+        push    ecx
+.shared_common2:
+        mov     ecx, shared_locked_mutex
+        call    mutex_lock
+        mov     eax, [locked_descr]
+        pop     [eax+SHARED_LOCKED_PAGE.parent]
+        jmp     .shared_common
+.pedescr_try_cow:
+        mov     eax, [ecx+sizeof.PEDESCR-PEDESCR.page_array_lock+edx*4]
+        test	eax, IMAGE_SCN_MEM_WRITE shr 20
+        jz	@f
+        or      dword [esp], PG_WRITE
+@@:
+        dec     eax
+        test    eax, 0xFF
+        jnz     .pedescr_alloc_copy
+        mov     dword [ecx+sizeof.PEDESCR-PEDESCR.page_array_lock+edx*4], 0
+        call    mutex_unlock
+        mov     eax, [locked_descr]
+        call    free
+        pop     eax edx ecx
+        or      eax, PG_SHARED
+        mov     [esi+edx*4], eax
+        jmp     .map
+.pedescr_alloc_copy:
+        push    ecx edx
+        stdcall kernel_alloc, 0x1000
+        pop     edx ecx
         test    eax, eax
-        jz      .no_hdll
-        or      al, PG_UWR
+        jz      .shared_forbidden_unlock
+        dec     dword [ecx+sizeof.PEDESCR-PEDESCR.page_array_lock+edx*4]
+        push    ecx esi edi
+        mov     esi, edi
+        mov     edi, eax
+        stdcall map_page, esi, [ecx+sizeof.PEDESCR-PEDESCR.page_array_lock+edx*4], PG_READ
+        mov     ecx, 0x1000/4
+        rep movsd
+        sub     esi, 0x1000
+        sub     edi, 0x1000
+        mov     eax, edi
+        call    get_pg_addr
+        and     dword [esp+12], 0xFFF
+        or      dword [esp+12], eax
+        stdcall map_page, esi, eax, [req_access]
+        stdcall free_kernel_space, edi
+        pop     edi esi ecx
+        call    mutex_unlock
+        mov     eax, [locked_descr]
+        call    free
+        pop     eax edx ecx
+        or      eax, PG_SHARED
         mov     [esi+edx*4], eax
-        stdcall map_page, edi, eax, [req_access]
-        push    esi edi
-        mov     esi, ebx
-        mov     ecx, 4096/4
-        rep movsd
-        pop     edi esi
-        pop     ecx ebx
-        popf
         stc
         ret
+.parent_smap:
+        test    dword [esp], PG_WRITE
+        jnz     @f
+        test    [req_access], PG_WRITE
+        jz      .shared_forbidden
+@@:
+        push    [ecx+SMAP.parent]
+        mov     ecx, shmem_list_mutex
+        call    mutex_lock
+        mov     eax, [esp]
+        inc     dword [esp]
+        inc     [eax+SMEM.refcount]
+        call    mutex_unlock
+        jmp     .shared_common2
 endp
 
+; in: esi -> process page table entry or esi < 0x1000 if no page table entry
+; in: edi = page number for mapped copy
+; in: shared_locked_mutex is held
+; destroys eax, ecx, edx
+proc unlock_and_unmap_page
+        mov     edx, [page_tabs+edi*4]
+        and     edx, not 0xFFF
+        mov     dword [page_tabs+edi*4], 0
+        mov     eax, edi
+        shl     eax, 12
+        invlpg  [eax]
+        mov     eax, [shared_locked_list+SHARED_LOCKED_PAGE.fd]
+.check_list:
+        cmp     eax, shared_locked_list
+        jz      .not_in_list
+        cmp     edx, [eax+SHARED_LOCKED_PAGE.address]
+        jz      .found_in_list
+        mov     eax, [eax+SHARED_LOCKED_PAGE.fd]
+        jmp     .check_list
+.found_in_list:
+        push    esi
+        mov     esi, [eax+SHARED_LOCKED_PAGE.parent]
+        mov     edx, [eax+SHARED_LOCKED_PAGE.fd]
+        mov     ecx, [eax+SHARED_LOCKED_PAGE.bk]
+        mov     [edx+SHARED_LOCKED_PAGE.bk], ecx
+        mov     [ecx+SHARED_LOCKED_PAGE.fd], edx
+        test    esi, esi
+        jz      .orphan
+        btr     esi, 0
+        jc      .parent_smap
+        push    eax
+        lea     ecx, [esi+PEDESCR.page_array_lock]
+        call    mutex_lock
+        mov     edx, [esp]
+        mov     edx, [edx+SHARED_LOCKED_PAGE.offs]
+        mov     eax, [esi+sizeof.PEDESCR+edx*4]
+        and     eax, 0xFF
+        cmp     eax, 0xFF
+        jz      .no_deref
+        mov     eax, [esi+sizeof.PEDESCR+edx*4]
+        dec     eax
+        test    eax, 0xFF
+        jnz     @f
+        call    free_page
+        xor     eax, eax
+@@:
+        mov     [esi+sizeof.PEDESCR+edx*4], eax
+.no_deref:
+        lea     ecx, [esi+PEDESCR.page_array_lock]
+        call    mutex_unlock
+        call    dereference_pe
+        pop     eax
+        call    free
+        pop     esi
+        ret
+.parent_smap:
+        call    free
+        call    dereference_smem
+        pop     esi
+        ret
+.orphan:
+        call    free
+        pop     esi
+        ret
+.not_in_list:
+        cmp     esi, 0x1000
+        jb      .just_free
+        mov     eax, [esi]
+        and     eax, not 0xFFF
+        cmp     eax, edx
+        jnz     .just_free
+        and     dword [esi], not PG_SHARED
+        ret
+.just_free:
+        mov     eax, edx
+        call    free_page
+        ret
+endp
+
 sys_IPC:
 ;input:
 ;  ebx=1 - set ipc buffer area
@@ -957,12 +1500,15 @@
            locals
              dst_slot   dd ?
              dst_offset dd ?
+             dst_ptr    dd ?
              buf_size   dd ?
              used_buf   dd ?
+             mapped_size dd ?
+             result     dd ?
            endl
 
-        pushf
-        cli
+        mov     ecx, ipc_mutex
+        call    mutex_lock
 
         mov     eax, [PID]
         call    pid_to_slot
@@ -974,6 +1520,7 @@
         mov     edi, [eax+SLOT_BASE+APPDATA.ipc_start] ;is ipc area defined?
         test    edi, edi
         jz      .no_ipc_area
+        mov     [dst_ptr], edi
 
         mov     ebx, edi
         and     ebx, 0xFFF
@@ -992,20 +1539,33 @@
         pop     edi esi
 @@:
         mov     [used_buf], ecx
-        stdcall map_mem_ipc, ecx, [dst_slot], \
-                edi, esi, PG_SWR
+        stdcall map_memEx, ecx, [dst_slot], \
+                edi, esi, PG_SWR, [ipc_ptab]
+        mov     [mapped_size], eax
+        mov     [result], 3 ; buffer overflow
+        sub     eax, [dst_offset]
+        jc      .no_copy_data
+        cmp     [buf_size], eax
+        jb      @f
+        mov     [buf_size], eax
+@@:
+        cmp     [buf_size], 8
+        jb      .no_copy_data
 
+        mov     [result], 2 ; ipc blocked
         mov     edi, [dst_offset]
         add     edi, [used_buf]
         cmp     dword [edi], 0
-        jnz     .ipc_blocked          ;if dword [buffer]<>0 - ipc blocked now
+        jnz     .no_copy_data         ;if dword [buffer]<>0 - ipc blocked now
 
+        mov     [result], 3 ; buffer overflow
         mov     edx, dword [edi+4]
         lea     ebx, [edx+8]
         add     ebx, [msg_size]
         cmp     ebx, [buf_size]
-        ja      .buffer_overflow       ;esi<0 - not enough memory in buffer
+        ja      .no_copy_data          ;esi<0 - not enough memory in buffer
 
+        mov     [result], 0
         mov     dword [edi+4], ebx
         mov     eax, [TASK_BASE]
         mov     eax, [eax+0x04]        ;eax - our PID
@@ -1019,56 +1579,35 @@
        ;    add esi, new_app_base
         cld
         rep movsb
+.no_copy_data:
+        stdcall unmap_memEx, [used_buf], [dst_slot], [dst_ptr], [mapped_size], [ipc_ptab]
 
-        mov     ebx, [ipc_tmp]
-        mov     edx, ebx
-        shr     ebx, 12
-        xor     eax, eax
-        mov     [page_tabs+ebx*4], eax
-        invlpg  [edx]
-
-        mov     ebx, [ipc_pdir]
-        mov     edx, ebx
-        shr     ebx, 12
-        xor     eax, eax
-        mov     [page_tabs+ebx*4], eax
-        invlpg  [edx]
-
-        mov     ebx, [ipc_ptab]
-        mov     edx, ebx
-        shr     ebx, 12
-        xor     eax, eax
-        mov     [page_tabs+ebx*4], eax
-        invlpg  [edx]
-
+        cmp     [result], 0
+        jnz     @f
         mov     eax, [dst_slot]
         shl     eax, 8
         or      [eax+SLOT_BASE+0xA8], dword 0x40
-        push    0
-        jmp     .ret
+@@:
+        mov     eax, [used_buf]
+        cmp     eax, [ipc_tmp]
+        je      @f
+        stdcall free_kernel_space, eax
+@@:
+        mov     ecx, ipc_mutex
+        call    mutex_unlock
+        mov     eax, [result]
+        ret
 .no_pid:
-        popf
+        mov     ecx, ipc_mutex
+        call    mutex_unlock
         mov     eax, 4
         ret
 .no_ipc_area:
-        popf
+        mov     ecx, ipc_mutex
+        call    mutex_unlock
         xor     eax, eax
         inc     eax
         ret
-.ipc_blocked:
-        push    2
-        jmp     .ret
-.buffer_overflow:
-        push    3
-.ret:
-        mov     eax, [used_buf]
-        cmp     eax, [ipc_tmp]
-        je      @f
-        stdcall free_kernel_space, eax
-@@:
-        pop     eax
-        popf
-        ret
 endp
 
 align 4
@@ -1105,7 +1644,7 @@
         cmp     ebx, 11
         jb      undefined_syscall
 
-        cmp     ebx, 27
+        cmp     ebx, 30
         ja      undefined_syscall
 
         jmp     dword [f68call+ebx*4-11*4]
@@ -1210,6 +1749,37 @@
         mov     [esp+SYSCALL_STACK._eax], eax
         ret
 
+.28:
+        cmp     ecx, OS_BASE
+        jae     .fail
+        stdcall load_file_maybe_pe, ecx
+        test    esi, esi
+        jz      .28.not_pe
+        stdcall map_pe_usermode, esi, eax, ebx
+        mov     [esp+32], eax
+        ret
+.28.resolve_fail:
+        movi    eax, -5
+        jmp     .28.error
+.28.not_pe:
+        cmp     eax, -0x1000
+        ja      .28.error
+        stdcall kernel_free, eax
+        movi    eax, -31
+.28.error:
+        mov     [esp+32], eax
+        ret
+
+.29:
+        stdcall unmap_pe_usermode, ecx
+        mov     [esp+32], eax
+        ret
+
+.30:
+        stdcall mprotect, edx, esi, ecx
+        mov     [esp+32], eax
+        ret
+
 .fail:
         xor     eax, eax
         mov     [esp+SYSCALL_STACK._eax], eax
@@ -1236,6 +1806,9 @@
            dd f68.25   ; unmask exception
            dd f68.26   ; user_unmap
            dd f68.27   ; load_file_umode
+           dd f68.28   ; map_pe_usermode
+           dd f68.29   ; unmap_pe_usermode
+           dd f68.30   ; mprotect
 
 
 align 4
Index: kernel/trunk/core/peuser.inc
===================================================================
--- kernel/trunk/core/peuser.inc	(revision 0)
+++ kernel/trunk/core/peuser.inc	(working copy)
@@ -0,0 +1,833 @@
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;                                                              ;;
+;; Copyright (C) KolibriOS team 2016. All rights reserved.      ;;
+;; Distributed under terms of the GNU General Public License    ;;
+;;                                                              ;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+; Checks whether the given file is already loaded as PE.
+; If so, returns pointer to PEDESCR which can be used for map_pe_usermode.
+;   out: eax = 0, ebx undefined
+;   out: esi -> PEDESCR
+; If not, loads the given file; if it is PE, creates PEDESCR;
+;   out: eax -> file data, ebx = file size
+;   out: esi -> PEDESCR
+; if it is not PE, returns loaded file as is.
+;   out: eax -> file data, ebx = file size
+;   out: esi = 0
+; On error:
+;   out: eax = negative error code, ebx = 0
+;   out: esi = 0
+proc load_file_maybe_pe stdcall uses edi, file_name:dword
+    locals
+      fileinfo rb 40
+      filedata dd ?
+      defaultbase dd ?
+      entry dd ?
+      stacksize dd ?
+    endl
+        and     [filedata], 0
+; 1. Lock the common mutex for PE list.
+        mov     ecx, pe_list_mutex
+        call    mutex_lock
+; 2. Check whether this PE file is already mapped somewhere.
+; 2a. Get the timestamp. If failed, pass filesystem error to the caller.
+        lea     eax, [fileinfo]
+        stdcall get_fileinfo, [file_name], eax
+        mov     edi, eax
+        neg     edi
+        jnz     .fail_unlock
+; 2b. Scan the list of PE files, for each file compare timestamp and name.
+; If all parameters match, go to 6. Otherwide, proceed to 3.
+        mov     esi, [pe_list.fd]
+.scan_existing:
+        cmp     esi, pe_list
+        jz      .load_new
+        mov     eax, dword [fileinfo+24]; last modified time
+        mov     edx, dword [fileinfo+28]; last modified date
+        cmp     dword [esi+PEDESCR.timestamp], eax
+        jnz     .continue_scan
+        cmp     dword [esi+PEDESCR.timestamp+4], edx
+        jnz     .continue_scan
+        stdcall strncmp, [esi+PEDESCR.name], [file_name], -1
+        test    eax, eax
+        jz      .already_loaded
+.continue_scan:
+        mov     esi, [esi+PEDESCR.fd]
+        jmp     .scan_existing
+
+; Either this file is not PE, or it has not been mapped yet.
+.load_new:
+; 3. Load and unpack file data.
+; If failed, return -5 "file not found".
+        stdcall load_file, [file_name]
+        movi    edi, -5
+        test    eax, eax
+        jz      .fail_unlock
+        mov     [filedata], eax
+        mov     dword [fileinfo+32], ebx
+; 4. Check that the file is valid PE, has image data and is not too large.
+; If not, pass the loaded file to the caller as is.
+        cmp     ebx, 40h
+        jb      .not_pe
+        cmp     word [eax], 'MZ'
+        jz      .check_mz
+        cmp     [eax+STRIPPED_PE_HEADER.Signature], STRIPPED_PE_SIGNATURE
+        jnz     .not_pe
+        mov     ecx, [eax+STRIPPED_PE_HEADER.SizeOfStackReserve]
+        mov     [stacksize], ecx
+        mov     ecx, [eax+STRIPPED_PE_HEADER.ImageBase]
+        mov     esi, [eax+STRIPPED_PE_HEADER.SizeOfImage]
+        mov     edi, [eax+STRIPPED_PE_HEADER.AddressOfEntryPoint]
+        jmp     .pe
+.check_mz:
+        mov     ecx, [eax+3Ch]
+        add     eax, ecx
+        add     ecx, IMAGE_NT_HEADERS.OptionalHeader
+        jc      .not_pe
+        cmp     ecx, ebx
+        ja      .not_pe
+        cmp     [eax+IMAGE_NT_HEADERS.Signature], 'PE'
+        jnz     .not_pe
+        movzx   edx, [eax+IMAGE_NT_HEADERS.FileHeader.SizeOfOptionalHeader]
+        cmp     edx, IMAGE_OPTIONAL_HEADER32.DataDirectory
+        jb      .not_pe
+        add     ecx, edx
+        jc      .not_pe
+        cmp     ecx, ebx
+        ja      .not_pe
+        cmp     [eax+IMAGE_NT_HEADERS.OptionalHeader.Magic], 10Bh
+        jnz     .not_pe
+        mov     ecx, [eax+IMAGE_NT_HEADERS.OptionalHeader.SizeOfStackReserve]
+        mov     [stacksize], ecx
+        mov     ecx, [eax+IMAGE_NT_HEADERS.OptionalHeader.ImageBase]
+        mov     esi, [eax+IMAGE_NT_HEADERS.OptionalHeader.SizeOfImage]
+        mov     edi, [eax+IMAGE_NT_HEADERS.OptionalHeader.AddressOfEntryPoint]
+.pe:
+        test    esi, esi
+        jz      .not_pe
+        cmp     esi, 16*1024*1024
+        ja      .not_pe
+        mov     [defaultbase], ecx
+        mov     [entry], edi
+        add     esi, 0xFFF
+        shr     esi, 12
+; 5. Allocate and initialize PEDESCR structure.
+; 5a. Calculate structure size: sizeof.PEDESCR + dword per image page + size of PE name.
+        mov     edi, [file_name]
+        mov     ecx, -1
+        xor     eax, eax
+        repnz scasb
+        not     ecx
+        lea     eax, [ecx+esi*4+sizeof.PEDESCR]
+; 5b. Allocate memory.
+; If failed, return -30 "no memory".
+        push    ecx
+        call    malloc
+        pop     ecx
+        movi    edi, -30
+        test    eax, eax
+        jz      .fail_and_free_data
+; 5c. Initialize PEDESCR structure.
+        mov     [eax+PEDESCR.size], esi
+        lea     edi, [eax+esi*4+sizeof.PEDESCR]
+        mov     esi, [file_name]
+        mov     [eax+PEDESCR.name], edi
+        rep movsb
+        mov     esi, eax
+        lea     edi, [eax+sizeof.PEDESCR]
+        mov     ecx, [eax+PEDESCR.size]
+        xor     eax, eax
+        rep stosd
+        mov     eax, dword [fileinfo+24]
+        mov     dword [esi+PEDESCR.timestamp], eax
+        mov     eax, dword [fileinfo+28]
+        mov     dword [esi+PEDESCR.timestamp+4], eax
+        mov     eax, [defaultbase]
+        mov     [esi+PEDESCR.defaultbase], eax
+        mov     eax, [entry]
+        mov     [esi+PEDESCR.entry], eax
+        mov     eax, [stacksize]
+        mov     [esi+PEDESCR.stacksize], eax
+        and     dword [esi+PEDESCR.refcount], 0; no SMAPs yet; later it will be incremented
+        lea     ecx, [esi+PEDESCR.page_array_lock]
+        call    mutex_init
+; 5d. Insert PEDESCR structure in tail of the common list.
+        mov     [esi+PEDESCR.fd], pe_list
+        mov     eax, [pe_list.bk]
+        mov     [pe_list.bk], esi
+        mov     [esi+PEDESCR.bk], eax
+        mov     [eax+PEDESCR.fd], esi
+.already_loaded:
+; We have got the PEDESCR structure,
+; either already-existed from step 2 or created at step 5.
+; In the last case we have also got the file data,
+; in the first case [filedata] is still zero.
+; 6. Increment reference counter in PEDESCR structure.
+        inc     [esi+PEDESCR.refcount]
+; 7. Release the common mutex for PE list.
+; We have got a new reference to our PEDESCR, it will not go away unexpectedly.
+        mov     ecx, pe_list_mutex
+        call    mutex_unlock
+        mov     eax, [filedata]
+        mov     ebx, dword [fileinfo+32]
+        ret
+.fail_and_free_data:
+        stdcall kernel_free, [filedata]
+.fail_unlock:
+        mov     ecx, pe_list_mutex
+        call    mutex_unlock
+.fail:
+        mov     eax, edi
+        xor     ebx, ebx
+        xor     esi, esi
+        ret
+.not_pe:
+        mov     ecx, pe_list_mutex
+        call    mutex_unlock
+        mov     eax, [filedata]
+        xor     esi, esi
+        ret
+endp
+
+proc map_pe_usermode stdcall uses ebx esi edi, descr:dword, filedata:dword, filesize:dword
+           locals
+             img_base     dd ?
+             peheader     dd ?
+             header_size  dd ?
+             num_sections dd ?
+             sections     dd ?
+             section_idx  dd ?
+             page_index   dd ?
+             page_offset  dd ?
+             cur_page     dd ?
+             cur_access   db ?
+                          rb 3
+             pages        dd ?
+             num_allocated_pages dd ?
+           endl
+
+; 1. Basic preparations.
+; 1a. Check that the process heap has been initialized.
+; Return -30 "no memory" if not.
+        mov     esi, [descr]
+        movi    edi, -30
+        mov     eax, [current_process]
+        cmp     [eax+PROC.heap_top], 0
+        jz      .fail_dereference
+; 1b. If filedata is passed, fill the required fields from header now.
+        mov     eax, [filedata]
+        mov     ebx, [filesize]
+        dec     edi ; -30 -> -31
+        test    eax, eax
+        jz      @f
+        call    .validate_header
+        jc      .fail_dereference
+@@:
+
+; 2. Generate array of pages for mapping in address space in the process.
+; It is possible to join this step with step 13, avoiding temporary allocation
+; and putting the result directly in the page table, but that would require
+; doing potentially long operations like loading/unpacking the file
+; while holding address space lock, which could block other threads
+; that just want to lazy-allocate their zero-only pages not related to PE.
+; So, keep generating and mapping separate.
+; 2a. Allocate memory.
+        inc     edi ; -31 -> -30
+        mov     eax, [esi+PEDESCR.size]
+        shl     eax, 2
+        call    malloc
+        test    eax, eax
+        jz      .fail_dereference
+        mov     [pages], eax
+; 2b. Acquire the lock.
+        lea     ecx, [esi+PEDESCR.page_array_lock]
+        call    mutex_lock
+; 2c. Prepare for loop over pages: set page index and page offset to zero.
+        xor     ecx, ecx
+        mov     [page_index], ecx
+        mov     [page_offset], ecx
+        mov     [num_allocated_pages], ecx
+.fill_pages:
+; 2d. For each page, test whether we need to regenerate it.
+; Pages that need to be regenerated are marked as zero in pages array.
+        mov     eax, [esi+sizeof.PEDESCR+ecx*4]
+        test    eax, eax
+        jz      .create_page
+; 2e. For each page that we do not need to regenerate,
+; increment reference counter if it is less than 0xFF
+; and go to 2t.
+        lea     edx, [eax+1]
+        test    edx, 0xFF
+        jz      .page_created
+        mov     [esi+sizeof.PEDESCR+ecx*4], edx
+        jmp     .page_created
+.create_page:
+; 2f. If the file has not been already loaded/unpacked,
+; do it now, validating the content.
+        cmp     [filedata], 0
+        jnz     @f
+        stdcall load_file, [esi+PEDESCR.name]
+        test    eax, eax
+        jz      .fail_free_pages
+        call    .validate_header
+        jc      .fail_free_pages
+@@:
+; 2h. Initialize for generating a page:
+; do not allocate a page until we will be sure that data are present,
+; there are no access rights yet.
+        and     [cur_page], 0
+        mov     [cur_access], 0
+; 2i. Check whether the page overlaps file header.
+; If not, go to 2m.
+        mov     eax, [page_offset]
+        cmp     eax, [header_size]
+        jae     .no_header
+; 2j. Allocate the page data.
+        stdcall kernel_alloc, 0x1000
+        test    eax, eax
+        jz      .fail_free_pages
+        mov     [cur_page], eax
+; 2k. Set access rights for header: readonly; copy header data.
+        mov     [cur_access], IMAGE_SCN_MEM_READ shr 28
+        mov     esi, [filedata]
+        mov     edi, eax
+        add     esi, [page_offset]
+        mov     ecx, [header_size]
+        sub     ecx, [page_offset]
+        cmp     ecx, 0x1000
+        jb      @f
+        mov     ecx, 0x1000
+@@:
+        mov     edx, ecx
+        shr     ecx, 2
+        rep movsd
+        mov     ecx, edx
+        and     ecx, 3
+        rep movsb
+; 2l. Fill the rest of the page with zeroes.
+        mov     ecx, 0x1000
+        sub     ecx, edx
+        mov     edx, ecx
+        shr     ecx, 2
+        and     edx, 3
+        xor     eax, eax
+        rep stosd
+        mov     ecx, edx
+        rep stosb
+.no_header:
+; 2m. Prepare for loop over sections.
+; Skip the loop if there are no sections.
+        mov     eax, [num_sections]
+        mov     ebx, [sections]
+        test    eax, eax
+        jz      .no_sections
+        mov     [section_idx], eax
+.sections_loop:
+; 2n. For every section, check whether it has data overlapped with
+; the current page; if so, allocate the page if not yet, copy the data
+; and fill rest of page with zeroes.
+; If data are present, there can be two cases:
+; - the current page has data from the beginning,
+; - first byte of the current page is not covered by the section.
+; The first case is typical, the second case is rare.
+; If the page has not been allocated yet, we can optimize by storing zeroes
+; only in areas that are not covered by the current section.
+; However, this becomes twisted in the second case,
+; so don't bother to optimize the rare case.
+        cmp     [ebx+COFF_SECTION.SizeOfRawData], 0
+        jz      .section_data_done
+        mov     esi, [page_offset]
+        sub     esi, [ebx+COFF_SECTION.VirtualAddress]
+        cmp     esi, [ebx+COFF_SECTION.SizeOfRawData]
+        jb      .beginning_inside
+        add     esi, 1000h
+        jnc     .section_data_done
+        jz      .section_data_done
+; Rare case: there is an overlap, but the first byte is not covered.
+; If the page has not been allocated, allocate it now and store 4K zeroes.
+        cmp     [cur_page], 0
+        jnz     @f
+        stdcall kernel_alloc, 0x1000
+        test    eax, eax
+        jz      .fail_free_pages
+        mov     [cur_page], eax
+        mov     edi, eax
+        xor     eax, eax
+        mov     ecx, 0x1000/4
+        rep stosd
+@@:
+        mov     edi, [ebx+COFF_SECTION.VirtualAddress]
+        and     edi, 0xFFF
+        xor     esi, esi
+.copy_data:
+        mov     eax, [ebx+COFF_SECTION.SizeOfRawData]
+        sub     eax, esi
+        mov     ecx, 0x1000
+        sub     ecx, edi
+        add     edi, [cur_page]
+        cmp     ecx, eax
+        jb      @f
+        mov     ecx, eax
+@@:
+        add     esi, [filedata]
+        add     esi, [ebx+COFF_SECTION.PtrRawData]
+        mov     edx, ecx
+        shr     ecx, 2
+        and     edx, 3
+        rep movsd
+        mov     ecx, edx
+        rep movsb
+        jmp     .section_data_done
+.beginning_inside:
+; Normal case: do not store zeroes which will be immediately overwritten.
+        xor     edi, edi
+        cmp     [cur_page], edi
+        jnz     .copy_data
+        stdcall kernel_alloc, 0x1000
+        test    eax, eax
+        jz      .fail_free_pages
+        mov     [cur_page], eax
+        mov     edi, eax
+        mov     ecx, [ebx+COFF_SECTION.SizeOfRawData]
+        sub     ecx, esi
+        cmp     ecx, 0x1000
+        jb      @f
+        mov     ecx, 0x1000
+@@:
+        add     esi, [filedata]
+        add     esi, [ebx+COFF_SECTION.PtrRawData]
+        mov     edx, ecx
+        shr     ecx, 2
+        rep movsd
+        mov     ecx, edx
+        and     ecx, 3
+        rep movsb
+        mov     ecx, 0x1000
+        sub     ecx, edx
+        mov     edx, ecx
+        shr     ecx, 2
+        and     edx, 3
+        xor     eax, eax
+        rep stosd
+        mov     ecx, edx
+        rep stosb
+.section_data_done:
+; 2o. Get size of the section header.
+; Characteristics is the last dword in both
+; COFF_SECTION and STRIPPED_PE_SECTION, so this helps to access it.
+        movi    ecx, sizeof.STRIPPED_PE_SECTION
+        cmp     [peheader], 0
+        jz      @f
+        mov     cl, sizeof.COFF_SECTION
+@@:
+; 2p. If the current page intersects virtual address range of the section,
+; update access rights using section access rights.
+        cmp     [ebx+COFF_SECTION.VirtualSize], 0
+        jz      .section_access_done
+        mov     esi, [page_offset]
+        sub     esi, [ebx+COFF_SECTION.VirtualAddress]
+        cmp     esi, [ebx+COFF_SECTION.VirtualSize]
+        jb      @f
+        add     esi, 0x1000
+        jnc     .section_access_done
+        jz      .section_access_done
+@@:
+        mov     eax, [ebx+ecx-4]
+        shr     eax, 28
+        or      [cur_access], al
+.section_access_done:
+; 2q. Advance to the next section, while there are sections left.
+        add     ebx, ecx
+        dec     [section_idx]
+        jnz     .sections_loop
+.no_sections:
+; 2r. Shareable pages can not be lazy-allocated
+; even if they only contain uninitialized data.
+; If the page is shareable and has not been allocated yet, do it now.
+        test    [cur_access], IMAGE_SCN_MEM_SHARED shr 28
+        jz      @f
+        cmp     [cur_page], 0
+        jnz     @f
+        stdcall kernel_alloc, 0x1000
+        test    eax, eax
+        jz      .fail_free_pages
+        mov     [cur_page], eax
+        mov     edi, eax
+        xor     eax, eax
+        mov     ecx, 0x1000/4
+        rep stosd
+@@:
+; 2s. Get and store the item for page array: 0xFF for pages with zeroes,
+; physical address of the page plus 1 for reference counter otherwise,
+; with access rights in bits 8-11 in both cases.
+        mov     edi, 0xFF
+        mov     eax, [cur_page]
+        test    eax, eax
+        jz      @f
+        call    get_pg_addr
+        lea     edi, [eax+1]
+        stdcall free_kernel_space, [cur_page]
+@@:
+        movzx   eax, [cur_access]
+        shl     eax, 8
+        or      eax, edi
+        mov     ecx, [page_index]
+        mov     esi, [descr]
+        mov     [esi+sizeof.PEDESCR+ecx*4], eax
+.page_created:
+; 2t. Transform the item from page array to page table entry:
+; - drop reference counter,
+; - map zero-only page to LAZY_ALLOC_PAGE
+;   with optional flags LAZY_ALLOC_{UNREADABLE,UNWRITABLE},
+;   PF handler will lazy-allocate it;
+; - for pages with data,
+;   map readable and executable to user bit,
+;   for shareable pages map writable to writable bit,
+;   for non-shareable pages ignore writable to support copy-on-write.
+        mov     edx, eax
+        and     eax, not 0xFFF
+        jz      .page_set_zero
+        inc     [num_allocated_pages]
+        or      eax, PG_READ+PG_SHARED
+        test    dh, (IMAGE_SCN_MEM_READ+IMAGE_SCN_MEM_EXECUTE) shr 28
+        jz      @f
+        or      al, PG_USER
+@@:
+        test    dh, IMAGE_SCN_MEM_SHARED shr 28
+        jz      @f
+        test    dh, IMAGE_SCN_MEM_WRITE shr 28
+        jz      @f
+        or      al, PG_WRITE
+@@:
+        jmp     .pte_generated
+.page_set_zero:
+        mov     al, LAZY_ALLOC_PAGE
+        test    dh, (IMAGE_SCN_MEM_READ+IMAGE_SCN_MEM_EXECUTE) shr 28
+        jnz     @f
+        or      al, LAZY_ALLOC_UNREADABLE
+@@:
+        test    dh, IMAGE_SCN_MEM_WRITE shr 28
+        jnz     @f
+        or      al, LAZY_ALLOC_UNWRITABLE
+@@:
+.pte_generated:
+        mov     edi, [pages]
+        mov     [edi+ecx*4], eax
+; 2u. Advance to the next page, until PEDESCR.size is reached.
+        inc     ecx
+        inc     [page_index]
+        add     [page_offset], 0x1000
+        cmp     ecx, [esi+PEDESCR.size]
+        jb      .fill_pages
+; 2v. Release the lock.
+        lea     ecx, [esi+PEDESCR.page_array_lock]
+        call    mutex_unlock
+; 3. Allocate a new SMAP.
+        movi    eax, sizeof.SMAP
+        call    malloc
+        test    eax, eax
+        jz      .fail_free_pages_unlocked
+        mov     ebx, eax
+; 4. Lock the address space so that a random PF from other thread
+; between end of step 5 and beginning of step 7 would not trash anything.
+        mov     ecx, [current_process]
+        add     ecx, PROC.heap_lock
+        call    mutex_lock
+; 5. Allocate space in the address space.
+; Prefer PEDESCR.defaultbase, but allow address anywhere else
+; if allocation at PEDESCR.defaultbase is not possible.
+        mov     edi, [esi+PEDESCR.size]
+        shl     edi, 12
+        stdcall user_alloc_at_nolock, [esi+PEDESCR.defaultbase], edi
+        test    eax, eax
+        jnz     @f
+        stdcall user_alloc_nolock, edi
+        test    eax, eax
+        jz      .user_alloc_failed
+@@:
+        mov     [img_base], eax
+; 6. Fill SMAP with values and insert it to the list of SMAPs.
+        mov     [ebx+SMAP.type], SMAP_TYPE_PE
+        mov     ecx, [current_process]
+        add     ecx, PROC.smap_list
+        mov     edx, [ecx+SMAP.fd]
+        mov     [ebx+SMAP.fd], edx
+        mov     [ebx+SMAP.bk], ecx
+        mov     [ecx+SMAP.fd], ebx
+        mov     [edx+SMAP.bk], ebx
+        mov     [ebx+SMAP.base], eax
+        mov     [ebx+SMAP.size], edi
+        mov     [ebx+SMAP.parent], esi
+; 7. Copy page table entries prepared at step 2 to the page table.
+        mov     edx, eax
+        shr     edx, 12
+        mov     ecx, [esi+PEDESCR.size]
+        mov     esi, [pages]
+        lea     edi, [page_tabs+edx*4]
+        rep movsd
+        mov     eax, [num_allocated_pages]
+        shl     eax, 12
+; 8. Release the address space lock.
+        mov     ecx, [current_process]
+        add     [ecx+PROC.mem_used], eax
+        add     ecx, PROC.heap_lock
+        call    mutex_unlock
+; 9. Cleanup and return allocated address.
+        mov     eax, [pages]
+        call    free
+        cmp     [filedata], 0
+        jz      @f
+        stdcall kernel_free, [filedata]
+@@:
+        mov     eax, [img_base]
+        ret
+.fail_and_free_data:
+        stdcall kernel_free, [filedata]
+.fail:
+        mov     eax, edi
+        ret
+.user_alloc_failed:
+        mov     ecx, [current_process]
+        add     ecx, PROC.heap_lock
+        call    mutex_unlock
+        mov     eax, ebx
+        call    free
+.fail_free_pages_unlocked:
+        lea     ecx, [esi+PEDESCR.page_array_lock]
+        call    mutex_lock
+.fail_free_pages:
+        mov     ecx, [page_index]
+        test    ecx, ecx
+        jz      .fail_free_pages_array
+        mov     eax, [esi+sizeof.PEDESCR+(ecx-1)*4]
+        mov     edx, eax
+        and     eax, not 0xFFF
+        jz      .fail_free_next
+        and     edx, 0xFF
+        cmp     edx, 0xFF
+        jz      .fail_free_next
+        dec     dword [esi+sizeof.PEDESCR+(ecx-1)*4]
+        dec     edx
+        jnz     .fail_free_next
+        mov     [esi+sizeof.PEDESCR+(ecx-1)*4], edx
+        call    free_page
+.fail_free_next:
+        dec     [page_index]
+        jmp     .fail_free_pages
+.fail_free_pages_array:
+        lea     ecx, [esi+PEDESCR.page_array_lock]
+        call    mutex_unlock
+        mov     eax, [pages]
+        call    free
+        movi    edi, -30
+.fail_dereference:
+        cmp     [filedata], 0
+        jz      @f
+        stdcall kernel_free, [filedata]
+@@:
+        call    dereference_pe
+        mov     eax, edi
+        ret
+
+.validate_header:
+        mov     [filedata], eax
+        cmp     ebx, 40h
+        jb      .validate_header.error
+        mov     [peheader], 0
+        cmp     word [eax], STRIPPED_PE_SIGNATURE
+        jz      .validate_header.stripped
+        cmp     word [eax], 'MZ'
+        jnz     .validate_header.error
+        mov     ecx, [eax+3Ch]
+        add     eax, ecx
+        add     ecx, IMAGE_NT_HEADERS.OptionalHeader
+        jc      .validate_header.error
+        cmp     ecx, ebx
+        ja      .validate_header.error
+        cmp     [eax+IMAGE_NT_HEADERS.Signature], 'PE'
+        jnz     .validate_header.error
+        mov     [peheader], eax
+        movzx   edx, [eax+IMAGE_NT_HEADERS.FileHeader.SizeOfOptionalHeader]
+        cmp     edx, IMAGE_OPTIONAL_HEADER32.DataDirectory
+        jb      .validate_header.error
+        add     ecx, edx
+        jc      .validate_header.error
+        cmp     ecx, ebx
+        ja      .validate_header.error
+        lea     edx, [eax+IMAGE_NT_HEADERS.OptionalHeader+edx]
+        mov     [sections], edx
+        movzx   edx, [eax+IMAGE_NT_HEADERS.FileHeader.NumberOfSections]
+        mov     [num_sections], edx
+        imul    edx, sizeof.COFF_SECTION
+        add     ecx, edx
+        jc      .validate_header.error
+        cmp     ecx, ebx
+        ja      .validate_header.error
+        mov     edx, [eax+IMAGE_NT_HEADERS.OptionalHeader.SizeOfHeaders]
+        mov     [header_size], edx
+        cmp     edx, ebx
+        ja      .validate_header.error
+        mov     edx, [num_sections]
+        mov     ecx, [sections]
+        test    edx, edx
+        jz      .validate_header.sections_ok
+@@:
+        mov     eax, [ecx+COFF_SECTION.PtrRawData]
+        add     eax, [ecx+COFF_SECTION.SizeOfRawData]
+        jc      .validate_header.error
+        cmp     eax, ebx
+        ja      .validate_header.error
+        add     ecx, sizeof.COFF_SECTION
+        dec     edx
+        jnz     @b
+.validate_header.sections_ok:
+.validate_header.ok:
+        clc
+        retn
+.validate_header.stripped:
+        movzx   ecx, [eax+STRIPPED_PE_HEADER.NumberOfRvaAndSizes]
+        lea     ecx, [sizeof.STRIPPED_PE_HEADER+ecx*8]
+        movzx   edx, [eax+STRIPPED_PE_HEADER.NumberOfSections]
+        mov     [num_sections], edx
+        imul    edx, sizeof.STRIPPED_PE_SECTION
+        add     edx, ecx
+        cmp     edx, ebx
+        ja      .validate_header.error
+        mov     edx, [eax+STRIPPED_PE_HEADER.SizeOfHeaders]
+        mov     [header_size], edx
+        cmp     edx, ebx
+        ja      .validate_header.error
+        add     ecx, eax
+        mov     [sections], ecx
+        mov     edx, [num_sections]
+        test    edx, edx
+        jz      .validate_header.stripped.sections_ok
+@@:
+        mov     eax, [ecx+STRIPPED_PE_SECTION.PtrRawData]
+        add     eax, [ecx+STRIPPED_PE_SECTION.SizeOfRawData]
+        jc      .validate_header.error
+        cmp     eax, ebx
+        ja      .validate_header.error
+        add     ecx, sizeof.STRIPPED_PE_SECTION
+        dec     edx
+        jnz     @b
+.validate_header.stripped.sections_ok:
+        clc
+        retn
+.validate_header.error:
+        stc
+        retn
+endp
+
+; in: edi -> SMAP
+; in: address space lock must be held
+proc release_pemap stdcall uses ebx esi, process:dword
+    locals
+        num_released_pages dd 0
+        mapped_pagedir dd -1
+    endl
+        mov     esi, [edi+SMAP.base]
+        mov     ebx, [edi+SMAP.parent]
+        shr     esi, 12
+        dec     esi
+        add     ebx, sizeof.PEDESCR
+        call    .get_page_tab_entry
+        mov     ecx, [eax]
+        and     ecx, not DONT_FREE_BLOCK
+        mov     [eax],  ecx
+        shr     ecx, 12
+        dec     ecx
+        jz      .released
+.release:
+        inc     esi
+        call    .get_page_tab_entry
+        mov     edx, [eax]
+        test    dl, 1
+        jz      .next
+        test    edx, PG_SHARED
+        jz      .next
+        mov     dword [eax], 0
+        inc     [num_released_pages]
+        xor     edx, [ebx]
+        test    edx, not 0xFFF
+        jnz     .next
+        mov     edx, [ebx]
+        mov     eax, edx
+        and     edx, 0xFF
+        cmp     edx, 0xFF
+        jz      .next
+        dec     eax
+        test    dword [ebx], IMAGE_SCN_MEM_SHARED shr 20
+        jnz     @f
+        test    eax, 0xFF
+        jnz     @f
+        call    free_page
+        xor     eax, eax
+@@:
+        mov     [ebx], eax
+.next:
+        add     ebx, 4
+        dec     ecx
+        jnz     .release
+        mov     eax, [num_released_pages]
+        shl     eax, 12
+        mov     edx, [process]
+        sub     [edx+PROC.mem_used], eax
+        cmp     [mapped_pagedir], -1
+        jz      .released
+        stdcall map_page, [tmp_task_ptab], 0, PG_UNMAP
+.released:
+        ret
+
+.get_page_tab_entry:
+        mov     eax, [process]
+        cmp     eax, [current_process]
+        jnz     @f
+        lea     eax, [page_tabs+esi*4]
+        retn
+@@:
+        push    edx
+        mov     edx, esi
+        shr     edx, 10
+        cmp     edx, [mapped_pagedir]
+        jz      @f
+        mov     [mapped_pagedir], edx
+        mov     eax, [eax+PROC.pdt_0+edx*4]
+        and     eax, not 0xFFF
+        stdcall map_page, [tmp_task_ptab], eax, PG_SWR
+@@:
+        mov     eax, [tmp_task_ptab]
+        mov     edx, esi
+        and     edx, 0x3FF
+        lea     eax, [eax+edx*4]
+        pop     edx
+        retn
+endp
+
+proc unmap_pe_usermode stdcall uses ebx esi edi, address:dword
+        mov     ecx, [current_process]
+        lea     edi, [ecx+PROC.smap_list]
+        add     ecx, PROC.heap_lock
+        call    mutex_lock
+        mov     esi, edi
+        mov     eax, [address]
+.scan:
+        mov     edi, [edi+SMAP.fd]
+        cmp     edi, esi
+        jz      .notfound
+        cmp     [edi+SMAP.base], eax
+        jnz     .scan
+        mov     eax, [edi+SMAP.fd]
+        mov     edx, [edi+SMAP.bk]
+        mov     [eax+SMAP.bk], edx
+        mov     [edx+SMAP.fd], eax
+        call    mutex_unlock
+        stdcall destroy_smap, [current_process]
+        xor     eax, eax
+        ret
+.notfound:
+        call    mutex_unlock
+        or      eax, -1
+        ret
+endp
Index: kernel/trunk/core/sys32.inc
===================================================================
--- kernel/trunk/core/sys32.inc	(revision 6766)
+++ kernel/trunk/core/sys32.inc	(working copy)
@@ -313,7 +313,7 @@
                                   ;incorrect address in the program
 
         mov     eax, [page_tabs+ebx*4]
-        test    eax, 2
+        test    eax, 1
         jz      .fail             ;address not reserved for use. error
 
         pop     ebx
Index: kernel/trunk/core/taskman.inc
===================================================================
--- kernel/trunk/core/taskman.inc	(revision 6766)
+++ kernel/trunk/core/taskman.inc	(working copy)
@@ -42,10 +42,30 @@
         filename_size   rd 1
         cmdline_size    rd 1
         path_string     rd 1
+        pedescr         rd 1
 ends
 
+; Pointer to this structure is passed as the third argument
+; to usermode PE loader by the kernel.
+struct kernel_init_data
+version         dw      ?
+flags           dw      ?
+syscall_method  dd      ?
+; either one of SYSCALL_METHOD_xxx or pointer to procedure
+exe_base        dd      ?
+stack_base      dd      ?
+stack_size      dd      ?
+exe_path        dd      ?
+command_line    dd      ?
+environment     dd      ?
+ends
+SYSCALL_METHOD_I40 = 1
+SYSCALL_METHOD_SYSENTER = 2
+SYSCALL_METHOD_SYSCALL = 3
+
 macro _clear_ op
-{  mov ecx, op/4
+{
+        mov     ecx, op/4
         xor     eax, eax
         cld
         rep stosd
@@ -88,6 +108,7 @@
         filename_size   rd  1
         cmdline_size    rd  1
         path_string     rd  1
+        pedescr         rd  1
     endl
 
         mov     [flags], edx
@@ -96,25 +117,32 @@
         mov     [path_string], eax
         mov     ebx, [ebp]
         stdcall get_full_file_name, eax, maxPathLength
+        mov     edi, -ERROR_FILE_NOT_FOUND
         test    eax, eax
         jz      .err_file
 
-        stdcall load_file, [path_string]
-        mov     esi, -ERROR_FILE_NOT_FOUND
-        test    eax, eax
-        jz      .err_file
-
+        stdcall load_file_maybe_pe, [path_string]
+        mov     [pedescr], esi
         mov     [file_base], eax
         mov     [file_size], ebx
+
+        test    esi, esi
+        jnz     .file_ok
+
+        mov     edi, eax
+        cmp     eax, -0x1000
+        ja      .err_file
+
         lea     ebx, [hdr_cmdline]
         call    test_app_header
-        mov     esi, -0x1F
+        mov     edi, -0x1F
         test    eax, eax
         jz      .err_hdr
 
+.file_ok:
         call    lock_application_table
         call    alloc_thread_slot
-        mov     esi, -0x20  ; too many processes
+        mov     edi, -0x20  ; too many processes
         test    eax, eax
         jz      .err_0
 
@@ -155,8 +183,15 @@
         add     [hdr_emem], ebx
 @@:
         mov     [cmdline_size], eax
+        xor     eax, eax
+        cmp     [pedescr], eax
+        jz      @f
+        mov     [hdr_eip], eax
+        mov     [hdr_esp], eax
+        mov     [hdr_emem], eax
+@@:
         stdcall create_process, [hdr_emem]
-        mov     esi, -30    ; no memory
+        mov     edi, -30    ; no memory
         test    eax, eax
         jz      .err_hdr
 
@@ -191,12 +226,17 @@
         ret
 
 .err_0:
+        mov     esi, [pedescr]
+        test    esi, esi
+        jz      @f
+        call    dereference_pe
+@@:
         call    unlock_application_table
 .err_hdr:
         stdcall kernel_free, [file_base]
 .err_file:
         stdcall kernel_free, [path_string]
-        mov     eax, esi
+        mov     eax, edi
         ret
 endp
 
@@ -318,13 +358,18 @@
         jz      .fail
         mov     [process], eax
 
-        lea     edi, [eax+PROC.heap_lock]
-        mov     ecx, (PROC.ht_free-PROC.heap_lock)/4
+        lea     edi, [eax+PROC.heap_base]
 
         list_init eax
         add     eax, PROC.thr_list
         list_init eax
+        add     eax, PROC.smap_list - PROC.thr_list
+        list_init eax
 
+        lea     ecx, [eax+PROC.heap_lock-PROC.smap_list]
+        call    mutex_init
+
+        mov     ecx, (PROC.ht_free-PROC.heap_base)/4
         xor     eax, eax
         cld
         rep stosd
@@ -358,6 +403,8 @@
 
         lea     edx, [edi-4096]
         mov     esi, [app_tabs]
+        test    esi, esi
+        jz      .no_page_dirs
 
 .alloc_page_dir:
         call    alloc_page
@@ -376,6 +423,7 @@
         dec     esi
         jnz     .alloc_page_dir
 
+.no_page_dirs:
         stdcall map_page, [tmp_task_ptab], 0, PG_UNMAP
         mov     eax, [process]
 
@@ -385,7 +433,7 @@
         ret
 .fail:
         mov     ecx, [process]
-        jcxz    @F
+        jecxz   @F
 
         call    destroy_process
 @@:
@@ -407,8 +455,6 @@
         mov     eax, [esi]
         test    eax, 1
         jz      .next
-        test    eax, 2
-        jz      .next
         test    eax, 1 shl 9
         jnz     .next                     ;skip shared pages
         call    free_page
@@ -434,8 +480,16 @@
         mov     esi, ecx
         list_del esi
 
-        mov     esi, [esi+PROC.dlls_list_ptr]
-        call    destroy_all_hdlls
+        lea     ebx, [esi+PROC.smap_list]
+        mov     edi, [esi+PROC.smap_list+SMAP.fd]
+.smap_list_destroy:
+        cmp     edi, ebx
+        jz      .smap_list_done
+        push    [edi+SMAP.fd]
+        stdcall destroy_smap, [esp+4]
+        pop     edi
+        jmp     .smap_list_destroy
+.smap_list_done:
 
         mov     esi, [esp]
         add     esi, PROC.pdt_0
@@ -559,6 +613,7 @@
          r_count    dd ?
          offset dd ?
          tmp_r_cnt  dd ?
+         mapped_size dd ?
        endl
 
         mov     [slot], eax
@@ -568,6 +623,8 @@
         mov     [offset], esi
 
         pushad
+        mov     ecx, proc_mem_mutex
+        call    mutex_lock
 .read_mem:
         mov     edx, [offset]
         mov     ebx, [tmp_r_cnt]
@@ -587,13 +644,14 @@
 
         push    ecx
         stdcall map_memEx, [proc_mem_map], \
-                [slot], ebx, ecx, PG_READ
+                [slot], ebx, ecx, PG_READ, [proc_mem_tab]
+        mov     [mapped_size], eax
         pop     ecx
 
         mov     esi, [offset]
         and     esi, 0xfff
         sub     eax, esi
-        jbe     .ret
+        jbe     .ret_unmap
         cmp     ecx, eax
         jbe     @f
         mov     ecx, eax
@@ -601,17 +659,26 @@
 @@:
         add     esi, [proc_mem_map]
         mov     edi, [buff]
-        mov     edx, ecx
+        push    ecx
         rep movsb
-        add     [r_count], edx
+        stdcall unmap_memEx, [proc_mem_map], \
+                [slot], ebx, [mapped_size], [proc_mem_tab]
+        pop     ecx
+        add     [r_count], ecx
 
-        add     [offset], edx
-        sub     [tmp_r_cnt], edx
+        add     [offset], ecx
+        sub     [tmp_r_cnt], ecx
         jnz     .read_mem
 .ret:
+        mov     ecx, proc_mem_mutex
+        call    mutex_unlock
         popad
         mov     eax, [r_count]
         ret
+.ret_unmap:
+        stdcall unmap_memEx, [proc_mem_map], \
+                [slot], ebx, [mapped_size], [proc_mem_tab]
+        jmp     .ret
 endp
 
 align 4
@@ -630,6 +697,7 @@
          w_count    dd ?
          offset dd ?
          tmp_w_cnt  dd ?
+         mapped_size dd ?
        endl
 
         mov     [slot], eax
@@ -639,7 +707,9 @@
         mov     [offset], esi
 
         pushad
-.read_mem:
+        mov     ecx, proc_mem_mutex
+        call    mutex_lock
+.write_mem:
         mov     edx, [offset]
         mov     ebx, [tmp_w_cnt]
 
@@ -657,13 +727,14 @@
         mov     ebx, [offset]
         push    ecx
         stdcall map_memEx, [proc_mem_map], \
-                [slot], ebx, ecx, PG_SWR
+                [slot], ebx, ecx, PG_SWR, [proc_mem_tab]
+        mov     [mapped_size], eax
         pop     ecx
 
         mov     edi, [offset]
         and     edi, 0xfff
         sub     eax, edi
-        jbe     .ret
+        jbe     .ret_unmap
         cmp     ecx, eax
         jbe     @f
         mov     ecx, eax
@@ -671,17 +742,25 @@
 @@:
         add     edi, [proc_mem_map]
         mov     esi, [buff]
-        mov     edx, ecx
+        push    ecx
         rep movsb
+        stdcall unmap_memEx, [proc_mem_map], \
+                [slot], ebx, [mapped_size], [proc_mem_tab]
+        pop     ecx
 
-        add     [w_count], edx
-        add     [offset], edx
-        sub     [tmp_w_cnt], edx
-        jnz     .read_mem
+        add     [w_count], ecx
+        add     [offset], ecx
+        sub     [tmp_w_cnt], ecx
+        jnz     .write_mem
 .ret:
+        mov     ecx, proc_mem_mutex
+        call    mutex_unlock
         popad
         mov     eax, [w_count]
         ret
+.ret_unmap:
+        stdcall unmap_memEx, [proc_mem_map], [slot], ebx, [mapped_size], [proc_mem_tab]
+        jmp     .ret
 endp
 
 ;ebx = 1 - kernel thread
@@ -824,6 +903,76 @@
         mov     ebp, [ebp+APPDATA.exec_params]
         test    ebp, ebp
         jz      .exit
+        cmp     [ebp+APP_HDR.pedescr], 0
+        jz      .init_legacy_app
+; init PE application
+        mov     eax, [current_process]
+        mov     [eax+PROC.mem_used], 0xF000 ; leave first 64K as unallocatable
+        call    init_heap
+        mov     eax, [current_process]
+        mov     [eax+PROC.mem_used], 0
+        stdcall map_pe_usermode, [ebp+APP_HDR.pedescr],\
+                [ebp+APP_HDR.img_base], [ebp+APP_HDR.img_size]
+        cmp     eax, -0x1000
+        ja      .failed
+        push    eax
+        stdcall load_file_maybe_pe, pe_loader_usermode
+        test    esi, esi
+        jz      .pe_loader_notfound
+        mov     edx, [esi+PEDESCR.entry]
+        mov     [esp+4+20h], edx
+        stdcall map_pe_usermode, esi, eax, ebx
+        cmp     eax, -0x1000
+        ja      .pe_loader_failed
+        add     [esp+4+20h], eax
+        push    eax
+        mov     eax, [ebp+APP_HDR.filename_size]
+        add     eax, [ebp+APP_HDR.cmdline_size]
+        add     eax, sizeof.kernel_init_data + 2
+        stdcall user_alloc, eax
+        test    eax, eax
+        jz      .failed
+        mov     ebx, eax
+        mov     dword [eax+kernel_init_data.version], 1 + (0 shl 16) ; version, flags
+        mov     [eax+kernel_init_data.syscall_method], SYSCALL_METHOD_I40
+        lea     edi, [eax+sizeof.kernel_init_data]
+        mov     [eax+kernel_init_data.exe_path], edi
+        mov     esi, [ebp+APP_HDR.path_string]
+        mov     ecx, [ebp+APP_HDR.filename_size]
+        rep movsb
+        mov     byte [edi], 0
+        inc     edi
+        mov     [eax+kernel_init_data.command_line], edi
+        lea     esi, [ebp+sizeof.APP_HDR]
+        mov     ecx, [ebp+APP_HDR.cmdline_size]
+        rep movsb
+        mov     byte [edi], 0
+        mov     ecx, [ebp+APP_HDR.pedescr]
+        mov     ecx, [ecx+PEDESCR.stacksize]
+        mov     [eax+kernel_init_data.stack_size], ecx
+        stdcall user_alloc, ecx
+        test    eax, eax
+        jz      .failed
+        mov     [ebx+kernel_init_data.stack_base], eax
+        add     eax, [ebx+kernel_init_data.stack_size]
+        sub     eax, 16
+        pop     dword [eax+4]
+        pop     [ebx+kernel_init_data.exe_base]
+        mov     dword [eax+8], 1 ; DLL_PROCESS_ATTACH
+        mov     dword [eax+12], ebx
+        mov     [esp+2Ch], eax
+        jmp     .common_tls
+.pe_loader_notfound:
+        cmp     eax, -0x1000
+        ja      .pe_loader_failed
+        stdcall kernel_free, eax
+.pe_loader_failed:
+        dbgstr 'Failed to load kolibri.dll'
+.failed:
+        stdcall kernel_free, [ebp+APP_HDR.path_string]
+        jmp     sys_end
+.init_legacy_app:
+; init MENUETxx application
         stdcall map_process_image, [ebp+APP_HDR._emem],\
                 [ebp+APP_HDR.img_base], [ebp+APP_HDR.img_size]
         mov     esi, [ebp+APP_HDR.path_string]
@@ -864,9 +1013,11 @@
         rep movsb
         mov     byte [edi], 0
 .check_tls_header:
+        stdcall free_kernel_space, [ebp+APP_HDR.img_base]
         cmp     word [6], '02'
-        jne     .cleanup
+        jne     .common
         call    init_heap
+.common_tls:
         stdcall user_alloc, 4096
         mov     edx, [current_slot]
         mov     [edx+APPDATA.tls_base], eax
@@ -876,8 +1027,7 @@
         mov     [tls_data_l+7], ah
         mov     dx, app_tls
         mov     fs, dx
-.cleanup:
-        stdcall free_kernel_space, [ebp+APP_HDR.img_base]
+.common:
         stdcall kernel_free, ebp
         mov     ebx, [current_slot]
         cmp     [ebx+APPDATA.debugger_slot], 0
Index: kernel/trunk/data32.inc
===================================================================
--- kernel/trunk/data32.inc	(revision 6766)
+++ kernel/trunk/data32.inc	(working copy)
@@ -179,6 +179,7 @@
         db      '/RD/1/KERNEL.MNT',0
 
 dev_data_path  db '/RD/1/DRIVERS/DEVICES.DAT',0
+pe_loader_usermode db '/rd/1/lib/kolibri.dll',0
 
 align 4
 
@@ -186,17 +187,17 @@
  .bk           dd shmem_list
  .fd           dd shmem_list
 
-dll_list:
- .bk           dd dll_list
- .fd           dd dll_list
+pe_list:
+ .bk           dd pe_list
+ .fd           dd pe_list
 
 pcidev_list:
  .bk           dd pcidev_list
  .fd           dd pcidev_list
 
-MAX_DEFAULT_DLL_ADDR = 0x80000000
-MIN_DEFAULT_DLL_ADDR = 0x70000000
-dll_cur_addr   dd MIN_DEFAULT_DLL_ADDR
+shared_locked_list:
+               dd shared_locked_list
+               dd shared_locked_list
 
 ; supported videomodes
 
@@ -374,6 +375,12 @@
 srv.fd              dd  ?
 srv.bk              dd  ?
 
+shmem_list_mutex    MUTEX
+pe_list_mutex       MUTEX
+shared_locked_mutex MUTEX
+proc_mem_mutex      MUTEX
+ipc_mutex           MUTEX
+
 LFBAddress          dd  ?
 
 PUTPIXEL            dd  ?
@@ -407,6 +414,7 @@
 proc_mem_tab        dd  ?
 
 tmp_task_ptab       dd  ?
+zero_page_tab       dd  ?
 
 default_io_map      dd  ?
 
Index: kernel/trunk/docs/sysfuncr.txt
===================================================================
--- kernel/trunk/docs/sysfuncr.txt	(revision 6766)
+++ kernel/trunk/docs/sysfuncr.txt	(working copy)
@@ -3590,6 +3590,67 @@
   eax - SF_SYS_MISC (68)
   ebx - SSF_LOAD_FILE (27)
 ======================================================================
+=========== Функция 68, подфункция 28 - загрузить PE-файл ============
+======================================================================
+Параметры:
+  * eax = 68 - номер функции
+  * ebx = 28 - номер подфункции
+  * ecx = указатель на строку с путём к файлу,
+    правила формирования строки указаны в описании функции 70.
+Возвращаемое значение:
+  * eax > 0xFFFFF000 - произошла ошибка, -eax = код ошибки
+  * eax <= 0xFFFFF000 - адрес загруженного файла
+Примечания:
+  * функция предназначена только для системного загрузчика внутри
+    kolibri.dll; загруженный файл ещё не готов к работе, ему требуется
+    донастройка. Вместо неё используйте
+    функцию dlopen() из kolibri.dll.
+======================================================================
+=========== Функция 68, подфункция 29 - выгрузить PE-файл ============
+======================================================================
+Параметры:
+  * eax = 68 - номер функции
+  * ebx = 29 - номер подфункции
+  * ecx = адрес загруженного PE-файла
+Возвращаемое значение:
+  * eax = 0 - успешно
+  * eax = -1 - адрес не соответствует никакому загруженному файлу
+Примечания:
+  * функция предназначена только для системного загрузчика внутри
+    kolibri.dll. Вместо неё используйте функцию dlclose()
+    из kolibri.dll.
+======================================================================
+==== Функция 68, подфункция 30 - изменить права доступа к памяти =====
+======================================================================
+Параметры:
+  * eax = 68 - номер функции
+  * ebx = 30 - номер подфункции
+  * ecx = новые права доступа: ноль или более из следующих бит:
+    * PROT_READ = 1 - разрешить чтение
+    * PROT_WRITE = 2 - разрешить запись
+    * PROT_EXEC = 4 - разрешить исполнение
+  * edx = начальный адрес участка памяти
+  * esi = размер участка памяти в байтах
+Возвращаемое значение:
+  * eax = -1 - ошибка
+  * иначе eax = старые права доступа
+Примечания:
+  * Функция изменяет права целым страницам (4096 байт). Функция
+    меняет права доступа у всех страниц, пересекающихся с запрошенным
+    участком.
+  * Функция считает ошибкой передачу участка памяти от функции 68.22.
+  * Если часть переданного участка памяти корректна, а часть - нет,
+    то функция возвращает ошибку, но не гарантируется, изменились ли
+    права доступа у корректной части.
+  * Если не было ошибки, то функция возвращает старые права доступа
+    у первой из запрошенных страниц.
+  * Текущая реализация не поддерживает разрешения исполнения отдельно
+    от чтения. Поэтому бит PROT_EXEC игнорируется на входе и копирует
+    разрешение на чтение на выходе.
+---------------------- Константы для регистров: ----------------------
+  eax - SF_SYS_MISC (68)
+  ebx - SSF_MPROTECT (30)
+======================================================================
 ======================== Функция 69 - отладка. =======================
 ======================================================================
 Процесс может загрузить другой процесс как отлаживаемый установкой
Index: kernel/trunk/kernel.asm
===================================================================
--- kernel/trunk/kernel.asm	(revision 6766)
+++ kernel/trunk/kernel.asm	(working copy)
@@ -389,6 +389,17 @@
         mov     ecx, application_table_mutex
         call    mutex_init
 
+        mov     ecx, shmem_list_mutex
+        call    mutex_init
+        mov     ecx, pe_list_mutex
+        call    mutex_init
+        mov     ecx, shared_locked_mutex
+        call    mutex_init
+        mov     ecx, proc_mem_mutex
+        call    mutex_init
+        mov     ecx, ipc_mutex
+        call    mutex_init
+
         mov     ecx, ide_mutex
         call    mutex_init
         mov     ecx, ide_channel1_mutex
@@ -572,6 +583,9 @@
         add     eax, ebx
         mov     [ipc_ptab], eax
 
+        add     eax, ebx
+        mov     [zero_page_tab], eax
+
         stdcall kernel_alloc, (unpack.LZMA_BASE_SIZE+(unpack.LZMA_LIT_SIZE shl \
                 (unpack.lc+unpack.lp)))*4
 
@@ -2841,30 +2855,23 @@
         mov     [bgrlockpid], eax
         cmp     [img_background], static_background_data
         jz      .nomem
-        stdcall user_alloc, [mem_BACKGROUND]
+        mov     ecx, [current_process]
+        add     ecx, PROC.heap_lock
+        call    mutex_lock
+        stdcall user_alloc_nolock, [mem_BACKGROUND]
         mov     [esp+32], eax
         test    eax, eax
-        jz      .nomem
+        jz      .nomem_unlock
         mov     ebx, eax
         shr     ebx, 12
-        or      dword [page_tabs+(ebx-1)*4], DONT_FREE_BLOCK
         mov     esi, [img_background]
         shr     esi, 12
         mov     ecx, [mem_BACKGROUND]
         add     ecx, 0xFFF
         shr     ecx, 12
-;--------------------------------------
-align 4
 .z:
-        mov     eax, [page_tabs+ebx*4]
-        test    al, 1
-        jz      @f
-        call    free_page
-;--------------------------------------
-align 4
-@@:
         mov     eax, [page_tabs+esi*4]
-        or      al, PG_UWR
+        or      eax, PG_UWR+PG_SHARED
         mov     [page_tabs+ebx*4], eax
         mov     eax, ebx
         shl     eax, 12
@@ -2871,10 +2878,16 @@
         invlpg  [eax]
         inc     ebx
         inc     esi
-        loop    .z
+        dec     ecx
+        jnz     .z
+        mov     ecx, [current_process]
+        add     ecx, PROC.heap_lock
+        call    mutex_unlock
         ret
-;--------------------------------------
-align 4
+.nomem_unlock:
+        mov     ecx, [current_process]
+        add     ecx, PROC.heap_lock
+        call    mutex_unlock
 .nomem:
         and     [bgrlockpid], 0
         mov     [bgrlock], 0
@@ -2888,30 +2901,7 @@
         mov     eax, [CURRENT_TASK]
         cmp     [bgrlockpid], eax
         jnz     .err
-        mov     eax, ecx
-        mov     ebx, ecx
-        shr     eax, 12
-        mov     ecx, [page_tabs+(eax-1)*4]
-        test    cl, USED_BLOCK+DONT_FREE_BLOCK
-        jz      .err
-        jnp     .err
-        push    eax
-        shr     ecx, 12
-        dec     ecx
-;--------------------------------------
-align 4
-@@:
-        and     dword [page_tabs+eax*4], 0
-        mov     edx, eax
-        shl     edx, 12
-        push    eax
-        invlpg  [edx]
-        pop     eax
-        inc     eax
-        loop    @b
-        pop     eax
-        and     dword [page_tabs+(eax-1)*4], not DONT_FREE_BLOCK
-        stdcall user_free, ebx
+        stdcall user_free, ecx
         mov     [esp+32], eax
         and     [bgrlockpid], 0
         mov     [bgrlock], 0
@@ -4841,6 +4831,14 @@
         pop     ax dx
 end if
 
+if 0
+        push    eax edx
+        mov     al, bl
+        mov     dx, 0x402
+        out     dx, al
+        pop     edx eax
+end if
+
         mov     [msg_board_data+ecx], bl
         cmp     byte [debug_direct_print], 1
         jnz     .end
Index: kernel/trunk/kernel32.inc
===================================================================
--- kernel/trunk/kernel32.inc	(revision 6766)
+++ kernel/trunk/kernel32.inc	(working copy)
@@ -15,6 +15,7 @@
 include "core/memory.inc"
 include "core/mtrr.inc"
 include "core/heap.inc"
+include "core/peuser.inc"
 include "core/malloc.inc"       ; small kernel heap
 include "core/taskman.inc"
 include "core/dll.inc"
Index: programs/system/test/trunk/Tupfile.lua
===================================================================
--- programs/system/test/trunk/Tupfile.lua	(revision 6766)
+++ programs/system/test/trunk/Tupfile.lua	(working copy)
@@ -1,3 +1,4 @@
 if tup.getconfig("NO_FASM") ~= "" then return end
 tup.rule("echo lang fix " .. ((tup.getconfig("LANG") == "") and "en" or tup.getconfig("LANG")) .. " > lang.inc", {"lang.inc"})
-tup.rule({"test.asm", extra_inputs = {"lang.inc"}}, "fasm %f %o " .. tup.getconfig("KPACK_CMD"), "test")
+ROOT = "../../../.."
+tup.rule({"test.asm", extra_inputs = {"lang.inc"}}, "fasm %f %o " .. tup.getconfig("PESTRIP_CMD") .. tup.getconfig("KPACK_CMD"), "test")
Index: programs/system/test/trunk/test.asm
===================================================================
--- programs/system/test/trunk/test.asm	(revision 6766)
+++ programs/system/test/trunk/test.asm	(working copy)
@@ -3,23 +3,8 @@
 ;    PROTECTION TEST
 ;
 ;-------------------------------------------------------------------------------
-; last update:  07/03/2014
-; changed by:   Marat Zakiyanov aka Mario79, aka Mario
-; changes:      Optimisations and code refactoring.
-;               Reducing the consumption of RAM, 4 KB instead of 64 KB.
-;               Translation into Russian.
-;---------------------------------------------------------------------
-use32
-	org 0x0
-
-	db 'MENUET01'	; 8 byte id
-	dd 0x01		; header version
-	dd START	; start of code
-	dd I_END	; size of image
-	dd IM_END	; memory for app
-	dd stack_top	; esp
-	dd 0x0		; I_Param
-	dd 0x0		; I_Icon
+format PE GUI 0.80
+section '.flat' code readable executable
 ;-------------------------------------------------------------------------------
 include '../../../macros.inc'
 include 'lang.inc'
@@ -63,26 +48,31 @@
 notest3:
 	cmp	ah,4
 	jnz	notest4
- 	mov	[0x10000],byte 1
+ 	mov	[0x0],byte 1
 ;-------------------------------------------------------------------------------	
 notest4:
 	cmp	ah,5
 	jnz	notest5
-	jmp	dword 0x10000
-;-------------------------------------------------------------------------------
+ 	mov	[START],byte 1
+;-------------------------------------------------------------------------------	
 notest5:
 	cmp	ah,6
 	jnz	notest6
-	mov	esp,0
-	push	eax
+	jmp	dword 0x0
 ;-------------------------------------------------------------------------------
 notest6:
 	cmp	ah,7
 	jnz	notest7
-	in	al,0x60
+	mov	esp,0
+	push	eax
 ;-------------------------------------------------------------------------------
 notest7:
 	cmp	ah,8
+	jnz	notest8
+	in	al,0x60
+;-------------------------------------------------------------------------------
+notest8:
+	cmp	ah,9
 	jnz	still
 	out	0x60,al
 	jmp	still
@@ -97,7 +87,7 @@
 	mcall	0,<200,292>,<200,230>,0x14FFFFFF,,tlabel
 	mov	eax,8			   ; function 8 : define and draw button
 	mov	ebx,32*65536+10	    ; [x start] *65536 + [x size]
-	mov	ecx,75*65536+10	    ; [y start] *65536 + [y size]
+	mov	ecx,55*65536+10	    ; [y start] *65536 + [y size]
 	mov	edx,2			   ; button id
 	mov	esi,0x6888B8		   ; button color RRGGBB
 .newb:
@@ -104,7 +94,7 @@
 	mcall
 	add	ecx,20*65536
 	inc	edx
-	cmp	edx,9
+	cmp	edx,10
 	jb	.newb
 
 	cld
@@ -116,7 +106,7 @@
 	mov	eax,4
 .newline:
 	mcall
-	add	ebx,10
+	add	ebx,20
 	add	edx,40
 	cmp	[edx],byte 'x'
 	jnz	.newline
@@ -128,62 +118,38 @@
 ;-------------------------------------------------------------------------------
 if lang eq it
 text:
-	db 'Il programma usa 0x1000 byte di memoria '
-	db '                                        '
 	db 'Open debug board for rezult information '
-	db '                                        '
 	db '     CLI                                '
-	db '                                        '
 	db '     STI                                '
-	db '                                        '
-	db '     MOV [0x10000],BYTE 1               '
-	db '                                        '
-	db '     JMP DWORD 0x10000                  '
-	db '                                        '
+	db '     MOV [0x0],BYTE 1                   '
+	db '     MOV [START],BYTE 1                 '
+	db '     JMP DWORD 0x0                      '
 	db '     MOV ESP,0 & PUSH EAX               '
-	db '                                        '
 	db '     IN  Al,0x60                        '
-	db '                                        '
 	db '     OUT 0x60,AL                        '
 	db 'x'
 else if lang eq ru
 text:
-	db '�ਫ®¦¥­¨¥ ¨ᯮ«ì§ã¥â 0x1000 ¡ ©â ¯ ¬ïâ¨'
-	db '                                        '
 	db 'Žâªàëâì BOARD ¤«ï ¯à®ᬮâà  १ã«ìâ â   '
-	db '                                        '
 	db '     CLI                                '
-	db '                                        '
 	db '     STI                                '
-	db '                                        '
-	db '     MOV [0x10000],BYTE 1               '
-	db '                                        '
-	db '     JMP DWORD 0x10000                  '
-	db '                                        '
+	db '     MOV [0x0],BYTE 1                   '
+	db '     MOV [START],BYTE 1                 '
+	db '     JMP DWORD 0x0                      '
 	db '     MOV ESP,0 & PUSH EAX               '
-	db '                                        '
 	db '     IN  Al,0x60                        '
-	db '                                        '
 	db '     OUT 0x60,AL                        '
 	db 'x'
 else
 text:
-	db 'Application uses 0x1000 bytes of memory '
-	db '                                        '
 	db 'Open debug board for result information '
-	db '                                        '
 	db '     CLI                                '
-	db '                                        '
 	db '     STI                                '
-	db '                                        '
-	db '     MOV [0x10000],BYTE 1               '
-	db '                                        '
-	db '     JMP DWORD 0x10000                  '
-	db '                                        '
+	db '     MOV [0x0],BYTE 1                   '
+	db '     MOV [START],BYTE 1                 '
+	db '     JMP DWORD 0x0                      '
 	db '     MOV ESP,0 & PUSH EAX               '
-	db '                                        '
 	db '     IN  Al,0x60                        '
-	db '                                        '
 	db '     OUT 0x60,AL                        '
 	db 'x'
 end if
@@ -198,12 +164,3 @@
 tlabel:
 	db 'Kolibri protection test',0
 end if
-;-------------------------------------------------------------------------------
-I_END:
-;-------------------------------------------------------------------------------
-align 4
-	rb 256
-stack_top:
-;-------------------------------------------------------------------------------
-IM_END:
-;-------------------------------------------------------------------------------
\ No newline at end of file
