Subversion Repositories Kolibri OS

Compare Revisions

Regard whitespace Rev 9047 → Rev 9048

/kernel/branches/kolibrios-pe-clevermouse/const.inc
440,11 → 440,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
651,37 → 651,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 DQ
lo dd ?
810,6 → 789,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 ?
933,7 → 961,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 ?
971,6 → 1012,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 ?
/kernel/branches/kolibrios-pe-clevermouse/core/dll.inc
901,9 → 901,13
proc load_library stdcall, file_name:dword, encoding: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
917,105 → 921,19
pop ebp
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
1026,31 → 944,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
1058,15 → 964,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
1077,84 → 979,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
1161,111 → 1009,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_slot_idx]
shl ebx, 5
mov edx, [TASK_TABLE+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], MEM_BLOCK_DONT_FREE
; 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:
1272,88 → 1034,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
/kernel/branches/kolibrios-pe-clevermouse/core/heap.inc
23,8 → 23,13
MEM_BLOCK_USED = 0x08
MEM_BLOCK_DONT_FREE = 0x10
 
LAZY_ALLOC_PAGE = 2
LAZY_ALLOC_UNREADABLE = 20h
LAZY_ALLOC_UNWRITABLE = 40h
 
macro calc_index op
{ shr op, 12
{
shr op, 12
dec op
cmp op, 63
jna @f
561,35 → 566,42
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, MEM_BLOCK_FREE
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 esi edi
 
mov ebx, [current_process]
lea ecx, [ebx + PROC.heap_lock]
call mutex_lock
 
mov ecx, [alloc_size]
add ecx, (4095 + PAGE_SIZE)
and ecx, not 4095
628,15 → 640,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
652,9 → 655,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
664,15 → 664,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
697,9 → 707,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
752,15 → 759,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
775,8 → 773,6
push esi
 
mov esi, [base]
test esi, esi
jz .fail
 
push ebx
 
786,6 → 782,7
 
xor ebx, ebx
shr esi, 12
jz .cantfree
mov eax, [page_tabs + (esi-1)*4]
test al, MEM_BLOCK_USED
jz .cantfree
792,6 → 789,11
test al, MEM_BLOCK_DONT_FREE
jnz .cantfree
 
push 0
virtual at esp
.num_released_pages dd ?
end virtual
 
and eax, not 4095
mov ecx, eax
or al, MEM_BLOCK_FREE
801,16 → 803,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
817,17 → 821,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
 
850,18 → 850,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, MEM_BLOCK_USED
887,36 → 890,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 dword[edx], MEM_BLOCK_RESERVED
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 ?
@@:
add ebx, 4096 ; PAGESIZE?
.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
@@:
959,6 → 989,7
.err:
xor eax, eax
ret
endp
 
user_realloc:
; in: eax = pointer, ebx = new size
1004,37 → 1035,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, MEM_BLOCK_FREE
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
1043,13 → 1080,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
1119,9 → 1149,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]
1195,11 → 1222,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], MEM_BLOCK_RESERVED
inc esi
1218,25 → 1240,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]
 
1243,18 → 1288,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 = 5
E_ACCESS = 10
1273,23 → 1314,17
SHM_OPEN_MASK = 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
1296,9 → 1331,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
@@:
1316,22 → 1354,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
1341,13 → 1379,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]
1376,16 → 1412,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:
 
1393,37 → 1429,43
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_slot_idx]
shl ebx, BSF sizeof.TASKDATA
mov ebx, [TASK_TABLE + ebx + TASKDATA.pid]
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
mov ecx, [current_process]
add ecx, PROC.heap_lock
call mutex_lock
 
stdcall user_alloc, [esi + SMEM.size]
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
1430,44 → 1472,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
 
1474,48 → 1523,54
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
 
 
/kernel/branches/kolibrios-pe-clevermouse/core/memory.inc
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 ;page in application memory
572,6 → 572,7
cmp ebx, page_tabs
jb .kernel_space ;page in kernel memory
 
xor eax, eax
cmp ebx, kernel_tabs
jb .alloc;.app_tabs ;page tables of application ;
;simply create one
580,37 → 581,64
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
jnz .err_access ;Page presents
; 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 ;Page is present
;Access error ?
 
shr ebx, 12
mov ecx, ebx
shr ecx, 10
mov edx, [master_tab+ecx*4]
test edx, PG_READ
jz .fail ;page table is not created
test dword [master_tab+ecx*4], PG_READ
jz .fail_unlock ;page table is not created
;incorrect address in program
 
mov eax, [page_tabs+ebx*4]
test eax, 2
jz .fail ;address is not reserved for usage. Error
test eax, PG_READ
jnz .exit_unlock ; already resolved by a parallel thread
test eax, LAZY_ALLOC_PAGE
jz .fail_unlock ;address is not reserved for use, error
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,50 → 645,70
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 ;page does not present
 
test eax, 12 ;U/S (+below)
test esi, 12 ;U/S (+below)
jnz .fail ;application requested kernel memory
;test eax, 8
;jnz .fail ;the reserved bit is set in page tables. Added in P4/Xeon
;test esi, 8
;jnz .fail ;the reserved bit is set in page tables
;added in P4/Xeon
 
;an attempt to write to a protected kernel page
 
cmp ebx, tss._io_map_0
677,7 → 725,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 → 744,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 → 1023,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 → 1044,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 → 1065,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 → 1163,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 → 1186,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 → 1499,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 → 1519,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 → 1538,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+TASKDATA.pid] ;eax - our PID
1019,56 → 1578,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, BSF sizeof.APPDATA
or [eax+SLOT_BASE+APPDATA.occurred_events], EVENT_IPC
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
1103,7 → 1641,7
jbe sys_sheduler
cmp ebx, 11
jb undefined_syscall
cmp ebx, 29
cmp ebx, 32
ja undefined_syscall
xor eax, eax
jmp dword [f68call+ebx*4-11*4]
1224,7 → 1762,37
stdcall user_ring, ecx
mov [esp+SYSCALL_STACK._eax], eax
ret
.30:
cmp ecx, OS_BASE
jae .fail
stdcall load_file_maybe_pe, ecx
test esi, esi
jz .30.not_pe
stdcall map_pe_usermode, esi, eax, ebx
mov [esp+32], eax
ret
.30.resolve_fail:
movi eax, -5
jmp .30.error
.30.not_pe:
cmp eax, -0x1000
ja .30.error
stdcall kernel_free, eax
movi eax, -31
.30.error:
mov [esp+32], eax
ret
 
.31:
stdcall unmap_pe_usermode, ecx
mov [esp+32], eax
ret
 
.32:
stdcall mprotect, edx, esi, ecx
mov [esp+32], eax
ret
 
.fail:
mov [esp+SYSCALL_STACK._eax], eax
ret
1251,6 → 1819,9
dd f68.27 ; load_file_umode
dd f68.28 ; loadFileUnicode
dd f68.29 ; user_ring
dd f68.30 ; map_pe_usermode
dd f68.31 ; unmap_pe_usermode
dd f68.32 ; mprotect
 
align 4
proc load_pe_driver stdcall, file:dword, cmdline:dword
/kernel/branches/kolibrios-pe-clevermouse/core/peuser.inc
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 MEM_BLOCK_DONT_FREE
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
/kernel/branches/kolibrios-pe-clevermouse/core/sys32.inc
307,7 → 307,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
/kernel/branches/kolibrios-pe-clevermouse/core/taskman.inc
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
98,6 → 118,7
filename_size rd 1
cmdline_size rd 1
path_string rd 1
pedescr rd 1
endl
 
mov [flags], edx
104,24 → 125,34
mov [cmdline], ecx
mov [path_string], ebx
mov [filename_size], eax
mov esi, -ERROR_FILE_NOT_FOUND
mov edi, -ERROR_FILE_NOT_FOUND
test eax, eax
jz .err_file
stdcall load_file, ebx
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 ; fill our app header data locals with values from header of given program (if its correct)
mov esi, -TASKMAN_ERROR_NOT_A_EXECUTABLE
mov edi, -TASKMAN_ERROR_NOT_A_EXECUTABLE
test eax, eax
jz .err_hdr
 
.file_ok:
call lock_application_table
call alloc_thread_slot ; create a slot for new thread
mov esi, -TASKMAN_ERROR_TOO_MANY_PROCESSES
mov edi, -TASKMAN_ERROR_TOO_MANY_PROCESSES
test eax, eax
jz .err_0
 
162,8 → 193,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] ; create a new process
mov esi, -TASKMAN_ERROR_OUT_OF_MEMORY
mov edi, -TASKMAN_ERROR_OUT_OF_MEMORY
test eax, eax
jz .err_hdr
 
203,12 → 241,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
 
330,13 → 373,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
370,6 → 418,8
 
lea edx, [edi-4096]
mov esi, [app_tabs]
test esi, esi
jz .no_page_dirs
 
.alloc_page_dir:
call alloc_page
388,6 → 438,7
dec esi
jnz .alloc_page_dir
 
.no_page_dirs:
stdcall map_page, [tmp_task_ptab], 0, PG_UNMAP
mov eax, [process]
 
397,7 → 448,7
ret
.fail:
mov ecx, [process]
jcxz @F
jecxz @F
 
call destroy_process
@@:
419,8 → 470,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
446,8 → 495,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
532,6 → 589,7
r_count dd ?
offset dd ?
tmp_r_cnt dd ?
mapped_size dd ?
endl
 
mov [slot], eax
541,6 → 599,8
mov [offset], esi
 
pushad
mov ecx, proc_mem_mutex
call mutex_lock
.read_mem:
mov edx, [offset]
mov ebx, [tmp_r_cnt]
560,13 → 620,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
574,17 → 635,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
603,6 → 673,7
w_count dd ?
offset dd ?
tmp_w_cnt dd ?
mapped_size dd ?
endl
 
mov [slot], eax
612,7 → 683,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]
 
630,13 → 703,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
644,17 → 718,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
799,6 → 881,76
jz .exit
; APPDATA.exec_params have first thread only,
; so second and next threads don't get here (they jump to .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]
846,8 → 998,9
mov byte [edi], 0
.check_tls_header:
cmp word [6], '02'
jne .try_load_dll ;.cleanup
jne .try_load_dll ;.common
call init_heap
.common_tls:
stdcall user_alloc, 4096
mov edx, [current_slot]
mov [edx+APPDATA.tls_base], eax
862,7 → 1015,7
; Test app header version
mov ecx, dword[ebp+APP_HDR.img_base]
cmp dword[ecx+8], 2
jne .cleanup
jne .common
;if APP_HEADER.version = 2 => load lib/dll.obj & change eip to APP_STARTUP_THUNK
DEBUGF 1, 'K : App header version 2\n'
stdcall load_library, dll_lib_path, 0
889,7 → 1042,9
mov [ecx+REG_EIP], eax
; } End patch by Coldy, For DLL autoload
.cleanup:
mov fs, dx
 
.common:
stdcall free_kernel_space, [ebp+APP_HDR.img_base]
stdcall kernel_free, ebp
mov ebx, [current_slot]
/kernel/branches/kolibrios-pe-clevermouse/data32.inc
181,6 → 181,8
dll_lib_path db '/RD/1/LIB/DLL.OBJ',0
dll_error_msg db '"DLL.OBJ not found!\nTerminate application!" -dE',0
; } End patch by Coldy, For DLL autoload
pe_loader_usermode db '/rd/1/lib/kolibri.dll',0
 
align 4
 
shmem_list:
187,17 → 189,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
 
399,6 → 401,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 ?
432,6 → 440,7
proc_mem_tab dd ?
 
tmp_task_ptab dd ?
zero_page_tab dd ?
 
default_io_map dd ?
 
/kernel/branches/kolibrios-pe-clevermouse/docs/sysfuncr.txt
3660,6 → 3660,67
* edx = размер загруженного файла или 0
Примечания:
* функция загружает и, при необходимости, распаковывает файл (kunpack)
======================================================================
=========== Функция 68, подфункция 29 - загрузить PE-файл ============
======================================================================
Параметры:
* eax = 68 - номер функции
* ebx = 29 - номер подфункции
* ecx = указатель на строку с путём к файлу,
правила формирования строки указаны в описании функции 70.
Возвращаемое значение:
* eax > 0xFFFFF000 - произошла ошибка, -eax = код ошибки
* eax <= 0xFFFFF000 - адрес загруженного файла
Примечания:
* функция предназначена только для системного загрузчика внутри
kolibri.dll; загруженный файл ещё не готов к работе, ему требуется
донастройка. Вместо неё используйте
функцию dlopen() из kolibri.dll.
======================================================================
=========== Функция 68, подфункция 30 - выгрузить PE-файл ============
======================================================================
Параметры:
* eax = 68 - номер функции
* ebx = 30 - номер подфункции
* ecx = адрес загруженного PE-файла
Возвращаемое значение:
* eax = 0 - успешно
* eax = -1 - адрес не соответствует никакому загруженному файлу
Примечания:
* функция предназначена только для системного загрузчика внутри
kolibri.dll. Вместо неё используйте функцию dlclose()
из kolibri.dll.
======================================================================
==== Функция 68, подфункция 31 - изменить права доступа к памяти =====
======================================================================
Параметры:
* eax = 68 - номер функции
* ebx = 31 - номер подфункции
* 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 (31)
 
======================================================================
======================== Функция 69 - отладка. =======================
/kernel/branches/kolibrios-pe-clevermouse/docs/sysfuncs.txt
3645,6 → 3645,68
---------------------- Constants for registers: ----------------------
eax - SF_SYS_MISC (68)
ebx - SSF_MEM_ALLOC_RING (29)
======================================================================
============ Function 68, subfunction 30 - load PE-file ==============
======================================================================
Parameters:
* eax = 68 - function number
* ebx = 30 - subfunction number
* ecx = pointer to the string with path to file,
rules of path forming can be found in function 70 description.
Returned value:
* eax > 0xFFFFF000 - error, -eax = error code
* eax <= 0xFFFFF000 - pointer to the loaded file
Remarks:
* This function is to be called only by system loader from
kolibri.dll; the file loaded is not ready yet, it requires further
configuration. Use dlopen() from kolibri.dll instead of this
function.
======================================================================
=========== Function 68, subfunction 31 - unload PE-file =============
======================================================================
Parameters:
* eax = 68 - function number
* ebx = 31 - subfunction number
* ecx = pointer to the loaded file
Returned value:
* eax = 0 - success
* eax = -1 - provided address does not correspond to any loaded file
Remarks:
* This function is to be called only by system loader from
kolibri.dll. Use dlclose() from kolibri.dll instead of this
function.
======================================================================
===== Function 68, subfunction 32 - modify memory access rights ======
======================================================================
Parameters:
* eax = 68 - function number
* ebx = 32 - subfunction number
* ecx = new access rights: zero or more of the following bits:
* PROT_READ = 1 - allow reading
* PROT_WRITE = 2 - allow writing
* PROT_EXEC = 4 - allow execution
* edx = pointer to begin of memory region
* esi = size of memory region in bytes
Returned value:
* eax = -1 - error
* else eax = old access rights
Remarks:
* The function modifies access rights to whole pages (4096 bytes).
* The function modifies access rights to all the pages intersecting
provided memory region.
* It is considered an error if a memory region returned by function
68.22 is passed to this function.
* If any part of the passed memory region is incorrect, then the
function returns an error. However it is not guaranteed that
access rights of the correct part have been changed.
* If there was no error, the function returns old access rights of
the first provided page.
* Current implementation does not support execution access rights
without reading rights. Therefore bit PROT_EXEC is ignored on
entering the function, and becomes a copy of PROT_READ at exit.
---------------------- Constants for registers: ----------------------
eax - SF_SYS_MISC (68)
ebx - SSF_MPROTECT (32)
 
======================================================================
====================== Function 69 - debugging. ======================
/kernel/branches/kolibrios-pe-clevermouse/kernel.asm
322,6 → 322,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
513,6 → 524,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
 
2879,30 → 2893,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], MEM_BLOCK_DONT_FREE
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
2909,10 → 2916,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
2926,30 → 2939,7
mov eax, [current_slot_idx]
cmp [bgrlockpid], eax
jnz .err
mov eax, ecx
mov ebx, ecx
shr eax, 12
mov ecx, [page_tabs+(eax-1)*4]
test cl, MEM_BLOCK_USED or MEM_BLOCK_DONT_FREE
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 MEM_BLOCK_DONT_FREE
stdcall user_free, ebx
stdcall user_free, ecx
mov [esp+32], eax
and [bgrlockpid], 0
mov [bgrlock], 0
4925,6 → 4915,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
/kernel/branches/kolibrios-pe-clevermouse/kernel32.inc
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"