[CLEVERMOUSE_PE_KERNEL] Apply CleverMouse PE patch

git-svn-id: svn://kolibrios.org@9048 a494cfbc-eb01-0410-851d-a64ba20cac60
This commit is contained in:
Magomed Kostoev (mkostoevr) 2021-07-09 19:26:55 +00:00
parent 360e379fc7
commit eccd8f2198
12 changed files with 2408 additions and 868 deletions

View File

@ -440,11 +440,11 @@ ends
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 @@ struct SMEM
name rb 32 ;+24
ends
struct SMAP APPOBJ
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
struct SMAP
fd dd ? ;next in mmapped list
bk dd ? ;prev in mmapped list
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 @@ struct PCIDEV
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,6 +961,19 @@ struct COFF_SECTION
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 ?
@ -971,6 +1012,62 @@ SPE_DIRECTORY_IMPORT = 0
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 ?

View File

@ -901,9 +901,13 @@ align 4
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 @@ proc load_library stdcall, file_name:dword, encoding:dword
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
; 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
mov [filesize], ebx
; 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 @@ proc load_library stdcall, file_name:dword, encoding:dword
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 @@ proc load_library stdcall, file_name:dword, encoding:dword
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,282 +979,78 @@ proc load_library stdcall, file_name:dword, encoding:dword
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
;
;@@:
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:
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
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
endp
align 4
stop_all_services:

View File

@ -23,8 +23,13 @@ MEM_BLOCK_FREE = 0x04
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 @@ proc init_heap
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 @@ proc user_alloc stdcall, alloc_size:dword
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 @@ proc user_alloc stdcall, alloc_size:dword
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 @@ proc user_alloc stdcall, alloc_size:dword
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 @@ proc user_alloc_at stdcall, address:dword, alloc_size:dword
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 @@ proc user_alloc_at stdcall, address:dword, alloc_size:dword
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 @@ proc user_free stdcall, base:dword
push esi
mov esi, [base]
test esi, esi
jz .fail
push ebx
@ -786,12 +782,18 @@ proc user_free stdcall, base:dword
xor ebx, ebx
shr esi, 12
jz .cantfree
mov eax, [page_tabs + (esi-1)*4]
test al, MEM_BLOCK_USED
jz .cantfree
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,33 +803,31 @@ proc user_free stdcall, base:dword
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
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 @@ endp
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 @@ proc user_unmap stdcall, base:dword, offset:dword, size:dword
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 @@ user_normalize:
.err:
xor eax, eax
ret
endp
user_realloc:
; in: eax = pointer, ebx = new size
@ -1004,37 +1035,43 @@ user_realloc:
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]
test al, 1
jz .loop
call free_page
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
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 @@ user_realloc:
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 @@ user_realloc:
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 @@ user_realloc:
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,24 +1240,47 @@ user_realloc:
; param
; eax= shm_map object
align 4
destroy_smap:
pushfd
cli
; edi= shm_map object
; [esp+4] = process
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
lock dec [esi + SMEM.refcount]
jnz .done
proc dereference_smem
mov ecx, shmem_list_mutex
call mutex_lock
dec [esi+SMEM.refcount]
jnz mutex_unlock
mov ecx, [esi + SMEM.bk]
mov edx, [esi + SMEM.fd]
@ -1243,18 +1288,14 @@ destroy_smap:
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,31 +1314,28 @@ SHM_CREATE = 2 shl 2
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
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 @@ align 4
.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 @@ align 4
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 @@ align 4
.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,129 +1429,148 @@ align 4
and eax, SHM_ACCESS_MASK
cmp eax, [esi + SMEM.access]
mov [access], eax
mov edx, E_ACCESS
ja .fail
mov ebx, [current_slot_idx]
shl ebx, BSF sizeof.TASKDATA
mov ebx, [TASK_TABLE + ebx + TASKDATA.pid]
mov eax, sizeof.SMAP
call create_kernel_object
test eax, eax
mov edi, eax
mov edx, E_NOMEM
jz .fail
mov [edx_ret], E_ACCESS
ja .exit_unlock
inc [esi+SMEM.refcount]
mov ecx, shmem_list_mutex
call mutex_unlock
mov [edi + SMAP.magic], 'SMAP'
mov [edi + SMAP.destroy], destroy_smap
mov [edi + SMAP.parent], esi
mov [edi + SMAP.base], 0
stdcall user_alloc, [esi + SMEM.size]
mov eax, sizeof.SMAP
call malloc
test eax, eax
mov [mapped], eax
mov edx, E_NOMEM
mov edi, eax
mov [edx_ret], E_NOMEM
jz .cleanup2
mov [edi+SMAP.type], SMAP_TYPE_SMEM
mov [edi + SMAP.parent], esi
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
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
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
.exit:
mov edx, [size]
.fail:
mov eax, [mapped]
jz .exit
mov [edx_ret], 0
popfd
pop edi
pop esi
pop ebx
.exit:
mov eax, [mapped]
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
.cleanup2:
mov [size], edx
.cleanup3:
mov ecx, [current_process]
add ecx, PROC.heap_lock
call mutex_unlock
mov eax, edi
call destroy_smap
call free
.cleanup2:
call dereference_smem
jmp .exit
endp
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

File diff suppressed because it is too large Load Diff

View File

@ -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

View File

@ -307,7 +307,7 @@ show_error_parameters:
; 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

View File

@ -42,10 +42,30 @@ struct APP_HDR
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,30 +118,41 @@ proc fs_execute
filename_size rd 1
cmdline_size rd 1
path_string rd 1
pedescr rd 1
endl
mov [flags], edx
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 @@ proc fs_execute
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 @@ proc fs_execute
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 @@ proc create_process stdcall, app_size:dword
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 @@ proc create_process stdcall, app_size:dword
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 @@ proc create_process stdcall, app_size:dword
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 @@ proc create_process stdcall, app_size:dword
ret
.fail:
mov ecx, [process]
jcxz @F
jecxz @F
call destroy_process
@@:
@ -419,8 +470,6 @@ proc destroy_page_table stdcall, pg_tab:dword
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 @@ align 4
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 @@ proc read_process_memory
r_count dd ?
offset dd ?
tmp_r_cnt dd ?
mapped_size dd ?
endl
mov [slot], eax
@ -541,6 +599,8 @@ proc read_process_memory
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 @@ proc read_process_memory
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 @@ proc read_process_memory
@@:
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 @@ proc write_process_memory
w_count dd ?
offset dd ?
tmp_w_cnt dd ?
mapped_size dd ?
endl
mov [slot], eax
@ -612,7 +683,9 @@ proc write_process_memory
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 @@ proc write_process_memory
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 @@ proc write_process_memory
@@:
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 @@ common_app_entry:
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 @@ common_app_entry:
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 @@ common_app_entry:
; 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 @@ common_app_entry:
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]

View File

@ -181,23 +181,25 @@ dev_data_path db '/RD/1/DRIVERS/DEVICES.DAT',0
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:
.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 @@ os_stack_seg dd ?
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_pdir dd ?
proc_mem_tab dd ?
tmp_task_ptab dd ?
zero_page_tab dd ?
default_io_map dd ?

View File

@ -3660,6 +3660,67 @@ Architecture Software Developer's Manual, Volume 3, Appendix B);
* 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 - отладка. =======================

View File

@ -3645,6 +3645,68 @@ Remarks:
---------------------- 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. ======================

View File

@ -322,6 +322,17 @@ high_code:
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 @@ high_code:
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,40 +2893,39 @@ align 4
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
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 @@ nosb6:
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 @@ if defined debug_com_base
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

View File

@ -15,6 +15,7 @@ include "core/fpu.inc" ; all fpu/sse support
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"