forked from KolibriOS/kolibrios
8b61a2e72d
git-svn-id: svn://kolibrios.org@5585 a494cfbc-eb01-0410-851d-a64ba20cac60
1414 lines
36 KiB
PHP
1414 lines
36 KiB
PHP
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||
;; ;;
|
||
;; Copyright (C) KolibriOS team 2004-2015. All rights reserved. ;;
|
||
;; Distributed under terms of the GNU General Public License ;;
|
||
;; ;;
|
||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||
|
||
$Revision$
|
||
|
||
|
||
DRV_COMPAT equ 5 ;minimal required drivers version
|
||
DRV_CURRENT equ 6 ;current drivers model version
|
||
|
||
DRV_VERSION equ (DRV_COMPAT shl 16) or DRV_CURRENT
|
||
PID_KERNEL equ 1 ;os_idle thread
|
||
|
||
|
||
|
||
align 4
|
||
proc get_notify stdcall, p_ev:dword
|
||
|
||
.wait:
|
||
mov ebx, [current_slot]
|
||
test dword [ebx+APPDATA.event_mask], EVENT_NOTIFY
|
||
jz @f
|
||
and dword [ebx+APPDATA.event_mask], not EVENT_NOTIFY
|
||
mov edi, [p_ev]
|
||
mov dword [edi], EV_INTR
|
||
mov eax, [ebx+APPDATA.event]
|
||
mov dword [edi+4], eax
|
||
ret
|
||
@@:
|
||
call change_task
|
||
jmp .wait
|
||
endp
|
||
|
||
|
||
handle equ IOCTL.handle
|
||
io_code equ IOCTL.io_code
|
||
input equ IOCTL.input
|
||
inp_size equ IOCTL.inp_size
|
||
output equ IOCTL.output
|
||
out_size equ IOCTL.out_size
|
||
|
||
|
||
align 4
|
||
proc srv_handler stdcall, ioctl:dword
|
||
mov esi, [ioctl]
|
||
test esi, esi
|
||
jz .err
|
||
|
||
mov edi, [esi+handle]
|
||
cmp [edi+SRV.magic], ' SRV'
|
||
jne .fail
|
||
|
||
cmp [edi+SRV.size], sizeof.SRV
|
||
jne .fail
|
||
|
||
; stdcall [edi+SRV.srv_proc], esi
|
||
mov eax, [edi+SRV.srv_proc]
|
||
test eax, eax
|
||
jz .fail
|
||
stdcall eax, esi
|
||
ret
|
||
.fail:
|
||
xor eax, eax
|
||
not eax
|
||
mov [esi+output], eax
|
||
mov [esi+out_size], 4
|
||
ret
|
||
.err:
|
||
xor eax, eax
|
||
not eax
|
||
ret
|
||
endp
|
||
|
||
; param
|
||
; ecx= io_control
|
||
;
|
||
; retval
|
||
; eax= error code
|
||
|
||
align 4
|
||
srv_handlerEx:
|
||
cmp ecx, OS_BASE
|
||
jae .fail
|
||
|
||
mov eax, [ecx+handle]
|
||
cmp [eax+SRV.magic], ' SRV'
|
||
jne .fail
|
||
|
||
cmp [eax+SRV.size], sizeof.SRV
|
||
jne .fail
|
||
|
||
; stdcall [eax+SRV.srv_proc], ecx
|
||
mov eax, [eax+SRV.srv_proc]
|
||
test eax, eax
|
||
jz .fail
|
||
stdcall eax, ecx
|
||
ret
|
||
.fail:
|
||
or eax, -1
|
||
ret
|
||
|
||
restore handle
|
||
restore io_code
|
||
restore input
|
||
restore inp_size
|
||
restore output
|
||
restore out_size
|
||
|
||
align 4
|
||
proc get_service stdcall, sz_name:dword
|
||
mov eax, [sz_name]
|
||
test eax, eax
|
||
jnz @F
|
||
ret
|
||
@@:
|
||
mov edx, [srv.fd]
|
||
@@:
|
||
cmp edx, srv.fd-SRV.fd
|
||
je .not_load
|
||
|
||
stdcall strncmp, edx, [sz_name], 16
|
||
test eax, eax
|
||
mov eax, edx
|
||
je .nothing
|
||
|
||
mov edx, [edx+SRV.fd]
|
||
jmp @B
|
||
.not_load:
|
||
mov eax, [sz_name]
|
||
push edi
|
||
sub esp, 36
|
||
mov edi, esp
|
||
mov dword [edi], '/sys'
|
||
mov dword [edi+4], '/dri'
|
||
mov dword [edi+8], 'vers'
|
||
mov byte [edi+12], '/'
|
||
@@:
|
||
mov dl, [eax]
|
||
mov [edi+13], dl
|
||
inc eax
|
||
inc edi
|
||
test dl, dl
|
||
jnz @b
|
||
mov dword [edi+12], '.sys'
|
||
mov byte [edi+16], 0
|
||
mov edi, esp
|
||
stdcall load_pe_driver, edi, 0
|
||
add esp, 36
|
||
pop edi
|
||
.nothing:
|
||
ret
|
||
endp
|
||
|
||
reg_service:
|
||
xor eax, eax
|
||
mov ecx, [esp+8]
|
||
jecxz .nothing
|
||
push sizeof.SRV
|
||
push ecx
|
||
pushd [esp+12]
|
||
call reg_service_ex
|
||
.nothing:
|
||
ret 8
|
||
|
||
reg_usb_driver:
|
||
push sizeof.USBSRV
|
||
pushd [esp+12]
|
||
pushd [esp+12]
|
||
call reg_service_ex
|
||
test eax, eax
|
||
jz .nothing
|
||
mov ecx, [esp+12]
|
||
mov [eax+USBSRV.usb_func], ecx
|
||
.nothing:
|
||
ret 12
|
||
|
||
proc reg_service_ex stdcall, name:dword, handler:dword, srvsize:dword
|
||
|
||
push ebx
|
||
|
||
xor eax, eax
|
||
|
||
cmp [name], eax
|
||
je .fail
|
||
|
||
; cmp [handler], eax
|
||
; je .fail
|
||
|
||
mov eax, [srvsize]
|
||
call malloc
|
||
test eax, eax
|
||
jz .fail
|
||
|
||
push esi
|
||
push edi
|
||
mov edi, eax
|
||
mov esi, [name]
|
||
movsd
|
||
movsd
|
||
movsd
|
||
movsd
|
||
pop edi
|
||
pop esi
|
||
|
||
mov [eax+SRV.magic], ' SRV'
|
||
mov [eax+SRV.size], sizeof.SRV
|
||
|
||
mov ebx, srv.fd-SRV.fd
|
||
mov edx, [ebx+SRV.fd]
|
||
mov [eax+SRV.fd], edx
|
||
mov [eax+SRV.bk], ebx
|
||
mov [ebx+SRV.fd], eax
|
||
mov [edx+SRV.bk], eax
|
||
|
||
mov ecx, [handler]
|
||
mov [eax+SRV.srv_proc], ecx
|
||
pop ebx
|
||
ret
|
||
.fail:
|
||
xor eax, eax
|
||
pop ebx
|
||
ret
|
||
endp
|
||
|
||
align 4
|
||
proc get_proc stdcall, exp:dword, sz_name:dword
|
||
|
||
mov edx, [exp]
|
||
.next:
|
||
mov eax, [edx]
|
||
test eax, eax
|
||
jz .end
|
||
|
||
push edx
|
||
stdcall strncmp, eax, [sz_name], 16
|
||
pop edx
|
||
test eax, eax
|
||
jz .ok
|
||
|
||
add edx, 8
|
||
jmp .next
|
||
.ok:
|
||
mov eax, [edx+4]
|
||
.end:
|
||
ret
|
||
endp
|
||
|
||
align 4
|
||
proc get_coff_sym stdcall, pSym:dword,count:dword, sz_sym:dword
|
||
|
||
@@:
|
||
stdcall strncmp, [pSym], [sz_sym], 8
|
||
test eax, eax
|
||
jz .ok
|
||
add [pSym], 18
|
||
dec [count]
|
||
jnz @b
|
||
xor eax, eax
|
||
ret
|
||
.ok:
|
||
mov eax, [pSym]
|
||
mov eax, [eax+8]
|
||
ret
|
||
endp
|
||
|
||
align 4
|
||
proc get_curr_task
|
||
mov eax, [CURRENT_TASK]
|
||
shl eax, 8
|
||
ret
|
||
endp
|
||
|
||
align 4
|
||
proc get_fileinfo stdcall, file_name:dword, info:dword
|
||
locals
|
||
cmd dd ?
|
||
offset dd ?
|
||
dd ?
|
||
count dd ?
|
||
buff dd ?
|
||
db ?
|
||
name dd ?
|
||
endl
|
||
|
||
xor eax, eax
|
||
mov ebx, [file_name]
|
||
mov ecx, [info]
|
||
|
||
mov [cmd], 5
|
||
mov [offset], eax
|
||
mov [offset+4], eax
|
||
mov [count], eax
|
||
mov [buff], ecx
|
||
mov byte [buff+4], al
|
||
mov [name], ebx
|
||
|
||
mov eax, 70
|
||
lea ebx, [cmd]
|
||
int 0x40
|
||
ret
|
||
endp
|
||
|
||
align 4
|
||
proc read_file stdcall,file_name:dword, buffer:dword, off:dword,\
|
||
bytes:dword
|
||
locals
|
||
cmd dd ?
|
||
offset dd ?
|
||
dd ?
|
||
count dd ?
|
||
buff dd ?
|
||
db ?
|
||
name dd ?
|
||
endl
|
||
|
||
xor eax, eax
|
||
mov ebx, [file_name]
|
||
mov ecx, [off]
|
||
mov edx, [bytes]
|
||
mov esi, [buffer]
|
||
|
||
mov [cmd], eax
|
||
mov [offset], ecx
|
||
mov [offset+4], eax
|
||
mov [count], edx
|
||
mov [buff], esi
|
||
mov byte [buff+4], al
|
||
mov [name], ebx
|
||
|
||
pushad
|
||
lea ebx, [cmd]
|
||
call file_system_lfn_protected
|
||
popad
|
||
ret
|
||
endp
|
||
|
||
; description
|
||
; allocate kernel memory and loads the specified file
|
||
;
|
||
; param
|
||
; file_name= path to file
|
||
;
|
||
; retval
|
||
; eax= file image in kernel memory
|
||
; ebx= size of file
|
||
;
|
||
; warging
|
||
; You mast call kernel_free() to delete each file
|
||
; loaded by the load_file() function
|
||
|
||
align 4
|
||
proc load_file stdcall, file_name:dword
|
||
locals
|
||
attr dd ?
|
||
flags dd ?
|
||
cr_time dd ?
|
||
cr_date dd ?
|
||
acc_time dd ?
|
||
acc_date dd ?
|
||
mod_time dd ?
|
||
mod_date dd ?
|
||
file_size dd ?
|
||
|
||
file dd ?
|
||
file2 dd ?
|
||
endl
|
||
|
||
push esi
|
||
push edi
|
||
|
||
lea eax, [attr]
|
||
stdcall get_fileinfo, [file_name], eax
|
||
test eax, eax
|
||
jnz .fail
|
||
|
||
mov eax, [file_size]
|
||
cmp eax, 1024*1024*16
|
||
ja .fail
|
||
|
||
stdcall kernel_alloc, [file_size]
|
||
mov [file], eax
|
||
test eax, eax
|
||
jz .fail
|
||
|
||
stdcall read_file, [file_name], eax, dword 0, [file_size]
|
||
cmp ebx, [file_size]
|
||
jne .cleanup
|
||
|
||
mov eax, [file]
|
||
cmp dword [eax], 0x4B43504B
|
||
jne .exit
|
||
mov ebx, [eax+4]
|
||
mov [file_size], ebx
|
||
stdcall kernel_alloc, ebx
|
||
|
||
test eax, eax
|
||
jz .cleanup
|
||
|
||
mov [file2], eax
|
||
|
||
pushad
|
||
mov ecx, unpack_mutex
|
||
call mutex_lock
|
||
popad
|
||
|
||
stdcall unpack, [file], eax
|
||
|
||
pushad
|
||
mov ecx, unpack_mutex
|
||
call mutex_unlock
|
||
popad
|
||
|
||
stdcall kernel_free, [file]
|
||
mov eax, [file2]
|
||
mov ebx, [file_size]
|
||
.exit:
|
||
push eax
|
||
lea edi, [eax+ebx] ;cleanup remain space
|
||
mov ecx, 4096 ;from file end
|
||
and ebx, 4095
|
||
jz @f
|
||
sub ecx, ebx
|
||
xor eax, eax
|
||
cld
|
||
rep stosb
|
||
@@:
|
||
mov ebx, [file_size]
|
||
pop eax
|
||
pop edi
|
||
pop esi
|
||
ret
|
||
.cleanup:
|
||
stdcall kernel_free, [file]
|
||
.fail:
|
||
xor eax, eax
|
||
xor ebx, ebx
|
||
pop edi
|
||
pop esi
|
||
ret
|
||
endp
|
||
|
||
; description
|
||
; allocate user memory and loads the specified file
|
||
;
|
||
; param
|
||
; file_name= path to file
|
||
;
|
||
; retval
|
||
; eax= file image in user memory
|
||
; ebx= size of file
|
||
;
|
||
; warging
|
||
; You mast call kernel_free() to delete each file
|
||
; loaded by the load_file() function
|
||
|
||
align 4
|
||
proc load_file_umode stdcall, file_name:dword
|
||
locals
|
||
attr dd ?
|
||
flags dd ?
|
||
cr_time dd ?
|
||
cr_date dd ?
|
||
acc_time dd ?
|
||
acc_date dd ?
|
||
mod_time dd ?
|
||
mod_date dd ?
|
||
file_size dd ?
|
||
|
||
km_file dd ?
|
||
um_file dd ?
|
||
endl
|
||
|
||
push esi
|
||
push edi
|
||
push ebx
|
||
|
||
lea eax, [attr]
|
||
stdcall get_fileinfo, [file_name], eax ;find file and get info
|
||
test eax, eax
|
||
jnz .err_1
|
||
|
||
mov eax, [file_size]
|
||
cmp eax, 1024*1024*16 ;to be enough for anybody (c)
|
||
ja .err_1
|
||
;it is very likely that the file is packed
|
||
stdcall kernel_alloc, [file_size] ;with kpack, so allocate memory from kernel heap
|
||
mov [km_file], eax
|
||
test eax, eax
|
||
jz .err_1
|
||
|
||
stdcall read_file, [file_name], eax, dword 0, [file_size]
|
||
cmp ebx, [file_size]
|
||
|
||
jne .err_2
|
||
|
||
mov eax, [km_file]
|
||
cmp dword [eax], 0x4B43504B ; check kpack signature
|
||
jne .raw_file
|
||
|
||
mov ebx, [eax+4] ;get real size of file
|
||
mov [file_size], ebx
|
||
stdcall user_alloc, ebx ;and allocate space from user heap
|
||
mov [um_file], eax
|
||
test eax, eax
|
||
jz .err_2
|
||
|
||
mov edx, [file_size] ;preallocate page memory
|
||
shr eax, 10
|
||
lea edi, [page_tabs+eax]
|
||
add edx, 4095
|
||
shr edx, 12
|
||
@@:
|
||
call alloc_page
|
||
test eax, eax
|
||
jz .err_3
|
||
|
||
or eax, PG_UWR
|
||
stosd
|
||
dec edx
|
||
jnz @B
|
||
|
||
pushad
|
||
mov ecx, unpack_mutex
|
||
call mutex_lock
|
||
|
||
stdcall unpack, [km_file], [um_file]
|
||
|
||
mov ecx, unpack_mutex
|
||
call mutex_unlock
|
||
popad
|
||
|
||
stdcall kernel_free, [km_file] ;we don't need packed file anymore
|
||
.exit:
|
||
|
||
mov edi, [um_file]
|
||
mov esi, [um_file]
|
||
mov eax, [file_size]
|
||
mov edx, eax
|
||
|
||
add edi, eax ;cleanup remain space
|
||
mov ecx, 4096 ;from file end
|
||
and eax, 4095
|
||
jz @f
|
||
sub ecx, eax
|
||
xor eax, eax
|
||
cld
|
||
rep stosb
|
||
@@:
|
||
mov eax, [um_file]
|
||
|
||
pop ebx
|
||
pop edi
|
||
pop esi
|
||
ret
|
||
|
||
.raw_file: ; sometimes we load unpacked file
|
||
stdcall user_alloc, ebx ; allocate space from user heap
|
||
mov [um_file], eax
|
||
|
||
test eax, eax
|
||
jz .err_2
|
||
|
||
shr eax, 10 ; and remap pages.
|
||
|
||
mov ecx, [file_size]
|
||
add ecx, 4095
|
||
shr ecx, 12
|
||
|
||
mov esi, [km_file]
|
||
shr esi, 10
|
||
add esi, page_tabs
|
||
|
||
lea edi, [page_tabs+eax]
|
||
|
||
cld
|
||
@@:
|
||
lodsd
|
||
and eax, 0xFFFFF000
|
||
or eax, PG_UWR
|
||
stosd
|
||
loop @B
|
||
|
||
stdcall free_kernel_space, [km_file] ; release allocated kernel space
|
||
jmp .exit ; physical pages still in use
|
||
.err_3:
|
||
stdcall user_free, [um_file]
|
||
.err_2:
|
||
stdcall kernel_free, [km_file]
|
||
.err_1:
|
||
xor eax, eax
|
||
xor edx, edx
|
||
|
||
pop ebx
|
||
pop edi
|
||
pop esi
|
||
ret
|
||
endp
|
||
|
||
|
||
uglobal
|
||
align 4
|
||
unpack_mutex MUTEX
|
||
endg
|
||
|
||
align 4
|
||
proc get_proc_ex stdcall uses ebx esi, proc_name:dword, imports:dword
|
||
mov ebx, [imports]
|
||
test ebx, ebx
|
||
jz .end
|
||
xor esi, esi
|
||
.look_up:
|
||
|
||
mov eax, [ebx+32]
|
||
mov eax, [OS_BASE+eax+esi*4]
|
||
add eax, OS_BASE
|
||
stdcall strncmp, eax, [proc_name], 256
|
||
test eax, eax
|
||
jz .ok
|
||
|
||
inc esi
|
||
cmp esi, [ebx+24]
|
||
jb .look_up
|
||
.end:
|
||
xor eax, eax
|
||
ret
|
||
.ok:
|
||
mov eax, [ebx+28]
|
||
mov eax, [OS_BASE+eax+esi*4]
|
||
add eax, OS_BASE
|
||
ret
|
||
endp
|
||
|
||
align 4
|
||
proc fix_coff_symbols stdcall uses ebx esi, sec:dword, symbols:dword,\
|
||
sym_count:dword, strings:dword, imports:dword
|
||
locals
|
||
retval dd ?
|
||
endl
|
||
|
||
mov edi, [symbols]
|
||
mov [retval], 1
|
||
.fix:
|
||
movzx ebx, [edi+COFF_SYM.SectionNumber]
|
||
test ebx, ebx
|
||
jnz .internal
|
||
mov eax, dword [edi+COFF_SYM.Name]
|
||
test eax, eax
|
||
jnz @F
|
||
|
||
mov edi, [edi+4]
|
||
add edi, [strings]
|
||
@@:
|
||
push edi
|
||
stdcall get_proc_ex, edi, [imports]
|
||
pop edi
|
||
|
||
xor ebx, ebx
|
||
test eax, eax
|
||
jnz @F
|
||
|
||
mov esi, msg_unresolved
|
||
call sys_msg_board_str
|
||
mov esi, edi
|
||
call sys_msg_board_str
|
||
mov esi, msg_CR
|
||
call sys_msg_board_str
|
||
|
||
mov [retval], 0
|
||
@@:
|
||
mov edi, [symbols]
|
||
mov [edi+COFF_SYM.Value], eax
|
||
jmp .next
|
||
.internal:
|
||
cmp bx, -1
|
||
je .next
|
||
cmp bx, -2
|
||
je .next
|
||
|
||
dec ebx
|
||
shl ebx, 3
|
||
lea ebx, [ebx+ebx*4]
|
||
add ebx, [sec]
|
||
|
||
mov eax, [ebx+COFF_SECTION.VirtualAddress]
|
||
add [edi+COFF_SYM.Value], eax
|
||
.next:
|
||
add edi, sizeof.COFF_SYM
|
||
mov [symbols], edi
|
||
dec [sym_count]
|
||
jnz .fix
|
||
mov eax, [retval]
|
||
ret
|
||
endp
|
||
|
||
align 4
|
||
proc fix_coff_relocs stdcall uses ebx esi, coff:dword, sym:dword, \
|
||
delta:dword
|
||
locals
|
||
n_sec dd ?
|
||
endl
|
||
|
||
mov eax, [coff]
|
||
movzx ebx, [eax+COFF_HEADER.nSections]
|
||
mov [n_sec], ebx
|
||
lea esi, [eax+20]
|
||
.fix_sec:
|
||
mov edi, [esi+COFF_SECTION.PtrReloc]
|
||
add edi, [coff]
|
||
|
||
movzx ecx, [esi+COFF_SECTION.NumReloc]
|
||
test ecx, ecx
|
||
jz .next
|
||
.reloc_loop:
|
||
mov ebx, [edi+COFF_RELOC.SymIndex]
|
||
add ebx, ebx
|
||
lea ebx, [ebx+ebx*8]
|
||
add ebx, [sym]
|
||
|
||
mov edx, [ebx+COFF_SYM.Value]
|
||
|
||
cmp [edi+COFF_RELOC.Type], 6
|
||
je .dir_32
|
||
|
||
cmp [edi+COFF_RELOC.Type], 20
|
||
jne .next_reloc
|
||
.rel_32:
|
||
mov eax, [edi+COFF_RELOC.VirtualAddress]
|
||
add eax, [esi+COFF_SECTION.VirtualAddress]
|
||
sub edx, eax
|
||
sub edx, 4
|
||
jmp .fix
|
||
.dir_32:
|
||
mov eax, [edi+COFF_RELOC.VirtualAddress]
|
||
add eax, [esi+COFF_SECTION.VirtualAddress]
|
||
.fix:
|
||
add eax, [delta]
|
||
add [eax], edx
|
||
.next_reloc:
|
||
add edi, 10
|
||
dec ecx
|
||
jnz .reloc_loop
|
||
.next:
|
||
add esi, sizeof.COFF_SECTION
|
||
dec [n_sec]
|
||
jnz .fix_sec
|
||
.exit:
|
||
ret
|
||
endp
|
||
|
||
align 4
|
||
proc rebase_coff stdcall uses ebx esi, coff:dword, sym:dword, \
|
||
delta:dword
|
||
locals
|
||
n_sec dd ?
|
||
endl
|
||
|
||
mov eax, [coff]
|
||
movzx ebx, [eax+COFF_HEADER.nSections]
|
||
mov [n_sec], ebx
|
||
lea esi, [eax+20]
|
||
mov edx, [delta]
|
||
.fix_sec:
|
||
mov edi, [esi+COFF_SECTION.PtrReloc]
|
||
add edi, [coff]
|
||
|
||
movzx ecx, [esi+COFF_SECTION.NumReloc]
|
||
test ecx, ecx
|
||
jz .next
|
||
.reloc_loop:
|
||
cmp [edi+COFF_RELOC.Type], 6
|
||
jne .next_reloc
|
||
.dir_32:
|
||
mov eax, [edi+COFF_RELOC.VirtualAddress]
|
||
add eax, [esi+COFF_SECTION.VirtualAddress]
|
||
add [eax+edx], edx
|
||
.next_reloc:
|
||
add edi, 10
|
||
dec ecx
|
||
jnz .reloc_loop
|
||
.next:
|
||
add esi, sizeof.COFF_SECTION
|
||
dec [n_sec]
|
||
jnz .fix_sec
|
||
.exit:
|
||
ret
|
||
endp
|
||
|
||
; in: edx -> COFF_SECTION struct
|
||
; out: eax = alignment as mask for bits to drop
|
||
coff_get_align:
|
||
; Rules:
|
||
; - if alignment is not given, use default = 4K;
|
||
; - if alignment is given and is no more than 4K, use it;
|
||
; - if alignment is more than 4K, revert to 4K.
|
||
push ecx
|
||
mov cl, byte [edx+COFF_SECTION.Characteristics+2]
|
||
mov eax, 1
|
||
shr cl, 4
|
||
dec cl
|
||
js .default
|
||
cmp cl, 12
|
||
jbe @f
|
||
.default:
|
||
mov cl, 12
|
||
@@:
|
||
shl eax, cl
|
||
pop ecx
|
||
dec eax
|
||
ret
|
||
|
||
align 4
|
||
proc load_library stdcall, file_name:dword
|
||
locals
|
||
fullname rb 260
|
||
fileinfo rb 40
|
||
coff dd ?
|
||
img_base dd ?
|
||
endl
|
||
|
||
; resolve file name
|
||
mov ebx, [file_name]
|
||
lea edi, [fullname+1]
|
||
mov byte [edi-1], '/'
|
||
stdcall get_full_file_name, edi, 259
|
||
test al, al
|
||
jz .fail
|
||
|
||
; scan for required DLL in list of already loaded for this process,
|
||
; ignore timestamp
|
||
cli
|
||
|
||
mov esi, [current_process]
|
||
lea 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
|
||
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
|
||
test eax, eax
|
||
jz .fail
|
||
mov [coff], eax
|
||
mov dword [fileinfo+32], ebx
|
||
|
||
; allocate DLLDESCR struct; size is DLLDESCR.sizeof plus size of DLL name
|
||
mov esi, edi
|
||
mov ecx, -1
|
||
xor eax, eax
|
||
repnz scasb
|
||
not ecx
|
||
lea eax, [ecx+sizeof.DLLDESCR]
|
||
push ecx
|
||
call malloc
|
||
pop ecx
|
||
test eax, eax
|
||
jz .fail_and_free_coff
|
||
; save timestamp
|
||
lea edi, [eax+DLLDESCR.name]
|
||
rep movsb
|
||
mov esi, eax
|
||
mov eax, dword [fileinfo+24]
|
||
mov dword [esi+DLLDESCR.timestamp], eax
|
||
mov eax, dword [fileinfo+28]
|
||
mov dword [esi+DLLDESCR.timestamp+4], eax
|
||
|
||
; calculate size of loaded DLL
|
||
mov edx, [coff]
|
||
movzx ecx, [edx+COFF_HEADER.nSections]
|
||
xor ebx, ebx
|
||
|
||
add edx, 20
|
||
@@:
|
||
call coff_get_align
|
||
add ebx, eax
|
||
not eax
|
||
and ebx, eax
|
||
add ebx, [edx+COFF_SECTION.SizeOfRawData]
|
||
add edx, sizeof.COFF_SECTION
|
||
dec ecx
|
||
jnz @B
|
||
; it must be nonzero and not too big
|
||
mov [esi+DLLDESCR.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
|
||
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
|
||
|
||
; 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
|
||
add edx, 20
|
||
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 esi, [edx+COFF_SECTION.PtrRawData]
|
||
push ecx
|
||
mov ecx, [edx+COFF_SECTION.SizeOfRawData]
|
||
test esi, esi
|
||
jnz .copy
|
||
xor eax, eax
|
||
rep stosb
|
||
jmp .next
|
||
.copy:
|
||
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]
|
||
sub edi, ebx
|
||
jc .fail_and_free_data
|
||
mov [esi+DLLDESCR.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
|
||
|
||
; fixup symbols
|
||
mov edx, ebx
|
||
mov eax, [ebx+COFF_HEADER.nSymbols]
|
||
add edx, 20
|
||
mov ecx, [esi+DLLDESCR.symbols_num]
|
||
lea ecx, [ecx*9]
|
||
add ecx, ecx
|
||
add ecx, [esi+DLLDESCR.symbols_ptr]
|
||
|
||
stdcall fix_coff_symbols, edx, [esi+DLLDESCR.symbols_ptr], eax, \
|
||
ecx, 0
|
||
; test eax, eax
|
||
; jnz @F
|
||
;
|
||
;@@:
|
||
|
||
stdcall get_coff_sym, [esi+DLLDESCR.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
|
||
@@:
|
||
mov [esi+DLLDESCR.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 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:
|
||
inc [esi+DLLDESCR.refcount]
|
||
push esi
|
||
call init_heap
|
||
pop esi
|
||
|
||
mov edi, [esi+DLLDESCR.size]
|
||
stdcall user_alloc_at, [esi+DLLDESCR.defaultbase], edi
|
||
test eax, eax
|
||
jnz @f
|
||
stdcall user_alloc, edi
|
||
test eax, eax
|
||
jz .fail_and_dereference
|
||
@@:
|
||
mov [img_base], eax
|
||
mov eax, sizeof.HDLL
|
||
call malloc
|
||
test eax, eax
|
||
jz .fail_and_free_user
|
||
mov ebx, [CURRENT_TASK]
|
||
shl ebx, 5
|
||
mov edx, [CURRENT_TASK+ebx+TASKDATA.pid]
|
||
mov [eax+HDLL.pid], edx
|
||
push eax
|
||
call init_dlls_in_thread
|
||
pop ebx
|
||
test eax, eax
|
||
jz .fail_and_free_user
|
||
mov edx, [eax+HDLL.fd]
|
||
mov [ebx+HDLL.fd], edx
|
||
mov [ebx+HDLL.bk], eax
|
||
mov [eax+HDLL.fd], ebx
|
||
mov [edx+HDLL.bk], ebx
|
||
mov eax, ebx
|
||
mov ebx, [img_base]
|
||
mov [eax+HDLL.base], ebx
|
||
mov [eax+HDLL.size], edi
|
||
mov [eax+HDLL.refcount], 1
|
||
mov [eax+HDLL.parent], esi
|
||
mov edx, ebx
|
||
shr edx, 12
|
||
or dword [page_tabs+(edx-1)*4], DONT_FREE_BLOCK
|
||
; copy entries of page table from kernel-side image to usermode
|
||
; use copy-on-write for user-mode image, so map as readonly
|
||
xor edi, edi
|
||
mov ecx, [esi+DLLDESCR.data]
|
||
shr ecx, 12
|
||
.map_pages_loop:
|
||
mov eax, [page_tabs+ecx*4]
|
||
and eax, not 0xFFF
|
||
or al, PG_UR
|
||
xchg eax, [page_tabs+edx*4]
|
||
test al, 1
|
||
jz @f
|
||
call free_page
|
||
@@:
|
||
invlpg [ebx+edi]
|
||
inc ecx
|
||
inc edx
|
||
add edi, 0x1000
|
||
cmp edi, [esi+DLLDESCR.size]
|
||
jb .map_pages_loop
|
||
|
||
; if real user-mode base is not equal to preferred base, relocate image
|
||
sub ebx, [esi+DLLDESCR.defaultbase]
|
||
jz @f
|
||
stdcall rebase_coff, [esi+DLLDESCR.coff_hdr], [esi+DLLDESCR.symbols_ptr], ebx
|
||
@@:
|
||
|
||
mov eax, [esi+DLLDESCR.exports]
|
||
sub eax, [esi+DLLDESCR.defaultbase]
|
||
add eax, [img_base]
|
||
sti
|
||
ret
|
||
.fail_and_free_data:
|
||
stdcall kernel_free, [esi+DLLDESCR.data]
|
||
.fail_and_free_dll:
|
||
mov eax, esi
|
||
call free
|
||
.fail_and_free_coff:
|
||
stdcall kernel_free, [coff]
|
||
.fail:
|
||
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]
|
||
mov eax, esi
|
||
call free
|
||
.ret:
|
||
ret
|
||
|
||
destroy_hdll:
|
||
push ebx ecx esi edi
|
||
mov ebx, [eax+HDLL.base]
|
||
mov esi, [eax+HDLL.parent]
|
||
mov edx, [esi+DLLDESCR.size]
|
||
|
||
push eax
|
||
mov esi, [eax+HDLL.parent]
|
||
mov eax, [eax+HDLL.refcount]
|
||
call dereference_dll
|
||
pop eax
|
||
mov edx, [eax+HDLL.bk]
|
||
mov ebx, [eax+HDLL.fd]
|
||
mov [ebx+HDLL.bk], edx
|
||
mov [edx+HDLL.fd], ebx
|
||
call free
|
||
pop edi esi ecx ebx
|
||
ret
|
||
|
||
; ecx -> APPDATA for slot, esi = dlls_list_ptr
|
||
destroy_all_hdlls:
|
||
test esi, esi
|
||
jz .ret
|
||
.loop:
|
||
mov eax, [esi+HDLL.fd]
|
||
cmp eax, esi
|
||
jz free
|
||
call destroy_hdll
|
||
jmp .loop
|
||
.ret:
|
||
ret
|
||
|
||
align 4
|
||
stop_all_services:
|
||
push ebp
|
||
mov edx, [srv.fd]
|
||
.next:
|
||
cmp edx, srv.fd-SRV.fd
|
||
je .done
|
||
cmp [edx+SRV.magic], ' SRV'
|
||
jne .next
|
||
cmp [edx+SRV.size], sizeof.SRV
|
||
jne .next
|
||
|
||
mov ebx, [edx+SRV.entry]
|
||
mov edx, [edx+SRV.fd]
|
||
test ebx, ebx
|
||
jz .next
|
||
|
||
push edx
|
||
mov ebp, esp
|
||
push 0
|
||
push -1
|
||
call ebx
|
||
mov esp, ebp
|
||
pop edx
|
||
jmp .next
|
||
.done:
|
||
pop ebp
|
||
ret
|
||
|
||
; param
|
||
; eax= size
|
||
; ebx= pid
|
||
|
||
align 4
|
||
create_kernel_object:
|
||
|
||
push ebx
|
||
call malloc
|
||
pop ebx
|
||
test eax, eax
|
||
jz .fail
|
||
|
||
mov ecx, [current_slot]
|
||
add ecx, APP_OBJ_OFFSET
|
||
|
||
pushfd
|
||
cli
|
||
mov edx, [ecx+APPOBJ.fd]
|
||
mov [eax+APPOBJ.fd], edx
|
||
mov [eax+APPOBJ.bk], ecx
|
||
mov [eax+APPOBJ.pid], ebx
|
||
|
||
mov [ecx+APPOBJ.fd], eax
|
||
mov [edx+APPOBJ.bk], eax
|
||
popfd
|
||
.fail:
|
||
ret
|
||
|
||
; param
|
||
; eax= object
|
||
|
||
align 4
|
||
destroy_kernel_object:
|
||
|
||
pushfd
|
||
cli
|
||
mov ebx, [eax+APPOBJ.fd]
|
||
mov ecx, [eax+APPOBJ.bk]
|
||
mov [ebx+APPOBJ.bk], ecx
|
||
mov [ecx+APPOBJ.fd], ebx
|
||
popfd
|
||
|
||
xor edx, edx ;clear common header
|
||
mov [eax], edx
|
||
mov [eax+4], edx
|
||
mov [eax+8], edx
|
||
mov [eax+12], edx
|
||
mov [eax+16], edx
|
||
|
||
call free ;release object memory
|
||
ret
|
||
|
||
|
||
|
||
; param
|
||
; e<EFBFBD><EFBFBD>= size
|
||
|
||
align 4
|
||
create_object:
|
||
|
||
push esi
|
||
push edi
|
||
pushfd
|
||
cli
|
||
|
||
mov esi, [current_process]
|
||
mov eax, [esi+PROC.ht_free]
|
||
mov edi, [esi+PROC.ht_next]
|
||
dec eax
|
||
js .err0
|
||
|
||
mov [esi+PROC.ht_free], eax
|
||
mov eax, [esi+PROC.htab+edi*4]
|
||
mov [esi+PROC.ht_next], eax
|
||
popfd
|
||
|
||
mov eax, ecx
|
||
call malloc
|
||
test eax, eax
|
||
jz .err1
|
||
|
||
mov [eax+FUTEX.handle], edi
|
||
mov [esi+PROC.htab+edi*4], eax
|
||
pop edi
|
||
pop esi
|
||
ret
|
||
|
||
.err1:
|
||
pushfd
|
||
cli
|
||
|
||
mov eax, [esi+PROC.ht_next]
|
||
mov [esi+PROC.htab+edi*4], eax
|
||
mov [esi+PROC.ht_next], edi
|
||
inc [esi+PROC.ht_free]
|
||
.err0:
|
||
popfd
|
||
pop edi
|
||
pop esi
|
||
xor eax, eax
|
||
ret
|
||
|
||
|
||
align 4
|
||
;struct futex* __fastcall create_futex(int *ptr)
|
||
create_futex:
|
||
push ecx
|
||
mov ecx, sizeof.FUTEX
|
||
call create_object
|
||
pop ecx
|
||
test eax, eax
|
||
jz .fail
|
||
|
||
mov [eax+FUTEX.magic], 'FUTX'
|
||
mov [eax+FUTEX.destroy], 0
|
||
mov [eax+FUTEX.pointer], ecx
|
||
lea ecx, [eax+FUTEX.wait_list]
|
||
list_init ecx
|
||
mov [eax+FUTEX.flags], 0
|
||
.fail:
|
||
ret
|
||
|