/kernel/branches/kolibrios-pe-clevermouse/const.inc |
---|
440,11 → 440,11 |
struct PROC |
list LHEAD |
thr_list LHEAD |
smap_list LHEAD |
heap_lock MUTEX |
heap_base rd 1 |
heap_top rd 1 |
mem_used rd 1 |
dlls_list_ptr rd 1 |
pdt_0_phys rd 1 |
pdt_1_phys rd 1 |
io_map_0 rd 1 |
651,37 → 651,16 |
name rb 32 ;+24 |
ends |
struct SMAP APPOBJ |
struct SMAP |
fd dd ? ;next in mmapped list |
bk dd ? ;prev in mmapped list |
base dd ? ;mapped base |
parent dd ? ;SMEM |
ends |
struct DLLDESCR |
bk dd ? |
fd dd ? ;+4 |
data dd ? ;+8 |
size dd ? ;+12 |
timestamp dq ? |
refcount dd ? |
defaultbase dd ? |
coff_hdr dd ? |
symbols_ptr dd ? |
symbols_num dd ? |
symbols_lim dd ? |
exports dd ? ;export table |
name rb 260 |
ends |
struct HDLL |
fd dd ? ;next object in list |
bk dd ? ;prev object in list |
pid dd ? ;owner id |
base dd ? ;mapped base |
size dd ? ;mapped size |
refcount dd ? ;reference counter for this process and this lib |
parent dd ? ;DLLDESCR |
type dd ? ;SMAP_TYPE_SMEM or SMAP_TYPE_PE |
parent dd ? ;SMEM or PEDESCR |
ends |
SMAP_TYPE_SMEM = 1 |
SMAP_TYPE_PE = 2 |
struct DQ |
lo dd ? |
810,6 → 789,55 |
owner dd ? ; pointer to SRV or 0 |
ends |
struct PEDESCR |
bk dd ? |
fd dd ? |
size dd ? ; in pages |
timestamp dq ? |
refcount dd ? |
defaultbase dd ? |
name dd ? |
entry dd ? |
stacksize dd ? |
page_array_lock MUTEX |
; After those fields the array follows, one dword per every of [size] pages. |
; The value of every field has 3 parts: |
; - upper 20 bits are page number or zero; |
; - next 4 bits are access rights shareable/executable/readable/writable |
; in the same order as IMAGE_SCN_MEM_xxx shifted appropriately; |
; - lower 8 bits are reference counter. |
; The exact meaning depends on page type. |
; * For a page with data in non-shareable section |
; which has at least one unmodified copy: |
; - upper 20 bits are page number for unmodified copy, |
; - reference counter = number of unmodified copies is nonzero up to 0xFF. |
; If reference counter reaches 0xFF, it becomes locked at this value. |
; If reference counter reaches zero, the last copy changes ownership |
; to the last process, |
; and the page is converted to the following state. |
; * For a page with data in non-shareable section |
; with no unmodified copies: |
; - all fields are reset to zero. |
; The original content is lost; map_pe_usermode would reload from file. |
; * For a page with zeroes in non-shareable section: |
; - upper 20 bits are zero, |
; - lower 8 bits are 0xFF. |
; * For a page in shareable section with data or with zeroes: |
; - upper 20 bits are page number for all copies, |
; - lower 8 bits are reference counter from 1 to 0xFF. |
; Reference counter does not actually matter here, |
; it equals [refcount] unless 0xFF was once reached, |
; but is kept for consistency. |
ends |
struct SHARED_LOCKED_PAGE |
fd dd ? |
bk dd ? |
address dd ? |
parent dd ? |
offs dd ? |
ends |
struct IDE_DATA |
ProgrammingInterface dd ? |
Interrupt dw ? |
933,7 → 961,20 |
NumLinenum dw ? |
Characteristics dd ? |
ends |
IMAGE_SCN_MEM_SHARED = 10000000h |
IMAGE_SCN_MEM_EXECUTE = 20000000h |
IMAGE_SCN_MEM_READ = 40000000h |
IMAGE_SCN_MEM_WRITE = 80000000h |
struct STRIPPED_PE_SECTION |
Name rb 8 |
VirtualSize dd ? |
VirtualAddress dd ? |
SizeOfRawData dd ? |
PtrRawData dd ? |
Characteristics dd ? |
ends |
struct COFF_RELOC |
VirtualAddress dd ? |
SymIndex dd ? |
971,6 → 1012,62 |
SPE_DIRECTORY_EXPORT = 1 |
SPE_DIRECTORY_BASERELOC = 2 |
struct IMAGE_DATA_DIRECTORY |
VirtualAddress dd ? |
isize dd ? |
ends |
struct IMAGE_OPTIONAL_HEADER32 |
Magic dw ? |
MajorLinkerVersion db ? |
MinorLinkerVersion db ? |
SizeOfCode dd ? |
SizeOfInitializedData dd ? |
SizeOfUninitializedData dd ? |
AddressOfEntryPoint dd ? |
BaseOfCode dd ? |
BaseOfData dd ? |
ImageBase dd ? |
SectionAlignment dd ? |
FileAlignment dd ? |
MajorOperatingSystemVersion dw ? |
MinorOperatingSystemVersion dw ? |
MajorImageVersion dw ? |
MinorImageVersion dw ? |
MajorSubsystemVersion dw ? |
MinorSubsystemVersion dw ? |
Win32VersionValue dd ? |
SizeOfImage dd ? |
SizeOfHeaders dd ? |
CheckSum dd ? |
Subsystem dw ? |
DllCharacteristics dw ? |
SizeOfStackReserve dd ? |
SizeOfStackCommit dd ? |
SizeOfHeapReserve dd ? |
SizeOfHeapCommit dd ? |
LoaderFlags dd ? |
NumberOfDirectories dd ? |
DataDirectory IMAGE_DATA_DIRECTORY ? |
Directories rb sizeof.IMAGE_DATA_DIRECTORY*15 |
ends |
struct IMAGE_FILE_HEADER |
Machine dw ? |
NumberOfSections dw ? |
TimeDateStamp dd ? |
PointerToSymbolTable dd ? |
NumberOfSymbols dd ? |
SizeOfOptionalHeader dw ? |
Characteristics dw ? |
ends |
struct IMAGE_NT_HEADERS |
Signature dd ? |
FileHeader IMAGE_FILE_HEADER |
OptionalHeader IMAGE_OPTIONAL_HEADER32 |
ends |
struct IOCTL |
handle dd ? |
io_code dd ? |
/kernel/branches/kolibrios-pe-clevermouse/core/dll.inc |
---|
901,9 → 901,13 |
proc load_library stdcall, file_name:dword, encoding:dword |
locals |
fullname dd ? |
fileinfo rb 40 |
filesize dd ? |
coff dd ? |
img_base dd ? |
img_size dd ? |
symbols_ptr dd ? |
symbols_lim dd ? |
exports dd ? |
endl |
; resolve file name |
917,105 → 921,19 |
pop ebp |
test eax, eax |
jz .fail |
; scan for required DLL in list of already loaded for this process, |
; ignore timestamp |
cli |
mov esi, [current_process] |
mov edi, [fullname] |
mov ebx, [esi+PROC.dlls_list_ptr] |
test ebx, ebx |
jz .not_in_process |
mov esi, [ebx+HDLL.fd] |
.scan_in_process: |
cmp esi, ebx |
jz .not_in_process |
mov eax, [esi+HDLL.parent] |
add eax, DLLDESCR.name |
stdcall strncmp, eax, edi, -1 |
test eax, eax |
jnz .next_in_process |
; simple variant: load DLL which is already loaded in this process |
; just increment reference counters and return address of exports table |
inc [esi+HDLL.refcount] |
mov ecx, [esi+HDLL.parent] |
inc [ecx+DLLDESCR.refcount] |
mov eax, [ecx+DLLDESCR.exports] |
sub eax, [ecx+DLLDESCR.defaultbase] |
add eax, [esi+HDLL.base] |
sti |
push eax |
stdcall kernel_free, [fullname] |
pop eax |
ret |
.next_in_process: |
mov esi, [esi+HDLL.fd] |
jmp .scan_in_process |
.not_in_process: |
; scan in full list, compare timestamp |
sti |
lea eax, [fileinfo] |
stdcall get_fileinfo, edi, eax |
test eax, eax |
jnz .fail |
cli |
mov esi, [dll_list.fd] |
.scan_for_dlls: |
cmp esi, dll_list |
jz .load_new |
lea eax, [esi+DLLDESCR.name] |
stdcall strncmp, eax, edi, -1 |
test eax, eax |
jnz .continue_scan |
.test_prev_dll: |
mov eax, dword [fileinfo+24]; last modified time |
mov edx, dword [fileinfo+28]; last modified date |
cmp dword [esi+DLLDESCR.timestamp], eax |
jnz .continue_scan |
cmp dword [esi+DLLDESCR.timestamp+4], edx |
jz .dll_already_loaded |
.continue_scan: |
mov esi, [esi+DLLDESCR.fd] |
jmp .scan_for_dlls |
; new DLL |
.load_new: |
sti |
; load file |
stdcall load_file, edi |
stdcall load_file, [fullname] |
test eax, eax |
jz .fail |
mov [coff], eax |
mov dword [fileinfo+32], ebx |
mov [filesize], ebx |
; allocate DLLDESCR struct; size is DLLDESCR.sizeof plus size of DLL name |
mov esi, edi |
mov ecx, -1 |
xor eax, eax |
repnz scasb |
not ecx |
lea eax, [ecx+sizeof.DLLDESCR] |
push ecx |
call malloc |
pop ecx |
test eax, eax |
jz .fail_and_free_coff |
; save timestamp |
lea edi, [eax+DLLDESCR.name] |
rep movsb |
mov esi, eax |
mov eax, dword [fileinfo+24] |
mov dword [esi+DLLDESCR.timestamp], eax |
mov eax, dword [fileinfo+28] |
mov dword [esi+DLLDESCR.timestamp+4], eax |
; calculate size of loaded DLL |
mov edx, [coff] |
movzx ecx, [edx+COFF_HEADER.nSections] |
movzx ecx, [eax+COFF_HEADER.nSections] |
xor ebx, ebx |
add edx, 20 |
lea edx, [eax+20] |
@@: |
call coff_get_align |
add ebx, eax |
1026,31 → 944,19 |
dec ecx |
jnz @B |
; it must be nonzero and not too big |
mov [esi+DLLDESCR.size], ebx |
mov [img_size], ebx |
test ebx, ebx |
jz .fail_and_free_dll |
cmp ebx, MAX_DEFAULT_DLL_ADDR-MIN_DEFAULT_DLL_ADDR |
ja .fail_and_free_dll |
; allocate memory for kernel-side image |
stdcall kernel_alloc, ebx |
jz .fail_and_free_coff |
cmp ebx, 0x10000000 |
ja .fail_and_free_coff |
; allocate memory |
call init_heap |
stdcall user_alloc, [img_size] |
test eax, eax |
jz .fail_and_free_dll |
mov [esi+DLLDESCR.data], eax |
; calculate preferred base address |
add ebx, 0x1FFF |
and ebx, not 0xFFF |
mov ecx, [dll_cur_addr] |
lea edx, [ecx+ebx] |
cmp edx, MAX_DEFAULT_DLL_ADDR |
jb @f |
mov ecx, MIN_DEFAULT_DLL_ADDR |
lea edx, [ecx+ebx] |
@@: |
mov [esi+DLLDESCR.defaultbase], ecx |
mov [dll_cur_addr], edx |
jz .fail_and_free_coff |
mov [img_base], eax |
; copy sections and set correct values for VirtualAddress'es in headers |
push esi |
mov edx, [coff] |
movzx ebx, [edx+COFF_HEADER.nSections] |
mov edi, eax |
1058,15 → 964,11 |
cld |
@@: |
call coff_get_align |
add ecx, eax |
add edi, eax |
not eax |
and ecx, eax |
and edi, eax |
mov [edx+COFF_SECTION.VirtualAddress], ecx |
add ecx, [edx+COFF_SECTION.SizeOfRawData] |
mov [edx+COFF_SECTION.VirtualAddress], edi |
mov esi, [edx+COFF_SECTION.PtrRawData] |
push ecx |
mov ecx, [edx+COFF_SECTION.SizeOfRawData] |
test esi, esi |
jnz .copy |
1077,84 → 979,30 |
add esi, [coff] |
rep movsb |
.next: |
pop ecx |
add edx, sizeof.COFF_SECTION |
dec ebx |
jnz @B |
pop esi |
; save some additional data from COFF file |
; later we will use COFF header, headers for sections and symbol table |
; and also relocations table for all sections |
mov edx, [coff] |
mov ebx, [edx+COFF_HEADER.pSymTable] |
mov edi, dword [fileinfo+32] |
mov edi, [filesize] |
sub edi, ebx |
jc .fail_and_free_data |
mov [esi+DLLDESCR.symbols_lim], edi |
mov [symbols_lim], edi |
add ebx, edx |
movzx ecx, [edx+COFF_HEADER.nSections] |
lea ecx, [ecx*5] |
lea edi, [edi+ecx*8+20] |
add edx, 20 |
@@: |
movzx eax, [edx+COFF_SECTION.NumReloc] |
lea eax, [eax*5] |
lea edi, [edi+eax*2] |
add edx, sizeof.COFF_SECTION |
sub ecx, 5 |
jnz @b |
stdcall kernel_alloc, edi |
test eax, eax |
jz .fail_and_free_data |
mov edx, [coff] |
movzx ecx, [edx+COFF_HEADER.nSections] |
lea ecx, [ecx*5] |
lea ecx, [ecx*2+5] |
mov [esi+DLLDESCR.coff_hdr], eax |
push esi |
mov esi, edx |
mov edi, eax |
rep movsd |
pop esi |
mov [esi+DLLDESCR.symbols_ptr], edi |
push esi |
mov ecx, [edx+COFF_HEADER.nSymbols] |
mov [esi+DLLDESCR.symbols_num], ecx |
mov ecx, [esi+DLLDESCR.symbols_lim] |
mov esi, ebx |
rep movsb |
pop esi |
mov ebx, [esi+DLLDESCR.coff_hdr] |
push esi |
movzx eax, [edx+COFF_HEADER.nSections] |
lea edx, [ebx+20] |
@@: |
movzx ecx, [edx+COFF_SECTION.NumReloc] |
lea ecx, [ecx*5] |
mov esi, [edx+COFF_SECTION.PtrReloc] |
mov [edx+COFF_SECTION.PtrReloc], edi |
sub [edx+COFF_SECTION.PtrReloc], ebx |
add esi, [coff] |
shr ecx, 1 |
rep movsd |
adc ecx, ecx |
rep movsw |
add edx, sizeof.COFF_SECTION |
dec eax |
jnz @b |
pop esi |
; coff_hdr = coff |
; symbols_num = coff.nSymbols |
mov [symbols_ptr], ebx |
mov ebx, edx |
; fixup symbols |
mov edx, ebx |
mov eax, [ebx+COFF_HEADER.nSymbols] |
mov eax, [edx+COFF_HEADER.nSymbols] |
add edx, 20 |
mov ecx, [esi+DLLDESCR.symbols_num] |
lea ecx, [ecx*9] |
lea ecx, [eax*9] |
add ecx, ecx |
add ecx, [esi+DLLDESCR.symbols_ptr] |
add ecx, [symbols_ptr] |
stdcall fix_coff_symbols, edx, [esi+DLLDESCR.symbols_ptr], eax, \ |
stdcall fix_coff_symbols, edx, [symbols_ptr], eax, \ |
ecx, 0 |
; test eax, eax |
; jnz @F |
1161,111 → 1009,25 |
; |
;@@: |
stdcall get_coff_sym, [esi+DLLDESCR.symbols_ptr], [ebx+COFF_HEADER.nSymbols], szEXPORTS |
stdcall get_coff_sym, [symbols_ptr], [ebx+COFF_HEADER.nSymbols], szEXPORTS |
test eax, eax |
jnz @F |
stdcall get_coff_sym, [esi+DLLDESCR.symbols_ptr], [ebx+COFF_HEADER.nSymbols], sz_EXPORTS |
stdcall get_coff_sym, [symbols_ptr], [ebx+COFF_HEADER.nSymbols], sz_EXPORTS |
@@: |
mov [esi+DLLDESCR.exports], eax |
mov [exports], eax |
; fix relocs in the hidden copy in kernel memory to default address |
; it is first fix; usually this will be enough, but second fix |
; can be necessary if real load address will not equal assumption |
mov eax, [esi+DLLDESCR.data] |
sub eax, [esi+DLLDESCR.defaultbase] |
stdcall fix_coff_relocs, ebx, [esi+DLLDESCR.symbols_ptr], eax |
stdcall fix_coff_relocs, ebx, [symbols_ptr], 0 |
stdcall kernel_free, [coff] |
cli |
; initialize DLLDESCR struct |
and dword [esi+DLLDESCR.refcount], 0; no HDLLs yet; later it will be incremented |
mov [esi+DLLDESCR.fd], dll_list |
mov eax, [dll_list.bk] |
mov [dll_list.bk], esi |
mov [esi+DLLDESCR.bk], eax |
mov [eax+DLLDESCR.fd], esi |
.dll_already_loaded: |
stdcall kernel_free, [fullname] |
inc [esi+DLLDESCR.refcount] |
push esi |
call init_heap |
pop esi |
mov edi, [esi+DLLDESCR.size] |
stdcall user_alloc_at, [esi+DLLDESCR.defaultbase], edi |
test eax, eax |
jnz @f |
stdcall user_alloc, edi |
test eax, eax |
jz .fail_and_dereference |
@@: |
mov [img_base], eax |
mov eax, sizeof.HDLL |
call malloc |
test eax, eax |
jz .fail_and_free_user |
mov ebx, [current_slot_idx] |
shl ebx, 5 |
mov edx, [TASK_TABLE+ebx+TASKDATA.pid] |
mov [eax+HDLL.pid], edx |
push eax |
call init_dlls_in_thread |
pop ebx |
test eax, eax |
jz .fail_and_free_user |
mov edx, [eax+HDLL.fd] |
mov [ebx+HDLL.fd], edx |
mov [ebx+HDLL.bk], eax |
mov [eax+HDLL.fd], ebx |
mov [edx+HDLL.bk], ebx |
mov eax, ebx |
mov ebx, [img_base] |
mov [eax+HDLL.base], ebx |
mov [eax+HDLL.size], edi |
mov [eax+HDLL.refcount], 1 |
mov [eax+HDLL.parent], esi |
mov edx, ebx |
shr edx, 12 |
or dword [page_tabs+(edx-1)*4], MEM_BLOCK_DONT_FREE |
; copy entries of page table from kernel-side image to usermode |
; use copy-on-write for user-mode image, so map as readonly |
xor edi, edi |
mov ecx, [esi+DLLDESCR.data] |
shr ecx, 12 |
.map_pages_loop: |
mov eax, [page_tabs+ecx*4] |
and eax, not 0xFFF |
or al, PG_UR |
xchg eax, [page_tabs+edx*4] |
test al, 1 |
jz @f |
call free_page |
@@: |
invlpg [ebx+edi] |
inc ecx |
inc edx |
add edi, 0x1000 |
cmp edi, [esi+DLLDESCR.size] |
jb .map_pages_loop |
; if real user-mode base is not equal to preferred base, relocate image |
sub ebx, [esi+DLLDESCR.defaultbase] |
jz @f |
stdcall rebase_coff, [esi+DLLDESCR.coff_hdr], [esi+DLLDESCR.symbols_ptr], ebx |
@@: |
mov eax, [esi+DLLDESCR.exports] |
sub eax, [esi+DLLDESCR.defaultbase] |
add eax, [img_base] |
sti |
mov eax, [exports] |
ret |
.fail_and_free_data: |
stdcall kernel_free, [esi+DLLDESCR.data] |
.fail_and_free_dll: |
mov eax, esi |
call free |
stdcall user_free, [img_base] |
.fail_and_free_coff: |
stdcall kernel_free, [coff] |
.fail: |
1272,88 → 1034,24 |
stdcall kernel_free, [fullname] |
xor eax, eax |
ret |
.fail_and_free_user: |
stdcall user_free, [img_base] |
.fail_and_dereference: |
mov eax, 1 ; delete 1 reference |
call dereference_dll |
sti |
xor eax, eax |
ret |
endp |
; initialize [APPDATA.dlls_list_ptr] for given thread |
; DLL is per-process object, so APPDATA.dlls_list_ptr must be |
; kept in sync for all threads of one process. |
; out: eax = APPDATA.dlls_list_ptr if all is OK, |
; NULL if memory allocation failed |
init_dlls_in_thread: |
mov ebx, [current_process] |
mov eax, [ebx+PROC.dlls_list_ptr] |
test eax, eax |
jnz .ret |
mov eax, 8 |
call malloc ; FIXME |
test eax, eax |
jz .ret |
mov [eax], eax |
mov [eax+4], eax |
mov ebx, [current_process] |
mov [ebx+PROC.dlls_list_ptr], eax |
.ret: |
ret |
; in: eax = number of references to delete, esi -> DLLDESCR struc |
dereference_dll: |
sub [esi+DLLDESCR.refcount], eax |
jnz .ret |
mov eax, [esi+DLLDESCR.fd] |
mov edx, [esi+DLLDESCR.bk] |
mov [eax+DLLDESCR.bk], edx |
mov [edx+DLLDESCR.fd], eax |
stdcall kernel_free, [esi+DLLDESCR.coff_hdr] |
stdcall kernel_free, [esi+DLLDESCR.data] |
; in: esi -> PEDESCR struct |
proc dereference_pe |
mov ecx, pe_list_mutex |
call mutex_lock |
dec [esi+PEDESCR.refcount] |
jnz mutex_unlock |
mov eax, [esi+PEDESCR.fd] |
mov edx, [esi+PEDESCR.bk] |
mov [eax+PEDESCR.bk], edx |
mov [edx+PEDESCR.fd], eax |
call mutex_unlock |
mov eax, esi |
call free |
.ret: |
ret |
endp |
destroy_hdll: |
push ebx ecx esi edi |
mov ebx, [eax+HDLL.base] |
mov esi, [eax+HDLL.parent] |
mov edx, [esi+DLLDESCR.size] |
push eax |
mov esi, [eax+HDLL.parent] |
mov eax, [eax+HDLL.refcount] |
call dereference_dll |
pop eax |
mov edx, [eax+HDLL.bk] |
mov ebx, [eax+HDLL.fd] |
mov [ebx+HDLL.bk], edx |
mov [edx+HDLL.fd], ebx |
call free |
pop edi esi ecx ebx |
ret |
; ecx -> APPDATA for slot, esi = dlls_list_ptr |
destroy_all_hdlls: |
test esi, esi |
jz .ret |
.loop: |
mov eax, [esi+HDLL.fd] |
cmp eax, esi |
jz free |
call destroy_hdll |
jmp .loop |
.ret: |
ret |
align 4 |
stop_all_services: |
push ebp |
/kernel/branches/kolibrios-pe-clevermouse/core/heap.inc |
---|
23,8 → 23,13 |
MEM_BLOCK_USED = 0x08 |
MEM_BLOCK_DONT_FREE = 0x10 |
LAZY_ALLOC_PAGE = 2 |
LAZY_ALLOC_UNREADABLE = 20h |
LAZY_ALLOC_UNWRITABLE = 40h |
macro calc_index op |
{ shr op, 12 |
{ |
shr op, 12 |
dec op |
cmp op, 63 |
jna @f |
561,35 → 566,42 |
sub eax, PAGE_SIZE |
ret |
@@: |
lea ecx, [ebx + PROC.heap_lock] |
call mutex_init |
mov esi, [ebx + PROC.mem_used] |
add esi, 4095 |
and esi, not 4095 |
mov [ebx + PROC.mem_used], esi |
mov edx, [ebx+PROC.mem_used] |
add edx, 4095 |
and edx, not 4095 |
mov [ebx+PROC.mem_used], edx |
mov eax, HEAP_TOP |
mov [ebx + PROC.heap_base], esi |
mov [ebx+PROC.heap_base], edx |
mov [ebx + PROC.heap_top], eax |
sub eax, esi |
shr esi, 10 |
sub eax, edx |
shr edx, 10 |
mov ecx, eax |
sub eax, PAGE_SIZE |
or ecx, MEM_BLOCK_FREE |
mov [page_tabs + esi], ecx |
mov [page_tabs + edx], ecx |
ret |
endp |
align 4 |
proc user_alloc stdcall, alloc_size:dword |
proc user_alloc ;stdcall, alloc_size:dword |
mov ecx, [current_process] |
add ecx, PROC.heap_lock |
call mutex_lock |
stdcall user_alloc_nolock, [esp+4] |
push eax |
mov ecx, [current_process] |
add ecx, PROC.heap_lock |
call mutex_unlock |
pop eax |
ret 4 |
endp |
proc user_alloc_nolock stdcall, alloc_size:dword |
push ebx esi edi |
mov ebx, [current_process] |
lea ecx, [ebx + PROC.heap_lock] |
call mutex_lock |
mov ecx, [alloc_size] |
add ecx, (4095 + PAGE_SIZE) |
and ecx, not 4095 |
628,15 → 640,6 |
jnz @B |
.no: |
mov edx, [current_process] |
mov ebx, [alloc_size] |
add ebx, 0xFFF |
and ebx, not 0xFFF |
add [edx + PROC.mem_used], ebx |
lea ecx, [edx + PROC.heap_lock] |
call mutex_unlock |
lea eax, [esi + 4096] |
pop edi |
652,9 → 655,6 |
add esi, eax |
jmp .scan |
.m_exit: |
mov ecx, [current_process] |
lea ecx, [ecx + PROC.heap_lock] |
call mutex_unlock |
xor eax, eax |
pop edi |
664,15 → 664,25 |
endp |
align 4 |
proc user_alloc_at stdcall, address:dword, alloc_size:dword |
proc user_alloc_at ;stdcall, address:dword, alloc_size:dword |
mov ecx, [current_process] |
add ecx, PROC.heap_lock |
call mutex_lock |
stdcall user_alloc_at_nolock, [esp+8], [esp+8] |
push eax |
mov ecx, [current_process] |
add ecx, PROC.heap_lock |
call mutex_unlock |
pop eax |
ret 8 |
endp |
proc user_alloc_at_nolock stdcall, address:dword, alloc_size:dword |
push ebx |
push esi |
push edi |
mov ebx, [current_process] |
lea ecx, [ebx + PROC.heap_lock] |
call mutex_lock |
mov edx, [address] |
and edx, not 0xFFF |
697,9 → 707,6 |
mov esi, ecx |
jmp .scan |
.error: |
mov ecx, [current_process] |
lea ecx, [ecx + PROC.heap_lock] |
call mutex_unlock |
xor eax, eax |
pop edi |
752,15 → 759,6 |
mov [page_tabs + ebx*4], ecx |
.nothird: |
mov edx, [current_process] |
mov ebx, [alloc_size] |
add ebx, 0xFFF |
and ebx, not 0xFFF |
add [edx + PROC.mem_used], ebx |
lea ecx, [edx + PROC.heap_lock] |
call mutex_unlock |
mov eax, [address] |
pop edi |
775,8 → 773,6 |
push esi |
mov esi, [base] |
test esi, esi |
jz .fail |
push ebx |
786,6 → 782,7 |
xor ebx, ebx |
shr esi, 12 |
jz .cantfree |
mov eax, [page_tabs + (esi-1)*4] |
test al, MEM_BLOCK_USED |
jz .cantfree |
792,6 → 789,11 |
test al, MEM_BLOCK_DONT_FREE |
jnz .cantfree |
push 0 |
virtual at esp |
.num_released_pages dd ? |
end virtual |
and eax, not 4095 |
mov ecx, eax |
or al, MEM_BLOCK_FREE |
801,16 → 803,18 |
shr ecx, 12 |
jz .released |
.release: |
xor eax, eax |
xchg eax, [page_tabs + esi*4] |
test al, 1 |
jz @F |
test eax, PG_SHARED |
jnz @F |
call free_page |
mov edx, [page_tabs+esi*4] |
mov dword [page_tabs+esi*4], 0 |
mov eax, esi |
shl eax, 12 |
invlpg [eax] |
test dl, 1 |
jz @F |
inc [.num_released_pages] |
test edx, PG_SHARED |
jnz @f |
mov eax, edx |
call free_page |
@@: |
inc esi |
dec ecx |
817,17 → 821,13 |
jnz .release |
.released: |
push edi |
pop eax ; .num_released_pages |
shl eax, 12 |
mov edx, [current_process] |
lea ecx, [edx + PROC.heap_lock] |
mov esi, dword [edx + PROC.heap_base] |
mov edi, dword [edx + PROC.heap_top] |
sub ebx, [edx + PROC.mem_used] |
neg ebx |
mov [edx + PROC.mem_used], ebx |
sub [edx + PROC.mem_used], eax |
call user_normalize |
pop edi |
.exit: |
call mutex_unlock |
850,18 → 850,21 |
align 4 |
proc user_unmap stdcall, base:dword, offset:dword, size:dword |
mov ecx, [current_process] |
add ecx, PROC.heap_lock |
call mutex_lock |
push ebx |
mov ebx, [base] ; must be valid pointer |
test ebx, ebx |
jz .error |
mov edx, [offset] ; check offset |
add edx, ebx ; must be below 2Gb app limit |
jc .error |
js .error |
shr ebx, 12 ; chek block attributes |
jz .error |
lea ebx, [page_tabs + ebx*4] |
mov eax, [ebx-4] ; block attributes |
test al, MEM_BLOCK_USED |
887,36 → 890,63 |
and ebx, not 4095 ; is it required ? |
add ebx, [base] |
push 0 |
virtual at esp |
.num_released_pages dd ? |
end virtual |
.unmap: |
mov eax, [edx] ; get page addres |
test al, 1 ; page mapped ? |
jz @F |
jz .next |
test eax, PG_SHARED ; page shared ? |
jnz @F |
mov dword[edx], MEM_BLOCK_RESERVED |
jnz .next |
inc [.num_released_pages] |
mov dword [edx], LAZY_ALLOC_PAGE |
; mark page as reserved |
test eax, PG_READ |
jnz @f |
or dword [edx], LAZY_ALLOC_UNREADABLE |
@@: |
test eax, PG_WRITE |
jnz @f |
or dword [edx], LAZY_ALLOC_UNWRITABLE |
@@: |
invlpg [ebx] ; when we start using |
call free_page ; empty c-o-w page instead this ? |
@@: |
add ebx, 4096 ; PAGESIZE? |
.next: |
add ebx, 4096 |
add edx, 4 |
dec ecx |
jnz .unmap |
pop eax ; .num_released_pages |
pop ebx |
or al, 1 ; return non zero on success |
shl eax, 12 |
mov ecx, [current_process] |
sub [ecx+PROC.mem_used], eax |
push eax |
add ecx, PROC.heap_lock |
call mutex_unlock |
pop eax ; return number of released bytes |
ret |
.error: |
pop ebx |
mov ecx, [current_process] |
add ecx, PROC.heap_lock |
call mutex_unlock |
xor eax, eax ; something wrong |
dec eax |
ret |
endp |
align 4 |
user_normalize: |
; in: esi=heap_base, edi=heap_top |
proc user_normalize uses esi edi |
; in: edx->PROC |
; out: eax=0 <=> OK |
; destroys: ebx,edx,esi,edi |
; destroys: ebx,edx |
mov esi, dword [edx+PROC.heap_base] |
mov edi, dword [edx+PROC.heap_top] |
shr esi, 12 |
shr edi, 12 |
@@: |
959,6 → 989,7 |
.err: |
xor eax, eax |
ret |
endp |
user_realloc: |
; in: eax = pointer, ebx = new size |
1004,37 → 1035,43 |
cmp edx, ebx |
jb .realloc_add |
; release part of allocated memory |
push edx |
push 0 |
virtual at esp |
.num_released_pages dd ? |
end virtual |
.loop: |
cmp edx, ebx |
jz .release_done |
dec edx |
xor eax, eax |
xchg eax, [page_tabs + edx*4] |
push dword [page_tabs + edx*4] |
mov dword [page_tabs + edx*4], 0 |
mov eax, edx |
shl eax, 12 |
invlpg [eax] |
pop eax |
test al, 1 |
jz .loop |
inc [.num_released_pages] |
test eax, PG_SHARED |
jnz .loop |
call free_page |
mov eax, edx |
shl eax, 12 |
invlpg [eax] |
jmp .loop |
.release_done: |
pop eax ; .num_released_pages |
mov edx, [current_process] |
shl eax, 12 |
sub [edx+PROC.mem_used], eax |
pop edx |
sub ebx, ecx |
cmp ebx, 1 |
jnz .nofreeall |
mov eax, [page_tabs + ecx*4] |
and eax, not 0xFFF |
mov edx, [current_process] |
mov ebx, [edx + PROC.mem_used] |
sub ebx, eax |
add ebx, 0x1000 |
or al, MEM_BLOCK_FREE |
mov [page_tabs + ecx*4], eax |
push esi edi |
mov esi, [edx + PROC.heap_base] |
mov edi, [edx + PROC.heap_top] |
mov [edx + PROC.mem_used], ebx |
mov edx, [current_process] |
call user_normalize |
pop edi esi |
jmp .ret0 ; all freed |
.nofreeall: |
sub edx, ecx |
1043,13 → 1080,6 |
xchg [page_tabs + ecx*4], ebx |
shr ebx, 12 |
sub ebx, edx |
push ebx ecx edx |
mov edx, [current_process] |
shl ebx, 12 |
sub ebx, [edx + PROC.mem_used] |
neg ebx |
mov [edx + PROC.mem_used], ebx |
pop edx ecx ebx |
lea eax, [ecx + 1] |
shl eax, 12 |
push eax |
1119,9 → 1149,6 |
cld |
rep stosd |
pop edi |
mov edx, [current_process] |
shl ebx, 12 |
add [edx + PROC.mem_used], ebx |
mov ecx, [current_process] |
lea ecx, [ecx + PROC.heap_lock] |
1195,11 → 1222,6 |
dec edx |
jnz @b |
.no: |
push ebx |
mov edx, [current_process] |
shl ebx, 12 |
add [edx + PROC.mem_used], ebx |
pop ebx |
@@: |
mov dword [page_tabs + esi*4], MEM_BLOCK_RESERVED |
inc esi |
1218,25 → 1240,48 |
; param |
; eax= shm_map object |
; edi= shm_map object |
; [esp+4] = process |
align 4 |
destroy_smap: |
pushfd |
cli |
proc destroy_smap ;stdcall, process:dword |
push esi |
push edi |
mov esi, [edi+SMAP.parent] |
cmp [edi+SMAP.type], SMAP_TYPE_SMEM |
jz .smem |
mov ecx, [esp+8] |
add ecx, PROC.heap_lock |
call mutex_lock |
stdcall release_pemap, [esp+8] |
mov ecx, [esp+8] |
add ecx, PROC.heap_lock |
call mutex_unlock |
sub ecx, PROC.heap_lock |
cmp ecx, [current_process] |
jnz @f |
stdcall user_free, [edi+SMAP.base] |
@@: |
call dereference_pe |
jmp .common |
.smem: |
mov eax, [current_process] |
cmp [esp+8], eax |
jnz @f |
stdcall user_free, [edi+SMAP.base] |
@@: |
call dereference_smem |
.common: |
mov eax, edi |
call free |
pop esi |
ret 4 |
endp |
mov edi, eax |
mov esi, [eax + SMAP.parent] |
test esi, esi |
jz .done |
proc dereference_smem |
mov ecx, shmem_list_mutex |
call mutex_lock |
dec [esi+SMEM.refcount] |
jnz mutex_unlock |
lock dec [esi + SMEM.refcount] |
jnz .done |
mov ecx, [esi + SMEM.bk] |
mov edx, [esi + SMEM.fd] |
1243,18 → 1288,14 |
mov [ecx + SMEM.fd], edx |
mov [edx + SMEM.bk], ecx |
mov ecx, shmem_list_mutex |
call mutex_unlock |
stdcall kernel_free, [esi + SMEM.base] |
mov eax, esi |
call free |
.done: |
mov eax, edi |
call destroy_kernel_object |
pop edi |
pop esi |
popfd |
ret |
endp |
E_NOTFOUND = 5 |
E_ACCESS = 10 |
1273,23 → 1314,17 |
SHM_OPEN_MASK = 3 shl 2 |
align 4 |
proc shmem_open stdcall name:dword, size:dword, access:dword |
proc shmem_open stdcall uses ebx esi edi, name:dword, size:dword, access:dword |
locals |
action dd ? |
owner_access dd ? |
mapped dd ? |
edx_ret dd ? |
endl |
push ebx |
push esi |
push edi |
mov [mapped], 0 |
mov [owner_access], 0 |
pushfd ;mutex required |
cli |
mov eax, [access] |
and eax, SHM_OPEN_MASK |
mov [action], eax |
1296,9 → 1331,12 |
mov ebx, [name] |
test ebx, ebx |
mov edx, E_PARAM |
jz .fail |
mov [edx_ret], E_PARAM |
jz .exit |
mov ecx, shmem_list_mutex |
call mutex_lock |
mov esi, [shmem_list.fd] |
align 4 |
@@: |
1316,22 → 1354,22 |
.not_found: |
mov eax, [action] |
mov [edx_ret], E_NOTFOUND |
cmp eax, SHM_OPEN |
mov edx, E_NOTFOUND |
je .fail |
je .exit_unlock |
mov [edx_ret], E_PARAM |
cmp eax, SHM_CREATE |
mov edx, E_PARAM |
je .create_shm |
cmp eax, SHM_OPEN_ALWAYS |
jne .fail |
jne .exit_unlock |
.create_shm: |
mov ecx, [size] |
test ecx, ecx |
jz .fail |
jz .exit_unlock |
add ecx, 4095 |
and ecx, -4096 |
1341,13 → 1379,11 |
call malloc |
test eax, eax |
mov esi, eax |
mov edx, E_NOMEM |
jz .fail |
mov [edx_ret], E_NOMEM |
jz .exit_unlock |
stdcall kernel_alloc, [size] |
test eax, eax |
mov [mapped], eax |
mov edx, E_NOMEM |
jz .cleanup |
mov ecx, [size] |
1376,16 → 1412,16 |
.found: |
mov eax, [action] |
mov [edx_ret], E_ACCESS |
cmp eax, SHM_CREATE |
mov edx, E_ACCESS |
je .exit |
je .exit_unlock |
mov [edx_ret], E_PARAM |
cmp eax, SHM_OPEN |
mov edx, E_PARAM |
je .create_map |
cmp eax, SHM_OPEN_ALWAYS |
jne .fail |
jne .exit_unlock |
.create_map: |
1393,37 → 1429,43 |
and eax, SHM_ACCESS_MASK |
cmp eax, [esi + SMEM.access] |
mov [access], eax |
mov edx, E_ACCESS |
ja .fail |
mov [edx_ret], E_ACCESS |
ja .exit_unlock |
mov ebx, [current_slot_idx] |
shl ebx, BSF sizeof.TASKDATA |
mov ebx, [TASK_TABLE + ebx + TASKDATA.pid] |
inc [esi+SMEM.refcount] |
mov ecx, shmem_list_mutex |
call mutex_unlock |
mov eax, sizeof.SMAP |
call create_kernel_object |
call malloc |
test eax, eax |
mov edi, eax |
mov edx, E_NOMEM |
jz .fail |
mov [edx_ret], E_NOMEM |
jz .cleanup2 |
inc [esi + SMEM.refcount] |
mov [edi + SMAP.magic], 'SMAP' |
mov [edi + SMAP.destroy], destroy_smap |
mov [edi+SMAP.type], SMAP_TYPE_SMEM |
mov [edi + SMAP.parent], esi |
mov [edi + SMAP.base], 0 |
mov ecx, [current_process] |
add ecx, PROC.heap_lock |
call mutex_lock |
stdcall user_alloc, [esi + SMEM.size] |
stdcall user_alloc_nolock, [esi+SMEM.size] |
test eax, eax |
mov [mapped], eax |
mov edx, E_NOMEM |
jz .cleanup2 |
jz .cleanup3 |
mov [edi + SMAP.base], eax |
mov ecx, [current_process] |
mov edx, [ecx+PROC.smap_list+SMAP.bk] |
add ecx, PROC.smap_list |
mov [edi+SMAP.fd], ecx |
mov [edi+SMAP.bk], edx |
mov [ecx+SMAP.bk], edi |
mov [edx+SMAP.fd], edi |
mov ecx, [esi + SMEM.size] |
mov [size], ecx |
mov [edi + SMAP.size], ecx |
mov [edx_ret], ecx |
shr ecx, 12 |
shr eax, 10 |
1430,44 → 1472,51 |
mov esi, [esi + SMEM.base] |
shr esi, 10 |
lea edi, [page_tabs + eax] |
add esi, page_tabs |
xor ebx, ebx |
mov edx, [access] |
or edx, [owner_access] |
shl edx, 1 |
or edx, PG_SHARED + PG_UR |
@@: |
lodsd |
and eax, 0xFFFFF000 |
or eax, edx |
stosd |
loop @B |
mov edi, [page_tabs+esi+ebx*4] |
and edi, 0xFFFFF000 |
or edi, edx |
mov [page_tabs+eax+ebx*4], edi |
inc ebx |
dec ecx |
jnz @B |
xor edx, edx |
mov ecx, [current_process] |
shl ebx, 12 |
add [ecx+PROC.mem_used], ebx |
add ecx, PROC.heap_lock |
call mutex_unlock |
cmp [owner_access], 0 |
jne .fail |
jz .exit |
mov [edx_ret], 0 |
.exit: |
mov edx, [size] |
.fail: |
mov eax, [mapped] |
popfd |
pop edi |
pop esi |
pop ebx |
mov edx, [edx_ret] |
ret |
.cleanup: |
mov [size], edx |
mov eax, esi |
call free |
.exit_unlock: |
mov ecx, shmem_list_mutex |
call mutex_unlock |
jmp .exit |
.cleanup3: |
mov ecx, [current_process] |
add ecx, PROC.heap_lock |
call mutex_unlock |
mov eax, edi |
call free |
.cleanup2: |
mov [size], edx |
mov eax, edi |
call destroy_smap |
call dereference_smem |
jmp .exit |
endp |
1474,48 → 1523,54 |
align 4 |
proc shmem_close stdcall, name:dword |
mov eax, [name] |
test eax, eax |
cmp [name], 0 |
jz .fail |
push esi |
push edi |
pushfd |
cli |
mov esi, [current_slot] |
add esi, APP_OBJ_OFFSET |
mov ecx, [current_process] |
lea edi, [ecx+PROC.smap_list] |
add ecx, PROC.heap_lock |
call mutex_lock |
mov esi, edi |
.next: |
mov eax, [esi + APPOBJ.fd] |
test eax, eax |
jz @F |
mov edi, [edi+SMAP.fd] |
cmp edi, esi |
je .notfound |
cmp eax, esi |
mov esi, eax |
je @F |
cmp [eax + SMAP.magic], 'SMAP' |
cmp [edi + SMAP.type], SMAP_TYPE_SMEM |
jne .next |
mov edi, [eax + SMAP.parent] |
test edi, edi |
jz .next |
mov eax, [edi + SMAP.parent] |
add eax, SMEM.name |
lea edi, [edi + SMEM.name] |
stdcall strncmp, [name], edi, 32 |
stdcall strncmp, [name], eax, 32 |
test eax, eax |
jne .next |
stdcall user_free, [esi + SMAP.base] |
mov eax, [edi+SMAP.fd] |
mov edx, [edi+SMAP.bk] |
mov [eax+SMAP.bk], edx |
mov [edx+SMAP.fd], eax |
mov eax, esi |
call [esi + APPOBJ.destroy] |
@@: |
popfd |
mov ecx, [current_process] |
add ecx, PROC.heap_lock |
call mutex_unlock |
stdcall destroy_smap, [current_process] |
.exit: |
pop edi |
pop esi |
.fail: |
ret |
.notfound: |
mov ecx, [current_process] |
add ecx, PROC.heap_lock |
call mutex_unlock |
jmp .exit |
endp |
/kernel/branches/kolibrios-pe-clevermouse/core/memory.inc |
---|
564,7 → 564,7 |
push ebx ;that is locals: .err_addr = cr2 |
inc [pg_data.pages_faults] |
mov eax, [pf_err_code] |
mov esi, [pf_err_code] |
cmp ebx, OS_BASE ;ebx == .err_addr |
jb .user_space ;page in application memory |
572,6 → 572,7 |
cmp ebx, page_tabs |
jb .kernel_space ;page in kernel memory |
xor eax, eax |
cmp ebx, kernel_tabs |
jb .alloc;.app_tabs ;page tables of application ; |
;simply create one |
580,37 → 581,64 |
mov esp, ebp |
pop ebx ;restore exception number (#PF) |
ret |
.fail_maybe_unlock: |
test esi, esi |
jz .fail |
.fail_unlock: |
mov ecx, [current_process] |
add ecx, PROC.heap_lock |
call mutex_unlock |
jmp .fail |
.user_space: |
test eax, PG_READ |
jnz .err_access ;Page presents |
; PF entry in IDT is interrupt gate, so up to this moment |
; atomicity was guaranteed by cleared IF. |
; It is inpractical to guard all modifications in the page table by cli/sti, |
; so enable interrupts and acquire the address space lock. |
; Unfortunately, that enables the scenario when the fault of current thread |
; is resolved by another thread when the current thread waits in mutex_lock, |
; so watch out: in lock-protected section we can find out that |
; there is no error already. |
sti |
mov ecx, [current_process] |
add ecx, PROC.heap_lock |
call mutex_lock |
test esi, PG_READ |
jnz .err_access ;Page is present |
;Access error ? |
shr ebx, 12 |
mov ecx, ebx |
shr ecx, 10 |
mov edx, [master_tab+ecx*4] |
test edx, PG_READ |
jz .fail ;page table is not created |
test dword [master_tab+ecx*4], PG_READ |
jz .fail_unlock ;page table is not created |
;incorrect address in program |
mov eax, [page_tabs+ebx*4] |
test eax, 2 |
jz .fail ;address is not reserved for usage. Error |
test eax, PG_READ |
jnz .exit_unlock ; already resolved by a parallel thread |
test eax, LAZY_ALLOC_PAGE |
jz .fail_unlock ;address is not reserved for use, error |
test eax, LAZY_ALLOC_UNREADABLE |
jnz .fail_unlock |
.alloc: |
call alloc_page |
mov esi, eax |
call alloc_zero_page |
test eax, eax |
jz .fail |
jz .fail_maybe_unlock |
stdcall map_page, [.err_addr], eax, PG_UWR |
mov edi, [.err_addr] |
and edi, 0xFFFFF000 |
mov ecx, 1024 |
xor eax, eax |
;cld ;caller is duty for this |
rep stosd |
mov edx, PG_UWR |
test esi, LAZY_ALLOC_UNWRITABLE |
jz @f |
mov edx, PG_UR |
@@: |
stdcall map_page, [.err_addr], eax, edx |
mov ecx, [current_process] |
add [ecx+PROC.mem_used], 0x1000 |
.exit_unlock: |
mov ecx, [current_process] |
add ecx, PROC.heap_lock |
call mutex_unlock |
.exit: ;iret with repeat fault instruction |
add esp, 12;clear in stack: locals(.err_addr) + #PF + ret_to_caller |
restore_ring3_context |
617,50 → 645,70 |
iretd |
.err_access: |
; access denied? this may be a result of copy-on-write protection for DLL |
; check list of HDLLs |
; access denied? this may be a result of copy-on-write protection |
; Check whether the problem has already been resolved |
; while we were waiting in mutex_lock. |
mov eax, ebx |
shr eax, 12 |
mov eax, [page_tabs+eax*4] |
test eax, PG_READ |
jz .fail_unlock ; someone has free'd the page |
test eax, PG_USER |
jz .fail_unlock ; page is mprotect'ed without PROT_READ |
test eax, PG_WRITE |
jnz .exit_unlock ; someone has enabled write |
test eax, PG_SHARED |
jz .fail_unlock ; only shared pages can be copy-on-write |
; check list of mapped data |
and ebx, not 0xFFF |
mov eax, [current_process] |
mov eax, [eax+PROC.dlls_list_ptr] |
test eax, eax |
jz .fail |
mov esi, [eax+HDLL.fd] |
.scan_hdll: |
cmp esi, eax |
jz .fail |
mov edx, ebx |
sub edx, [esi+HDLL.base] |
cmp edx, [esi+HDLL.size] |
jb .fault_in_hdll |
.scan_hdll.next: |
mov esi, [esi+HDLL.fd] |
jmp .scan_hdll |
.fault_in_hdll: |
; allocate new page, map it as rw and copy data |
call alloc_page |
test eax, eax |
jz .fail |
stdcall map_page, ebx, eax, PG_UWR |
mov edi, ebx |
mov ecx, 1024 |
sub ebx, [esi+HDLL.base] |
mov esi, [esi+HDLL.parent] |
mov esi, [esi+DLLDESCR.data] |
add esi, ebx |
rep movsd |
jmp .exit |
call find_smap_by_address |
test esi, esi |
jz .fail_unlock |
; ignore children of SMEM, only children of PEDESCR can have copy-on-write data |
cmp [esi+SMAP.type], SMAP_TYPE_PE |
jnz .fail_unlock |
shr edi, 12 |
; lock page array in PEDESCR |
mov esi, [esi+SMAP.parent] |
lea ecx, [esi+PEDESCR.page_array_lock] |
push eax |
call mutex_lock |
pop eax |
; check whether the page is shared |
; PG_SHARED flag could be set by lock_and_map_page |
xor eax, [esi+sizeof.PEDESCR+edi*4] |
test eax, not 0xFFF |
jnz .fail_unlock2 |
; check whether write is allowed by section attributes |
mov eax, [esi+sizeof.PEDESCR+edi*4] |
test eax, IMAGE_SCN_MEM_WRITE shr 20 |
jz .fail_unlock2 |
; if we're faulting on the page which was originally shareable writable, |
; it means that someone has disabled writing with mprotect; fail |
test eax, IMAGE_SCN_MEM_SHARED shr 20 |
jnz .fail_unlock2 |
stdcall pe_copy_on_write, PG_UWR |
jc .fail_unlock2 |
.exit_unlock2: |
lea ecx, [esi+PEDESCR.page_array_lock] |
call mutex_unlock |
jmp .exit_unlock |
.fail_unlock2: |
lea ecx, [esi+PEDESCR.page_array_lock] |
call mutex_unlock |
jmp .fail_unlock |
.kernel_space: |
test eax, PG_READ |
test esi, PG_READ |
jz .fail ;page does not present |
test eax, 12 ;U/S (+below) |
test esi, 12 ;U/S (+below) |
jnz .fail ;application requested kernel memory |
;test eax, 8 |
;jnz .fail ;the reserved bit is set in page tables. Added in P4/Xeon |
;test esi, 8 |
;jnz .fail ;the reserved bit is set in page tables |
;added in P4/Xeon |
;an attempt to write to a protected kernel page |
cmp ebx, tss._io_map_0 |
677,7 → 725,7 |
jz .fail |
push eax |
stdcall map_page, [.err_addr], eax, dword PG_SWR |
stdcall map_page, [.err_addr], eax, PG_SWR |
pop eax |
mov edi, [.err_addr] |
and edi, -4096 |
696,9 → 744,274 |
jmp .exit |
endp |
; Sometimes we can just allocate a page and let the caller fill it. |
; Sometimes we need a zero-filled page, but we can zero it at the target. |
; Sometimes we need a zero-filled page before mapping to the target. |
; This function is for the last case. |
; out: eax = physical page |
; destroys: nothing |
proc alloc_zero_page |
call alloc_page |
test eax, eax |
jz .nothing |
spin_lock_irqsave zero_page_spinlock |
push ecx edx edi eax |
mov edi, [zero_page_tab] |
stdcall map_page, edi, [esp+4], PG_SWR |
pushd 0 [esp+4] edi ; for map_page |
mov ecx, 0x1000/4 |
xor eax, eax |
rep stosd |
call map_page |
pop eax edi edx ecx |
spin_unlock_irqrestore zero_page_spinlock |
.nothing: |
ret |
endp |
; in: ebx = address |
; out if SMAP exists for this address: esi -> SMAP, edi = ebx - SMAP.base |
; out if SMAP does not exist: esi = 0 |
proc find_smap_by_address |
mov edx, [current_process] |
add edx, PROC.smap_list |
mov esi, [edx+SMAP.fd] |
.scan: |
cmp esi, edx |
jz .fail |
mov edi, ebx |
sub edi, [esi+SMAP.base] |
cmp edi, [esi+SMAP.size] |
jb .exit |
mov esi, [esi+SMAP.fd] |
jmp .scan |
.fail: |
xor esi, esi |
.exit: |
ret |
endp |
; Someone is about to write to copy-on-write page inside mapped PE. |
; Provide a page that can be written to. |
; in: esi -> PEDESCR |
; in: edi = page number inside PE |
; in: eax = [esi+sizeof.PEDESCR+edi*4] |
; in: ebx = address in process, must be page-aligned |
; in: [esp+4] = access rights for the new page |
; out: CF=0 - ok, CF=1 - error, no memory |
proc pe_copy_on_write |
; 1. Decrement reference counter unless it is 0xFF. |
mov edx, eax |
and edx, 0xFF |
cmp edx, 0xFF |
jz @f |
dec eax |
@@: |
; 2. If reference counter is zero now, transfer ownership from PEDESCR to the process. |
test eax, 0xFF |
jnz .alloc_copy |
mov dword [esi+sizeof.PEDESCR+edi*4], 0 |
and eax, not 0xFFF |
.remap: |
stdcall map_page, ebx, eax, [esp+4] |
clc |
ret 4 |
.alloc_copy: |
; 3. Otherwise, store updated reference counter to PEDESCR, |
; allocate new page, map it as rw and copy data. |
mov [esi+sizeof.PEDESCR+edi*4], eax |
stdcall kernel_alloc, 0x1000 |
test eax, eax |
jz .error |
push esi |
mov esi, ebx |
mov edi, eax |
mov ecx, 0x1000/4 |
rep movsd |
mov esi, eax |
call get_pg_addr |
push eax |
stdcall free_kernel_space, esi |
pop eax |
pop esi |
jmp .remap |
.error: |
stc |
ret 4 |
endp |
PROT_READ = 1 |
PROT_WRITE = 2 |
PROT_EXEC = 4 |
proc mprotect stdcall uses ebx esi edi, address:dword, size:dword, access:dword |
locals |
retval dd -1 |
smap_ptr dd 0 |
endl |
mov ecx, [current_process] |
add ecx, PROC.heap_lock |
call mutex_lock |
test [access], not (PROT_READ+PROT_WRITE+PROT_EXEC) |
jnz .error |
cmp [size], 0 |
jz .error |
mov eax, [address] |
add [size], eax |
and eax, not 0xFFF |
.addrloop: |
mov [address], eax |
mov ecx, eax |
cmp eax, OS_BASE |
jae .error |
shr eax, 22 |
test byte [master_tab+eax*4], PG_READ |
jz .error |
shr ecx, 12 |
mov eax, [page_tabs+ecx*4] |
test al, PG_READ |
jnz .page_present |
test al, LAZY_ALLOC_PAGE |
jz .error |
cmp [retval], -1 |
jnz .skip_query |
inc [retval] |
test al, LAZY_ALLOC_UNREADABLE |
jnz @f |
or [retval], PROT_READ+PROT_EXEC |
@@: |
test al, LAZY_ALLOC_UNWRITABLE |
jnz @f |
or [retval], PROT_WRITE |
@@: |
.skip_query: |
and al, not (LAZY_ALLOC_UNREADABLE+LAZY_ALLOC_UNWRITABLE) |
test [access], PROT_READ |
jnz @f |
or al, LAZY_ALLOC_UNREADABLE |
@@: |
test [access], PROT_WRITE |
jnz @f |
or al, LAZY_ALLOC_UNWRITABLE |
@@: |
mov [page_tabs+ecx*4], eax |
jmp .nextpage |
.page_present: |
test eax, PG_SHARED |
jnz .page_shared |
.normal_page: |
cmp [retval], -1 |
jnz .skip_query2 |
inc [retval] |
test al, PG_USER |
jz @f |
or [retval], PROT_READ+PROT_EXEC |
@@: |
test al, PG_WRITE |
jz @f |
or [retval], PROT_WRITE |
@@: |
.skip_query2: |
and al, not (PG_USER+PG_WRITE) |
test [access], PROT_READ |
jz @f |
or al, PG_USER |
@@: |
test [access], PROT_WRITE |
jz @f |
or al, PG_WRITE |
@@: |
mov [page_tabs+ecx*4], eax |
mov eax, [address] |
invlpg [eax] |
jmp .nextpage |
.page_shared: |
mov esi, [smap_ptr] |
test esi, esi |
jz .find_smap |
mov edx, [address] |
sub edx, [esi+SMAP.base] |
cmp edx, [esi+SMAP.size] |
jb .found_smap |
.find_smap: |
mov ebx, [address] |
call find_smap_by_address |
mov [smap_ptr], esi |
test esi, esi |
jz .normal_page |
.found_smap: |
cmp [esi+SMAP.type], SMAP_TYPE_PE |
jnz .error |
shr edi, 12 |
mov esi, [esi+SMAP.parent] |
lea ecx, [esi+PEDESCR.page_array_lock] |
push eax |
call mutex_lock |
pop eax |
xor eax, [esi+sizeof.PEDESCR+edi*4] |
test eax, not 0xFFF |
jnz .normal_page_unlock |
mov eax, [esi+sizeof.PEDESCR+edi*4] |
test eax, IMAGE_SCN_MEM_SHARED shr 20 |
jnz .normal_page_unlock |
cmp [retval], -1 |
jnz .skip_query3 |
mov edx, [address] |
shr edx, 12 |
inc [retval] |
test byte [page_tabs+edx*4], PG_USER |
jz @f |
or [retval], PROT_READ+PROT_EXEC |
@@: |
test eax, IMAGE_SCN_MEM_WRITE shr 20 |
jz @f |
or [retval], PROT_WRITE |
@@: |
.skip_query3: |
test [access], PROT_WRITE |
jz .no_write |
push PG_SWR |
test [access], PROT_READ |
jz @f |
pop edx |
push PG_UWR |
@@: |
call pe_copy_on_write |
lea ecx, [esi+PEDESCR.page_array_lock] |
call mutex_unlock |
jmp .nextpage |
.normal_page_unlock: |
lea ecx, [esi+PEDESCR.page_array_lock] |
call mutex_unlock |
mov ecx, [address] |
shr ecx, 12 |
mov eax, [page_tabs+ecx*4] |
jmp .normal_page |
.no_write: |
lea ecx, [esi+PEDESCR.page_array_lock] |
call mutex_unlock |
mov ecx, [address] |
shr ecx, 12 |
mov eax, [page_tabs+ecx*4] |
jmp .skip_query2 |
.nextpage: |
mov eax, [address] |
add eax, 0x1000 |
cmp eax, [size] |
jb .addrloop |
.exit: |
mov ecx, [current_process] |
add ecx, PROC.heap_lock |
call mutex_unlock |
mov eax, [retval] |
ret |
.error: |
or [retval], -1 |
jmp .exit |
endp |
; returns number of mapped bytes |
proc map_mem_ipc stdcall, lin_addr:dword,slot:dword,\ |
ofs:dword,buf_size:dword,req_access:dword |
proc map_memEx stdcall uses ebx esi edi, lin_addr:dword,slot:dword,\ |
ofs:dword,buf_size:dword,req_access:dword,where:dword |
locals |
count dd ? |
process dd ? |
710,17 → 1023,20 |
mov eax, [slot] |
shl eax, 8 |
mov eax, [SLOT_BASE+eax+APPDATA.process] |
test eax, eax |
mov ecx, [SLOT_BASE+eax+APPDATA.process] |
test ecx, ecx |
jz .exit |
mov [process], eax |
mov [process], ecx |
add ecx, PROC.heap_lock |
call mutex_lock |
mov eax, [process] |
mov ebx, [ofs] |
shr ebx, 22 |
mov eax, [eax+PROC.pdt_0+ebx*4] ;get page table |
mov esi, [ipc_ptab] |
mov esi, [where] |
and eax, 0xFFFFF000 |
jz .exit |
jz .unlock_exit |
stdcall map_page, esi, eax, PG_SWR |
@@: |
mov edi, [lin_addr] |
728,18 → 1044,17 |
mov ecx, [buf_size] |
add ecx, 4095 |
shr ecx, 12 |
inc ecx ; ??????????? |
mov edx, [ofs] |
shr edx, 12 |
and edx, 0x3FF |
.map: |
stdcall safe_map_page, [slot], [req_access], [ofs] |
jnc .exit |
stdcall lock_and_map_page, [slot], [req_access], [ofs] |
jnc .unlock_exit |
add [count], PAGE_SIZE |
add [ofs], PAGE_SIZE |
dec ecx |
jz .exit |
jz .unlock_exit |
add edi, PAGE_SIZE |
inc edx |
750,76 → 1065,98 |
mov eax, [process] |
mov eax, [eax+PROC.pdt_0+ebx*4] |
and eax, 0xFFFFF000 |
jz .exit |
jz .unlock_exit |
stdcall map_page, esi, eax, PG_SWR |
xor edx, edx |
jmp .map |
.unlock_exit: |
mov ecx, [process] |
add ecx, PROC.heap_lock |
call mutex_unlock |
.exit: |
mov eax, [count] |
ret |
endp |
proc map_memEx stdcall, lin_addr:dword,slot:dword,\ |
ofs:dword,buf_size:dword,req_access:dword |
proc unmap_memEx stdcall uses ebx esi edi, lin_addr:dword,slot:dword,\ |
ofs:dword,mapped_size:dword,pagedir:dword |
locals |
count dd ? |
process dd ? |
endl |
mov [count], 0 |
cmp [buf_size], 0 |
cmp [mapped_size], 0 |
jz .exit |
mov eax, [slot] |
shl eax, 8 |
mov eax, [SLOT_BASE+eax+APPDATA.process] |
test eax, eax |
jz .exit |
mov [process], eax |
mov ecx, [SLOT_BASE+eax+APPDATA.process] |
mov [process], ecx |
xor eax, eax |
test ecx, ecx |
jz @f |
add ecx, PROC.heap_lock |
call mutex_lock |
mov ebx, [ofs] |
shr ebx, 22 |
mov eax, [process] |
mov eax, [eax+PROC.pdt_0+ebx*4] ;get page table |
mov esi, [proc_mem_tab] |
@@: |
xor esi, esi |
and eax, 0xFFFFF000 |
jz .exit |
jz @f |
mov esi, [pagedir] |
stdcall map_page, esi, eax, PG_SWR |
@@: |
mov ecx, shared_locked_mutex |
call mutex_lock |
mov edi, [lin_addr] |
and edi, 0xFFFFF000 |
mov ecx, [buf_size] |
shr edi, 12 |
mov ecx, [mapped_size] |
add ecx, 4095 |
shr ecx, 12 |
inc ecx ; ??????????? |
mov [mapped_size], ecx |
mov edx, [ofs] |
shr edx, 12 |
and edx, 0x3FF |
lea esi, [esi+edx*4] |
.map: |
stdcall safe_map_page, [slot], [req_access], [ofs] |
jnc .exit |
add [count], PAGE_SIZE |
add [ofs], PAGE_SIZE |
dec ecx |
jz .exit |
call unlock_and_unmap_page |
dec [mapped_size] |
jz .done |
add edi, PAGE_SIZE |
inc edx |
cmp edx, 1024 |
inc edi |
add esi, 4 |
test esi, 0xFFF |
jnz .map |
inc ebx |
xor esi, esi |
cmp [process], 0 |
jz .map |
mov eax, [process] |
mov eax, [eax+PROC.pdt_0+ebx*4] |
and eax, 0xFFFFF000 |
jz .exit |
jz .map |
mov esi, [pagedir] |
stdcall map_page, esi, eax, PG_SWR |
xor edx, edx |
jmp .map |
.done: |
mov ecx, shared_locked_mutex |
call mutex_unlock |
cmp [process], 0 |
jz .exit |
mov ecx, [process] |
add ecx, PROC.heap_lock |
call mutex_unlock |
.exit: |
mov eax, [count] |
mov eax, [pagedir] |
mov ecx, eax |
shr ecx, 12 |
mov dword [page_tabs+ecx*4], 0 |
invlpg [eax] |
ret |
endp |
826,16 → 1163,23 |
; in: esi+edx*4 = pointer to page table entry |
; in: [slot], [req_access], [ofs] on the stack |
; in: edi = linear address to map |
; in: address space lock must be held |
; out: CF cleared <=> failed |
; destroys: only eax |
proc safe_map_page stdcall, slot:dword, req_access:dword, ofs:dword |
proc lock_and_map_page stdcall, slot:dword, req_access:dword, ofs:dword |
locals |
locked_descr dd ? |
endl |
mov eax, [esi+edx*4] |
test al, PG_READ |
test eax, PG_READ |
jz .not_present |
test al, PG_WRITE |
jz .resolve_readonly |
; normal case: writable page, just map with requested access |
test eax, PG_SHARED |
jnz .resolve_shared |
; normal case: not shared allocated page, mark as shared and map with requested access |
or dword [esi+edx*4], PG_SHARED |
.map: |
and eax, not 0xFFF |
stdcall map_page, edi, eax, [req_access] |
stc |
.fail: |
842,70 → 1186,268 |
ret |
.not_present: |
; check for alloc-on-demand page |
test al, 2 |
test eax, LAZY_ALLOC_PAGE |
jz .fail |
; allocate new page, save it to source page table |
push ecx |
call alloc_page |
call alloc_zero_page |
pop ecx |
test eax, eax |
jz .fail |
or al, PG_UWR |
or eax, PG_READ+PG_SHARED |
test dword [esi+edx*4], LAZY_ALLOC_UNREADABLE |
jnz @f |
or eax, PG_USER |
@@: |
test dword [esi+edx*4], LAZY_ALLOC_UNWRITABLE |
jnz @f |
or eax, PG_WRITE |
@@: |
mov [esi+edx*4], eax |
jmp .map |
.resolve_readonly: |
; readonly page, probably copy-on-write |
; check: readonly request of readonly page is ok |
test [req_access], PG_WRITE |
jz .map |
; find control structure for this page |
pushf |
cli |
cld |
push ebx ecx |
.resolve_shared: |
push ecx edx eax |
mov eax, sizeof.SHARED_LOCKED_PAGE |
call malloc |
mov [locked_descr], eax |
test eax, eax |
jz .fail_pop |
mov edx, [esp] |
and edx, not 0xFFF |
mov [eax+SHARED_LOCKED_PAGE.address], edx |
mov eax, [slot] |
shl eax, 8 |
mov eax, [SLOT_BASE+eax+APPDATA.process] |
mov eax, [eax+PROC.dlls_list_ptr] |
test eax, eax |
jz .no_hdll |
mov ecx, [eax+HDLL.fd] |
.scan_hdll: |
mov ecx, [eax+PROC.smap_list] |
add eax, PROC.smap_list |
.find_shared_parent: |
cmp ecx, eax |
jz .no_hdll |
mov ebx, [ofs] |
and ebx, not 0xFFF |
sub ebx, [ecx+HDLL.base] |
cmp ebx, [ecx+HDLL.size] |
jb .hdll_found |
mov ecx, [ecx+HDLL.fd] |
jmp .scan_hdll |
.no_hdll: |
pop ecx ebx |
popf |
jz .shared_orphan |
mov edx, [ofs] |
sub edx, [ecx+SMAP.base] |
cmp edx, [ecx+SMAP.size] |
jb .found_shared_parent |
mov ecx, [ecx+SMAP.fd] |
jmp .find_shared_parent |
.shared_abandoned: |
call mutex_unlock |
.shared_orphan: |
; no copy-on-write for orphans |
test dword [esp], PG_WRITE |
jnz @f |
test [req_access], PG_WRITE |
jnz .shared_forbidden |
@@: |
; locking the same normal page for second time: |
; the first lock_and_map_page has set PG_SHARED, |
; now we must cooperate with that other thread. |
mov ecx, shared_locked_mutex |
call mutex_lock |
mov eax, [locked_descr] |
mov [eax+SHARED_LOCKED_PAGE.parent], 0 |
.shared_common: |
mov edx, [shared_locked_list+SHARED_LOCKED_PAGE.bk] |
mov [eax+SHARED_LOCKED_PAGE.fd], shared_locked_list |
mov [eax+SHARED_LOCKED_PAGE.bk], edx |
mov [edx+SHARED_LOCKED_PAGE.fd], eax |
mov [shared_locked_list+SHARED_LOCKED_PAGE.bk], edx |
call mutex_unlock |
pop eax edx ecx |
jmp .map |
.shared_forbidden_unlock: |
call mutex_unlock |
.shared_forbidden: |
mov eax, [locked_descr] |
call free |
.fail_pop: |
pop eax edx ecx |
clc |
ret |
.hdll_found: |
; allocate page, save it in page table, map it, copy contents from base |
mov eax, [ecx+HDLL.parent] |
add ebx, [eax+DLLDESCR.data] |
call alloc_page |
.found_shared_parent: |
shr edx, 12 |
mov eax, [locked_descr] |
mov [eax+SHARED_LOCKED_PAGE.offs], edx |
cmp [ecx+SMAP.type], SMAP_TYPE_PE |
jnz .parent_smap |
push edx |
mov ecx, [ecx+SMAP.parent] |
add ecx, PEDESCR.page_array_lock |
call mutex_lock |
pop edx |
mov eax, [esp] |
xor eax, [ecx+sizeof.PEDESCR-PEDESCR.page_array_lock+edx*4] |
test eax, not 0xFFF |
jnz .shared_abandoned |
test dword [esp], PG_WRITE |
jnz @f |
test [req_access], PG_WRITE |
jnz .pedescr_try_cow |
@@: |
mov eax, [ecx+sizeof.PEDESCR-PEDESCR.page_array_lock+edx*4] |
inc eax |
test eax, 0xFF |
jnz @f |
dec eax |
@@: |
mov [ecx+sizeof.PEDESCR-PEDESCR.page_array_lock+edx*4], eax |
push ecx |
mov ecx, pe_list_mutex |
call mutex_lock |
mov eax, [esp] |
inc dword [eax+PEDESCR.refcount-PEDESCR.page_array_lock] |
call mutex_unlock |
pop ecx |
call mutex_unlock |
sub ecx, PEDESCR.page_array_lock |
push ecx |
.shared_common2: |
mov ecx, shared_locked_mutex |
call mutex_lock |
mov eax, [locked_descr] |
pop [eax+SHARED_LOCKED_PAGE.parent] |
jmp .shared_common |
.pedescr_try_cow: |
mov eax, [ecx+sizeof.PEDESCR-PEDESCR.page_array_lock+edx*4] |
test eax, IMAGE_SCN_MEM_WRITE shr 20 |
jz @f |
or dword [esp], PG_WRITE |
@@: |
dec eax |
test eax, 0xFF |
jnz .pedescr_alloc_copy |
mov dword [ecx+sizeof.PEDESCR-PEDESCR.page_array_lock+edx*4], 0 |
call mutex_unlock |
mov eax, [locked_descr] |
call free |
pop eax edx ecx |
or eax, PG_SHARED |
mov [esi+edx*4], eax |
jmp .map |
.pedescr_alloc_copy: |
push ecx edx |
stdcall kernel_alloc, 0x1000 |
pop edx ecx |
test eax, eax |
jz .no_hdll |
or al, PG_UWR |
jz .shared_forbidden_unlock |
dec dword [ecx+sizeof.PEDESCR-PEDESCR.page_array_lock+edx*4] |
push ecx esi edi |
mov esi, edi |
mov edi, eax |
stdcall map_page, esi, [ecx+sizeof.PEDESCR-PEDESCR.page_array_lock+edx*4], PG_READ |
mov ecx, 0x1000/4 |
rep movsd |
sub esi, 0x1000 |
sub edi, 0x1000 |
mov eax, edi |
call get_pg_addr |
and dword [esp+12], 0xFFF |
or dword [esp+12], eax |
stdcall map_page, esi, eax, [req_access] |
stdcall free_kernel_space, edi |
pop edi esi ecx |
call mutex_unlock |
mov eax, [locked_descr] |
call free |
pop eax edx ecx |
or eax, PG_SHARED |
mov [esi+edx*4], eax |
stdcall map_page, edi, eax, [req_access] |
push esi edi |
mov esi, ebx |
mov ecx, 4096/4 |
rep movsd |
pop edi esi |
pop ecx ebx |
popf |
stc |
ret |
.parent_smap: |
test dword [esp], PG_WRITE |
jnz @f |
test [req_access], PG_WRITE |
jz .shared_forbidden |
@@: |
push [ecx+SMAP.parent] |
mov ecx, shmem_list_mutex |
call mutex_lock |
mov eax, [esp] |
inc dword [esp] |
inc [eax+SMEM.refcount] |
call mutex_unlock |
jmp .shared_common2 |
endp |
; in: esi -> process page table entry or esi < 0x1000 if no page table entry |
; in: edi = page number for mapped copy |
; in: shared_locked_mutex is held |
; destroys eax, ecx, edx |
proc unlock_and_unmap_page |
mov edx, [page_tabs+edi*4] |
and edx, not 0xFFF |
mov dword [page_tabs+edi*4], 0 |
mov eax, edi |
shl eax, 12 |
invlpg [eax] |
mov eax, [shared_locked_list+SHARED_LOCKED_PAGE.fd] |
.check_list: |
cmp eax, shared_locked_list |
jz .not_in_list |
cmp edx, [eax+SHARED_LOCKED_PAGE.address] |
jz .found_in_list |
mov eax, [eax+SHARED_LOCKED_PAGE.fd] |
jmp .check_list |
.found_in_list: |
push esi |
mov esi, [eax+SHARED_LOCKED_PAGE.parent] |
mov edx, [eax+SHARED_LOCKED_PAGE.fd] |
mov ecx, [eax+SHARED_LOCKED_PAGE.bk] |
mov [edx+SHARED_LOCKED_PAGE.bk], ecx |
mov [ecx+SHARED_LOCKED_PAGE.fd], edx |
test esi, esi |
jz .orphan |
btr esi, 0 |
jc .parent_smap |
push eax |
lea ecx, [esi+PEDESCR.page_array_lock] |
call mutex_lock |
mov edx, [esp] |
mov edx, [edx+SHARED_LOCKED_PAGE.offs] |
mov eax, [esi+sizeof.PEDESCR+edx*4] |
and eax, 0xFF |
cmp eax, 0xFF |
jz .no_deref |
mov eax, [esi+sizeof.PEDESCR+edx*4] |
dec eax |
test eax, 0xFF |
jnz @f |
call free_page |
xor eax, eax |
@@: |
mov [esi+sizeof.PEDESCR+edx*4], eax |
.no_deref: |
lea ecx, [esi+PEDESCR.page_array_lock] |
call mutex_unlock |
call dereference_pe |
pop eax |
call free |
pop esi |
ret |
.parent_smap: |
call free |
call dereference_smem |
pop esi |
ret |
.orphan: |
call free |
pop esi |
ret |
.not_in_list: |
cmp esi, 0x1000 |
jb .just_free |
mov eax, [esi] |
and eax, not 0xFFF |
cmp eax, edx |
jnz .just_free |
and dword [esi], not PG_SHARED |
ret |
.just_free: |
mov eax, edx |
call free_page |
ret |
endp |
sys_IPC: |
;input: |
; ebx=1 - set ipc buffer area |
957,12 → 1499,15 |
locals |
dst_slot dd ? |
dst_offset dd ? |
dst_ptr dd ? |
buf_size dd ? |
used_buf dd ? |
mapped_size dd ? |
result dd ? |
endl |
pushf |
cli |
mov ecx, ipc_mutex |
call mutex_lock |
mov eax, [PID] |
call pid_to_slot |
974,6 → 1519,7 |
mov edi, [eax+SLOT_BASE+APPDATA.ipc_start] ;is ipc area defined? |
test edi, edi |
jz .no_ipc_area |
mov [dst_ptr], edi |
mov ebx, edi |
and ebx, 0xFFF |
992,20 → 1538,33 |
pop edi esi |
@@: |
mov [used_buf], ecx |
stdcall map_mem_ipc, ecx, [dst_slot], \ |
edi, esi, PG_SWR |
stdcall map_memEx, ecx, [dst_slot], \ |
edi, esi, PG_SWR, [ipc_ptab] |
mov [mapped_size], eax |
mov [result], 3 ; buffer overflow |
sub eax, [dst_offset] |
jc .no_copy_data |
cmp [buf_size], eax |
jb @f |
mov [buf_size], eax |
@@: |
cmp [buf_size], 8 |
jb .no_copy_data |
mov [result], 2 ; ipc blocked |
mov edi, [dst_offset] |
add edi, [used_buf] |
cmp dword [edi], 0 |
jnz .ipc_blocked ;if dword [buffer]<>0 - ipc blocked now |
jnz .no_copy_data ;if dword [buffer]<>0 - ipc blocked now |
mov [result], 3 ; buffer overflow |
mov edx, dword [edi+4] |
lea ebx, [edx+8] |
add ebx, [msg_size] |
cmp ebx, [buf_size] |
ja .buffer_overflow ;esi<0 - not enough memory in buffer |
ja .no_copy_data ;esi<0 - not enough memory in buffer |
mov [result], 0 |
mov dword [edi+4], ebx |
mov eax, [TASK_BASE] |
mov eax, [eax+TASKDATA.pid] ;eax - our PID |
1019,56 → 1578,35 |
; add esi, new_app_base |
cld |
rep movsb |
.no_copy_data: |
stdcall unmap_memEx, [used_buf], [dst_slot], [dst_ptr], [mapped_size], [ipc_ptab] |
mov ebx, [ipc_tmp] |
mov edx, ebx |
shr ebx, 12 |
xor eax, eax |
mov [page_tabs+ebx*4], eax |
invlpg [edx] |
mov ebx, [ipc_pdir] |
mov edx, ebx |
shr ebx, 12 |
xor eax, eax |
mov [page_tabs+ebx*4], eax |
invlpg [edx] |
mov ebx, [ipc_ptab] |
mov edx, ebx |
shr ebx, 12 |
xor eax, eax |
mov [page_tabs+ebx*4], eax |
invlpg [edx] |
cmp [result], 0 |
jnz @f |
mov eax, [dst_slot] |
shl eax, BSF sizeof.APPDATA |
or [eax+SLOT_BASE+APPDATA.occurred_events], EVENT_IPC |
push 0 |
jmp .ret |
@@: |
mov eax, [used_buf] |
cmp eax, [ipc_tmp] |
je @f |
stdcall free_kernel_space, eax |
@@: |
mov ecx, ipc_mutex |
call mutex_unlock |
mov eax, [result] |
ret |
.no_pid: |
popf |
mov ecx, ipc_mutex |
call mutex_unlock |
mov eax, 4 |
ret |
.no_ipc_area: |
popf |
mov ecx, ipc_mutex |
call mutex_unlock |
xor eax, eax |
inc eax |
ret |
.ipc_blocked: |
push 2 |
jmp .ret |
.buffer_overflow: |
push 3 |
.ret: |
mov eax, [used_buf] |
cmp eax, [ipc_tmp] |
je @f |
stdcall free_kernel_space, eax |
@@: |
pop eax |
popf |
ret |
endp |
align 4 |
1103,7 → 1641,7 |
jbe sys_sheduler |
cmp ebx, 11 |
jb undefined_syscall |
cmp ebx, 29 |
cmp ebx, 32 |
ja undefined_syscall |
xor eax, eax |
jmp dword [f68call+ebx*4-11*4] |
1224,7 → 1762,37 |
stdcall user_ring, ecx |
mov [esp+SYSCALL_STACK._eax], eax |
ret |
.30: |
cmp ecx, OS_BASE |
jae .fail |
stdcall load_file_maybe_pe, ecx |
test esi, esi |
jz .30.not_pe |
stdcall map_pe_usermode, esi, eax, ebx |
mov [esp+32], eax |
ret |
.30.resolve_fail: |
movi eax, -5 |
jmp .30.error |
.30.not_pe: |
cmp eax, -0x1000 |
ja .30.error |
stdcall kernel_free, eax |
movi eax, -31 |
.30.error: |
mov [esp+32], eax |
ret |
.31: |
stdcall unmap_pe_usermode, ecx |
mov [esp+32], eax |
ret |
.32: |
stdcall mprotect, edx, esi, ecx |
mov [esp+32], eax |
ret |
.fail: |
mov [esp+SYSCALL_STACK._eax], eax |
ret |
1251,6 → 1819,9 |
dd f68.27 ; load_file_umode |
dd f68.28 ; loadFileUnicode |
dd f68.29 ; user_ring |
dd f68.30 ; map_pe_usermode |
dd f68.31 ; unmap_pe_usermode |
dd f68.32 ; mprotect |
align 4 |
proc load_pe_driver stdcall, file:dword, cmdline:dword |
/kernel/branches/kolibrios-pe-clevermouse/core/peuser.inc |
---|
0,0 → 1,833 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2016. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
; Checks whether the given file is already loaded as PE. |
; If so, returns pointer to PEDESCR which can be used for map_pe_usermode. |
; out: eax = 0, ebx undefined |
; out: esi -> PEDESCR |
; If not, loads the given file; if it is PE, creates PEDESCR; |
; out: eax -> file data, ebx = file size |
; out: esi -> PEDESCR |
; if it is not PE, returns loaded file as is. |
; out: eax -> file data, ebx = file size |
; out: esi = 0 |
; On error: |
; out: eax = negative error code, ebx = 0 |
; out: esi = 0 |
proc load_file_maybe_pe stdcall uses edi, file_name:dword |
locals |
fileinfo rb 40 |
filedata dd ? |
defaultbase dd ? |
entry dd ? |
stacksize dd ? |
endl |
and [filedata], 0 |
; 1. Lock the common mutex for PE list. |
mov ecx, pe_list_mutex |
call mutex_lock |
; 2. Check whether this PE file is already mapped somewhere. |
; 2a. Get the timestamp. If failed, pass filesystem error to the caller. |
lea eax, [fileinfo] |
stdcall get_fileinfo, [file_name], eax |
mov edi, eax |
neg edi |
jnz .fail_unlock |
; 2b. Scan the list of PE files, for each file compare timestamp and name. |
; If all parameters match, go to 6. Otherwide, proceed to 3. |
mov esi, [pe_list.fd] |
.scan_existing: |
cmp esi, pe_list |
jz .load_new |
mov eax, dword [fileinfo+24]; last modified time |
mov edx, dword [fileinfo+28]; last modified date |
cmp dword [esi+PEDESCR.timestamp], eax |
jnz .continue_scan |
cmp dword [esi+PEDESCR.timestamp+4], edx |
jnz .continue_scan |
stdcall strncmp, [esi+PEDESCR.name], [file_name], -1 |
test eax, eax |
jz .already_loaded |
.continue_scan: |
mov esi, [esi+PEDESCR.fd] |
jmp .scan_existing |
; Either this file is not PE, or it has not been mapped yet. |
.load_new: |
; 3. Load and unpack file data. |
; If failed, return -5 "file not found". |
stdcall load_file, [file_name] |
movi edi, -5 |
test eax, eax |
jz .fail_unlock |
mov [filedata], eax |
mov dword [fileinfo+32], ebx |
; 4. Check that the file is valid PE, has image data and is not too large. |
; If not, pass the loaded file to the caller as is. |
cmp ebx, 40h |
jb .not_pe |
cmp word [eax], 'MZ' |
jz .check_mz |
cmp [eax+STRIPPED_PE_HEADER.Signature], STRIPPED_PE_SIGNATURE |
jnz .not_pe |
mov ecx, [eax+STRIPPED_PE_HEADER.SizeOfStackReserve] |
mov [stacksize], ecx |
mov ecx, [eax+STRIPPED_PE_HEADER.ImageBase] |
mov esi, [eax+STRIPPED_PE_HEADER.SizeOfImage] |
mov edi, [eax+STRIPPED_PE_HEADER.AddressOfEntryPoint] |
jmp .pe |
.check_mz: |
mov ecx, [eax+3Ch] |
add eax, ecx |
add ecx, IMAGE_NT_HEADERS.OptionalHeader |
jc .not_pe |
cmp ecx, ebx |
ja .not_pe |
cmp [eax+IMAGE_NT_HEADERS.Signature], 'PE' |
jnz .not_pe |
movzx edx, [eax+IMAGE_NT_HEADERS.FileHeader.SizeOfOptionalHeader] |
cmp edx, IMAGE_OPTIONAL_HEADER32.DataDirectory |
jb .not_pe |
add ecx, edx |
jc .not_pe |
cmp ecx, ebx |
ja .not_pe |
cmp [eax+IMAGE_NT_HEADERS.OptionalHeader.Magic], 10Bh |
jnz .not_pe |
mov ecx, [eax+IMAGE_NT_HEADERS.OptionalHeader.SizeOfStackReserve] |
mov [stacksize], ecx |
mov ecx, [eax+IMAGE_NT_HEADERS.OptionalHeader.ImageBase] |
mov esi, [eax+IMAGE_NT_HEADERS.OptionalHeader.SizeOfImage] |
mov edi, [eax+IMAGE_NT_HEADERS.OptionalHeader.AddressOfEntryPoint] |
.pe: |
test esi, esi |
jz .not_pe |
cmp esi, 16*1024*1024 |
ja .not_pe |
mov [defaultbase], ecx |
mov [entry], edi |
add esi, 0xFFF |
shr esi, 12 |
; 5. Allocate and initialize PEDESCR structure. |
; 5a. Calculate structure size: sizeof.PEDESCR + dword per image page + size of PE name. |
mov edi, [file_name] |
mov ecx, -1 |
xor eax, eax |
repnz scasb |
not ecx |
lea eax, [ecx+esi*4+sizeof.PEDESCR] |
; 5b. Allocate memory. |
; If failed, return -30 "no memory". |
push ecx |
call malloc |
pop ecx |
movi edi, -30 |
test eax, eax |
jz .fail_and_free_data |
; 5c. Initialize PEDESCR structure. |
mov [eax+PEDESCR.size], esi |
lea edi, [eax+esi*4+sizeof.PEDESCR] |
mov esi, [file_name] |
mov [eax+PEDESCR.name], edi |
rep movsb |
mov esi, eax |
lea edi, [eax+sizeof.PEDESCR] |
mov ecx, [eax+PEDESCR.size] |
xor eax, eax |
rep stosd |
mov eax, dword [fileinfo+24] |
mov dword [esi+PEDESCR.timestamp], eax |
mov eax, dword [fileinfo+28] |
mov dword [esi+PEDESCR.timestamp+4], eax |
mov eax, [defaultbase] |
mov [esi+PEDESCR.defaultbase], eax |
mov eax, [entry] |
mov [esi+PEDESCR.entry], eax |
mov eax, [stacksize] |
mov [esi+PEDESCR.stacksize], eax |
and dword [esi+PEDESCR.refcount], 0; no SMAPs yet; later it will be incremented |
lea ecx, [esi+PEDESCR.page_array_lock] |
call mutex_init |
; 5d. Insert PEDESCR structure in tail of the common list. |
mov [esi+PEDESCR.fd], pe_list |
mov eax, [pe_list.bk] |
mov [pe_list.bk], esi |
mov [esi+PEDESCR.bk], eax |
mov [eax+PEDESCR.fd], esi |
.already_loaded: |
; We have got the PEDESCR structure, |
; either already-existed from step 2 or created at step 5. |
; In the last case we have also got the file data, |
; in the first case [filedata] is still zero. |
; 6. Increment reference counter in PEDESCR structure. |
inc [esi+PEDESCR.refcount] |
; 7. Release the common mutex for PE list. |
; We have got a new reference to our PEDESCR, it will not go away unexpectedly. |
mov ecx, pe_list_mutex |
call mutex_unlock |
mov eax, [filedata] |
mov ebx, dword [fileinfo+32] |
ret |
.fail_and_free_data: |
stdcall kernel_free, [filedata] |
.fail_unlock: |
mov ecx, pe_list_mutex |
call mutex_unlock |
.fail: |
mov eax, edi |
xor ebx, ebx |
xor esi, esi |
ret |
.not_pe: |
mov ecx, pe_list_mutex |
call mutex_unlock |
mov eax, [filedata] |
xor esi, esi |
ret |
endp |
proc map_pe_usermode stdcall uses ebx esi edi, descr:dword, filedata:dword, filesize:dword |
locals |
img_base dd ? |
peheader dd ? |
header_size dd ? |
num_sections dd ? |
sections dd ? |
section_idx dd ? |
page_index dd ? |
page_offset dd ? |
cur_page dd ? |
cur_access db ? |
rb 3 |
pages dd ? |
num_allocated_pages dd ? |
endl |
; 1. Basic preparations. |
; 1a. Check that the process heap has been initialized. |
; Return -30 "no memory" if not. |
mov esi, [descr] |
movi edi, -30 |
mov eax, [current_process] |
cmp [eax+PROC.heap_top], 0 |
jz .fail_dereference |
; 1b. If filedata is passed, fill the required fields from header now. |
mov eax, [filedata] |
mov ebx, [filesize] |
dec edi ; -30 -> -31 |
test eax, eax |
jz @f |
call .validate_header |
jc .fail_dereference |
@@: |
; 2. Generate array of pages for mapping in address space in the process. |
; It is possible to join this step with step 13, avoiding temporary allocation |
; and putting the result directly in the page table, but that would require |
; doing potentially long operations like loading/unpacking the file |
; while holding address space lock, which could block other threads |
; that just want to lazy-allocate their zero-only pages not related to PE. |
; So, keep generating and mapping separate. |
; 2a. Allocate memory. |
inc edi ; -31 -> -30 |
mov eax, [esi+PEDESCR.size] |
shl eax, 2 |
call malloc |
test eax, eax |
jz .fail_dereference |
mov [pages], eax |
; 2b. Acquire the lock. |
lea ecx, [esi+PEDESCR.page_array_lock] |
call mutex_lock |
; 2c. Prepare for loop over pages: set page index and page offset to zero. |
xor ecx, ecx |
mov [page_index], ecx |
mov [page_offset], ecx |
mov [num_allocated_pages], ecx |
.fill_pages: |
; 2d. For each page, test whether we need to regenerate it. |
; Pages that need to be regenerated are marked as zero in pages array. |
mov eax, [esi+sizeof.PEDESCR+ecx*4] |
test eax, eax |
jz .create_page |
; 2e. For each page that we do not need to regenerate, |
; increment reference counter if it is less than 0xFF |
; and go to 2t. |
lea edx, [eax+1] |
test edx, 0xFF |
jz .page_created |
mov [esi+sizeof.PEDESCR+ecx*4], edx |
jmp .page_created |
.create_page: |
; 2f. If the file has not been already loaded/unpacked, |
; do it now, validating the content. |
cmp [filedata], 0 |
jnz @f |
stdcall load_file, [esi+PEDESCR.name] |
test eax, eax |
jz .fail_free_pages |
call .validate_header |
jc .fail_free_pages |
@@: |
; 2h. Initialize for generating a page: |
; do not allocate a page until we will be sure that data are present, |
; there are no access rights yet. |
and [cur_page], 0 |
mov [cur_access], 0 |
; 2i. Check whether the page overlaps file header. |
; If not, go to 2m. |
mov eax, [page_offset] |
cmp eax, [header_size] |
jae .no_header |
; 2j. Allocate the page data. |
stdcall kernel_alloc, 0x1000 |
test eax, eax |
jz .fail_free_pages |
mov [cur_page], eax |
; 2k. Set access rights for header: readonly; copy header data. |
mov [cur_access], IMAGE_SCN_MEM_READ shr 28 |
mov esi, [filedata] |
mov edi, eax |
add esi, [page_offset] |
mov ecx, [header_size] |
sub ecx, [page_offset] |
cmp ecx, 0x1000 |
jb @f |
mov ecx, 0x1000 |
@@: |
mov edx, ecx |
shr ecx, 2 |
rep movsd |
mov ecx, edx |
and ecx, 3 |
rep movsb |
; 2l. Fill the rest of the page with zeroes. |
mov ecx, 0x1000 |
sub ecx, edx |
mov edx, ecx |
shr ecx, 2 |
and edx, 3 |
xor eax, eax |
rep stosd |
mov ecx, edx |
rep stosb |
.no_header: |
; 2m. Prepare for loop over sections. |
; Skip the loop if there are no sections. |
mov eax, [num_sections] |
mov ebx, [sections] |
test eax, eax |
jz .no_sections |
mov [section_idx], eax |
.sections_loop: |
; 2n. For every section, check whether it has data overlapped with |
; the current page; if so, allocate the page if not yet, copy the data |
; and fill rest of page with zeroes. |
; If data are present, there can be two cases: |
; - the current page has data from the beginning, |
; - first byte of the current page is not covered by the section. |
; The first case is typical, the second case is rare. |
; If the page has not been allocated yet, we can optimize by storing zeroes |
; only in areas that are not covered by the current section. |
; However, this becomes twisted in the second case, |
; so don't bother to optimize the rare case. |
cmp [ebx+COFF_SECTION.SizeOfRawData], 0 |
jz .section_data_done |
mov esi, [page_offset] |
sub esi, [ebx+COFF_SECTION.VirtualAddress] |
cmp esi, [ebx+COFF_SECTION.SizeOfRawData] |
jb .beginning_inside |
add esi, 1000h |
jnc .section_data_done |
jz .section_data_done |
; Rare case: there is an overlap, but the first byte is not covered. |
; If the page has not been allocated, allocate it now and store 4K zeroes. |
cmp [cur_page], 0 |
jnz @f |
stdcall kernel_alloc, 0x1000 |
test eax, eax |
jz .fail_free_pages |
mov [cur_page], eax |
mov edi, eax |
xor eax, eax |
mov ecx, 0x1000/4 |
rep stosd |
@@: |
mov edi, [ebx+COFF_SECTION.VirtualAddress] |
and edi, 0xFFF |
xor esi, esi |
.copy_data: |
mov eax, [ebx+COFF_SECTION.SizeOfRawData] |
sub eax, esi |
mov ecx, 0x1000 |
sub ecx, edi |
add edi, [cur_page] |
cmp ecx, eax |
jb @f |
mov ecx, eax |
@@: |
add esi, [filedata] |
add esi, [ebx+COFF_SECTION.PtrRawData] |
mov edx, ecx |
shr ecx, 2 |
and edx, 3 |
rep movsd |
mov ecx, edx |
rep movsb |
jmp .section_data_done |
.beginning_inside: |
; Normal case: do not store zeroes which will be immediately overwritten. |
xor edi, edi |
cmp [cur_page], edi |
jnz .copy_data |
stdcall kernel_alloc, 0x1000 |
test eax, eax |
jz .fail_free_pages |
mov [cur_page], eax |
mov edi, eax |
mov ecx, [ebx+COFF_SECTION.SizeOfRawData] |
sub ecx, esi |
cmp ecx, 0x1000 |
jb @f |
mov ecx, 0x1000 |
@@: |
add esi, [filedata] |
add esi, [ebx+COFF_SECTION.PtrRawData] |
mov edx, ecx |
shr ecx, 2 |
rep movsd |
mov ecx, edx |
and ecx, 3 |
rep movsb |
mov ecx, 0x1000 |
sub ecx, edx |
mov edx, ecx |
shr ecx, 2 |
and edx, 3 |
xor eax, eax |
rep stosd |
mov ecx, edx |
rep stosb |
.section_data_done: |
; 2o. Get size of the section header. |
; Characteristics is the last dword in both |
; COFF_SECTION and STRIPPED_PE_SECTION, so this helps to access it. |
movi ecx, sizeof.STRIPPED_PE_SECTION |
cmp [peheader], 0 |
jz @f |
mov cl, sizeof.COFF_SECTION |
@@: |
; 2p. If the current page intersects virtual address range of the section, |
; update access rights using section access rights. |
cmp [ebx+COFF_SECTION.VirtualSize], 0 |
jz .section_access_done |
mov esi, [page_offset] |
sub esi, [ebx+COFF_SECTION.VirtualAddress] |
cmp esi, [ebx+COFF_SECTION.VirtualSize] |
jb @f |
add esi, 0x1000 |
jnc .section_access_done |
jz .section_access_done |
@@: |
mov eax, [ebx+ecx-4] |
shr eax, 28 |
or [cur_access], al |
.section_access_done: |
; 2q. Advance to the next section, while there are sections left. |
add ebx, ecx |
dec [section_idx] |
jnz .sections_loop |
.no_sections: |
; 2r. Shareable pages can not be lazy-allocated |
; even if they only contain uninitialized data. |
; If the page is shareable and has not been allocated yet, do it now. |
test [cur_access], IMAGE_SCN_MEM_SHARED shr 28 |
jz @f |
cmp [cur_page], 0 |
jnz @f |
stdcall kernel_alloc, 0x1000 |
test eax, eax |
jz .fail_free_pages |
mov [cur_page], eax |
mov edi, eax |
xor eax, eax |
mov ecx, 0x1000/4 |
rep stosd |
@@: |
; 2s. Get and store the item for page array: 0xFF for pages with zeroes, |
; physical address of the page plus 1 for reference counter otherwise, |
; with access rights in bits 8-11 in both cases. |
mov edi, 0xFF |
mov eax, [cur_page] |
test eax, eax |
jz @f |
call get_pg_addr |
lea edi, [eax+1] |
stdcall free_kernel_space, [cur_page] |
@@: |
movzx eax, [cur_access] |
shl eax, 8 |
or eax, edi |
mov ecx, [page_index] |
mov esi, [descr] |
mov [esi+sizeof.PEDESCR+ecx*4], eax |
.page_created: |
; 2t. Transform the item from page array to page table entry: |
; - drop reference counter, |
; - map zero-only page to LAZY_ALLOC_PAGE |
; with optional flags LAZY_ALLOC_{UNREADABLE,UNWRITABLE}, |
; PF handler will lazy-allocate it; |
; - for pages with data, |
; map readable and executable to user bit, |
; for shareable pages map writable to writable bit, |
; for non-shareable pages ignore writable to support copy-on-write. |
mov edx, eax |
and eax, not 0xFFF |
jz .page_set_zero |
inc [num_allocated_pages] |
or eax, PG_READ+PG_SHARED |
test dh, (IMAGE_SCN_MEM_READ+IMAGE_SCN_MEM_EXECUTE) shr 28 |
jz @f |
or al, PG_USER |
@@: |
test dh, IMAGE_SCN_MEM_SHARED shr 28 |
jz @f |
test dh, IMAGE_SCN_MEM_WRITE shr 28 |
jz @f |
or al, PG_WRITE |
@@: |
jmp .pte_generated |
.page_set_zero: |
mov al, LAZY_ALLOC_PAGE |
test dh, (IMAGE_SCN_MEM_READ+IMAGE_SCN_MEM_EXECUTE) shr 28 |
jnz @f |
or al, LAZY_ALLOC_UNREADABLE |
@@: |
test dh, IMAGE_SCN_MEM_WRITE shr 28 |
jnz @f |
or al, LAZY_ALLOC_UNWRITABLE |
@@: |
.pte_generated: |
mov edi, [pages] |
mov [edi+ecx*4], eax |
; 2u. Advance to the next page, until PEDESCR.size is reached. |
inc ecx |
inc [page_index] |
add [page_offset], 0x1000 |
cmp ecx, [esi+PEDESCR.size] |
jb .fill_pages |
; 2v. Release the lock. |
lea ecx, [esi+PEDESCR.page_array_lock] |
call mutex_unlock |
; 3. Allocate a new SMAP. |
movi eax, sizeof.SMAP |
call malloc |
test eax, eax |
jz .fail_free_pages_unlocked |
mov ebx, eax |
; 4. Lock the address space so that a random PF from other thread |
; between end of step 5 and beginning of step 7 would not trash anything. |
mov ecx, [current_process] |
add ecx, PROC.heap_lock |
call mutex_lock |
; 5. Allocate space in the address space. |
; Prefer PEDESCR.defaultbase, but allow address anywhere else |
; if allocation at PEDESCR.defaultbase is not possible. |
mov edi, [esi+PEDESCR.size] |
shl edi, 12 |
stdcall user_alloc_at_nolock, [esi+PEDESCR.defaultbase], edi |
test eax, eax |
jnz @f |
stdcall user_alloc_nolock, edi |
test eax, eax |
jz .user_alloc_failed |
@@: |
mov [img_base], eax |
; 6. Fill SMAP with values and insert it to the list of SMAPs. |
mov [ebx+SMAP.type], SMAP_TYPE_PE |
mov ecx, [current_process] |
add ecx, PROC.smap_list |
mov edx, [ecx+SMAP.fd] |
mov [ebx+SMAP.fd], edx |
mov [ebx+SMAP.bk], ecx |
mov [ecx+SMAP.fd], ebx |
mov [edx+SMAP.bk], ebx |
mov [ebx+SMAP.base], eax |
mov [ebx+SMAP.size], edi |
mov [ebx+SMAP.parent], esi |
; 7. Copy page table entries prepared at step 2 to the page table. |
mov edx, eax |
shr edx, 12 |
mov ecx, [esi+PEDESCR.size] |
mov esi, [pages] |
lea edi, [page_tabs+edx*4] |
rep movsd |
mov eax, [num_allocated_pages] |
shl eax, 12 |
; 8. Release the address space lock. |
mov ecx, [current_process] |
add [ecx+PROC.mem_used], eax |
add ecx, PROC.heap_lock |
call mutex_unlock |
; 9. Cleanup and return allocated address. |
mov eax, [pages] |
call free |
cmp [filedata], 0 |
jz @f |
stdcall kernel_free, [filedata] |
@@: |
mov eax, [img_base] |
ret |
.fail_and_free_data: |
stdcall kernel_free, [filedata] |
.fail: |
mov eax, edi |
ret |
.user_alloc_failed: |
mov ecx, [current_process] |
add ecx, PROC.heap_lock |
call mutex_unlock |
mov eax, ebx |
call free |
.fail_free_pages_unlocked: |
lea ecx, [esi+PEDESCR.page_array_lock] |
call mutex_lock |
.fail_free_pages: |
mov ecx, [page_index] |
test ecx, ecx |
jz .fail_free_pages_array |
mov eax, [esi+sizeof.PEDESCR+(ecx-1)*4] |
mov edx, eax |
and eax, not 0xFFF |
jz .fail_free_next |
and edx, 0xFF |
cmp edx, 0xFF |
jz .fail_free_next |
dec dword [esi+sizeof.PEDESCR+(ecx-1)*4] |
dec edx |
jnz .fail_free_next |
mov [esi+sizeof.PEDESCR+(ecx-1)*4], edx |
call free_page |
.fail_free_next: |
dec [page_index] |
jmp .fail_free_pages |
.fail_free_pages_array: |
lea ecx, [esi+PEDESCR.page_array_lock] |
call mutex_unlock |
mov eax, [pages] |
call free |
movi edi, -30 |
.fail_dereference: |
cmp [filedata], 0 |
jz @f |
stdcall kernel_free, [filedata] |
@@: |
call dereference_pe |
mov eax, edi |
ret |
.validate_header: |
mov [filedata], eax |
cmp ebx, 40h |
jb .validate_header.error |
mov [peheader], 0 |
cmp word [eax], STRIPPED_PE_SIGNATURE |
jz .validate_header.stripped |
cmp word [eax], 'MZ' |
jnz .validate_header.error |
mov ecx, [eax+3Ch] |
add eax, ecx |
add ecx, IMAGE_NT_HEADERS.OptionalHeader |
jc .validate_header.error |
cmp ecx, ebx |
ja .validate_header.error |
cmp [eax+IMAGE_NT_HEADERS.Signature], 'PE' |
jnz .validate_header.error |
mov [peheader], eax |
movzx edx, [eax+IMAGE_NT_HEADERS.FileHeader.SizeOfOptionalHeader] |
cmp edx, IMAGE_OPTIONAL_HEADER32.DataDirectory |
jb .validate_header.error |
add ecx, edx |
jc .validate_header.error |
cmp ecx, ebx |
ja .validate_header.error |
lea edx, [eax+IMAGE_NT_HEADERS.OptionalHeader+edx] |
mov [sections], edx |
movzx edx, [eax+IMAGE_NT_HEADERS.FileHeader.NumberOfSections] |
mov [num_sections], edx |
imul edx, sizeof.COFF_SECTION |
add ecx, edx |
jc .validate_header.error |
cmp ecx, ebx |
ja .validate_header.error |
mov edx, [eax+IMAGE_NT_HEADERS.OptionalHeader.SizeOfHeaders] |
mov [header_size], edx |
cmp edx, ebx |
ja .validate_header.error |
mov edx, [num_sections] |
mov ecx, [sections] |
test edx, edx |
jz .validate_header.sections_ok |
@@: |
mov eax, [ecx+COFF_SECTION.PtrRawData] |
add eax, [ecx+COFF_SECTION.SizeOfRawData] |
jc .validate_header.error |
cmp eax, ebx |
ja .validate_header.error |
add ecx, sizeof.COFF_SECTION |
dec edx |
jnz @b |
.validate_header.sections_ok: |
.validate_header.ok: |
clc |
retn |
.validate_header.stripped: |
movzx ecx, [eax+STRIPPED_PE_HEADER.NumberOfRvaAndSizes] |
lea ecx, [sizeof.STRIPPED_PE_HEADER+ecx*8] |
movzx edx, [eax+STRIPPED_PE_HEADER.NumberOfSections] |
mov [num_sections], edx |
imul edx, sizeof.STRIPPED_PE_SECTION |
add edx, ecx |
cmp edx, ebx |
ja .validate_header.error |
mov edx, [eax+STRIPPED_PE_HEADER.SizeOfHeaders] |
mov [header_size], edx |
cmp edx, ebx |
ja .validate_header.error |
add ecx, eax |
mov [sections], ecx |
mov edx, [num_sections] |
test edx, edx |
jz .validate_header.stripped.sections_ok |
@@: |
mov eax, [ecx+STRIPPED_PE_SECTION.PtrRawData] |
add eax, [ecx+STRIPPED_PE_SECTION.SizeOfRawData] |
jc .validate_header.error |
cmp eax, ebx |
ja .validate_header.error |
add ecx, sizeof.STRIPPED_PE_SECTION |
dec edx |
jnz @b |
.validate_header.stripped.sections_ok: |
clc |
retn |
.validate_header.error: |
stc |
retn |
endp |
; in: edi -> SMAP |
; in: address space lock must be held |
proc release_pemap stdcall uses ebx esi, process:dword |
locals |
num_released_pages dd 0 |
mapped_pagedir dd -1 |
endl |
mov esi, [edi+SMAP.base] |
mov ebx, [edi+SMAP.parent] |
shr esi, 12 |
dec esi |
add ebx, sizeof.PEDESCR |
call .get_page_tab_entry |
mov ecx, [eax] |
and ecx, not MEM_BLOCK_DONT_FREE |
mov [eax], ecx |
shr ecx, 12 |
dec ecx |
jz .released |
.release: |
inc esi |
call .get_page_tab_entry |
mov edx, [eax] |
test dl, 1 |
jz .next |
test edx, PG_SHARED |
jz .next |
mov dword [eax], 0 |
inc [num_released_pages] |
xor edx, [ebx] |
test edx, not 0xFFF |
jnz .next |
mov edx, [ebx] |
mov eax, edx |
and edx, 0xFF |
cmp edx, 0xFF |
jz .next |
dec eax |
test dword [ebx], IMAGE_SCN_MEM_SHARED shr 20 |
jnz @f |
test eax, 0xFF |
jnz @f |
call free_page |
xor eax, eax |
@@: |
mov [ebx], eax |
.next: |
add ebx, 4 |
dec ecx |
jnz .release |
mov eax, [num_released_pages] |
shl eax, 12 |
mov edx, [process] |
sub [edx+PROC.mem_used], eax |
cmp [mapped_pagedir], -1 |
jz .released |
stdcall map_page, [tmp_task_ptab], 0, PG_UNMAP |
.released: |
ret |
.get_page_tab_entry: |
mov eax, [process] |
cmp eax, [current_process] |
jnz @f |
lea eax, [page_tabs+esi*4] |
retn |
@@: |
push edx |
mov edx, esi |
shr edx, 10 |
cmp edx, [mapped_pagedir] |
jz @f |
mov [mapped_pagedir], edx |
mov eax, [eax+PROC.pdt_0+edx*4] |
and eax, not 0xFFF |
stdcall map_page, [tmp_task_ptab], eax, PG_SWR |
@@: |
mov eax, [tmp_task_ptab] |
mov edx, esi |
and edx, 0x3FF |
lea eax, [eax+edx*4] |
pop edx |
retn |
endp |
proc unmap_pe_usermode stdcall uses ebx esi edi, address:dword |
mov ecx, [current_process] |
lea edi, [ecx+PROC.smap_list] |
add ecx, PROC.heap_lock |
call mutex_lock |
mov esi, edi |
mov eax, [address] |
.scan: |
mov edi, [edi+SMAP.fd] |
cmp edi, esi |
jz .notfound |
cmp [edi+SMAP.base], eax |
jnz .scan |
mov eax, [edi+SMAP.fd] |
mov edx, [edi+SMAP.bk] |
mov [eax+SMAP.bk], edx |
mov [edx+SMAP.fd], eax |
call mutex_unlock |
stdcall destroy_smap, [current_process] |
xor eax, eax |
ret |
.notfound: |
call mutex_unlock |
or eax, -1 |
ret |
endp |
/kernel/branches/kolibrios-pe-clevermouse/core/sys32.inc |
---|
307,7 → 307,7 |
; incorrect address in the program |
mov eax, [page_tabs+ebx*4] |
test eax, 2 |
test eax, 1 |
jz .fail ; address not reserved for use. error |
pop ebx |
/kernel/branches/kolibrios-pe-clevermouse/core/taskman.inc |
---|
42,10 → 42,30 |
filename_size rd 1 |
cmdline_size rd 1 |
path_string rd 1 |
pedescr rd 1 |
ends |
; Pointer to this structure is passed as the third argument |
; to usermode PE loader by the kernel. |
struct kernel_init_data |
version dw ? |
flags dw ? |
syscall_method dd ? |
; either one of SYSCALL_METHOD_xxx or pointer to procedure |
exe_base dd ? |
stack_base dd ? |
stack_size dd ? |
exe_path dd ? |
command_line dd ? |
environment dd ? |
ends |
SYSCALL_METHOD_I40 = 1 |
SYSCALL_METHOD_SYSENTER = 2 |
SYSCALL_METHOD_SYSCALL = 3 |
macro _clear_ op |
{ mov ecx, op/4 |
{ |
mov ecx, op/4 |
xor eax, eax |
cld |
rep stosd |
98,6 → 118,7 |
filename_size rd 1 |
cmdline_size rd 1 |
path_string rd 1 |
pedescr rd 1 |
endl |
mov [flags], edx |
104,24 → 125,34 |
mov [cmdline], ecx |
mov [path_string], ebx |
mov [filename_size], eax |
mov esi, -ERROR_FILE_NOT_FOUND |
mov edi, -ERROR_FILE_NOT_FOUND |
test eax, eax |
jz .err_file |
stdcall load_file, ebx |
test eax, eax |
jz .err_file |
stdcall load_file_maybe_pe, [path_string] |
mov [pedescr], esi |
mov [file_base], eax |
mov [file_size], ebx |
test esi, esi |
jnz .file_ok |
mov edi, eax |
cmp eax, -0x1000 |
ja .err_file |
lea ebx, [hdr_cmdline] |
call test_app_header ; fill our app header data locals with values from header of given program (if its correct) |
mov esi, -TASKMAN_ERROR_NOT_A_EXECUTABLE |
mov edi, -TASKMAN_ERROR_NOT_A_EXECUTABLE |
test eax, eax |
jz .err_hdr |
.file_ok: |
call lock_application_table |
call alloc_thread_slot ; create a slot for new thread |
mov esi, -TASKMAN_ERROR_TOO_MANY_PROCESSES |
mov edi, -TASKMAN_ERROR_TOO_MANY_PROCESSES |
test eax, eax |
jz .err_0 |
162,8 → 193,15 |
add [hdr_emem], ebx |
@@: |
mov [cmdline_size], eax |
xor eax, eax |
cmp [pedescr], eax |
jz @f |
mov [hdr_eip], eax |
mov [hdr_esp], eax |
mov [hdr_emem], eax |
@@: |
stdcall create_process, [hdr_emem] ; create a new process |
mov esi, -TASKMAN_ERROR_OUT_OF_MEMORY |
mov edi, -TASKMAN_ERROR_OUT_OF_MEMORY |
test eax, eax |
jz .err_hdr |
203,12 → 241,17 |
ret |
.err_0: |
mov esi, [pedescr] |
test esi, esi |
jz @f |
call dereference_pe |
@@: |
call unlock_application_table |
.err_hdr: |
stdcall kernel_free, [file_base] |
.err_file: |
stdcall kernel_free, [path_string] |
mov eax, esi |
mov eax, edi |
ret |
endp |
330,13 → 373,18 |
jz .fail |
mov [process], eax |
lea edi, [eax+PROC.heap_lock] |
mov ecx, (PROC.ht_free-PROC.heap_lock)/4 |
lea edi, [eax+PROC.heap_base] |
list_init eax |
add eax, PROC.thr_list |
list_init eax |
add eax, PROC.smap_list - PROC.thr_list |
list_init eax |
lea ecx, [eax+PROC.heap_lock-PROC.smap_list] |
call mutex_init |
mov ecx, (PROC.ht_free-PROC.heap_base)/4 |
xor eax, eax |
cld |
rep stosd |
370,6 → 418,8 |
lea edx, [edi-4096] |
mov esi, [app_tabs] |
test esi, esi |
jz .no_page_dirs |
.alloc_page_dir: |
call alloc_page |
388,6 → 438,7 |
dec esi |
jnz .alloc_page_dir |
.no_page_dirs: |
stdcall map_page, [tmp_task_ptab], 0, PG_UNMAP |
mov eax, [process] |
397,7 → 448,7 |
ret |
.fail: |
mov ecx, [process] |
jcxz @F |
jecxz @F |
call destroy_process |
@@: |
419,8 → 470,6 |
mov eax, [esi] |
test eax, 1 |
jz .next |
test eax, 2 |
jz .next |
test eax, 1 shl 9 |
jnz .next ;skip shared pages |
call free_page |
446,8 → 495,16 |
mov esi, ecx |
list_del esi |
mov esi, [esi+PROC.dlls_list_ptr] |
call destroy_all_hdlls |
lea ebx, [esi+PROC.smap_list] |
mov edi, [esi+PROC.smap_list+SMAP.fd] |
.smap_list_destroy: |
cmp edi, ebx |
jz .smap_list_done |
push [edi+SMAP.fd] |
stdcall destroy_smap, [esp+4] |
pop edi |
jmp .smap_list_destroy |
.smap_list_done: |
mov esi, [esp] |
add esi, PROC.pdt_0 |
532,6 → 589,7 |
r_count dd ? |
offset dd ? |
tmp_r_cnt dd ? |
mapped_size dd ? |
endl |
mov [slot], eax |
541,6 → 599,8 |
mov [offset], esi |
pushad |
mov ecx, proc_mem_mutex |
call mutex_lock |
.read_mem: |
mov edx, [offset] |
mov ebx, [tmp_r_cnt] |
560,13 → 620,14 |
push ecx |
stdcall map_memEx, [proc_mem_map], \ |
[slot], ebx, ecx, PG_READ |
[slot], ebx, ecx, PG_READ, [proc_mem_tab] |
mov [mapped_size], eax |
pop ecx |
mov esi, [offset] |
and esi, 0xfff |
sub eax, esi |
jbe .ret |
jbe .ret_unmap |
cmp ecx, eax |
jbe @f |
mov ecx, eax |
574,17 → 635,26 |
@@: |
add esi, [proc_mem_map] |
mov edi, [buff] |
mov edx, ecx |
push ecx |
rep movsb |
add [r_count], edx |
stdcall unmap_memEx, [proc_mem_map], \ |
[slot], ebx, [mapped_size], [proc_mem_tab] |
pop ecx |
add [r_count], ecx |
add [offset], edx |
sub [tmp_r_cnt], edx |
add [offset], ecx |
sub [tmp_r_cnt], ecx |
jnz .read_mem |
.ret: |
mov ecx, proc_mem_mutex |
call mutex_unlock |
popad |
mov eax, [r_count] |
ret |
.ret_unmap: |
stdcall unmap_memEx, [proc_mem_map], \ |
[slot], ebx, [mapped_size], [proc_mem_tab] |
jmp .ret |
endp |
align 4 |
603,6 → 673,7 |
w_count dd ? |
offset dd ? |
tmp_w_cnt dd ? |
mapped_size dd ? |
endl |
mov [slot], eax |
612,7 → 683,9 |
mov [offset], esi |
pushad |
.read_mem: |
mov ecx, proc_mem_mutex |
call mutex_lock |
.write_mem: |
mov edx, [offset] |
mov ebx, [tmp_w_cnt] |
630,13 → 703,14 |
mov ebx, [offset] |
push ecx |
stdcall map_memEx, [proc_mem_map], \ |
[slot], ebx, ecx, PG_SWR |
[slot], ebx, ecx, PG_SWR, [proc_mem_tab] |
mov [mapped_size], eax |
pop ecx |
mov edi, [offset] |
and edi, 0xfff |
sub eax, edi |
jbe .ret |
jbe .ret_unmap |
cmp ecx, eax |
jbe @f |
mov ecx, eax |
644,17 → 718,25 |
@@: |
add edi, [proc_mem_map] |
mov esi, [buff] |
mov edx, ecx |
push ecx |
rep movsb |
stdcall unmap_memEx, [proc_mem_map], \ |
[slot], ebx, [mapped_size], [proc_mem_tab] |
pop ecx |
add [w_count], edx |
add [offset], edx |
sub [tmp_w_cnt], edx |
jnz .read_mem |
add [w_count], ecx |
add [offset], ecx |
sub [tmp_w_cnt], ecx |
jnz .write_mem |
.ret: |
mov ecx, proc_mem_mutex |
call mutex_unlock |
popad |
mov eax, [w_count] |
ret |
.ret_unmap: |
stdcall unmap_memEx, [proc_mem_map], [slot], ebx, [mapped_size], [proc_mem_tab] |
jmp .ret |
endp |
;ebx = 1 - kernel thread |
799,6 → 881,76 |
jz .exit |
; APPDATA.exec_params have first thread only, |
; so second and next threads don't get here (they jump to .exit) |
cmp [ebp+APP_HDR.pedescr], 0 |
jz .init_legacy_app |
; init PE application |
mov eax, [current_process] |
mov [eax+PROC.mem_used], 0xF000 ; leave first 64K as unallocatable |
call init_heap |
mov eax, [current_process] |
mov [eax+PROC.mem_used], 0 |
stdcall map_pe_usermode, [ebp+APP_HDR.pedescr],\ |
[ebp+APP_HDR.img_base], [ebp+APP_HDR.img_size] |
cmp eax, -0x1000 |
ja .failed |
push eax |
stdcall load_file_maybe_pe, pe_loader_usermode |
test esi, esi |
jz .pe_loader_notfound |
mov edx, [esi+PEDESCR.entry] |
mov [esp+4+20h], edx |
stdcall map_pe_usermode, esi, eax, ebx |
cmp eax, -0x1000 |
ja .pe_loader_failed |
add [esp+4+20h], eax |
push eax |
mov eax, [ebp+APP_HDR.filename_size] |
add eax, [ebp+APP_HDR.cmdline_size] |
add eax, sizeof.kernel_init_data + 2 |
stdcall user_alloc, eax |
test eax, eax |
jz .failed |
mov ebx, eax |
mov dword [eax+kernel_init_data.version], 1 + (0 shl 16) ; version, flags |
mov [eax+kernel_init_data.syscall_method], SYSCALL_METHOD_I40 |
lea edi, [eax+sizeof.kernel_init_data] |
mov [eax+kernel_init_data.exe_path], edi |
mov esi, [ebp+APP_HDR.path_string] |
mov ecx, [ebp+APP_HDR.filename_size] |
rep movsb |
mov byte [edi], 0 |
inc edi |
mov [eax+kernel_init_data.command_line], edi |
lea esi, [ebp+sizeof.APP_HDR] |
mov ecx, [ebp+APP_HDR.cmdline_size] |
rep movsb |
mov byte [edi], 0 |
mov ecx, [ebp+APP_HDR.pedescr] |
mov ecx, [ecx+PEDESCR.stacksize] |
mov [eax+kernel_init_data.stack_size], ecx |
stdcall user_alloc, ecx |
test eax, eax |
jz .failed |
mov [ebx+kernel_init_data.stack_base], eax |
add eax, [ebx+kernel_init_data.stack_size] |
sub eax, 16 |
pop dword [eax+4] |
pop [ebx+kernel_init_data.exe_base] |
mov dword [eax+8], 1 ; DLL_PROCESS_ATTACH |
mov dword [eax+12], ebx |
mov [esp+2Ch], eax |
jmp .common_tls |
.pe_loader_notfound: |
cmp eax, -0x1000 |
ja .pe_loader_failed |
stdcall kernel_free, eax |
.pe_loader_failed: |
dbgstr 'Failed to load kolibri.dll' |
.failed: |
stdcall kernel_free, [ebp+APP_HDR.path_string] |
jmp sys_end |
.init_legacy_app: |
; init MENUETxx application |
stdcall map_process_image, [ebp+APP_HDR._emem],\ |
[ebp+APP_HDR.img_base], [ebp+APP_HDR.img_size] |
mov esi, [ebp+APP_HDR.path_string] |
846,8 → 998,9 |
mov byte [edi], 0 |
.check_tls_header: |
cmp word [6], '02' |
jne .try_load_dll ;.cleanup |
jne .try_load_dll ;.common |
call init_heap |
.common_tls: |
stdcall user_alloc, 4096 |
mov edx, [current_slot] |
mov [edx+APPDATA.tls_base], eax |
862,7 → 1015,7 |
; Test app header version |
mov ecx, dword[ebp+APP_HDR.img_base] |
cmp dword[ecx+8], 2 |
jne .cleanup |
jne .common |
;if APP_HEADER.version = 2 => load lib/dll.obj & change eip to APP_STARTUP_THUNK |
DEBUGF 1, 'K : App header version 2\n' |
stdcall load_library, dll_lib_path, 0 |
889,7 → 1042,9 |
mov [ecx+REG_EIP], eax |
; } End patch by Coldy, For DLL autoload |
.cleanup: |
mov fs, dx |
.common: |
stdcall free_kernel_space, [ebp+APP_HDR.img_base] |
stdcall kernel_free, ebp |
mov ebx, [current_slot] |
/kernel/branches/kolibrios-pe-clevermouse/data32.inc |
---|
181,6 → 181,8 |
dll_lib_path db '/RD/1/LIB/DLL.OBJ',0 |
dll_error_msg db '"DLL.OBJ not found!\nTerminate application!" -dE',0 |
; } End patch by Coldy, For DLL autoload |
pe_loader_usermode db '/rd/1/lib/kolibri.dll',0 |
align 4 |
shmem_list: |
187,17 → 189,17 |
.bk dd shmem_list |
.fd dd shmem_list |
dll_list: |
.bk dd dll_list |
.fd dd dll_list |
pe_list: |
.bk dd pe_list |
.fd dd pe_list |
pcidev_list: |
.bk dd pcidev_list |
.fd dd pcidev_list |
MAX_DEFAULT_DLL_ADDR = 0x80000000 |
MIN_DEFAULT_DLL_ADDR = 0x70000000 |
dll_cur_addr dd MIN_DEFAULT_DLL_ADDR |
shared_locked_list: |
dd shared_locked_list |
dd shared_locked_list |
; supported videomodes |
399,6 → 401,12 |
srv.fd dd ? |
srv.bk dd ? |
shmem_list_mutex MUTEX |
pe_list_mutex MUTEX |
shared_locked_mutex MUTEX |
proc_mem_mutex MUTEX |
ipc_mutex MUTEX |
LFBAddress dd ? |
PUTPIXEL dd ? |
432,6 → 440,7 |
proc_mem_tab dd ? |
tmp_task_ptab dd ? |
zero_page_tab dd ? |
default_io_map dd ? |
/kernel/branches/kolibrios-pe-clevermouse/docs/sysfuncr.txt |
---|
3660,6 → 3660,67 |
* edx = размер загруженного файла или 0 |
Примечания: |
* функция загружает и, при необходимости, распаковывает файл (kunpack) |
====================================================================== |
=========== Функция 68, подфункция 29 - загрузить PE-файл ============ |
====================================================================== |
Параметры: |
* eax = 68 - номер функции |
* ebx = 29 - номер подфункции |
* ecx = указатель на строку с путём к файлу, |
правила формирования строки указаны в описании функции 70. |
Возвращаемое значение: |
* eax > 0xFFFFF000 - произошла ошибка, -eax = код ошибки |
* eax <= 0xFFFFF000 - адрес загруженного файла |
Примечания: |
* функция предназначена только для системного загрузчика внутри |
kolibri.dll; загруженный файл ещё не готов к работе, ему требуется |
донастройка. Вместо неё используйте |
функцию dlopen() из kolibri.dll. |
====================================================================== |
=========== Функция 68, подфункция 30 - выгрузить PE-файл ============ |
====================================================================== |
Параметры: |
* eax = 68 - номер функции |
* ebx = 30 - номер подфункции |
* ecx = адрес загруженного PE-файла |
Возвращаемое значение: |
* eax = 0 - успешно |
* eax = -1 - адрес не соответствует никакому загруженному файлу |
Примечания: |
* функция предназначена только для системного загрузчика внутри |
kolibri.dll. Вместо неё используйте функцию dlclose() |
из kolibri.dll. |
====================================================================== |
==== Функция 68, подфункция 31 - изменить права доступа к памяти ===== |
====================================================================== |
Параметры: |
* eax = 68 - номер функции |
* ebx = 31 - номер подфункции |
* ecx = новые права доступа: ноль или более из следующих бит: |
* PROT_READ = 1 - разрешить чтение |
* PROT_WRITE = 2 - разрешить запись |
* PROT_EXEC = 4 - разрешить исполнение |
* edx = начальный адрес участка памяти |
* esi = размер участка памяти в байтах |
Возвращаемое значение: |
* eax = -1 - ошибка |
* иначе eax = старые права доступа |
Примечания: |
* Функция изменяет права целым страницам (4096 байт). Функция |
меняет права доступа у всех страниц, пересекающихся с запрошенным |
участком. |
* Функция считает ошибкой передачу участка памяти от функции 68.22. |
* Если часть переданного участка памяти корректна, а часть - нет, |
то функция возвращает ошибку, но не гарантируется, изменились ли |
права доступа у корректной части. |
* Если не было ошибки, то функция возвращает старые права доступа |
у первой из запрошенных страниц. |
* Текущая реализация не поддерживает разрешения исполнения отдельно |
от чтения. Поэтому бит PROT_EXEC игнорируется на входе и копирует |
разрешение на чтение на выходе. |
---------------------- Константы для регистров: ---------------------- |
eax - SF_SYS_MISC (68) |
ebx - SSF_MPROTECT (31) |
====================================================================== |
======================== Функция 69 - отладка. ======================= |
/kernel/branches/kolibrios-pe-clevermouse/docs/sysfuncs.txt |
---|
3645,6 → 3645,68 |
---------------------- Constants for registers: ---------------------- |
eax - SF_SYS_MISC (68) |
ebx - SSF_MEM_ALLOC_RING (29) |
====================================================================== |
============ Function 68, subfunction 30 - load PE-file ============== |
====================================================================== |
Parameters: |
* eax = 68 - function number |
* ebx = 30 - subfunction number |
* ecx = pointer to the string with path to file, |
rules of path forming can be found in function 70 description. |
Returned value: |
* eax > 0xFFFFF000 - error, -eax = error code |
* eax <= 0xFFFFF000 - pointer to the loaded file |
Remarks: |
* This function is to be called only by system loader from |
kolibri.dll; the file loaded is not ready yet, it requires further |
configuration. Use dlopen() from kolibri.dll instead of this |
function. |
====================================================================== |
=========== Function 68, subfunction 31 - unload PE-file ============= |
====================================================================== |
Parameters: |
* eax = 68 - function number |
* ebx = 31 - subfunction number |
* ecx = pointer to the loaded file |
Returned value: |
* eax = 0 - success |
* eax = -1 - provided address does not correspond to any loaded file |
Remarks: |
* This function is to be called only by system loader from |
kolibri.dll. Use dlclose() from kolibri.dll instead of this |
function. |
====================================================================== |
===== Function 68, subfunction 32 - modify memory access rights ====== |
====================================================================== |
Parameters: |
* eax = 68 - function number |
* ebx = 32 - subfunction number |
* ecx = new access rights: zero or more of the following bits: |
* PROT_READ = 1 - allow reading |
* PROT_WRITE = 2 - allow writing |
* PROT_EXEC = 4 - allow execution |
* edx = pointer to begin of memory region |
* esi = size of memory region in bytes |
Returned value: |
* eax = -1 - error |
* else eax = old access rights |
Remarks: |
* The function modifies access rights to whole pages (4096 bytes). |
* The function modifies access rights to all the pages intersecting |
provided memory region. |
* It is considered an error if a memory region returned by function |
68.22 is passed to this function. |
* If any part of the passed memory region is incorrect, then the |
function returns an error. However it is not guaranteed that |
access rights of the correct part have been changed. |
* If there was no error, the function returns old access rights of |
the first provided page. |
* Current implementation does not support execution access rights |
without reading rights. Therefore bit PROT_EXEC is ignored on |
entering the function, and becomes a copy of PROT_READ at exit. |
---------------------- Constants for registers: ---------------------- |
eax - SF_SYS_MISC (68) |
ebx - SSF_MPROTECT (32) |
====================================================================== |
====================== Function 69 - debugging. ====================== |
/kernel/branches/kolibrios-pe-clevermouse/kernel.asm |
---|
322,6 → 322,17 |
mov ecx, application_table_mutex |
call mutex_init |
mov ecx, shmem_list_mutex |
call mutex_init |
mov ecx, pe_list_mutex |
call mutex_init |
mov ecx, shared_locked_mutex |
call mutex_init |
mov ecx, proc_mem_mutex |
call mutex_init |
mov ecx, ipc_mutex |
call mutex_init |
mov ecx, ide_mutex |
call mutex_init |
mov ecx, ide_channel1_mutex |
513,6 → 524,9 |
add eax, ebx |
mov [ipc_ptab], eax |
add eax, ebx |
mov [zero_page_tab], eax |
stdcall kernel_alloc, (unpack.LZMA_BASE_SIZE+(unpack.LZMA_LIT_SIZE shl \ |
(unpack.lc+unpack.lp)))*4 |
2879,30 → 2893,23 |
mov [bgrlockpid], eax |
cmp [img_background], static_background_data |
jz .nomem |
stdcall user_alloc, [mem_BACKGROUND] |
mov ecx, [current_process] |
add ecx, PROC.heap_lock |
call mutex_lock |
stdcall user_alloc_nolock, [mem_BACKGROUND] |
mov [esp+32], eax |
test eax, eax |
jz .nomem |
jz .nomem_unlock |
mov ebx, eax |
shr ebx, 12 |
or dword [page_tabs+(ebx-1)*4], MEM_BLOCK_DONT_FREE |
mov esi, [img_background] |
shr esi, 12 |
mov ecx, [mem_BACKGROUND] |
add ecx, 0xFFF |
shr ecx, 12 |
;-------------------------------------- |
align 4 |
.z: |
mov eax, [page_tabs+ebx*4] |
test al, 1 |
jz @f |
call free_page |
;-------------------------------------- |
align 4 |
@@: |
mov eax, [page_tabs+esi*4] |
or al, PG_UWR |
or eax, PG_UWR+PG_SHARED |
mov [page_tabs+ebx*4], eax |
mov eax, ebx |
shl eax, 12 |
2909,10 → 2916,16 |
invlpg [eax] |
inc ebx |
inc esi |
loop .z |
dec ecx |
jnz .z |
mov ecx, [current_process] |
add ecx, PROC.heap_lock |
call mutex_unlock |
ret |
;-------------------------------------- |
align 4 |
.nomem_unlock: |
mov ecx, [current_process] |
add ecx, PROC.heap_lock |
call mutex_unlock |
.nomem: |
and [bgrlockpid], 0 |
mov [bgrlock], 0 |
2926,30 → 2939,7 |
mov eax, [current_slot_idx] |
cmp [bgrlockpid], eax |
jnz .err |
mov eax, ecx |
mov ebx, ecx |
shr eax, 12 |
mov ecx, [page_tabs+(eax-1)*4] |
test cl, MEM_BLOCK_USED or MEM_BLOCK_DONT_FREE |
jz .err |
jnp .err |
push eax |
shr ecx, 12 |
dec ecx |
;-------------------------------------- |
align 4 |
@@: |
and dword [page_tabs+eax*4], 0 |
mov edx, eax |
shl edx, 12 |
push eax |
invlpg [edx] |
pop eax |
inc eax |
loop @b |
pop eax |
and dword [page_tabs+(eax-1)*4], not MEM_BLOCK_DONT_FREE |
stdcall user_free, ebx |
stdcall user_free, ecx |
mov [esp+32], eax |
and [bgrlockpid], 0 |
mov [bgrlock], 0 |
4925,6 → 4915,14 |
pop ax dx |
end if |
if 0 |
push eax edx |
mov al, bl |
mov dx, 0x402 |
out dx, al |
pop edx eax |
end if |
mov [msg_board_data+ecx], bl |
cmp byte [debug_direct_print], 1 |
jnz .end |
/kernel/branches/kolibrios-pe-clevermouse/kernel32.inc |
---|
15,6 → 15,7 |
include "core/memory.inc" |
include "core/mtrr.inc" |
include "core/heap.inc" |
include "core/peuser.inc" |
include "core/malloc.inc" ; small kernel heap |
include "core/taskman.inc" |
include "core/dll.inc" |