[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 struct PROC
list LHEAD list LHEAD
thr_list LHEAD thr_list LHEAD
smap_list LHEAD
heap_lock MUTEX heap_lock MUTEX
heap_base rd 1 heap_base rd 1
heap_top rd 1 heap_top rd 1
mem_used rd 1 mem_used rd 1
dlls_list_ptr rd 1
pdt_0_phys rd 1 pdt_0_phys rd 1
pdt_1_phys rd 1 pdt_1_phys rd 1
io_map_0 rd 1 io_map_0 rd 1
@ -651,37 +651,16 @@ struct SMEM
name rb 32 ;+24 name rb 32 ;+24
ends ends
struct SMAP APPOBJ struct SMAP
base dd ? ;mapped base fd dd ? ;next in mmapped list
parent dd ? ;SMEM bk dd ? ;prev in mmapped list
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 base dd ? ;mapped base
size dd ? ;mapped size size dd ? ;mapped size
refcount dd ? ;reference counter for this process and this lib type dd ? ;SMAP_TYPE_SMEM or SMAP_TYPE_PE
parent dd ? ;DLLDESCR parent dd ? ;SMEM or PEDESCR
ends ends
SMAP_TYPE_SMEM = 1
SMAP_TYPE_PE = 2
struct DQ struct DQ
lo dd ? lo dd ?
@ -810,6 +789,55 @@ struct PCIDEV
owner dd ? ; pointer to SRV or 0 owner dd ? ; pointer to SRV or 0
ends 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 struct IDE_DATA
ProgrammingInterface dd ? ProgrammingInterface dd ?
Interrupt dw ? Interrupt dw ?
@ -933,6 +961,19 @@ struct COFF_SECTION
NumLinenum dw ? NumLinenum dw ?
Characteristics dd ? Characteristics dd ?
ends 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 struct COFF_RELOC
VirtualAddress dd ? VirtualAddress dd ?
@ -971,6 +1012,62 @@ SPE_DIRECTORY_IMPORT = 0
SPE_DIRECTORY_EXPORT = 1 SPE_DIRECTORY_EXPORT = 1
SPE_DIRECTORY_BASERELOC = 2 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 struct IOCTL
handle dd ? handle dd ?
io_code dd ? io_code dd ?

View File

@ -901,9 +901,13 @@ align 4
proc load_library stdcall, file_name:dword, encoding:dword proc load_library stdcall, file_name:dword, encoding:dword
locals locals
fullname dd ? fullname dd ?
fileinfo rb 40 filesize dd ?
coff dd ? coff dd ?
img_base dd ? img_base dd ?
img_size dd ?
symbols_ptr dd ?
symbols_lim dd ?
exports dd ?
endl endl
; resolve file name ; resolve file name
@ -917,105 +921,19 @@ proc load_library stdcall, file_name:dword, encoding:dword
pop ebp pop ebp
test eax, eax test eax, eax
jz .fail 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 ; load file
stdcall load_file, edi stdcall load_file, [fullname]
test eax, eax test eax, eax
jz .fail jz .fail
mov [coff], eax 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 ; calculate size of loaded DLL
mov edx, [coff] movzx ecx, [eax+COFF_HEADER.nSections]
movzx ecx, [edx+COFF_HEADER.nSections]
xor ebx, ebx xor ebx, ebx
add edx, 20 lea edx, [eax+20]
@@: @@:
call coff_get_align call coff_get_align
add ebx, eax add ebx, eax
@ -1026,31 +944,19 @@ proc load_library stdcall, file_name:dword, encoding:dword
dec ecx dec ecx
jnz @B jnz @B
; it must be nonzero and not too big ; it must be nonzero and not too big
mov [esi+DLLDESCR.size], ebx mov [img_size], ebx
test ebx, ebx test ebx, ebx
jz .fail_and_free_dll jz .fail_and_free_coff
cmp ebx, MAX_DEFAULT_DLL_ADDR-MIN_DEFAULT_DLL_ADDR cmp ebx, 0x10000000
ja .fail_and_free_dll ja .fail_and_free_coff
; allocate memory for kernel-side image ; allocate memory
stdcall kernel_alloc, ebx call init_heap
stdcall user_alloc, [img_size]
test eax, eax test eax, eax
jz .fail_and_free_dll jz .fail_and_free_coff
mov [esi+DLLDESCR.data], eax mov [img_base], 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
; copy sections and set correct values for VirtualAddress'es in headers ; copy sections and set correct values for VirtualAddress'es in headers
push esi
mov edx, [coff] mov edx, [coff]
movzx ebx, [edx+COFF_HEADER.nSections] movzx ebx, [edx+COFF_HEADER.nSections]
mov edi, eax mov edi, eax
@ -1058,15 +964,11 @@ proc load_library stdcall, file_name:dword, encoding:dword
cld cld
@@: @@:
call coff_get_align call coff_get_align
add ecx, eax
add edi, eax add edi, eax
not eax not eax
and ecx, eax
and edi, eax and edi, eax
mov [edx+COFF_SECTION.VirtualAddress], ecx mov [edx+COFF_SECTION.VirtualAddress], edi
add ecx, [edx+COFF_SECTION.SizeOfRawData]
mov esi, [edx+COFF_SECTION.PtrRawData] mov esi, [edx+COFF_SECTION.PtrRawData]
push ecx
mov ecx, [edx+COFF_SECTION.SizeOfRawData] mov ecx, [edx+COFF_SECTION.SizeOfRawData]
test esi, esi test esi, esi
jnz .copy jnz .copy
@ -1077,282 +979,78 @@ proc load_library stdcall, file_name:dword, encoding:dword
add esi, [coff] add esi, [coff]
rep movsb rep movsb
.next: .next:
pop ecx
add edx, sizeof.COFF_SECTION add edx, sizeof.COFF_SECTION
dec ebx dec ebx
jnz @B 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 edx, [coff]
mov ebx, [edx+COFF_HEADER.pSymTable] mov ebx, [edx+COFF_HEADER.pSymTable]
mov edi, dword [fileinfo+32] mov edi, [filesize]
sub edi, ebx sub edi, ebx
jc .fail_and_free_data jc .fail_and_free_data
mov [esi+DLLDESCR.symbols_lim], edi mov [symbols_lim], edi
add ebx, edx add ebx, edx
movzx ecx, [edx+COFF_HEADER.nSections] ; coff_hdr = coff
lea ecx, [ecx*5] ; symbols_num = coff.nSymbols
lea edi, [edi+ecx*8+20] mov [symbols_ptr], ebx
add edx, 20 mov ebx, edx
@@:
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
; fixup symbols ; fixup symbols
mov edx, ebx mov eax, [edx+COFF_HEADER.nSymbols]
mov eax, [ebx+COFF_HEADER.nSymbols]
add edx, 20 add edx, 20
mov ecx, [esi+DLLDESCR.symbols_num] lea ecx, [eax*9]
lea ecx, [ecx*9]
add ecx, ecx 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 ecx, 0
; test eax, eax ; test eax, eax
; jnz @F ; 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 test eax, eax
jnz @F 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 stdcall fix_coff_relocs, ebx, [symbols_ptr], 0
; 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 kernel_free, [coff] 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] 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 mov eax, [exports]
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
ret ret
.fail_and_free_data: .fail_and_free_data:
stdcall kernel_free, [esi+DLLDESCR.data] stdcall user_free, [img_base]
.fail_and_free_dll:
mov eax, esi
call free
.fail_and_free_coff: .fail_and_free_coff:
stdcall kernel_free, [coff] stdcall kernel_free, [coff]
.fail: .fail:
stdcall kernel_free, [fullname] stdcall kernel_free, [fullname]
xor eax, eax xor eax, eax
ret 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 endp
; initialize [APPDATA.dlls_list_ptr] for given thread ; in: esi -> PEDESCR struct
; DLL is per-process object, so APPDATA.dlls_list_ptr must be proc dereference_pe
; kept in sync for all threads of one process. mov ecx, pe_list_mutex
; out: eax = APPDATA.dlls_list_ptr if all is OK, call mutex_lock
; NULL if memory allocation failed dec [esi+PEDESCR.refcount]
init_dlls_in_thread: jnz mutex_unlock
mov ebx, [current_process] mov eax, [esi+PEDESCR.fd]
mov eax, [ebx+PROC.dlls_list_ptr] mov edx, [esi+PEDESCR.bk]
test eax, eax mov [eax+PEDESCR.bk], edx
jnz .ret mov [edx+PEDESCR.fd], eax
call mutex_unlock
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]
mov eax, esi mov eax, esi
call free 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 ret
endp
align 4 align 4
stop_all_services: stop_all_services:

View File

@ -23,8 +23,13 @@ MEM_BLOCK_FREE = 0x04
MEM_BLOCK_USED = 0x08 MEM_BLOCK_USED = 0x08
MEM_BLOCK_DONT_FREE = 0x10 MEM_BLOCK_DONT_FREE = 0x10
LAZY_ALLOC_PAGE = 2
LAZY_ALLOC_UNREADABLE = 20h
LAZY_ALLOC_UNWRITABLE = 40h
macro calc_index op macro calc_index op
{ shr op, 12 {
shr op, 12
dec op dec op
cmp op, 63 cmp op, 63
jna @f jna @f
@ -561,35 +566,42 @@ proc init_heap
sub eax, PAGE_SIZE sub eax, PAGE_SIZE
ret ret
@@: @@:
lea ecx, [ebx + PROC.heap_lock]
call mutex_init
mov esi, [ebx + PROC.mem_used] mov edx, [ebx+PROC.mem_used]
add esi, 4095 add edx, 4095
and esi, not 4095 and edx, not 4095
mov [ebx + PROC.mem_used], esi mov [ebx+PROC.mem_used], edx
mov eax, HEAP_TOP mov eax, HEAP_TOP
mov [ebx + PROC.heap_base], esi mov [ebx+PROC.heap_base], edx
mov [ebx + PROC.heap_top], eax mov [ebx+PROC.heap_top], eax
sub eax, esi sub eax, edx
shr esi, 10 shr edx, 10
mov ecx, eax mov ecx, eax
sub eax, PAGE_SIZE sub eax, PAGE_SIZE
or ecx, MEM_BLOCK_FREE or ecx, MEM_BLOCK_FREE
mov [page_tabs + esi], ecx mov [page_tabs + edx], ecx
ret ret
endp endp
align 4 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 push ebx esi edi
mov ebx, [current_process] mov ebx, [current_process]
lea ecx, [ebx + PROC.heap_lock]
call mutex_lock
mov ecx, [alloc_size] mov ecx, [alloc_size]
add ecx, (4095 + PAGE_SIZE) add ecx, (4095 + PAGE_SIZE)
and ecx, not 4095 and ecx, not 4095
@ -628,15 +640,6 @@ proc user_alloc stdcall, alloc_size:dword
jnz @B jnz @B
.no: .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] lea eax, [esi + 4096]
pop edi pop edi
@ -652,9 +655,6 @@ proc user_alloc stdcall, alloc_size:dword
add esi, eax add esi, eax
jmp .scan jmp .scan
.m_exit: .m_exit:
mov ecx, [current_process]
lea ecx, [ecx + PROC.heap_lock]
call mutex_unlock
xor eax, eax xor eax, eax
pop edi pop edi
@ -664,15 +664,25 @@ proc user_alloc stdcall, alloc_size:dword
endp endp
align 4 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 ebx
push esi push esi
push edi push edi
mov ebx, [current_process] mov ebx, [current_process]
lea ecx, [ebx + PROC.heap_lock]
call mutex_lock
mov edx, [address] mov edx, [address]
and edx, not 0xFFF and edx, not 0xFFF
@ -697,9 +707,6 @@ proc user_alloc_at stdcall, address:dword, alloc_size:dword
mov esi, ecx mov esi, ecx
jmp .scan jmp .scan
.error: .error:
mov ecx, [current_process]
lea ecx, [ecx + PROC.heap_lock]
call mutex_unlock
xor eax, eax xor eax, eax
pop edi pop edi
@ -751,16 +758,7 @@ proc user_alloc_at stdcall, address:dword, alloc_size:dword
or cl, MEM_BLOCK_FREE or cl, MEM_BLOCK_FREE
mov [page_tabs + ebx*4], ecx mov [page_tabs + ebx*4], ecx
.nothird: .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] mov eax, [address]
pop edi pop edi
@ -775,8 +773,6 @@ proc user_free stdcall, base:dword
push esi push esi
mov esi, [base] mov esi, [base]
test esi, esi
jz .fail
push ebx push ebx
@ -786,12 +782,18 @@ proc user_free stdcall, base:dword
xor ebx, ebx xor ebx, ebx
shr esi, 12 shr esi, 12
jz .cantfree
mov eax, [page_tabs + (esi-1)*4] mov eax, [page_tabs + (esi-1)*4]
test al, MEM_BLOCK_USED test al, MEM_BLOCK_USED
jz .cantfree jz .cantfree
test al, MEM_BLOCK_DONT_FREE test al, MEM_BLOCK_DONT_FREE
jnz .cantfree jnz .cantfree
push 0
virtual at esp
.num_released_pages dd ?
end virtual
and eax, not 4095 and eax, not 4095
mov ecx, eax mov ecx, eax
or al, MEM_BLOCK_FREE or al, MEM_BLOCK_FREE
@ -800,35 +802,33 @@ proc user_free stdcall, base:dword
mov ebx, ecx mov ebx, ecx
shr ecx, 12 shr ecx, 12
jz .released jz .released
.release: .release:
xor eax, eax mov edx, [page_tabs+esi*4]
xchg eax, [page_tabs + esi*4] mov dword [page_tabs+esi*4], 0
test al, 1
jz @F
test eax, PG_SHARED
jnz @F
call free_page
mov eax, esi mov eax, esi
shl eax, 12 shl eax, 12
invlpg [eax] 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 inc esi
dec ecx dec ecx
jnz .release jnz .release
.released: .released:
push edi
pop eax ; .num_released_pages
shl eax, 12
mov edx, [current_process] mov edx, [current_process]
lea ecx, [edx + PROC.heap_lock] lea ecx, [edx + PROC.heap_lock]
mov esi, dword [edx + PROC.heap_base] sub [edx + PROC.mem_used], eax
mov edi, dword [edx + PROC.heap_top]
sub ebx, [edx + PROC.mem_used]
neg ebx
mov [edx + PROC.mem_used], ebx
call user_normalize call user_normalize
pop edi .exit:
.exit:
call mutex_unlock call mutex_unlock
xor eax, eax xor eax, eax
@ -850,18 +850,21 @@ endp
align 4 align 4
proc user_unmap stdcall, base:dword, offset:dword, size:dword proc user_unmap stdcall, base:dword, offset:dword, size:dword
mov ecx, [current_process]
add ecx, PROC.heap_lock
call mutex_lock
push ebx push ebx
mov ebx, [base] ; must be valid pointer mov ebx, [base] ; must be valid pointer
test ebx, ebx
jz .error
mov edx, [offset] ; check offset mov edx, [offset] ; check offset
add edx, ebx ; must be below 2Gb app limit add edx, ebx ; must be below 2Gb app limit
jc .error
js .error js .error
shr ebx, 12 ; chek block attributes shr ebx, 12 ; chek block attributes
jz .error
lea ebx, [page_tabs + ebx*4] lea ebx, [page_tabs + ebx*4]
mov eax, [ebx-4] ; block attributes mov eax, [ebx-4] ; block attributes
test al, MEM_BLOCK_USED 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 ? and ebx, not 4095 ; is it required ?
add ebx, [base] add ebx, [base]
.unmap: push 0
virtual at esp
.num_released_pages dd ?
end virtual
.unmap:
mov eax, [edx] ; get page addres mov eax, [edx] ; get page addres
test al, 1 ; page mapped ? test al, 1 ; page mapped ?
jz @F jz .next
test eax, PG_SHARED ; page shared ? test eax, PG_SHARED ; page shared ?
jnz @F jnz .next
mov dword[edx], MEM_BLOCK_RESERVED inc [.num_released_pages]
mov dword [edx], LAZY_ALLOC_PAGE
; mark page as reserved ; 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 invlpg [ebx] ; when we start using
call free_page ; empty c-o-w page instead this ? call free_page ; empty c-o-w page instead this ?
@@: .next:
add ebx, 4096 ; PAGESIZE? add ebx, 4096
add edx, 4 add edx, 4
dec ecx dec ecx
jnz .unmap jnz .unmap
pop eax ; .num_released_pages
pop ebx 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 ret
.error: .error:
pop ebx pop ebx
mov ecx, [current_process]
add ecx, PROC.heap_lock
call mutex_unlock
xor eax, eax ; something wrong xor eax, eax ; something wrong
dec eax
ret ret
endp endp
align 4 align 4
user_normalize: proc user_normalize uses esi edi
; in: esi=heap_base, edi=heap_top ; in: edx->PROC
; out: eax=0 <=> OK ; 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 esi, 12
shr edi, 12 shr edi, 12
@@: @@:
@ -959,6 +989,7 @@ user_normalize:
.err: .err:
xor eax, eax xor eax, eax
ret ret
endp
user_realloc: user_realloc:
; in: eax = pointer, ebx = new size ; in: eax = pointer, ebx = new size
@ -1004,37 +1035,43 @@ user_realloc:
cmp edx, ebx cmp edx, ebx
jb .realloc_add jb .realloc_add
; release part of allocated memory ; release part of allocated memory
push edx
push 0
virtual at esp
.num_released_pages dd ?
end virtual
.loop: .loop:
cmp edx, ebx cmp edx, ebx
jz .release_done jz .release_done
dec edx dec edx
xor eax, eax push dword [page_tabs + edx*4]
xchg eax, [page_tabs + edx*4] mov dword [page_tabs + edx*4], 0
test al, 1
jz .loop
call free_page
mov eax, edx mov eax, edx
shl eax, 12 shl eax, 12
invlpg [eax] invlpg [eax]
pop eax
test al, 1
jz .loop
inc [.num_released_pages]
test eax, PG_SHARED
jnz .loop
call free_page
jmp .loop jmp .loop
.release_done: .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 sub ebx, ecx
cmp ebx, 1 cmp ebx, 1
jnz .nofreeall jnz .nofreeall
mov eax, [page_tabs + ecx*4] mov eax, [page_tabs + ecx*4]
and eax, not 0xFFF 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 or al, MEM_BLOCK_FREE
mov [page_tabs + ecx*4], eax mov [page_tabs + ecx*4], eax
push esi edi mov edx, [current_process]
mov esi, [edx + PROC.heap_base]
mov edi, [edx + PROC.heap_top]
mov [edx + PROC.mem_used], ebx
call user_normalize call user_normalize
pop edi esi
jmp .ret0 ; all freed jmp .ret0 ; all freed
.nofreeall: .nofreeall:
sub edx, ecx sub edx, ecx
@ -1043,13 +1080,6 @@ user_realloc:
xchg [page_tabs + ecx*4], ebx xchg [page_tabs + ecx*4], ebx
shr ebx, 12 shr ebx, 12
sub ebx, edx 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] lea eax, [ecx + 1]
shl eax, 12 shl eax, 12
push eax push eax
@ -1119,9 +1149,6 @@ user_realloc:
cld cld
rep stosd rep stosd
pop edi pop edi
mov edx, [current_process]
shl ebx, 12
add [edx + PROC.mem_used], ebx
mov ecx, [current_process] mov ecx, [current_process]
lea ecx, [ecx + PROC.heap_lock] lea ecx, [ecx + PROC.heap_lock]
@ -1195,11 +1222,6 @@ user_realloc:
dec edx dec edx
jnz @b jnz @b
.no: .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 mov dword [page_tabs + esi*4], MEM_BLOCK_RESERVED
inc esi inc esi
@ -1218,24 +1240,47 @@ user_realloc:
; param ; 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 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 proc dereference_smem
mov esi, [eax + SMAP.parent] mov ecx, shmem_list_mutex
test esi, esi call mutex_lock
jz .done dec [esi+SMEM.refcount]
jnz mutex_unlock
lock dec [esi + SMEM.refcount]
jnz .done
mov ecx, [esi + SMEM.bk] mov ecx, [esi + SMEM.bk]
mov edx, [esi + SMEM.fd] mov edx, [esi + SMEM.fd]
@ -1243,18 +1288,14 @@ destroy_smap:
mov [ecx + SMEM.fd], edx mov [ecx + SMEM.fd], edx
mov [edx + SMEM.bk], ecx mov [edx + SMEM.bk], ecx
mov ecx, shmem_list_mutex
call mutex_unlock
stdcall kernel_free, [esi + SMEM.base] stdcall kernel_free, [esi + SMEM.base]
mov eax, esi mov eax, esi
call free call free
.done:
mov eax, edi
call destroy_kernel_object
pop edi
pop esi
popfd
ret ret
endp
E_NOTFOUND = 5 E_NOTFOUND = 5
E_ACCESS = 10 E_ACCESS = 10
@ -1273,31 +1314,28 @@ SHM_CREATE = 2 shl 2
SHM_OPEN_MASK = 3 shl 2 SHM_OPEN_MASK = 3 shl 2
align 4 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 locals
action dd ? action dd ?
owner_access dd ? owner_access dd ?
mapped dd ? mapped dd ?
edx_ret dd ?
endl endl
push ebx
push esi
push edi
mov [mapped], 0 mov [mapped], 0
mov [owner_access], 0 mov [owner_access], 0
pushfd ;mutex required
cli
mov eax, [access] mov eax, [access]
and eax, SHM_OPEN_MASK and eax, SHM_OPEN_MASK
mov [action], eax mov [action], eax
mov ebx, [name] mov ebx, [name]
test ebx, ebx test ebx, ebx
mov edx, E_PARAM mov [edx_ret], E_PARAM
jz .fail jz .exit
mov ecx, shmem_list_mutex
call mutex_lock
mov esi, [shmem_list.fd] mov esi, [shmem_list.fd]
align 4 align 4
@ -1316,22 +1354,22 @@ align 4
.not_found: .not_found:
mov eax, [action] mov eax, [action]
mov [edx_ret], E_NOTFOUND
cmp eax, SHM_OPEN cmp eax, SHM_OPEN
mov edx, E_NOTFOUND je .exit_unlock
je .fail
mov [edx_ret], E_PARAM
cmp eax, SHM_CREATE cmp eax, SHM_CREATE
mov edx, E_PARAM
je .create_shm je .create_shm
cmp eax, SHM_OPEN_ALWAYS cmp eax, SHM_OPEN_ALWAYS
jne .fail jne .exit_unlock
.create_shm: .create_shm:
mov ecx, [size] mov ecx, [size]
test ecx, ecx test ecx, ecx
jz .fail jz .exit_unlock
add ecx, 4095 add ecx, 4095
and ecx, -4096 and ecx, -4096
@ -1341,13 +1379,11 @@ align 4
call malloc call malloc
test eax, eax test eax, eax
mov esi, eax mov esi, eax
mov edx, E_NOMEM mov [edx_ret], E_NOMEM
jz .fail jz .exit_unlock
stdcall kernel_alloc, [size] stdcall kernel_alloc, [size]
test eax, eax test eax, eax
mov [mapped], eax
mov edx, E_NOMEM
jz .cleanup jz .cleanup
mov ecx, [size] mov ecx, [size]
@ -1376,16 +1412,16 @@ align 4
.found: .found:
mov eax, [action] mov eax, [action]
mov [edx_ret], E_ACCESS
cmp eax, SHM_CREATE cmp eax, SHM_CREATE
mov edx, E_ACCESS je .exit_unlock
je .exit
mov [edx_ret], E_PARAM
cmp eax, SHM_OPEN cmp eax, SHM_OPEN
mov edx, E_PARAM
je .create_map je .create_map
cmp eax, SHM_OPEN_ALWAYS cmp eax, SHM_OPEN_ALWAYS
jne .fail jne .exit_unlock
.create_map: .create_map:
@ -1393,129 +1429,148 @@ align 4
and eax, SHM_ACCESS_MASK and eax, SHM_ACCESS_MASK
cmp eax, [esi + SMEM.access] cmp eax, [esi + SMEM.access]
mov [access], eax mov [access], eax
mov edx, E_ACCESS mov [edx_ret], E_ACCESS
ja .fail ja .exit_unlock
inc [esi+SMEM.refcount]
mov ecx, shmem_list_mutex
call mutex_unlock
mov ebx, [current_slot_idx]
shl ebx, BSF sizeof.TASKDATA
mov ebx, [TASK_TABLE + ebx + TASKDATA.pid]
mov eax, sizeof.SMAP mov eax, sizeof.SMAP
call malloc
call create_kernel_object
test eax, eax test eax, eax
mov edi, eax mov edi, eax
mov edx, E_NOMEM mov [edx_ret], E_NOMEM
jz .fail
inc [esi + SMEM.refcount]
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]
test eax, eax
mov [mapped], eax
mov edx, E_NOMEM
jz .cleanup2 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 [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 ecx, [esi + SMEM.size]
mov [size], ecx mov [edi + SMAP.size], ecx
mov [edx_ret], ecx
shr ecx, 12 shr ecx, 12
shr eax, 10 shr eax, 10
mov esi, [esi + SMEM.base] mov esi, [esi + SMEM.base]
shr esi, 10 shr esi, 10
lea edi, [page_tabs + eax]
add esi, page_tabs
xor ebx, ebx
mov edx, [access] mov edx, [access]
or edx, [owner_access] or edx, [owner_access]
shl edx, 1 shl edx, 1
or edx, PG_SHARED + PG_UR or edx, PG_SHARED + PG_UR
@@: @@:
lodsd mov edi, [page_tabs+esi+ebx*4]
and eax, 0xFFFFF000 and edi, 0xFFFFF000
or eax, edx or edi, edx
stosd mov [page_tabs+eax+ebx*4], edi
loop @B 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 cmp [owner_access], 0
jne .fail jz .exit
.exit: mov [edx_ret], 0
mov edx, [size]
.fail:
mov eax, [mapped]
popfd .exit:
pop edi mov eax, [mapped]
pop esi mov edx, [edx_ret]
pop ebx
ret ret
.cleanup: .cleanup:
mov [size], edx
mov eax, esi mov eax, esi
call free call free
.exit_unlock:
mov ecx, shmem_list_mutex
call mutex_unlock
jmp .exit jmp .exit
.cleanup2: .cleanup3:
mov [size], edx mov ecx, [current_process]
add ecx, PROC.heap_lock
call mutex_unlock
mov eax, edi mov eax, edi
call destroy_smap call free
.cleanup2:
call dereference_smem
jmp .exit jmp .exit
endp endp
align 4 align 4
proc shmem_close stdcall, name:dword proc shmem_close stdcall, name:dword
mov eax, [name] cmp [name], 0
test eax, eax
jz .fail jz .fail
push esi push esi
push edi push edi
pushfd
cli
mov esi, [current_slot] mov ecx, [current_process]
add esi, APP_OBJ_OFFSET lea edi, [ecx+PROC.smap_list]
add ecx, PROC.heap_lock
call mutex_lock
mov esi, edi
.next: .next:
mov eax, [esi + APPOBJ.fd] mov edi, [edi+SMAP.fd]
test eax, eax cmp edi, esi
jz @F je .notfound
cmp eax, esi cmp [edi + SMAP.type], SMAP_TYPE_SMEM
mov esi, eax
je @F
cmp [eax + SMAP.magic], 'SMAP'
jne .next jne .next
mov edi, [eax + SMAP.parent] mov eax, [edi + SMAP.parent]
test edi, edi add eax, SMEM.name
jz .next
lea edi, [edi + SMEM.name] stdcall strncmp, [name], eax, 32
stdcall strncmp, [name], edi, 32
test eax, eax test eax, eax
jne .next 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 mov ecx, [current_process]
call [esi + APPOBJ.destroy] add ecx, PROC.heap_lock
@@: call mutex_unlock
popfd
stdcall destroy_smap, [current_process]
.exit:
pop edi pop edi
pop esi pop esi
.fail: .fail:
ret ret
.notfound:
mov ecx, [current_process]
add ecx, PROC.heap_lock
call mutex_unlock
jmp .exit
endp 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 ; incorrect address in the program
mov eax, [page_tabs+ebx*4] mov eax, [page_tabs+ebx*4]
test eax, 2 test eax, 1
jz .fail ; address not reserved for use. error jz .fail ; address not reserved for use. error
pop ebx pop ebx

View File

@ -42,10 +42,30 @@ struct APP_HDR
filename_size rd 1 filename_size rd 1
cmdline_size rd 1 cmdline_size rd 1
path_string rd 1 path_string rd 1
pedescr rd 1
ends 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 macro _clear_ op
{ mov ecx, op/4 {
mov ecx, op/4
xor eax, eax xor eax, eax
cld cld
rep stosd rep stosd
@ -98,30 +118,41 @@ proc fs_execute
filename_size rd 1 filename_size rd 1
cmdline_size rd 1 cmdline_size rd 1
path_string rd 1 path_string rd 1
pedescr rd 1
endl endl
mov [flags], edx mov [flags], edx
mov [cmdline], ecx mov [cmdline], ecx
mov [path_string], ebx mov [path_string], ebx
mov [filename_size], eax mov [filename_size], eax
mov esi, -ERROR_FILE_NOT_FOUND mov edi, -ERROR_FILE_NOT_FOUND
test eax, eax test eax, eax
jz .err_file jz .err_file
stdcall load_file, ebx stdcall load_file, ebx
test eax, eax test eax, eax
jz .err_file jz .err_file
stdcall load_file_maybe_pe, [path_string]
mov [pedescr], esi
mov [file_base], eax mov [file_base], eax
mov [file_size], ebx mov [file_size], ebx
test esi, esi
jnz .file_ok
mov edi, eax
cmp eax, -0x1000
ja .err_file
lea ebx, [hdr_cmdline] lea ebx, [hdr_cmdline]
call test_app_header ; fill our app header data locals with values from header of given program (if its correct) 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 test eax, eax
jz .err_hdr jz .err_hdr
.file_ok:
call lock_application_table call lock_application_table
call alloc_thread_slot ; create a slot for new thread 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 test eax, eax
jz .err_0 jz .err_0
@ -162,8 +193,15 @@ proc fs_execute
add [hdr_emem], ebx add [hdr_emem], ebx
@@: @@:
mov [cmdline_size], eax 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 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 test eax, eax
jz .err_hdr jz .err_hdr
@ -203,12 +241,17 @@ proc fs_execute
ret ret
.err_0: .err_0:
mov esi, [pedescr]
test esi, esi
jz @f
call dereference_pe
@@:
call unlock_application_table call unlock_application_table
.err_hdr: .err_hdr:
stdcall kernel_free, [file_base] stdcall kernel_free, [file_base]
.err_file: .err_file:
stdcall kernel_free, [path_string] stdcall kernel_free, [path_string]
mov eax, esi mov eax, edi
ret ret
endp endp
@ -330,13 +373,18 @@ proc create_process stdcall, app_size:dword
jz .fail jz .fail
mov [process], eax mov [process], eax
lea edi, [eax+PROC.heap_lock] lea edi, [eax+PROC.heap_base]
mov ecx, (PROC.ht_free-PROC.heap_lock)/4
list_init eax list_init eax
add eax, PROC.thr_list add eax, PROC.thr_list
list_init eax 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 xor eax, eax
cld cld
rep stosd rep stosd
@ -370,6 +418,8 @@ proc create_process stdcall, app_size:dword
lea edx, [edi-4096] lea edx, [edi-4096]
mov esi, [app_tabs] mov esi, [app_tabs]
test esi, esi
jz .no_page_dirs
.alloc_page_dir: .alloc_page_dir:
call alloc_page call alloc_page
@ -388,6 +438,7 @@ proc create_process stdcall, app_size:dword
dec esi dec esi
jnz .alloc_page_dir jnz .alloc_page_dir
.no_page_dirs:
stdcall map_page, [tmp_task_ptab], 0, PG_UNMAP stdcall map_page, [tmp_task_ptab], 0, PG_UNMAP
mov eax, [process] mov eax, [process]
@ -397,7 +448,7 @@ proc create_process stdcall, app_size:dword
ret ret
.fail: .fail:
mov ecx, [process] mov ecx, [process]
jcxz @F jecxz @F
call destroy_process call destroy_process
@@: @@:
@ -419,8 +470,6 @@ proc destroy_page_table stdcall, pg_tab:dword
mov eax, [esi] mov eax, [esi]
test eax, 1 test eax, 1
jz .next jz .next
test eax, 2
jz .next
test eax, 1 shl 9 test eax, 1 shl 9
jnz .next ;skip shared pages jnz .next ;skip shared pages
call free_page call free_page
@ -446,8 +495,16 @@ align 4
mov esi, ecx mov esi, ecx
list_del esi list_del esi
mov esi, [esi+PROC.dlls_list_ptr] lea ebx, [esi+PROC.smap_list]
call destroy_all_hdlls 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] mov esi, [esp]
add esi, PROC.pdt_0 add esi, PROC.pdt_0
@ -532,6 +589,7 @@ proc read_process_memory
r_count dd ? r_count dd ?
offset dd ? offset dd ?
tmp_r_cnt dd ? tmp_r_cnt dd ?
mapped_size dd ?
endl endl
mov [slot], eax mov [slot], eax
@ -541,6 +599,8 @@ proc read_process_memory
mov [offset], esi mov [offset], esi
pushad pushad
mov ecx, proc_mem_mutex
call mutex_lock
.read_mem: .read_mem:
mov edx, [offset] mov edx, [offset]
mov ebx, [tmp_r_cnt] mov ebx, [tmp_r_cnt]
@ -560,13 +620,14 @@ proc read_process_memory
push ecx push ecx
stdcall map_memEx, [proc_mem_map], \ 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 pop ecx
mov esi, [offset] mov esi, [offset]
and esi, 0xfff and esi, 0xfff
sub eax, esi sub eax, esi
jbe .ret jbe .ret_unmap
cmp ecx, eax cmp ecx, eax
jbe @f jbe @f
mov ecx, eax mov ecx, eax
@ -574,17 +635,26 @@ proc read_process_memory
@@: @@:
add esi, [proc_mem_map] add esi, [proc_mem_map]
mov edi, [buff] mov edi, [buff]
mov edx, ecx push ecx
rep movsb 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 add [offset], ecx
sub [tmp_r_cnt], edx sub [tmp_r_cnt], ecx
jnz .read_mem jnz .read_mem
.ret: .ret:
mov ecx, proc_mem_mutex
call mutex_unlock
popad popad
mov eax, [r_count] mov eax, [r_count]
ret ret
.ret_unmap:
stdcall unmap_memEx, [proc_mem_map], \
[slot], ebx, [mapped_size], [proc_mem_tab]
jmp .ret
endp endp
align 4 align 4
@ -603,6 +673,7 @@ proc write_process_memory
w_count dd ? w_count dd ?
offset dd ? offset dd ?
tmp_w_cnt dd ? tmp_w_cnt dd ?
mapped_size dd ?
endl endl
mov [slot], eax mov [slot], eax
@ -612,7 +683,9 @@ proc write_process_memory
mov [offset], esi mov [offset], esi
pushad pushad
.read_mem: mov ecx, proc_mem_mutex
call mutex_lock
.write_mem:
mov edx, [offset] mov edx, [offset]
mov ebx, [tmp_w_cnt] mov ebx, [tmp_w_cnt]
@ -630,13 +703,14 @@ proc write_process_memory
mov ebx, [offset] mov ebx, [offset]
push ecx push ecx
stdcall map_memEx, [proc_mem_map], \ 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 pop ecx
mov edi, [offset] mov edi, [offset]
and edi, 0xfff and edi, 0xfff
sub eax, edi sub eax, edi
jbe .ret jbe .ret_unmap
cmp ecx, eax cmp ecx, eax
jbe @f jbe @f
mov ecx, eax mov ecx, eax
@ -644,17 +718,25 @@ proc write_process_memory
@@: @@:
add edi, [proc_mem_map] add edi, [proc_mem_map]
mov esi, [buff] mov esi, [buff]
mov edx, ecx push ecx
rep movsb rep movsb
stdcall unmap_memEx, [proc_mem_map], \
[slot], ebx, [mapped_size], [proc_mem_tab]
pop ecx
add [w_count], edx add [w_count], ecx
add [offset], edx add [offset], ecx
sub [tmp_w_cnt], edx sub [tmp_w_cnt], ecx
jnz .read_mem jnz .write_mem
.ret: .ret:
mov ecx, proc_mem_mutex
call mutex_unlock
popad popad
mov eax, [w_count] mov eax, [w_count]
ret ret
.ret_unmap:
stdcall unmap_memEx, [proc_mem_map], [slot], ebx, [mapped_size], [proc_mem_tab]
jmp .ret
endp endp
;ebx = 1 - kernel thread ;ebx = 1 - kernel thread
@ -799,6 +881,76 @@ common_app_entry:
jz .exit jz .exit
; APPDATA.exec_params have first thread only, ; APPDATA.exec_params have first thread only,
; so second and next threads don't get here (they jump to .exit) ; 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],\ stdcall map_process_image, [ebp+APP_HDR._emem],\
[ebp+APP_HDR.img_base], [ebp+APP_HDR.img_size] [ebp+APP_HDR.img_base], [ebp+APP_HDR.img_size]
mov esi, [ebp+APP_HDR.path_string] mov esi, [ebp+APP_HDR.path_string]
@ -846,8 +998,9 @@ common_app_entry:
mov byte [edi], 0 mov byte [edi], 0
.check_tls_header: .check_tls_header:
cmp word [6], '02' cmp word [6], '02'
jne .try_load_dll ;.cleanup jne .try_load_dll ;.common
call init_heap call init_heap
.common_tls:
stdcall user_alloc, 4096 stdcall user_alloc, 4096
mov edx, [current_slot] mov edx, [current_slot]
mov [edx+APPDATA.tls_base], eax mov [edx+APPDATA.tls_base], eax
@ -862,7 +1015,7 @@ common_app_entry:
; Test app header version ; Test app header version
mov ecx, dword[ebp+APP_HDR.img_base] mov ecx, dword[ebp+APP_HDR.img_base]
cmp dword[ecx+8], 2 cmp dword[ecx+8], 2
jne .cleanup jne .common
;if APP_HEADER.version = 2 => load lib/dll.obj & change eip to APP_STARTUP_THUNK ;if APP_HEADER.version = 2 => load lib/dll.obj & change eip to APP_STARTUP_THUNK
DEBUGF 1, 'K : App header version 2\n' DEBUGF 1, 'K : App header version 2\n'
stdcall load_library, dll_lib_path, 0 stdcall load_library, dll_lib_path, 0
@ -889,7 +1042,9 @@ common_app_entry:
mov [ecx+REG_EIP], eax mov [ecx+REG_EIP], eax
; } End patch by Coldy, For DLL autoload ; } End patch by Coldy, For DLL autoload
.cleanup: mov fs, dx
.common:
stdcall free_kernel_space, [ebp+APP_HDR.img_base] stdcall free_kernel_space, [ebp+APP_HDR.img_base]
stdcall kernel_free, ebp stdcall kernel_free, ebp
mov ebx, [current_slot] 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_lib_path db '/RD/1/LIB/DLL.OBJ',0
dll_error_msg db '"DLL.OBJ not found!\nTerminate application!" -dE',0 dll_error_msg db '"DLL.OBJ not found!\nTerminate application!" -dE',0
; } End patch by Coldy, For DLL autoload ; } End patch by Coldy, For DLL autoload
pe_loader_usermode db '/rd/1/lib/kolibri.dll',0
align 4 align 4
shmem_list: shmem_list:
.bk dd shmem_list .bk dd shmem_list
.fd dd shmem_list .fd dd shmem_list
dll_list: pe_list:
.bk dd dll_list .bk dd pe_list
.fd dd dll_list .fd dd pe_list
pcidev_list: pcidev_list:
.bk dd pcidev_list .bk dd pcidev_list
.fd dd pcidev_list .fd dd pcidev_list
MAX_DEFAULT_DLL_ADDR = 0x80000000 shared_locked_list:
MIN_DEFAULT_DLL_ADDR = 0x70000000 dd shared_locked_list
dll_cur_addr dd MIN_DEFAULT_DLL_ADDR dd shared_locked_list
; supported videomodes ; supported videomodes
@ -399,6 +401,12 @@ os_stack_seg dd ?
srv.fd dd ? srv.fd dd ?
srv.bk 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 ? LFBAddress dd ?
PUTPIXEL dd ? PUTPIXEL dd ?
@ -432,6 +440,7 @@ proc_mem_pdir dd ?
proc_mem_tab dd ? proc_mem_tab dd ?
tmp_task_ptab dd ? tmp_task_ptab dd ?
zero_page_tab dd ?
default_io_map dd ? default_io_map dd ?

View File

@ -3660,6 +3660,67 @@ Architecture Software Developer's Manual, Volume 3, Appendix B);
* edx = размер загруженного файла или 0 * edx = размер загруженного файла или 0
Примечания: Примечания:
* функция загружает и, при необходимости, распаковывает файл (kunpack) * функция загружает и, при необходимости, распаковывает файл (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 - отладка. ======================= ======================== Функция 69 - отладка. =======================

View File

@ -3645,6 +3645,68 @@ Remarks:
---------------------- Constants for registers: ---------------------- ---------------------- Constants for registers: ----------------------
eax - SF_SYS_MISC (68) eax - SF_SYS_MISC (68)
ebx - SSF_MEM_ALLOC_RING (29) 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. ====================== ====================== Function 69 - debugging. ======================

View File

@ -322,6 +322,17 @@ high_code:
mov ecx, application_table_mutex mov ecx, application_table_mutex
call mutex_init 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 mov ecx, ide_mutex
call mutex_init call mutex_init
mov ecx, ide_channel1_mutex mov ecx, ide_channel1_mutex
@ -513,6 +524,9 @@ high_code:
add eax, ebx add eax, ebx
mov [ipc_ptab], eax mov [ipc_ptab], eax
add eax, ebx
mov [zero_page_tab], eax
stdcall kernel_alloc, (unpack.LZMA_BASE_SIZE+(unpack.LZMA_LIT_SIZE shl \ stdcall kernel_alloc, (unpack.LZMA_BASE_SIZE+(unpack.LZMA_LIT_SIZE shl \
(unpack.lc+unpack.lp)))*4 (unpack.lc+unpack.lp)))*4
@ -2879,40 +2893,39 @@ align 4
mov [bgrlockpid], eax mov [bgrlockpid], eax
cmp [img_background], static_background_data cmp [img_background], static_background_data
jz .nomem 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 mov [esp+32], eax
test eax, eax test eax, eax
jz .nomem jz .nomem_unlock
mov ebx, eax mov ebx, eax
shr ebx, 12 shr ebx, 12
or dword [page_tabs+(ebx-1)*4], MEM_BLOCK_DONT_FREE
mov esi, [img_background] mov esi, [img_background]
shr esi, 12 shr esi, 12
mov ecx, [mem_BACKGROUND] mov ecx, [mem_BACKGROUND]
add ecx, 0xFFF add ecx, 0xFFF
shr ecx, 12 shr ecx, 12
;--------------------------------------
align 4
.z: .z:
mov eax, [page_tabs+ebx*4]
test al, 1
jz @f
call free_page
;--------------------------------------
align 4
@@:
mov eax, [page_tabs+esi*4] mov eax, [page_tabs+esi*4]
or al, PG_UWR or eax, PG_UWR+PG_SHARED
mov [page_tabs+ebx*4], eax mov [page_tabs+ebx*4], eax
mov eax, ebx mov eax, ebx
shl eax, 12 shl eax, 12
invlpg [eax] invlpg [eax]
inc ebx inc ebx
inc esi inc esi
loop .z dec ecx
jnz .z
mov ecx, [current_process]
add ecx, PROC.heap_lock
call mutex_unlock
ret ret
;-------------------------------------- .nomem_unlock:
align 4 mov ecx, [current_process]
add ecx, PROC.heap_lock
call mutex_unlock
.nomem: .nomem:
and [bgrlockpid], 0 and [bgrlockpid], 0
mov [bgrlock], 0 mov [bgrlock], 0
@ -2926,30 +2939,7 @@ nosb6:
mov eax, [current_slot_idx] mov eax, [current_slot_idx]
cmp [bgrlockpid], eax cmp [bgrlockpid], eax
jnz .err jnz .err
mov eax, ecx stdcall user_free, 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
mov [esp+32], eax mov [esp+32], eax
and [bgrlockpid], 0 and [bgrlockpid], 0
mov [bgrlock], 0 mov [bgrlock], 0
@ -4925,6 +4915,14 @@ if defined debug_com_base
pop ax dx pop ax dx
end if 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 mov [msg_board_data+ecx], bl
cmp byte [debug_direct_print], 1 cmp byte [debug_direct_print], 1
jnz .end jnz .end

View File

@ -15,6 +15,7 @@ include "core/fpu.inc" ; all fpu/sse support
include "core/memory.inc" include "core/memory.inc"
include "core/mtrr.inc" include "core/mtrr.inc"
include "core/heap.inc" include "core/heap.inc"
include "core/peuser.inc"
include "core/malloc.inc" ; small kernel heap include "core/malloc.inc" ; small kernel heap
include "core/taskman.inc" include "core/taskman.inc"
include "core/dll.inc" include "core/dll.inc"