;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;                                                              ;;
;; Copyright (C) KolibriOS team 2004-2007. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License    ;;
;;                                                              ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

$Revision$

EFL_IF      equ 0x0200
EFL_IOPL1   equ 0x1000
EFL_IOPL2   equ 0x2000
EFL_IOPL3   equ 0x3000


struc APP_HEADER_00
{ .banner      dq ?
  .version     dd ?    ;+8
  .start       dd ?    ;+12
  .i_end       dd ?    ;+16
  .mem_size    dd ?    ;+20
  .i_param     dd ?    ;+24
}

struc APP_HEADER_01
{ .banner      dq ?
  .version     dd ?    ;+8
  .start       dd ?    ;+12
  .i_end       dd ?    ;+16
  .mem_size    dd ?    ;+20
  .stack_top   dd ?    ;+24
  .i_param     dd ?    ;+28
  .i_icon      dd ?    ;+32
}


struc APP_PARAMS
{ .app_cmdline	 ;0x00
  .app_path	 ;0x04
  .app_eip	 ;0x08
  .app_esp	 ;0x0C
  .app_mem	 ;0x10
}

macro _clear_ op
{  mov ecx, op/4
   xor eax, eax
   cld
   rep stosd
}

align 4
test_app_header:
	   virtual at eax
	     APP_HEADER_00 APP_HEADER_00
	   end virtual
	   virtual at eax
	     APP_HEADER_01 APP_HEADER_01
	   end virtual

	   cmp dword [eax], 'MENU'
	   jne .fail
	   cmp word [eax+4],'ET'
	   jne .fail

	   cmp [eax+6], word '00'
	   jne	.check_01_header

	   mov	ecx,[APP_HEADER_00.start]
       mov  [ebx+0x08], ecx              ;app_eip
	   mov	edx,[APP_HEADER_00.mem_size]
       mov  [ebx+0x10], edx              ;app_mem
	   shr	edx,1
	   sub	edx,0x10
       mov  [ebx+0x0C], edx              ;app_esp
	   mov	ecx,[APP_HEADER_00.i_param]
       mov  [ebx], ecx                   ;app_cmdline
       mov  [ebx+4], dword 0             ;app_path
	   mov	edx, [APP_HEADER_00.i_end]
	   mov	[ebx+0x14], edx
	   ret

 .check_01_header:

	   cmp	[eax+6],word '01'
	   jne	.fail

	   mov	ecx,[APP_HEADER_01.start]
	   mov	[ebx+0x08], ecx 	       ;app_eip
	   mov	edx,[APP_HEADER_01.mem_size]

; \begin{diamond}[20.08.2006]
; sanity check (functions 19,58 load app_i_end bytes and that must
; fit in allocated memory to prevent kernel faults)
	   cmp	edx,[APP_HEADER_01.i_end]
	   jb	.fail
; \end{diamond}[20.08.2006]

       mov  [ebx+0x10], edx                  ;app_mem
	   mov	ecx,[APP_HEADER_01.stack_top]
       mov  [ebx+0x0C], ecx                  ;app_esp
	   mov	edx,[APP_HEADER_01.i_param]
       mov  [ebx], edx                       ;app_cmdline
	   mov	ecx,[APP_HEADER_01.i_icon]
       mov  [ebx+4], ecx                     ;app_path
	   mov	edx, [APP_HEADER_01.i_end]
	   mov	[ebx+0x14], edx
	   ret
.fail:
	   xor eax, eax
	   ret

align 4
proc mnt_exec stdcall file_base:dword, file_size:dword, \
                      path:dword, cmd_line:dword, flags:dword

           locals
             cmdline       rb 256
             filename      rb 1024

             save_cr3      dd ?
             slot      dd ?
             slot_base     dd ?

                          ;app header data
             hdr_cmdline   dd ? ;0x00
             hdr_path      dd ? ;0x04
             hdr_eip       dd ? ;0x08
             hdr_esp       dd ? ;0x0C
             hdr_mem       dd ? ;0x10
             hdr_i_end     dd ? ;0x14
           endl

           push ebx
           push edi
           push esi

           mov esi, [path]
           lea edi, [filename]
           lea ecx, [edi+1024]
@@:
           cmp edi, ecx
           jae .bigfilename
           lodsb
           stosb
           test al, al
           jnz @b

           lea edi, [cmdline]
           mov dword [edi],0
           mov esi, [cmd_line]
           test esi, esi
           jz .no_cmdline

           lea ecx, [edi+255]
           mov [edi+252], dword 0
@@:
           cmp edi, ecx
           jae .no_cmdline

           lodsb
           stosb
           test al, al
           jnz @b

.no_cmdline:

           mov eax, [file_base]
           lea ebx, [hdr_cmdline]
           call test_app_header
           mov ecx, -0x1F
           test eax, eax
           jz .err_hdr

           DEBUGF 1,"%s",new_process_loading

           lea ebx, [application_table_status]
           call wait_mutex

           call set_application_table_status

           call get_new_process_place
           test eax, eax
           mov ecx, -0x20      ; too many processes
           jz .err

           mov [slot], eax
           shl eax, 8
           add eax, SLOT_BASE
           mov [slot_base], eax
           mov edi, eax
           _clear_ 256     ;clean extended information about process

; write application name
           lea eax, [filename]
           stdcall strrchr,  eax, '/'  ; now eax points to name without path

           lea esi, [eax+1]
           test eax, eax
           jnz @F
           lea esi, [filename]
@@:
           mov ecx, 8  ; 8 chars for name
           mov edi, [slot_base]
.copy_process_name_loop:
           lodsb
           cmp al, '.'
           jz .copy_process_name_done
           test al, al
           jz .copy_process_name_done
           stosb
           loop .copy_process_name_loop
.copy_process_name_done:

           mov ebx, cr3
           mov [save_cr3], ebx

           stdcall create_app_space,[hdr_mem],[file_base],[file_size]
           mov ecx, -30  ; no memory
           test eax, eax
           jz .failed

           mov   ebx,[slot_base]
           mov   [ebx+APPDATA.dir_table],eax
           mov   ecx,[hdr_mem]
           mov   [ebx+APPDATA.mem_size],ecx

           mov edi, [file_size]
         ;  add edi, 4095
         ;  and edi, not 4095
           sub ecx, edi
           jna @F

           xor eax, eax
           cld
           rep stosb
@@:
           mov ecx, [file_base]
           call @mem_free@4

           lea eax, [hdr_cmdline]
           lea ebx, [cmdline]
           lea ecx, [filename]
           stdcall set_app_params ,[slot],eax,ebx,ecx,[flags]

           mov eax, [save_cr3]
           call set_cr3

           mov eax,[process_number]  ;set result
           mov [application_table_status], 0 ;unlock application_table_status mutex

           pop edi
           pop esi
           pop ebx

           ret

.bigfilename:
           pop edi
           pop esi
           pop ebx
           mov eax, -ERROR_FILE_NOT_FOUND
           ret
.failed:
           mov eax, [save_cr3]
           call set_cr3
.err:
.err_hdr:
           mov ecx, [file_base]
           call @mem_free@4

           pop edi
           pop esi
           pop ebx

           xor eax, eax
           mov [application_table_status],eax
           mov eax, ecx
           ret
endp

align 4
proc pe_app_param stdcall path:dword, raw:dword, ex_pg_dir:dword, ex_stack:dword

           locals
             slot        dd ?
             slot_base   dd ?
             pl0_stack   dd ?
           endl

           push ebx
           push esi
           push edi

           lea ebx, [application_table_status]
           call wait_mutex

           call set_application_table_status

           call get_new_process_place
           test eax, eax
           mov ecx, -0x20      ; too many processes
           jz .err

           mov [slot], eax
           shl eax, 8
           add eax, SLOT_BASE
           mov [slot_base], eax
           mov edi, eax
           _clear_ 256     ;clean extended information about process

; write application name
           stdcall strrchr,  [path], '/'  ; now eax points to name without path
           lea esi, [eax+1]
           test eax, eax
           jnz @F
           lea esi, [path]
@@:
           mov ecx, 8  ; 8 chars for name
           mov edi, [slot_base]
.copy_process_name_loop:
           lodsb
           cmp al, '.'
           jz .copy_process_name_done
           test al, al
           jz .copy_process_name_done
           stosb
           loop .copy_process_name_loop
.copy_process_name_done:

           mov eax, [ex_pg_dir]
           mov ebx, [slot_base]
           mov [ebx+APPDATA.dir_table],eax

           ;mov   eax,[hdr_mem]
           ;mov   [ebx+APPDATA.mem_size],eax


           mov ecx, 2
           call @frame_alloc@4
           lea edi, [eax+OS_BASE]
           mov [pl0_stack], edi

           mov [ebx+APPDATA.pl0_stack], edi
           add edi, RING0_STACK_SIZE
           mov [ebx+APPDATA.saved_esp0], edi
           mov [ebx+APPDATA.fpu_state],  edi
           mov [ebx+APPDATA.fpu_handler], 0
           mov [ebx+APPDATA.sse_handler], 0

;set default io permission map
           mov [ebx+APPDATA.io_map],\
               (tss._io_map_0-OS_BASE+PG_MAP)
           mov [ebx+APPDATA.io_map+4],\
               (tss._io_map_1-OS_BASE+PG_MAP)

           mov esi, fpu_data
           mov ecx, 512/4
           rep movsd

           mov eax, [slot]
           cmp eax,[TASK_COUNT]
           jle .noinc
           inc dword [TASK_COUNT]       ;update number of processes
.noinc:
           lea edx, [ebx+APP_EV_OFFSET]
           mov [ebx+APPDATA.fd_ev],edx
           mov [ebx+APPDATA.bk_ev],edx

           add edx, APP_OBJ_OFFSET-APP_EV_OFFSET
           mov [ebx+APPDATA.fd_obj],edx
           mov [ebx+APPDATA.bk_obj],edx

           mov ecx, [def_cursor]
           mov [ebx+APPDATA.cursor],ecx

           call _alloc_page
           lea edi, [eax+OS_BASE]         ; FIXME

           mov esi,[current_slot]
           mov esi,[esi+APPDATA.cur_dir]
           mov ecx,0x1000/4
           mov [ebx+APPDATA.cur_dir],edi
           rep movsd

           mov ebx, [slot]
           mov eax, ebx
           shl ebx, 5
           mov dword [CURRENT_TASK+ebx+0x10], 0

           lea    ecx,[draw_data+ebx]  ;ecx - pointer to draw data

; set window state to 'normal' (non-minimized/maximized/rolled-up) state
           mov     [ebx+window_data+WDATA.fl_wstate], WSTATE_NORMAL
           mov     [ebx+window_data+WDATA.fl_redraw], 1
           add    ebx,CURRENT_TASK        ;ebx - pointer to information about process
           mov    [ebx+TASKDATA.wnd_number],al;set window number on screen = process slot

           mov    [ebx+TASKDATA.event_mask],dword 1+2+4 ;set default event flags (see 40 function)

           inc    dword [process_number]
           mov    eax,[process_number]
           mov    [ebx+4],eax       ;set PID

;set draw data to full screen

           mov    [ecx+0],dword 0
           mov    [ecx+4],dword 0
           mov    eax,[Screen_Max_X]
           mov    [ecx+8],eax
           mov    eax,[Screen_Max_Y]
           mov    [ecx+12],eax

           mov ebx, [pl0_stack]

           mov eax,   [raw]
           lea ecx, [ebx+REG_EDI]
           mov edx,   [ex_stack]

           mov [ebx+REG_ENTRY],   dword  _sys_app_entry
           mov [ebx+REG_RESTART], dword _pe_restart
           mov [ebx+REG_RAW], eax
           mov [ebx+REG_CSTACK], ecx
           mov [ebx+REG_USTACK], edx

           lea ebx, [ebx+REG_ENTRY]

           mov ecx, [slot]
           shl ecx, 5
           mov [ecx*8+SLOT_BASE+APPDATA.saved_esp], ebx
           mov  [CURRENT_TASK+ecx+TASKDATA.state], 0

        ;   DEBUGF 1,"%s",new_process_running
.err:
           mov eax,[process_number]  ;set result
           mov [application_table_status], 0 ;unlock application_table_status mutex

           pop edi
           pop esi
           pop ebx

	   ret
endp

align 4
_pe_restart:
           add esp, 12
           popad
           iretd


align 4
proc get_new_process_place
;input:
;  none
;result:
;  eax=[new_process_place]<>0 - ok
;      0 - failed.
;This function find least empty slot.
;It doesn't increase [TASK_COUNT]!
	   mov	  eax,CURRENT_TASK
	   mov	  ebx,[TASK_COUNT]
	   inc	  ebx
	   shl	  ebx,5
	   add	  ebx,eax		;ebx - address of process information for (last+1) slot
.newprocessplace:
;eax = address of process information for current slot
	   cmp	  eax,ebx
	   jz	  .endnewprocessplace	;empty slot after high boundary
	   add	  eax,0x20
	   cmp	  word [eax+0xa],9	;check process state, 9 means that process slot is empty
	   jnz	  .newprocessplace
.endnewprocessplace:
	   mov	  ebx,eax
	   sub	  eax,CURRENT_TASK
	   shr	  eax,5 		;calculate slot index
	   cmp	  eax,256
	   jge	  .failed		;it should be <256
	   mov	  word [ebx+0xa],9	;set process state to 9 (for slot after hight boundary)
	   ret
.failed:
	   xor	  eax,eax
	   ret
endp

align 4
proc create_app_space stdcall, app_size:dword,img_base:dword,img_size:dword
           locals
             app_pages   dd ?
             img_pages   dd ?
             dir_addr    dd ?
             app_tabs    dd ?
           endl

           mov ebx, pg_data.pg_mutex
           call wait_mutex   ;ebx

           xor eax, eax
           mov [dir_addr], eax

           mov eax, [app_size]
           add eax, 4095
           and eax, not 4095
           mov [app_size], eax
           mov ebx, eax
           shr eax, 12
           mov [app_pages], eax

           add ebx, 0x3FFFFF
           and ebx, not 0x3FFFFF
           shr ebx, 22
           mov [app_tabs], ebx

           mov ecx, [img_size]
           add ecx, 4095
           and ecx, not 4095

           mov [img_size], ecx
           shr ecx, 12
           mov [img_pages], ecx

           call _alloc_page
           test eax, eax
           mov [dir_addr], eax
           jz .fail

           ;lea edi, [eax + OS_BASE]
           ;mov ecx, (OS_BASE shr 20)/4
           ;xor eax, eax
           ;cld
           ;rep stosd

           ;mov ecx, 1024-(OS_BASE shr 20)/4
           ;mov esi, _sys_pdbr+(OS_BASE shr 20)
           ;rep movsd

           lea edi, [eax+OS_BASE]
           mov ecx, 512
           xor eax, eax
           cld
           rep stosd

           mov esi, [img_base]

           mov ecx, 512                             ; FIX only core tabs
           mov esi, _sys_pdbr+(HEAP_BASE shr 20)
           rep movsd

           mov edi, [dir_addr]
           lea eax, [edi+PG_SW]
           mov [edi+OS_BASE+(page_tabs shr 20)], eax

           mov eax, edi
           call set_cr3

           mov esi, [img_base]

           mov ebx, [app_tabs]
           mov edi, master_tab
@@:
           call _alloc_page
           test eax, eax
           jz .fail

           or eax, PG_UW
           stosd
           dec ebx
           jnz @B

           mov edi, page_tabs
           mov ecx, [app_tabs]
           shl ecx, 10
           xor eax, eax
           rep stosd

           xor ebx, ebx
.alloc:
           call _alloc_page
           test eax, eax
           jz .fail

           stdcall map_page,ebx,eax,dword PG_UW
           add ebx, 0x1000
           dec [app_pages]
           jnz .alloc

           mov ecx, [img_size]                 ; FIXME remap md
           mov esi, [img_base]
           xor edi, edi

           rep movsb

.done:
           dec [pg_data.pg_mutex]
           mov eax, [dir_addr]
           ret
.fail:
           dec [pg_data.pg_mutex]
           cmp [dir_addr], 0
           je @f
           stdcall destroy_app_space, [dir_addr]
@@:
           xor eax, eax
           ret
endp

;addr_t __fastcall pe_app_space(size_t size);
align 4
@pe_app_space@4:
           sub esp, 16

           mov [esp+4],  ebx
           mov [esp+8],  esi
           mov [esp+12], edi

           lea ebx, [ecx+0x3FFFFF]

           call _alloc_page
           test eax, eax
           mov [esp], eax
           jz .fail

           mov ecx, 512
           lea edi, [eax + OS_BASE]
           xor eax, eax
           cld
           rep stosd

           mov ecx, 512                              ; FIX only core tabs
           mov esi, _sys_pdbr+(HEAP_BASE shr 20)
           rep movsd

           mov esi, [esp]
           shr ebx, 22
.new_ptab:
           call _alloc_page
           test eax, eax
           jz .fail

           lea edi, [eax+OS_BASE]
           or eax, PG_UW
           mov [esi+OS_BASE], eax

           mov ecx, 1024
           xor eax, eax
           rep stosd

           add esi, 4
           dec ebx
           jnz .new_ptab

           call _alloc_page
           test eax, eax
           jz .fail

           lea edi, [eax+OS_BASE]
           or eax, PG_UW

           mov ebx, [esp]
           lea edx, [ebx+PG_SW]
           mov [ebx+OS_BASE+(0x7FC00000 shr 20)], eax
           mov [ebx+OS_BASE+(page_tabs shr 20)], edx

           mov ecx, 1024
           xor eax, eax
           rep stosd

           mov eax, ebx
.fail:
           mov ebx, [esp+4]
           mov esi, [esp+8]
           mov edi, [esp+12]

           add esp, 16
           ret

align 4
set_cr3:

           mov ebx, [current_slot]
           mov [ebx+APPDATA.dir_table], eax
           mov cr3, eax
           ret

align 4
proc destroy_page_table stdcall, pg_tab:dword

           push ebx
           push esi

           mov esi, [pg_tab]
           mov ebx, 1024
.free:
           mov ecx, [esi]
           test ecx, 1
           jz .next

           test ecx, 1 shl 9
           jnz .next                      ;skip shared pages

           call @frame_free@4
.next:
           add esi, 4
           dec ebx
           jnz .free
           pop esi
           pop ebx
           ret
endp

align 4
proc destroy_app_space stdcall, pg_dir:dword

           mov ebx, pg_data.pg_mutex
           call wait_mutex   ;ebx

           xor   edx,edx
           mov   eax,0x2
           mov ebx, [pg_dir]
.loop:
;eax = current slot of process
           mov   ecx,eax
           shl   ecx,5
           cmp   byte [CURRENT_TASK+ecx+0xa],9  ;if process running?
           jz    @f                             ;skip empty slots

           shl   ecx,3
           cmp   [SLOT_BASE+ecx+0xB8],ebx       ;compare page directory addresses
           jnz   @f

           inc   edx                            ;thread found
@@:
           inc   eax
           cmp   eax,[TASK_COUNT]               ;exit loop if we look through all processes
           jle   .loop

;edx = number of threads
;our process is zombi so it isn't counted
           cmp   edx,1
           jg    .exit
;if there isn't threads then clear memory.

           mov eax, [pg_dir]
           and eax, -4096
           add eax, OS_BASE
           mov [tmp_task_pdir], eax
           mov esi, eax
           mov edi, (HEAP_BASE shr 20)/4
.destroy:
           mov eax, [esi]
           test eax, 1
           jz .next
           and eax, not 0xFFF
           add eax, OS_BASE

           stdcall destroy_page_table, eax

           mov ecx, [esi]
           call @frame_free@4
.next:
           add esi, 4
           dec edi
           jnz .destroy

           mov ecx, [pg_dir]
           call @frame_free@4
.exit:
           dec [pg_data.pg_mutex]
           ret
endp

align 4
get_pid:
           mov eax, [TASK_BASE]
           mov eax, [eax+TASKDATA.pid]
           ret

pid_to_slot:
;Input:
;  eax - pid of process
;Output:
;  eax - slot of process or 0 if process don't exists
;Search process by PID.
    push   ebx
    push   ecx
    mov    ebx,[TASK_COUNT]
    shl    ebx,5
    mov    ecx,2*32

.loop:
;ecx=offset of current process info entry
;ebx=maximum permitted offset
    cmp    byte [CURRENT_TASK+ecx+0xa],9
    jz	   .endloop		 ;skip empty slots
    cmp    [CURRENT_TASK+ecx+0x4],eax ;check PID
    jz	   .pid_found
.endloop:
    add    ecx,32
    cmp    ecx,ebx
    jle    .loop

    pop    ecx
    pop    ebx
    xor    eax,eax
    ret

.pid_found:
    shr    ecx,5
    mov    eax,ecx		 ;convert offset to index of slot
    pop    ecx
    pop    ebx
    ret

check_region:
;input:
;  ebx - start of buffer
;  ecx - size of buffer
;result:
;  eax = 1 region lays in app memory
;  eax = 0 region don't lays in app memory
     mov  eax,[CURRENT_TASK]
     jmp  check_process_region
;-----------------------------------------------------------------------------
check_process_region:
;input:
;  eax - slot
;  ebx - start of buffer
;  ecx - size of buffer
;result:
;  eax = 1 region lays in app memory
;  eax = 0 region don't lays in app memory

     test ecx,ecx
     jle  .ok
     shl  eax,5
     cmp  word [CURRENT_TASK+eax+0xa],0
     jnz  .failed
     shl  eax,3
     mov  eax,[SLOT_BASE+eax+0xb8]
     test eax,eax
     jz   .failed

     mov  eax,1
     ret

;    call MEM_Get_Linear_Address
;    push ebx
;    push ecx
;    push edx
;    mov  edx,ebx
;    and  edx,not (4096-1)
;    sub  ebx,edx
;    add  ecx,ebx
;    mov  ebx,edx
;    add  ecx,(4096-1)
;    and  ecx,not (4096-1)
;.loop:
;;eax - linear address of page directory
;;ebx - current page
;;ecx - current size
;    mov  edx,ebx
;    shr  edx,22
;    mov  edx,[eax+4*edx]
;    and  edx,not (4096-1)
;    test edx,edx
;    jz   .failed1
;    push eax
;    mov  eax,edx
;    call MEM_Get_Linear_Address
;    mov  edx,ebx
;    shr  edx,12
;    and  edx,(1024-1)
;    mov  eax,[eax+4*edx]
;    and  eax,not (4096-1)
;    test eax,eax
;    pop  eax
;    jz   .failed1
;    add  ebx,4096
;    sub  ecx,4096
;    jg   .loop
;    pop  edx
;    pop  ecx
;    pop  ebx
.ok:
    mov  eax,1
    ret
;
;.failed1:
;    pop  edx
;    pop  ecx
;    pop  ebx
.failed:
    xor  eax,eax
    ret

align 4
proc read_process_memory
;Input:
;  eax - process slot
;  ebx - buffer address
;  ecx - buffer size
;  edx - start address in other process
;Output:
;  eax - number of bytes read.
	   locals
	     slot	dd ?
	     buff	dd ?
	     r_count	dd ?
	     offset	dd ?
	     tmp_r_cnt	dd ?
	   endl

	   mov [slot], eax
	   mov [buff], ebx
	   and [r_count], 0
	   mov [tmp_r_cnt], ecx
	   mov [offset], edx

	   pushad
.read_mem:
	   mov edx, [offset]
	   mov ebx, [tmp_r_cnt]

	   mov ecx, 0x400000
	   and edx, 0x3FFFFF
	   sub ecx, edx
	   cmp ecx, ebx
	   jbe @f
	   mov ecx, ebx
@@:
	   cmp ecx, 0x8000
	   jna @F
	   mov ecx, 0x8000
@@:
	   mov eax, [slot]
	   shl	eax,8
	   mov ebx, [offset]
	   push ecx
	   stdcall map_memEx, [proc_mem_map],\
			      [SLOT_BASE+eax+0xB8],\
			      ebx, ecx
	   pop ecx

	   mov esi, [offset]
	   and esi, 0xfff
	   add esi, [proc_mem_map]
	   mov edi, [buff]
	   mov edx, ecx
	   rep movsb
	   add [r_count], edx

	   add [offset], edx
	   sub [tmp_r_cnt], edx
	   jnz .read_mem

	   popad
	   mov eax, [r_count]
	   ret
endp

align 4
proc write_process_memory
;Input:
;  eax - process slot
;  ebx - buffer address
;  ecx - buffer size
;  edx - start address in other process
;Output:
;  eax - number of bytes written

	   locals
	     slot	dd ?
	     buff	dd ?
	     w_count	dd ?
	     offset	dd ?
	     tmp_w_cnt	dd ?
	   endl

	   mov [slot], eax
	   mov [buff], ebx
	   and [w_count], 0
	   mov [tmp_w_cnt], ecx
	   mov [offset], edx

	   pushad
.read_mem:
	   mov edx, [offset]
	   mov ebx, [tmp_w_cnt]

	   mov ecx, 0x400000
	   and edx, 0x3FFFFF
	   sub ecx, edx
	   cmp ecx, ebx
	   jbe @f
	   mov ecx, ebx
@@:
	   cmp ecx, 0x8000
	   jna @F
	   mov ecx, 0x8000
@@:
	   mov eax, [slot]
	   shl	eax,8
	   mov ebx, [offset]
      ;     add ebx, new_app_base
	   push ecx
	   stdcall map_memEx, [proc_mem_map],\
			      [SLOT_BASE+eax+0xB8],\
			      ebx, ecx
	   pop ecx

	   mov edi, [offset]
	   and edi, 0xfff
	   add edi, [proc_mem_map]
	   mov esi, [buff]
	   mov edx, ecx
	   rep movsb

	   add [w_count], edx
	   add [offset], edx
	   sub [tmp_w_cnt], edx
	   jnz .read_mem

	   popad
	   mov eax, [w_count]
	   ret
endp

align 4
proc new_sys_threads
           locals
             slot      dd ?
             app_cmdline   dd ? ;0x00
             app_path      dd ? ;0x04
             app_eip       dd ? ;0x08
             app_esp       dd ? ;0x0C
             app_mem       dd ? ;0x10
           endl

           cmp eax,1
           jne .failed          ;other subfunctions

           xor  eax,eax
           mov [app_cmdline], eax
           mov [app_path], eax
           mov [app_eip], ebx
           mov [app_esp], ecx

           ;mov    esi,new_process_loading
           ;call   sys_msg_board_str
           DEBUGF 1,"%s",new_process_loading
.wait_lock:
           cmp [application_table_status],0
           je .get_lock

           call   change_task
           jmp .wait_lock

.get_lock:
           mov eax, 1
           xchg eax, [application_table_status]
           cmp eax, 0
           jne .wait_lock

           call   set_application_table_status

           call get_new_process_place
           test eax, eax
           jz .failed

           mov [slot], eax

           mov    esi,[current_slot]
           mov    ebx,esi         ;ebx=esi - pointer to extended information about current thread

           mov    edi, eax
           shl    edi,8
           add    edi,SLOT_BASE
           mov    edx,edi         ;edx=edi - pointer to extended infomation about new thread
           mov    ecx,256/4
           xor eax, eax
           cld
           rep    stosd           ;clean extended information about new thread
           mov    esi,ebx
           mov    edi,edx
           mov    ecx,11
           rep    movsb           ;copy process name

           mov eax,[ebx+APPDATA.heap_base]
           mov [edx+APPDATA.heap_base], eax

           mov ecx,[ebx+APPDATA.heap_top]
           mov [edx+APPDATA.heap_top], ecx

           mov eax,[ebx+APPDATA.mem_size]
           mov [edx+APPDATA.mem_size], eax

           mov ecx,[ebx+APPDATA.dir_table]
           mov [edx+APPDATA.dir_table],ecx  ;copy page directory

           lea eax, [app_cmdline]
           stdcall set_app_params ,[slot],eax,dword 0,\
                         dword 0,dword 0

           ;mov    esi,new_process_running
           ;call   sys_msg_board_str     ;output information about succefull startup
           DEBUGF 1,"%s",new_process_running

           mov    [application_table_status],0 ;unlock application_table_status mutex
           mov    eax,[process_number]  ;set result
           ret
.failed:
           mov    [application_table_status],0
           mov    eax,-1
           ret
endp

; param
;  ebx=mutex

align 4
wait_mutex:
           push eax
           push ebx
.do_wait:
           cmp dword [ebx],0
           je .get_lock

           call change_task
           jmp .do_wait
.get_lock:
           mov eax, 1
           xchg eax, [ebx]
           test eax, eax
           jnz .do_wait

           pop ebx
           pop eax
           ret



align 4
proc set_app_params stdcall,slot:dword, params:dword,\
			cmd_line:dword, app_path:dword, flags:dword

           locals
             pl0_stack dd ?
           endl

           mov ecx, 2            ;(RING0_STACK_SIZE+512) shr 12
           call @frame_alloc@4
           add eax, OS_BASE
           mov [pl0_stack], eax

           lea edi, [eax+RING0_STACK_SIZE]

           mov eax, [slot]
           mov ebx, eax

           shl eax, 8
           mov [eax+SLOT_BASE+APPDATA.fpu_state], edi
           mov [eax+SLOT_BASE+APPDATA.fpu_handler], 0
           mov [eax+SLOT_BASE+APPDATA.sse_handler], 0

;set default io permission map
           mov [eax+SLOT_BASE+APPDATA.io_map],\
               (tss._io_map_0-OS_BASE+PG_MAP)
           mov [eax+SLOT_BASE+APPDATA.io_map+4],\
               (tss._io_map_1-OS_BASE+PG_MAP)

           mov esi, fpu_data
           mov ecx, 512/4
           rep movsd

           cmp    ebx,[TASK_COUNT]
           jle    .noinc
           inc    dword [TASK_COUNT]       ;update number of processes
.noinc:
           shl ebx,8
           lea edx, [ebx+SLOT_BASE+APP_EV_OFFSET]
           mov [SLOT_BASE+APPDATA.fd_ev+ebx],edx
           mov [SLOT_BASE+APPDATA.bk_ev+ebx],edx

           add edx, APP_OBJ_OFFSET-APP_EV_OFFSET
           mov [SLOT_BASE+APPDATA.fd_obj+ebx],edx
           mov [SLOT_BASE+APPDATA.bk_obj+ebx],edx

           mov ecx, [def_cursor]
           mov [SLOT_BASE+APPDATA.cursor+ebx],ecx
           mov eax, [pl0_stack]
           mov [SLOT_BASE+APPDATA.pl0_stack+ebx],eax
           add eax, RING0_STACK_SIZE
           mov [SLOT_BASE+APPDATA.saved_esp0+ebx], eax

           call _alloc_page
           lea edi, [eax + OS_BASE]
           mov [ebx+SLOT_BASE+APPDATA.cur_dir], edi
           mov esi,[current_slot]
           mov esi,[esi+APPDATA.cur_dir]
           mov ecx,0x1000/4
           rep movsd

           shr ebx,3
           mov dword [CURRENT_TASK+ebx+0x10], 0

.add_command_line:
           mov edx,[params]
           mov edx,[edx]       ;app_cmdline
           test edx,edx
           jz @f           ;application doesn't need parameters

           mov     eax, edx
           add     eax, 256
           jc      @f

           cmp     eax, [SLOT_BASE+APPDATA.mem_size+ebx*8]
           ja      @f

           mov     byte [edx], 0   ;force empty string if no cmdline given
           mov     eax, [cmd_line]
           test    eax, eax
           jz      @f
           stdcall strncpy, edx, eax, 256
@@:
           mov edx,[params]
           mov edx, [edx+4]    ;app_path
           test edx,edx
           jz @F           ;application don't need path of file
           mov     eax, edx
           add     eax, 1024
           jc      @f
           cmp     eax, [SLOT_BASE+APPDATA.mem_size+ebx*8]
           ja      @f
           stdcall strncpy, edx, [app_path], 1024
@@:
           mov    ebx,[slot]
           mov    eax,ebx
           shl    ebx,5
           lea    ecx,[draw_data+ebx]  ;ecx - pointer to draw data

; set window state to 'normal' (non-minimized/maximized/rolled-up) state
           mov     [ebx+window_data+WDATA.fl_wstate], WSTATE_NORMAL
           mov     [ebx+window_data+WDATA.fl_redraw], 1
           add    ebx,CURRENT_TASK        ;ebx - pointer to information about process
           mov    [ebx+TASKDATA.wnd_number],al;set window number on screen = process slot

           mov    [ebx+TASKDATA.event_mask],dword 1+2+4 ;set default event flags (see 40 function)

           inc    dword [process_number]
           mov    eax,[process_number]
           mov    [ebx+4],eax       ;set PID

;set draw data to full screen

           mov    [ecx+0],dword 0
           mov    [ecx+4],dword 0
           mov    eax,[Screen_Max_X]
           mov    [ecx+8],eax
           mov    eax,[Screen_Max_Y]
           mov    [ecx+12],eax

           mov ebx, [pl0_stack]
           mov esi,[params]
           lea ecx, [ebx+REG_EIP]
           xor eax, eax

           mov [ebx+REG_RET], dword irq0.return
           mov [ebx+REG_EDI], eax
           mov [ebx+REG_ESI], eax
           mov [ebx+REG_EBP], eax
           mov [ebx+REG_ESP], ecx   ;ebx+REG_EIP
           mov [ebx+REG_EBX], eax
           mov [ebx+REG_EDX], eax
           mov [ebx+REG_ECX], eax
           mov [ebx+REG_EAX], eax

           mov eax, [esi+0x08]       ;app_eip
           mov [ebx+REG_EIP],  eax   ;app_entry
           mov [ebx+REG_CS], dword sel_app_code
               mov [ebx+REG_EFLAGS], dword EFL_IOPL3+EFL_IF

           mov eax, [esi+0x0C]       ;app_esp
           mov [ebx+REG_APP_ESP], eax    ;app_stack
           mov [ebx+REG_SS], dword sel_app_data

           lea ecx, [ebx+REG_RET]
           mov ebx, [slot]
           shl ebx, 5
           mov [ebx*8+SLOT_BASE+APPDATA.saved_esp], ecx

           xor  ecx, ecx    ; process state - running
; set if debuggee
           test byte [flags], 1
           jz   .no_debug

           inc  ecx     ; process state - suspended
           mov  eax,[CURRENT_TASK]
           mov  [SLOT_BASE+ebx*8+APPDATA.debugger_slot],eax
.no_debug:
           mov  [CURRENT_TASK+ebx+TASKDATA.state], cl
         ;  DEBUGF 1,"%s",new_process_running
           ret
endp

include "debug.inc"
