将 .py 和 .pyi 后缀名改为了 .vp 和 .vpi 后缀名
This commit is contained in:
277
VKernel/Kernel/sched/process.vp
Normal file
277
VKernel/Kernel/sched/process.vp
Normal file
@@ -0,0 +1,277 @@
|
||||
import mm
|
||||
import mm.mm as mm_mm
|
||||
import paging.paging as paging
|
||||
import drivers.serial.uart.serial as serial
|
||||
import drivers.fs.fat32.fat32 as fat32
|
||||
import drivers.fs.fat32.fat32_types as fat32_types
|
||||
import drivers.core.cpu.cpu as cpu
|
||||
import intr.gdt as gdt
|
||||
import viperlib
|
||||
import string
|
||||
import t, c
|
||||
|
||||
PROC_READY: t.CDefine = 0
|
||||
PROC_RUNNING: t.CDefine = 1
|
||||
PROC_BLOCKED: t.CDefine = 2
|
||||
PROC_DONE: t.CDefine = 3
|
||||
MAX_PROCESSES: t.CDefine = 8
|
||||
MAX_PROC_THREADS: t.CDefine = 8
|
||||
PROC_MAX_FDS: t.CDefine = 16
|
||||
PROC_MAX_DIRS: t.CDefine = 8
|
||||
KERN_STACK_SIZE: t.CDefine = 8192
|
||||
USER_STACK_SIZE: t.CDefine = 65536
|
||||
|
||||
|
||||
@t.Object
|
||||
class Process:
|
||||
pid: t.CInt
|
||||
pml4_root: t.CUInt64T
|
||||
threads: t.CArray[t.CInt, 8]
|
||||
thread_count: t.CInt
|
||||
state: t.CInt
|
||||
entry: t.CVoid | t.CPtr
|
||||
elf_base: t.CUInt64T
|
||||
heap_start: t.CUInt64T
|
||||
heap_size: t.CUInt64T
|
||||
name: t.CArray[t.CChar, 32]
|
||||
fd_table: t.CArray[t.CVoid | t.CPtr, PROC_MAX_FDS]
|
||||
fd_used: t.CArray[t.CUInt8T, PROC_MAX_FDS]
|
||||
dir_table: t.CArray[t.CVoid | t.CPtr, PROC_MAX_DIRS]
|
||||
dir_used: t.CArray[t.CUInt8T, PROC_MAX_DIRS]
|
||||
dir_pool: t.CArray[fat32_types.dirobj, PROC_MAX_DIRS]
|
||||
kern_stack: t.CUInt64T
|
||||
user_stack: t.CUInt64T
|
||||
|
||||
def addThread(self, tid: t.CInt) -> t.CInt:
|
||||
if self.thread_count >= MAX_PROC_THREADS: return -1
|
||||
self.threads[self.thread_count] = tid
|
||||
self.thread_count += 1
|
||||
return 0
|
||||
|
||||
def exit(self):
|
||||
self.state = PROC_DONE
|
||||
for i in range(PROC_MAX_FDS):
|
||||
if self.fd_used[i]:
|
||||
fp: t.CVoid | t.CPtr = self.fd_table[i]
|
||||
if fp:
|
||||
fat32.close(fp)
|
||||
self.fd_used[i] = 0
|
||||
self.fd_table[i] = t.CVoid(0, t.CPtr)
|
||||
for i in range(PROC_MAX_DIRS):
|
||||
if self.dir_used[i]:
|
||||
dp: t.CVoid | t.CPtr = self.dir_table[i]
|
||||
if dp:
|
||||
fat32.closedir(dp)
|
||||
self.dir_used[i] = 0
|
||||
self.dir_table[i] = t.CVoid(0, t.CPtr)
|
||||
m: ProcessManager | t.CPtr = _proc_mgr_ptr
|
||||
if m.current_pid == self.pid:
|
||||
m.current_pid = 0
|
||||
m.processes[0].state = PROC_RUNNING
|
||||
if self.pml4_root != 0:
|
||||
kernel_cr3: t.CUInt64T = m.processes[0].pml4_root
|
||||
if kernel_cr3 != 0:
|
||||
c.Asm(f"mov cr3, {c.AsmInp(kernel_cr3, t.ASM_DESCR.REG_ANY)}",
|
||||
op=[t.ASM_DESCR.CLOBBER_MEMORY])
|
||||
paging.set_active_pml4(kernel_cr3)
|
||||
|
||||
@property
|
||||
def is_running(self) -> t.CInt:
|
||||
if self.state == PROC_RUNNING:
|
||||
return 1
|
||||
return 0
|
||||
|
||||
@property
|
||||
def is_done(self) -> t.CInt:
|
||||
if self.state == PROC_DONE:
|
||||
return 1
|
||||
return 0
|
||||
|
||||
|
||||
@t.Object
|
||||
class ProcessManager:
|
||||
processes: t.CArray[Process, MAX_PROCESSES]
|
||||
current_pid: t.CInt
|
||||
count: t.CInt
|
||||
|
||||
def __init__():
|
||||
global _proc_mgr_ptr
|
||||
_proc_mgr_ptr = c.Addr(_proc_mgr)
|
||||
m: ProcessManager | t.CPtr = _proc_mgr_ptr
|
||||
m.current_pid = 0
|
||||
m.count = 1
|
||||
p: Process | t.CPtr = c.Addr(m.processes[0])
|
||||
p.pid = 0
|
||||
p.state = PROC_RUNNING
|
||||
p.thread_count = 0
|
||||
p.pml4_root = 0
|
||||
p.entry = None
|
||||
p.elf_base = 0
|
||||
p.heap_start = 0
|
||||
p.heap_size = 0
|
||||
name_str: str = "kernel"
|
||||
i: t.CInt = 0
|
||||
for ch in name_str:
|
||||
if i >= 31: break
|
||||
p.name[i] = ch
|
||||
i += 1
|
||||
p.name[i] = 0
|
||||
j: t.CInt
|
||||
for j in range(MAX_PROC_THREADS):
|
||||
p.threads[j] = -1
|
||||
for j in range(PROC_MAX_FDS):
|
||||
p.fd_used[j] = 0
|
||||
p.fd_table[j] = t.CVoid(0, t.CPtr)
|
||||
for j in range(PROC_MAX_DIRS):
|
||||
p.dir_used[j] = 0
|
||||
p.dir_table[j] = t.CVoid(0, t.CPtr)
|
||||
c.Asm(f"""mov {c.AsmOut(p.pml4_root, t.ASM_DESCR.OUTPUT_REG)}, cr3""",
|
||||
op=[t.ASM_DESCR.CLOBBER_MEMORY])
|
||||
|
||||
@staticmethod
|
||||
def _switch(pid: t.CInt) -> t.CInt:
|
||||
global _saved_cr3
|
||||
m: ProcessManager | t.CPtr = _proc_mgr_ptr
|
||||
if pid < 0 or pid >= m.count: return -1
|
||||
p: Process | t.CPtr = c.Addr(m.processes[pid])
|
||||
if p.state == PROC_DONE: return -1
|
||||
old_pid: t.CInt = m.current_pid
|
||||
if old_pid == pid: return 0
|
||||
if old_pid >= 0 and old_pid < m.count:
|
||||
m.processes[old_pid].state = PROC_READY
|
||||
p.state = PROC_RUNNING
|
||||
m.current_pid = pid
|
||||
c.Asm(f"""mov {c.AsmOut(_saved_cr3, t.ASM_DESCR.OUTPUT_REG)}, cr3
|
||||
mov rax, {c.AsmInp(p.pml4_root, t.ASM_DESCR.REG_ANY)}
|
||||
mov cr3, rax""",
|
||||
op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RAX])
|
||||
return 0
|
||||
|
||||
@staticmethod
|
||||
def current() -> Process | t.CPtr:
|
||||
m: ProcessManager | t.CPtr = _proc_mgr_ptr
|
||||
return c.Addr(m.processes[m.current_pid])
|
||||
|
||||
@staticmethod
|
||||
def get_process(pid: t.CInt) -> Process | t.CPtr:
|
||||
m: ProcessManager | t.CPtr = _proc_mgr_ptr
|
||||
if pid < 0 or pid >= m.count: return None
|
||||
return c.Addr(m.processes[pid])
|
||||
|
||||
@staticmethod
|
||||
def create_process(name: str, entry: t.CVoid | t.CPtr) -> Process | t.CPtr:
|
||||
m: ProcessManager | t.CPtr = _proc_mgr_ptr
|
||||
_dbp: t.CArray[t.CChar, 80]
|
||||
viperlib.snprintf(c.Addr(_dbp), 80, "[process] create_process count=%d MAX=%d\n", m.count, MAX_PROCESSES)
|
||||
serial.puts(_dbp)
|
||||
if m.count >= MAX_PROCESSES: return None
|
||||
pid: t.CInt = m.count
|
||||
m.count += 1
|
||||
p: Process | t.CPtr = c.Addr(m.processes[pid])
|
||||
p.pid = pid
|
||||
p.state = PROC_READY
|
||||
p.entry = entry
|
||||
p.elf_base = 0
|
||||
p.thread_count = 0
|
||||
p.heap_start = 0
|
||||
p.heap_size = 0
|
||||
string.memset(c.Addr(p.name), 0, 32)
|
||||
i: t.CInt = 0
|
||||
for ch in name:
|
||||
if i >= 31: break
|
||||
p.name[i] = ch
|
||||
i += 1
|
||||
p.name[i] = 0
|
||||
j: t.CInt
|
||||
for j in range(MAX_PROC_THREADS):
|
||||
p.threads[j] = -1
|
||||
for j in range(PROC_MAX_FDS):
|
||||
p.fd_used[j] = 0
|
||||
p.fd_table[j] = t.CVoid(0, t.CPtr)
|
||||
for j in range(PROC_MAX_DIRS):
|
||||
p.dir_used[j] = 0
|
||||
p.dir_table[j] = t.CVoid(0, t.CPtr)
|
||||
ks: t.CVoid | t.CPtr = mm_mm.malloc(KERN_STACK_SIZE)
|
||||
if ks is None:
|
||||
serial.puts("[process] kernel stack alloc failed\n")
|
||||
m.count = m.count - 1
|
||||
return None
|
||||
ks_size: t.CUInt64T = KERN_STACK_SIZE
|
||||
p.kern_stack = t.CUInt64T(ks) + ks_size
|
||||
us: t.CVoid | t.CPtr = mm_mm.malloc(USER_STACK_SIZE)
|
||||
if us is None:
|
||||
serial.puts("[process] user stack alloc failed\n")
|
||||
mm_mm.free(ks)
|
||||
m.count = m.count - 1
|
||||
return None
|
||||
us_size: t.CUInt64T = USER_STACK_SIZE
|
||||
p.user_stack = t.CUInt64T(us) + us_size
|
||||
c.Asm(f"""mov {c.AsmOut(p.pml4_root, t.ASM_DESCR.OUTPUT_REG)}, cr3""",
|
||||
op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RAX])
|
||||
return p
|
||||
|
||||
|
||||
_proc_mgr: ProcessManager = ProcessManager()
|
||||
_proc_mgr_ptr: ProcessManager | t.CPtr = c.Addr(_proc_mgr)
|
||||
_saved_cr3: t.CUInt64T
|
||||
|
||||
def current() -> t.CInt:
|
||||
m: ProcessManager | t.CPtr = _proc_mgr_ptr
|
||||
return m.current_pid
|
||||
|
||||
def switch_pid(new_pid: t.CInt):
|
||||
m: ProcessManager | t.CPtr = _proc_mgr_ptr
|
||||
if m.current_pid == new_pid: return
|
||||
if m.current_pid >= 0 and m.current_pid < m.count:
|
||||
old_p: Process | t.CPtr = c.Addr(m.processes[m.current_pid])
|
||||
if old_p.state != PROC_DONE:
|
||||
old_p.state = PROC_READY
|
||||
if new_pid >= 0 and new_pid < m.count:
|
||||
new_p: Process | t.CPtr = c.Addr(m.processes[new_pid])
|
||||
new_p.state = PROC_RUNNING
|
||||
new_cr3: t.CUInt64T = new_p.pml4_root
|
||||
if new_cr3 != 0:
|
||||
c.Asm(f"mov cr3, {c.AsmInp(new_cr3, t.ASM_DESCR.REG_ANY)}",
|
||||
op=[t.ASM_DESCR.CLOBBER_MEMORY])
|
||||
paging.set_active_pml4(new_cr3)
|
||||
# Update TSS RSP0 and GS kernel_rsp0 for the new process
|
||||
# This is needed so interrupts from Ring 3 use the correct kernel stack
|
||||
if new_p.kern_stack != 0:
|
||||
gdt.set_tss_rsp0(new_p.kern_stack)
|
||||
cpu.set_kernel_rsp0(new_p.kern_stack)
|
||||
m.current_pid = new_pid
|
||||
|
||||
def get_pid(tid: t.CInt) -> t.CInt:
|
||||
m: ProcessManager | t.CPtr = _proc_mgr_ptr
|
||||
i: t.CInt
|
||||
for i in range(m.count):
|
||||
p: Process | t.CPtr = c.Addr(m.processes[i])
|
||||
j: t.CInt
|
||||
for j in range(p.thread_count):
|
||||
if p.threads[j] == tid:
|
||||
return p.pid
|
||||
return -1
|
||||
|
||||
def drop_to_user_mode(entry: t.CVoid | t.CPtr, user_rsp: t.CUInt64T, kern_rsp: t.CUInt64T):
|
||||
# NOTE: Do NOT swapgs here. This OS uses reverse GS convention:
|
||||
# GS_BASE = 0 (kernel & user), KERNEL_GS_BASE = &_per_cpu
|
||||
# syscall/ISR entry does swapgs to get GS_BASE = &_per_cpu
|
||||
# syscall/ISR return does swapgs to restore GS_BASE = 0
|
||||
# GS state is restored in isrCommonhandler before _yield() if needed.
|
||||
c.Asm(f"""cli
|
||||
mov rsp, {c.AsmInp(kern_rsp, t.ASM_DESCR.REG_ANY)}
|
||||
mov rdx, {c.AsmInp(user_rsp, t.ASM_DESCR.REG_ANY)}
|
||||
mov rcx, {c.AsmInp(entry, t.ASM_DESCR.REG_ANY)}
|
||||
mov r11, 0x202
|
||||
push 0x23
|
||||
push rdx
|
||||
push r11
|
||||
push 0x1B
|
||||
push rcx
|
||||
iretq""",
|
||||
op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RAX,
|
||||
t.ASM_DESCR.CLOBBER_RCX, t.ASM_DESCR.CLOBBER_RDX,
|
||||
t.ASM_DESCR.CLOBBER_R11, t.ASM_DESCR.CLOBBER_RSI,
|
||||
t.ASM_DESCR.CLOBBER_RDI, t.ASM_DESCR.CLOBBER_R8,
|
||||
t.ASM_DESCR.CLOBBER_R9, t.ASM_DESCR.CLOBBER_R10,
|
||||
t.ASM_DESCR.CLOBBER_RBP])
|
||||
Reference in New Issue
Block a user