langsmoke/service.asm

1094 lines
25 KiB
NASM

;===============================================================================
;Copyright (C) Andrzej Adamczyk (at https://blackdev.org/). All rights reserved.
;===============================================================================
; information for linker
section .rodata
; align routine
align 0x08, db 0x00
kernel_service_list:
dq kernel_service_exit
dq kernel_service_framebuffer
dq kernel_service_memory_alloc
dq kernel_service_memory_release
dq kernel_service_task_pid
dq kernel_service_driver_mouse
dq kernel_service_storage_read
dq kernel_service_exec
dq kernel_service_ipc_send
dq kernel_service_ipc_receive
dq kernel_service_memory_share
dq driver_ps2_keyboard_key_read
dq kernel_service_task_status
dq kernel_stream_out
dq kernel_stream_in
dq kernel_service_serial_char
dq kernel_service_serial_string
dq kernel_service_serial_value
dq driver_rtc_time
dq kernel_stream_set
dq kernel_stream_get
dq kernel_service_sleep
dq kernel_service_uptime
dq kernel_stream_out_value
dq kernel_service_task
dq kernel_service_memory
dq kernel_service_thread
kernel_service_list_end:
; information for linker
section .text
;-------------------------------------------------------------------------------
; in:
; rdi - pointer to Memory descriptor
kernel_service_memory:
; preserve original registers
push rax
push r8
; kernel environment variables/rountines base addrrax
mov r8, qword [kernel_environment_base_address]
; return information about
; all available pages
mov rax, qword [r8 + KERNEL_STRUCTURE.page_total]
mov qword [rdi + LIB_SYS_STRUCTURE_MEMORY.total], rax
; and currently free
mov rax, qword [r8 + KERNEL_STRUCTURE.page_available]
mov qword [rdi + LIB_SYS_STRUCTURE_MEMORY.available], rax
; restore original registers
pop r8
pop rax
; return from routine
ret
;-------------------------------------------------------------------------------
; void
kernel_service_exit:
; retrieve pointer to current task descriptor
call kernel_task_active
; mark task as closed and not active
or word [r9 + KERNEL_TASK_STRUCTURE.flags], KERNEL_TASK_FLAG_closed
and word [r9 + KERNEL_TASK_STRUCTURE.flags], ~KERNEL_TASK_FLAG_active
; release rest of AP time
int 0x20
;-------------------------------------------------------------------------------
; in:
; rdi - sleep amount in microtime
kernel_service_sleep:
; preserve original registers
push rdi
push r8
push r9
; kernel environment variables/rountines base address
mov r8, qword [kernel_environment_base_address]
; retrieve pointer to current task descriptor
call kernel_task_active
; current uptime
add rdi, qword [r8 + KERNEL_STRUCTURE.hpet_microtime]
; go to sleep for N ticks
mov qword [r9 + KERNEL_TASK_STRUCTURE.sleep], rdi
; release the remaining CPU time
int 0x20
; restore original registers
pop r9
pop r8
pop rdi
; return from routine
ret
;-------------------------------------------------------------------------------
; out:
; rax - current uptime in microtime
kernel_service_uptime:
; return current microtime index
mov rax, qword [kernel_environment_base_address]
mov rax, qword [rax + KERNEL_STRUCTURE.hpet_microtime]
; return from routine
ret
;-------------------------------------------------------------------------------
; in:
; rdi - pointer to mouse descriptor
kernel_service_driver_mouse:
; preserve original registers
push rax
push r8
; kernel environment variables/rountines base address
mov r8, qword [kernel_environment_base_address]
; share information about mouse location and status
mov ax, word [r8 + KERNEL_STRUCTURE.driver_ps2_mouse_x]
mov word [rdi + LIB_SYS_STRUCTURE_MOUSE.x], ax
mov ax, word [r8 + KERNEL_STRUCTURE.driver_ps2_mouse_y]
mov word [rdi + LIB_SYS_STRUCTURE_MOUSE.y], ax
mov al, byte [r8 + KERNEL_STRUCTURE.driver_ps2_mouse_status]
mov byte [rdi + LIB_SYS_STRUCTURE_MOUSE.status], al
; restore original registers
pop r8
pop rax
; return from routine
ret
;-------------------------------------------------------------------------------
; in:
; rdx - stream flags
; rsi - length of file name/path
; rdi - pointer to file name/path
; out:
; rax - process ID
kernel_service_exec:
; preserve original registers
push rcx
push rsi
push rdi
push rbp
push r8
; kernel environment variables/rountines base address
mov r8, qword [kernel_environment_base_address]
; reorganize registers
mov rcx, rsi ; length of string
mov rsi, rdx ; pointer to string
xchg rsi, rdi ; stream flags
; execute file from path
call kernel_exec
; restore original registers
pop r8
pop rbp
pop rdi
pop rsi
pop rcx
; return from routine
ret
;-------------------------------------------------------------------------------
; in:
; rdi - pointer to framebuffer descriptor
kernel_service_framebuffer:
; preserve original registers
push rax
push rcx
push rdx
push rsi
push r8
push r9
push r11
; kernel environment variables/rountines base address
mov r8, qword [kernel_environment_base_address]
; return properties of framebuffer
; width in pixels
mov ax, word [r8 + KERNEL_STRUCTURE.framebuffer_width_pixel]
mov word [rdi + LIB_SYS_STRUCTURE_FRAMEBUFFER.width_pixel], ax
; height in pixels
mov ax, word [r8 + KERNEL_STRUCTURE.framebuffer_height_pixel]
mov word [rdi + LIB_SYS_STRUCTURE_FRAMEBUFFER.height_pixel], ax
; scanline in Bytes
mov eax, dword [r8 + KERNEL_STRUCTURE.framebuffer_scanline_byte]
mov dword [rdi + LIB_SYS_STRUCTURE_FRAMEBUFFER.scanline_byte], eax
; framebuffer manager
mov rax, qword [r8 + KERNEL_STRUCTURE.framebuffer_pid]
; framebuffer manager exist?
test rax, rax
jnz .return ; yes
; retrieve pointer to current task descriptor
call kernel_task_active
; calculate size of framebuffer space
mov eax, dword [rdi + LIB_SYS_STRUCTURE_FRAMEBUFFER.scanline_byte]
movzx ecx, word [rdi + LIB_SYS_STRUCTURE_FRAMEBUFFER.height_pixel]
mul rcx
; convert to pages
add rax, ~STATIC_PAGE_mask
shr rax, STATIC_PAGE_SIZE_shift
; share framebuffer memory space with process
xor ecx, ecx ; no framebuffer manager, if error on below function
xchg rcx, rax ; length of shared space in pages
mov rsi, qword [r8 + KERNEL_STRUCTURE.framebuffer_base_address]
mov r11, qword [r9 + KERNEL_TASK_STRUCTURE.cr3]
call kernel_memory_share
jc .return ; no enough memory?
; return pointer to shared memory of framebuffer
mov qword [rdi + LIB_SYS_STRUCTURE_FRAMEBUFFER.base_address], rax
; new framebuffer manager
mov rax, qword [r9 + KERNEL_TASK_STRUCTURE.pid]
mov qword [r8 + KERNEL_STRUCTURE.framebuffer_pid], rax
.return:
; inform about framebuffer manager
mov qword [rdi + LIB_SYS_STRUCTURE_FRAMEBUFFER.pid], rax
; restore original registers
pop r11
pop r9
pop r8
pop rsi
pop rdx
pop rcx
pop rax
; return from routine
ret
;-------------------------------------------------------------------------------
; in:
; rdi - ID of target process
; rsi - pointer to message data
kernel_service_ipc_send:
; preserve original registers
push rax
push rcx
push rsi
push rdi
push r8
; kernel environment variables/rountines base address
mov r8, qword [kernel_environment_base_address]
.lock:
; request an exclusive access
mov cl, LOCK
lock xchg byte [r8 + KERNEL_STRUCTURE.ipc_semaphore], cl
; assigned?
test cl, cl
jnz .lock ; no
.restart:
; amount of entries
mov rcx, KERNEL_IPC_limit
; set pointer to first message
mov rdx, qword [r8 + KERNEL_STRUCTURE.ipc_base_address]
.loop:
; free entry?
mov rax, qword [r8 + KERNEL_STRUCTURE.hpet_microtime]
cmp qword [rdx + LIB_SYS_STRUCTURE_IPC.ttl], rax
jbe .found ; yes
; next entry from list
add rdx, LIB_SYS_STRUCTURE_IPC.SIZE
; end of message list?
dec rcx
jz .restart ; yes
; no
jmp .loop
.found:
; set message time out
add rax, KERNEL_IPC_timeout
mov qword [rdx + LIB_SYS_STRUCTURE_IPC.ttl], rax
; set message source
call kernel_task_pid
mov qword [rdx + LIB_SYS_STRUCTURE_IPC.source], rax
; set message target
mov qword [rdx + LIB_SYS_STRUCTURE_IPC.target], rdi
; load data into message
mov ecx, LIB_SYS_IPC_DATA_size_byte
mov rdi, rdx
add rdi, LIB_SYS_STRUCTURE_IPC.data
rep movsb
.end:
; release access
mov byte [r8 + KERNEL_STRUCTURE.ipc_semaphore], UNLOCK
; restore original registers
pop r8
pop rdi
pop rsi
pop rcx
pop rax
; return from routine
ret
;-------------------------------------------------------------------------------
; in:
; rdi - pointer to message descriptor
; sil - message type
; out:
; TRUE if message retrieved
kernel_service_ipc_receive:
; preserve original registers
push rbx
push rcx
push rdi
push r8
push rsi
; kernel environment variables/rountines base address
mov r8, qword [kernel_environment_base_address]
.lock:
; request an exclusive access
mov cl, LOCK
lock xchg byte [r8 + KERNEL_STRUCTURE.ipc_semaphore], cl
; assigned?
test cl, cl
jnz .lock ; no
; retrieve ID of current process
call kernel_task_pid
; amount of entries
mov rcx, KERNEL_IPC_limit
; set pointer to first message
mov rsi, qword [r8 + KERNEL_STRUCTURE.ipc_base_address]
.loop:
; message alive?
mov rbx, qword [r8 + KERNEL_STRUCTURE.hpet_microtime]
cmp qword [rsi + LIB_SYS_STRUCTURE_IPC.ttl], rbx
ja .check ; yes
.next:
; next entry from list?
add rsi, LIB_SYS_STRUCTURE_IPC.SIZE
dec rcx
jnz .loop ; yes
; no message for us
xor eax, eax
; no
jmp .end
.check:
; message type selected?
cmp byte [rsp], LIB_SYS_IPC_TYPE_ANY
je .any ; no
; requested message type?
mov bl, byte [rsp]
cmp bl, byte [rsi + LIB_SYS_STRUCTURE_IPC.data + LIB_SYS_STRUCTURE_IPC_DEFAULT.type]
jne .next ; no
.any:
; message for us?
cmp qword [rsi + LIB_SYS_STRUCTURE_IPC.target], rax
jne .next ; no
; preserve original register
push rsi
; load message to process descriptor
mov ecx, LIB_SYS_STRUCTURE_IPC.SIZE
rep movsb
; restore original register
pop rsi
; release entry
mov qword [rsi + LIB_SYS_STRUCTURE_IPC.ttl], EMPTY
; message transferred
mov eax, TRUE
.end:
; release access
mov byte [r8 + KERNEL_STRUCTURE.ipc_semaphore], UNLOCK
; restore original registers
pop rsi
pop r8
pop rdi
pop rcx
pop rbx
; return from routine
ret
;-------------------------------------------------------------------------------
; in:
; rdi - length of space in Bytes
; out:
; rax - pointer to allocated space
; or EMPTY if no enough memory
kernel_service_memory_alloc:
; preserve original registers
push rbx
push rcx
push rsi
push rdi
push r8
push r9
push r11
; convert size to pages (align up to page boundaries)
add rdi, ~STATIC_PAGE_mask
shr rdi, STATIC_PAGE_SIZE_shift
; retrieve pointer to current task descriptor
call kernel_task_active
; set pointer of process paging array
mov r11, qword [r9 + KERNEL_TASK_STRUCTURE.cr3]
; aquire memory space from process memory map
mov r9, qword [r9 + KERNEL_TASK_STRUCTURE.memory_map]
mov rcx, rdi ; number of pages
call kernel_memory_acquire
jc .error ; no enough memory
; convert first page number to logical address
shl rdi, STATIC_PAGE_SIZE_shift
; assign pages to allocated memory in process space
mov rax, rdi
mov bx, KERNEL_PAGE_FLAG_present | KERNEL_PAGE_FLAG_write | KERNEL_PAGE_FLAG_user | KERNEL_PAGE_FLAG_process
call kernel_page_alloc
jnc .allocated ; space allocated
; take back modifications
mov rsi, rcx
call kernel_service_memory_release
.error:
; no enough memory
xor eax, eax
; end
jmp .end
.allocated:
; retrieve pointer to current task descriptor
call kernel_task_active
; process memory usage
add qword [r9 + KERNEL_TASK_STRUCTURE.page], rcx
.end:
; restore original registers
pop r11
pop r9
pop r8
pop rdi
pop rsi
pop rcx
pop rbx
; return from routine
ret
;-------------------------------------------------------------------------------
; in:
; rdi - pointer to allocated space
; rsi - length of space in Bytes
kernel_service_memory_release:
; preserve original registers
push rax
push rcx
push rsi
push rdi
push r9
push r11
; retrieve pointer to current task descriptor
call kernel_task_active
; convert bytes to pages
add rsi, ~STATIC_PAGE_mask
shr rsi, STATIC_PAGE_SIZE_shift
; pointer and counter at place
mov rcx, rsi
mov rsi, rdi
.loop:
; delete first physical page from logical address
mov r11, qword [r9 + KERNEL_TASK_STRUCTURE.cr3]
call kernel_page_remove
; page removed?
test rax, rax
jnz .release ; yes
; convert to page number
shr rsi, STATIC_PAGE_SIZE_shift
; continue
jmp .next
.release:
; release page inside kernels binary memory map
mov rdi, rax
or rdi, qword [kernel_page_mirror]
call kernel_memory_release_page
; release page inside process binary memory map
shr rsi, STATIC_PAGE_SIZE_shift
mov rdi, qword [r9 + KERNEL_TASK_STRUCTURE.memory_map]
bts qword [rdi], rsi
; process memory usage
dec qword [r9 + KERNEL_TASK_STRUCTURE.page]
.next:
; next page from space
inc rsi
shl rsi, STATIC_PAGE_SIZE_shift
; another page?
dec rcx
jnz .loop ; yes
; restore original registers
pop r11
pop r9
pop rdi
pop rsi
pop rcx
pop rax
; return from routine
ret
;-------------------------------------------------------------------------------
; in:
; rdi - pointer to source memory space
; rsi - length of space in Bytes
; rdx - target process ID
; out:
; rax - pointer to shared memory between processes
kernel_service_memory_share:
; preserve original registers
push rbx
push rcx
push rsi
push rdi
push r9
push r11
; convert Bytes to pages
mov rcx, rsi
add rcx, ~STATIC_PAGE_mask
shr rcx, STATIC_PAGE_SIZE_shift
; retrieve task paging structure pointer
call kernel_task_by_id
mov r11, qword [rbx + KERNEL_TASK_STRUCTURE.cr3]
; set source pointer in place
mov rsi, rdi
; acquire memory space from target process
mov r9, qword [rbx + KERNEL_TASK_STRUCTURE.memory_map]
call kernel_memory_acquire
; convert page number to offset
shl rdi, STATIC_PAGE_SIZE_shift
; connect memory space of parent process with child
mov rax, rdi
mov bx, KERNEL_PAGE_FLAG_present | KERNEL_PAGE_FLAG_write | KERNEL_PAGE_FLAG_user | KERNEL_PAGE_FLAG_process | KERNEL_PAGE_FLAG_shared
call kernel_page_clang
; restore original registers
pop r11
pop r9
pop rdi
pop rsi
pop rcx
pop rbx
; return from routine
ret
;-------------------------------------------------------------------------------
; out:
; rax - PID of current task
kernel_service_task_pid:
; preserve original registers
push r9
; retrieve pointer to current task descriptor
call kernel_task_active
; set pointer of process paging array
mov rax, qword [r9 + KERNEL_TASK_STRUCTURE.pid]
; restore original registers
pop r9
; return from routine
ret
;-------------------------------------------------------------------------------
; in:
; rdi - process ID
; out:
; ax - task status
kernel_service_task_status:
; preserve original registers
push rbx
push rdx
; retrieve pointer to current task descriptor
mov rdx, rdi
call kernel_task_by_id
; by default not found
xor ax, ax
; not found?
test rbx, rbx
jz .error ; yep
; set pointer of process paging array
mov ax, word [rbx + KERNEL_TASK_STRUCTURE.flags]
.error:
; restore original registers
pop rdx
pop rbx
; return from routine
ret
;-------------------------------------------------------------------------------
; in:
; rdi - ASCII character
kernel_service_serial_char:
; preserve original register
push rax
; send character to serial
mov al, dil
call driver_serial_char
; restore original register
pop rax
; return from routine
ret
;-------------------------------------------------------------------------------
; in:
; rdi - pointer to string
; rsi - length of string in Bytes
kernel_service_serial_string:
; preserve original registers
push rcx
push rsi
; send string to serial
mov rcx, rsi
mov rsi, rdi
call driver_serial_string
; restore original registers
pop rsi
pop rcx
; return from routine
ret
;-------------------------------------------------------------------------------
; in:
; rdi - value
; sil - base
; rdx - prefix length
; cl - TRUE/FALSE signed value?
kernel_service_serial_value:
; preserve original registers
push rax
push rbx
push rcx
push rdx
; send value to serial
mov rax, rdi
movzx ebx, sil
xchg rcx, rdx
call driver_serial_value
; restore original registers
pop rdx
pop rcx
pop rbx
pop rax
; return from routine
ret
;-------------------------------------------------------------------------------
; in:
; rdi - pointer to file descriptor
kernel_service_storage_read:
; preserve original registers
push rax
push rbx
push rcx
push rsi
push rbp
push r8
push r9
push r11
push rdi
; kernel environment variables/rountines base address
mov r8, qword [kernel_environment_base_address]
; prepare space for file descriptor
sub rsp, KERNEL_STORAGE_STRUCTURE_FILE.SIZE
mov rbp, rsp ; pointer of file descriptor
; get file properties
movzx eax, byte [r8 + KERNEL_STRUCTURE.storage_root_id]
movzx ecx, byte [rdi + LIB_SYS_STRUCTURE_STORAGE.length]
lea rsi, [rdi + LIB_SYS_STRUCTURE_STORAGE.name]
call kernel_storage_file
; file found?
cmp qword [rbp + KERNEL_STORAGE_STRUCTURE_FILE.id], EMPTY
je .end ; no
; prepare space for file content
mov rdi, qword [rbp + KERNEL_STORAGE_STRUCTURE_FILE.size_byte]
call kernel_service_memory_alloc
; no enough memory?
test rax, rax
jz .end ; yes
; load file content into prepared space
mov rsi, qword [rbp + KERNEL_STORAGE_STRUCTURE_FILE.id]
mov rdi, rax
movzx eax, byte [r8 + KERNEL_STRUCTURE.storage_root_id]
call kernel_storage_read
; retrieve current task pointer
call kernel_task_active
; restore file descriptor
mov rax, qword [rsp + KERNEL_STORAGE_STRUCTURE_FILE.SIZE]
; inform process about file location and size
push qword [rbp + KERNEL_STORAGE_STRUCTURE_FILE.size_byte]
pop qword [rax + LIB_SYS_STRUCTURE_STORAGE.size_byte]
mov qword [rax + LIB_SYS_STRUCTURE_STORAGE.address], rdi
.end:
; remove file descriptor from stack
add rsp, KERNEL_STORAGE_STRUCTURE_FILE.SIZE
; restore original registers
pop rdi
pop r11
pop r9
pop r8
pop rbp
pop rsi
pop rcx
pop rbx
pop rax
; return from routine
ret
;-------------------------------------------------------------------------------
; out:
; rax - pointer to list of first task descriptor
kernel_service_task:
; preserve original registers
push rbx
push rcx
push rdx
push rsi
push rdi
push r8
push r10
; kernel environment variables/rountines base address
mov r8, qword [kernel_environment_base_address]
.lock:
; request an exclusive access
mov al, LOCK
lock xchg byte [r8 + KERNEL_STRUCTURE.task_queue_semaphore], al
; assigned?
test al, al
jnz .lock ; no
; length of tasks descriptors in Bytes
mov eax, LIB_SYS_STRUCTURE_TASK.SIZE
mul qword [r8 + KERNEL_STRUCTURE.task_count]
; assign place for task descriptor list
mov rdi, rax
add rdi, STATIC_QWORD_SIZE_byte << STATIC_MULTIPLE_BY_2_shift
call kernel_service_memory_alloc
; store information about size of this space
add rdi, ~STATIC_PAGE_mask
shr rdi, STATIC_PAGE_SIZE_shift
mov qword [rax], rdi
; parse every entry
mov rbx, KERNEL_TASK_limit
mov r10, qword [r8 + KERNEL_STRUCTURE.task_queue_address]
; preserve memory space pointer of tasks descriptors
add rax, STATIC_QWORD_SIZE_byte << STATIC_MULTIPLE_BY_2_shift
push rax
.loop:
; entry exist?
cmp word [r10 + KERNEL_TASK_STRUCTURE.flags], EMPTY
je .next ; no
; do not pass kernel entry
cmp qword [r10 + KERNEL_TASK_STRUCTURE.pid], EMPTY
je .next
; share default information about task
; process ID
mov rdx, qword [r10 + KERNEL_TASK_STRUCTURE.pid]
mov qword [rax + LIB_SYS_STRUCTURE_TASK.pid], rdx
; process parents ID
mov rdx, qword [r10 + KERNEL_TASK_STRUCTURE.pid_parent]
mov qword [rax + LIB_SYS_STRUCTURE_TASK.pid_parent], rdx
; wake up process micotime
mov rdx, qword [r10 + KERNEL_TASK_STRUCTURE.sleep]
mov qword [rax + LIB_SYS_STRUCTURE_TASK.sleep], rdx
; amount of pages used by process
mov rdx, qword [r10 + KERNEL_TASK_STRUCTURE.page]
mov qword [rax + LIB_SYS_STRUCTURE_TASK.page], rdx
; current task status
mov dx, word [r10 + KERNEL_TASK_STRUCTURE.flags]
mov word [rax + LIB_SYS_STRUCTURE_TASK.flags], dx
; taks name length
movzx ecx, byte [r10 + KERNEL_TASK_STRUCTURE.length]
mov byte [rax + LIB_SYS_STRUCTURE_TASK.length], cl
; task name itself
lea rsi, [r10 + KERNEL_TASK_STRUCTURE.name]
lea rdi, [rax + LIB_SYS_STRUCTURE_TASK.name]
rep movsb
; next task descriptor position
add rax, LIB_SYS_STRUCTURE_TASK.SIZE
.next:
; move pointer to next entry of task table
add r10, KERNEL_TASK_STRUCTURE.SIZE
; end of tasks inside table?
dec rbx
jnz .loop ; no
; last entry set as empty
mov qword [rax + LIB_SYS_STRUCTURE_TASK.pid], EMPTY
; return memory pointer of tasks descriptors
pop rax
; release access
mov byte [r8 + KERNEL_STRUCTURE.task_queue_semaphore], UNLOCK
; restore original registers
pop r10
pop r8
pop rdi
pop rsi
pop rdx
pop rcx
pop rbx
; return from routine
ret
;-------------------------------------------------------------------------------
; in:
; rdi - pointer to function of current task to execute as thread
; rsi - pointer to string as name of thread
; rdx - length of that string
;out:
; rax - process ID of thread
kernel_service_thread:
; preserve original registers
push rbx
push rcx
push rdx
push rsi
push r9
push r10
push r11
push r15
push rdi
;-----------------------------------------------------------------------
; prepare task for execution
;-----------------------------------------------------------------------
; register new task on queue
mov rcx, rdx
call kernel_task_add
;-----------------------------------------------------------------------
; paging array of new process
;-----------------------------------------------------------------------
; make space for the process paging table
call kernel_memory_alloc_page
; update task entry about paging array
mov qword [r10 + KERNEL_TASK_STRUCTURE.cr3], rdi
;-----------------------------------------------------------------------
; context stack and return point (initialization entry)
;-----------------------------------------------------------------------
; describe the space under context stack of process
mov rax, KERNEL_TASK_STACK_address
mov bx, KERNEL_PAGE_FLAG_present | KERNEL_PAGE_FLAG_write | KERNEL_PAGE_FLAG_process
mov ecx, KERNEL_TASK_STACK_SIZE_page
mov r11, rdi
call kernel_page_alloc
; set process context stack pointer
mov rsi, KERNEL_TASK_STACK_pointer - (KERNEL_EXEC_STRUCTURE_RETURN.SIZE + KERNEL_EXEC_STACK_OFFSET_registers)
mov qword [r10 + KERNEL_TASK_STRUCTURE.rsp], rsi
; prepare exception exit mode on context stack of process
mov rsi, KERNEL_TASK_STACK_pointer - STATIC_PAGE_SIZE_byte
call kernel_page_address
; set pointer to return descriptor
and rax, STATIC_PAGE_mask ; drop flags
add rax, qword [kernel_page_mirror] ; convert to logical address
add rax, STATIC_PAGE_SIZE_byte - KERNEL_EXEC_STRUCTURE_RETURN.SIZE
; set first instruction executed by thread
mov rdx, qword [rsp]
mov qword [rax + KERNEL_EXEC_STRUCTURE_RETURN.rip], rdx
; code descriptor
mov qword [rax + KERNEL_EXEC_STRUCTURE_RETURN.cs], KERNEL_GDT_STRUCTURE.cs_ring3 | 0x03
; default processor state flags
mov qword [rax + KERNEL_EXEC_STRUCTURE_RETURN.eflags], KERNEL_TASK_EFLAGS_default
; default stack pointer
mov rdx, KERNEL_EXEC_STACK_pointer - 0x10 ; no args
mov qword [rax + KERNEL_EXEC_STRUCTURE_RETURN.rsp], rdx
; stack descriptor
mov qword [rax + KERNEL_EXEC_STRUCTURE_RETURN.ss], KERNEL_GDT_STRUCTURE.ds_ring3 | 0x03
;-----------------------------------------------------------------------
; stack
;-----------------------------------------------------------------------
; alloc stack space
mov rcx, KERNEL_EXEC_STACK_SIZE_page
call kernel_memory_alloc
; map executable space to thread paging array
mov rax, KERNEL_EXEC_STACK_address
or bx, KERNEL_PAGE_FLAG_user
mov rsi, rdi
sub rsi, qword [kernel_page_mirror]
call kernel_page_map
; process memory usage
add qword [r10 + KERNEL_TASK_STRUCTURE.page], rcx
; process stack size
add qword [r10 + KERNEL_TASK_STRUCTURE.stack], rcx
; aquire parent task properties
call kernel_task_active
; threads use same memory map as parent
mov rax, qword [r9 + KERNEL_TASK_STRUCTURE.memory_map]
mov qword [r10 + KERNEL_TASK_STRUCTURE.memory_map], rax
; threads use same streams as parent
; in
mov rax, qword [r9 + KERNEL_TASK_STRUCTURE.stream_in]
inc qword [rax + KERNEL_STREAM_STRUCTURE.count]
mov qword [r10 + KERNEL_TASK_STRUCTURE.stream_in], rax
; out
mov rax, qword [r9 + KERNEL_TASK_STRUCTURE.stream_out]
inc qword [rax + KERNEL_STREAM_STRUCTURE.count]
mov qword [r10 + KERNEL_TASK_STRUCTURE.stream_out], rax
; map kernel space to process
mov r15, qword [r9 + KERNEL_TASK_STRUCTURE.cr3]
or r15, qword [kernel_page_mirror]
call kernel_page_merge
; mark thread as ready
or word [r10 + KERNEL_TASK_STRUCTURE.flags], KERNEL_TASK_FLAG_active | KERNEL_TASK_FLAG_thread | KERNEL_TASK_FLAG_init
; return process ID of new thread
mov rax, qword [r10 + KERNEL_TASK_STRUCTURE.pid]
; restore original registers
pop rdi
pop r15
pop r11
pop r10
pop r9
pop rsi
pop rdx
pop rcx
pop rbx
; end of routine
ret