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