Files
ViperOS/VKernel/Kernel/intr/syscall.vp
T
TermiNexus dcb7c5c2c0 chore(ViperOS): 落库内核侧进行中的改动(26 文件,+1573/-1805)
内容由用户产出,本次仅代为提交、未做任何语义修改;含 static 修饰符前置迁移等(新增 static 前缀 16 行)。提交消息为中性描述——如需更精确的说明请 amend。
2026-09-28 15:24:52 +08:00

475 lines
15 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import drivers.serial.uart.serial as serial
import services.desktop as desktop
import drivers.fs.fat32.fat32 as fat32
import drivers.fs.fat32.fat32_types as fat32_types
import sched.sched as sched
import sched.process as process
import viperlib
import string
import mm.mm as mm
import paging.paging as paging
import execrunner.elf as elf
define CREATE_WINDOW = 1
define DRAW_TEXT = 2
define EXIT = 3
define OPEN = 4
define CLOSE = 5
define READ = 6
define WRITE = 7
define SEEK = 8
define TELL = 9
define SIZE = 10
define MKDIR = 11
define REMOVE = 12
define OPENDIR = 13
define READDIR = 14
define CLOSEDIR = 15
define STAT = 16
define WAIT_WINDOW = 17
define SERIAL_PUTS = 18
define LOAD_SO = 19
define SO_CALL1 = 20
define GET_WINBUF = 21
define WIN_FLUSH = 22
define POLL_EVENT = 23
define SET_CURSOR = 24
define YIELD = 25
define SET_TITLE = 26
define SET_GEOMETRY = 27
define SPAWN = 28
define MMAP = 29
define MUNMAP = 30
define SET_RESIZABLE = 31
define GET_WIN_SIZE = 32
define THREAD_CREATE = 33
define IA32_EFER = 0xC0000080
define IA32_STAR = 0xC0000081
define IA32_LSTAR = 0xC0000082
define IA32_FMASK = 0xC0000084
def wrmsr(msr: uint32, val: uint64):
lo: uint32 = uint32(val & 0xFFFFFFFF)
hi: uint32 = uint32(val >> 32)
__asm__(f"""mov ecx, {asminp(msr, ASM_DESCR.REG_ANY)}
mov eax, {asminp(lo, ASM_DESCR.REG_ANY)}
mov edx, {asminp(hi, ASM_DESCR.REG_ANY)}
wrmsr""",
op=[ASM_DESCR.CLOBBER_RCX, ASM_DESCR.CLOBBER_RAX, ASM_DESCR.CLOBBER_RDX])
def rdmsr(msr: uint32) -> uint64:
lo: uint32
hi: uint32
# rdmsr 固定写 EDX:EAX;out 绑定 + CLOBBER_RAX/RDX 冲突会导致 lo/hi
# 分配到非 EAX/EDX 读到垃圾。显式 mov 到输出寄存器(与 asm.inb 修复同模式)。
__asm__(f"""mov ecx, {asminp(msr, ASM_DESCR.REG_ANY)}
rdmsr
mov {asmout(lo, ASM_DESCR.OUTPUT_REG)}, eax
mov {asmout(hi, ASM_DESCR.OUTPUT_REG)}, edx""",
out=[asmout(lo, ASM_DESCR.OUTPUT_REG), asmout(hi, ASM_DESCR.OUTPUT_REG)],
op=[ASM_DESCR.CLOBBER_RCX, ASM_DESCR.CLOBBER_RAX, ASM_DESCR.CLOBBER_RDX])
return uint64(lo) | (uint64(hi) << 32)
def _current_proc() -> process.Process*:
return process.ProcessManager.current()
def _fd_alloc(p: process.Process*) -> int:
for i in range(process.PROC_MAX_FDS):
if not p.fd_used[i]:
p.fd_used[i] = 1
return i
return -1
def _fd_free(p: process.Process*, fd: int):
if fd >= 0 and fd < process.PROC_MAX_FDS:
p.fd_used[fd] = None
p.fd_table[fd] = None
def _dir_alloc(p: process.Process*) -> int:
for i in range(process.PROC_MAX_DIRS):
if not p.dir_used[i]:
p.dir_used[i] = 1
return i
return -1
def _dir_free(p: process.Process*, dd: int):
if dd >= 0 and dd < process.PROC_MAX_DIRS:
p.dir_used[dd] = None
p.dir_table[dd] = None
def CREATE_WINDOW(x: int, y: int, w: int, h: int, title: const str, style: int) -> int:
desktop.set_app_pid(process.current())
return desktop.create(x, y, w, h, title, style)
def DRAW_TEXT(win_id: int, x: int, y: int, text: const str, color: uint32) -> int:
return desktop.draw_text(win_id, x, y, text, color)
def EXIT(code: int) -> int:
serial.puts("[syscall] exit called\n")
desktop.destroy_by_pid(process.current())
return 0
def WAIT_WINDOW(win_id: int) -> int:
while desktop.is_active(win_id):
sched.Scheduler.try_reschedule()
return 0
def SERIAL_PUTS(str_ptr: str) -> int:
s: const str = str_ptr
serial.puts(s)
return 0
_loaded_so_base: rawptr = None
_loaded_so_path: [64]char
def LOAD_SO(path_ptr: str) -> uint64:
global _loaded_so_base
path: const str = path_ptr
serial.puts("[so] loading: ")
serial.puts(path)
serial.puts("\n")
base: rawptr = elf.load_so(path)
if base is not None:
_loaded_so_base = base
for i in range(63):
ch: char = path[i]
_loaded_so_path[i] = ch
if ch == 0: break
_loaded_so_path[63] = 0
return uint64(base)
return 0
def SO_CALL1(sym_name_ptr: str, arg1: rawptr) -> int:
if _loaded_so_base is None: return -1
sym_name: const str = sym_name_ptr
fn: rawptr = elf.get_so_symbol(_loaded_so_base, sym_name, &_loaded_so_path[0])
if fn is None:
serial.puts("[so] symbol not found\n")
return -2
__asm__(f"""mov rdi, {asminp(arg1, ASM_DESCR.REG_ANY)}
call {asminp(fn, ASM_DESCR.REG_ANY)}""",
op=[ASM_DESCR.CLOBBER_MEMORY, ASM_DESCR.CLOBBER_RAX,
ASM_DESCR.CLOBBER_RCX, ASM_DESCR.CLOBBER_RDX,
ASM_DESCR.CLOBBER_RDI, ASM_DESCR.CLOBBER_RSI,
ASM_DESCR.CLOBBER_R8, ASM_DESCR.CLOBBER_R9,
ASM_DESCR.CLOBBER_R10, ASM_DESCR.CLOBBER_R11])
serial.puts("[so] call returned\n")
return 0
def GET_WINBUF(win_id: int) -> uint64:
buf: rawptr = desktop.get_fb(win_id)
if buf is None:
return 0
return uint64(buf)
def WIN_FLUSH(win_id: int) -> int:
desktop.flush(win_id)
return 0
def SET_CURSOR(win_id: int, cursor_t: int) -> int:
desktop.set_cursor_type(win_id, cursor_t)
return 0
def OPEN(path_ptr: str, mode: uint32) -> int:
p: process.Process* = _current_proc()
path: const str = path_ptr
fat32.lock()
fp: rawptr = fat32.open(path, uint8(mode))
if not fp:
fat32.unlock()
return -1
fd: int = _fd_alloc(p)
if fd < 0:
fat32.close(fp)
fat32.unlock()
return -1
p.fd_table[fd] = fp
fat32.unlock()
return fd
def CLOSE(fd: int) -> int:
p: process.Process* = _current_proc()
if fd < 0 or fd >= process.PROC_MAX_FDS:
return int(fat32_types.FRESULT.FR_INVALID_OBJECT)
fp: rawptr = p.fd_table[fd]
if not fp:
return int(fat32_types.FRESULT.FR_INVALID_OBJECT)
fat32.lock()
res: int = int(fat32.close(fp))
fat32.unlock()
_fd_free(p, fd)
return res
def READ(fd: int, buf_ptr: rawptr, count: uint32) -> int:
p: process.Process* = _current_proc()
if fd < 0 or fd >= process.PROC_MAX_FDS:
return -1
fp: rawptr = p.fd_table[fd]
if not fp:
return -1
fat32.lock()
br: uint32 = fat32.read(fp, buf_ptr, count)
fat32.unlock()
return int(br)
def WRITE(fd: int, buf_ptr: rawptr, count: uint32) -> int:
p: process.Process* = _current_proc()
if fd < 0 or fd >= process.PROC_MAX_FDS:
return -1
fp: rawptr = p.fd_table[fd]
if not fp:
return -1
fat32.lock()
bw: uint32 = fat32.write(fp, buf_ptr, count)
fat32.unlock()
return int(bw)
def SEEK(fd: int, offset: uint32) -> int:
p: process.Process* = _current_proc()
if fd < 0 or fd >= process.PROC_MAX_FDS:
return int(fat32_types.FRESULT.FR_INVALID_OBJECT)
fp: rawptr = p.fd_table[fd]
if not fp:
return int(fat32_types.FRESULT.FR_INVALID_OBJECT)
fat32.lock()
r: int = int(fat32.seek(fp, offset))
fat32.unlock()
return r
def TELL(fd: int) -> uint32:
p: process.Process* = _current_proc()
if fd < 0 or fd >= process.PROC_MAX_FDS:
return 0
fp: rawptr = p.fd_table[fd]
if not fp:
return 0
fat32.lock()
pos: uint32 = fat32.tell(fp)
fat32.unlock()
return pos
def fsize(fd: int) -> uint32:
p: process.Process* = _current_proc()
if fd < 0 or fd >= process.PROC_MAX_FDS:
return 0
fp: rawptr = p.fd_table[fd]
if not fp:
return 0
fat32.lock()
sz: uint32 = fat32.size(fp)
fat32.unlock()
return sz
def MKDIR(path_ptr: str) -> int:
path: const str = path_ptr
fat32.lock()
r: int = int(fat32.mkdir(path))
fat32.unlock()
return r
def REMOVE(path_ptr: str) -> int:
path: const str = path_ptr
fat32.lock()
r: int = int(fat32.remove(path))
fat32.unlock()
return r
def OPENdir(path_ptr: str) -> int:
p: process.Process* = _current_proc()
path: const str = path_ptr
dd: int = _dir_alloc(p)
if dd < 0:
return -1
dp: fat32_types.dirobj* = &p.dir_pool[dd]
fat32.lock()
res: int = int(fat32.opendir(path, dp))
fat32.unlock()
if res != 0:
_dir_free(p, dd)
return -1
p.dir_table[dd] = rawptr(uint64(dp))
return dd
def READdir(dd: int, info_ptr: rawptr) -> int:
p: process.Process* = _current_proc()
if dd < 0 or dd >= process.PROC_MAX_DIRS:
return int(fat32_types.FRESULT.FR_INVALID_OBJECT)
dp: rawptr = p.dir_table[dd]
if not dp:
return int(fat32_types.FRESULT.FR_INVALID_OBJECT)
info: fat32_types.fileinfo* = info_ptr
fat32.lock()
r: int = int(fat32.readdir(dp, info))
fat32.unlock()
return r
def CLOSEdir(dd: int) -> int:
p: process.Process* = _current_proc()
if dd < 0 or dd >= process.PROC_MAX_DIRS:
return int(fat32_types.FRESULT.FR_INVALID_OBJECT)
dp: rawptr = p.dir_table[dd]
if not dp:
return int(fat32_types.FRESULT.FR_INVALID_OBJECT)
fat32.lock()
fat32.closedir(dp)
fat32.unlock()
_dir_free(p, dd)
return 0
def STAT(path_ptr: str, info_ptr: rawptr) -> int:
path: const str = path_ptr
info: fat32_types.fileinfo* = info_ptr
fat32.lock()
r: int = int(fat32.stat(path, info))
fat32.unlock()
return r
def SPAWN(path_ptr: str, blocking: int) -> int:
path: const str = path_ptr
pid: int = elf.spawn_elf(path)
if pid < 0:
return pid
if blocking:
p: process.Process* = process.ProcessManager.get_process(pid)
if p:
while p.state != process.PROC_DONE:
sched.Scheduler.try_reschedule()
return pid
define USER_HEAP_BASE = 0x20000000
def MMAP(size: uint64) -> uint64:
p: process.Process* = _current_proc()
if size == 0: return 0
aligned_size: uint64 = (size + 4095) & ~uint64(4095)
if p.heap_start == 0:
p.heap_start = USER_HEAP_BASE
heap_end: uint64 = p.heap_start + p.heap_size
new_end: uint64 = heap_end + aligned_size
for va in range(heap_end, new_end, 4096):
phys_page: rawptr = mm.malloc(4096)
if phys_page is None: return 0
paging.MapPage(va, uint64(phys_page), paging.PTE_PRESENT | paging.PTE_WRITABLE | paging.PTE_USER)
p.heap_size = p.heap_size + aligned_size
return heap_end
def MUNMAP(ptr: uint64, size: uint64) -> int:
return 0
extern def syscall_entry()
export def syscall_handler(num: uint64, arg1: uint64, arg2: uint64, arg3: uint64, arg4: uint64, arg5: uint64, arg6: uint64) -> uint64:
n: int = int(num)
if n == CREATE_WINDOW:
title_ptr: str = str(arg5)
return uint64(CREATE_WINDOW(int(arg1), int(arg2), int(arg3), int(arg4), title_ptr, int(arg6)))
elif n == DRAW_TEXT:
text_ptr: str = str(arg4)
return uint64(DRAW_TEXT(int(arg1), int(arg2), int(arg3), text_ptr, uint32(arg5)))
elif n == EXIT:
return uint64(EXIT(int(arg1)))
elif n == OPEN:
path_ptr: str = str(arg1)
return uint64(OPEN(path_ptr, uint32(arg2)))
elif n == CLOSE:
return uint64(CLOSE(int(arg1)))
elif n == READ:
buf_ptr: rawptr = rawptr(arg2)
return uint64(READ(int(arg1), buf_ptr, uint32(arg3)))
elif n == WRITE:
buf_ptr: rawptr = rawptr(arg2)
return uint64(WRITE(int(arg1), buf_ptr, uint32(arg3)))
elif n == SEEK:
return uint64(SEEK(int(arg1), uint32(arg2)))
elif n == TELL:
return uint64(TELL(int(arg1)))
elif n == SIZE:
return uint64(fsize(int(arg1)))
elif n == MKDIR:
path_ptr: str = str(arg1)
return uint64(MKDIR(path_ptr))
elif n == REMOVE:
path_ptr: str = str(arg1)
return uint64(REMOVE(path_ptr))
elif n == OPENDIR:
path_ptr: str = str(arg1)
return uint64(OPENdir(path_ptr))
elif n == READDIR:
info_ptr: rawptr = rawptr(arg2)
return uint64(READdir(int(arg1), info_ptr))
elif n == CLOSEDIR:
return uint64(CLOSEdir(int(arg1)))
elif n == STAT:
path_ptr: str = str(arg1)
info_ptr: rawptr = rawptr(arg2)
return uint64(STAT(path_ptr, info_ptr))
elif n == WAIT_WINDOW:
if int(arg2) == 1:
return uint64(desktop.is_active(int(arg1)))
elif int(arg2) == 2:
sched.Scheduler.try_reschedule()
return 0
return uint64(WAIT_WINDOW(int(arg1)))
elif n == SERIAL_PUTS:
str_ptr_sp: str = str(arg1)
return uint64(SERIAL_PUTS(str_ptr_sp))
elif n == LOAD_SO:
path_ptr_so: rawptr = rawptr(arg1)
return LOAD_SO(path_ptr_so)
elif n == SO_CALL1:
sym_ptr: rawptr = rawptr(arg1)
return uint64(SO_CALL1(sym_ptr, rawptr(arg2)))
elif n == GET_WINBUF:
return GET_WINBUF(int(arg1))
elif n == WIN_FLUSH:
return uint64(WIN_FLUSH(int(arg1)))
elif n == POLL_EVENT:
buf_ptr_ev: rawptr = rawptr(arg1)
caller_pid_ev: int = process.current()
return uint64(desktop.poll_event(buf_ptr_ev, caller_pid_ev))
elif n == SET_CURSOR:
desktop.set_cursor_type(int(arg1), int(arg2))
return 0
elif n == YIELD:
sched.Scheduler.try_reschedule()
return 0
elif n == SET_TITLE:
title_ptr_st: rawptr = rawptr(arg2)
return uint64(desktop.set_title(int(arg1), title_ptr_st))
elif n == SET_GEOMETRY:
return uint64(desktop.set_geometry(int(arg1), int(arg2), int(arg3), int(arg4), int(arg5)))
elif n == SET_RESIZABLE:
return uint64(desktop.set_resizable(int(arg1), int(arg2), int(arg3)))
elif n == GET_WIN_SIZE:
return uint64(desktop.get_size(int(arg1)))
elif n == SPAWN:
path_ptr_sp: rawptr = rawptr(arg1)
return uint64(SPAWN(path_ptr_sp, int(arg2)))
elif n == MMAP:
return MMAP(arg1)
elif n == MUNMAP:
return uint64(MUNMAP(arg1, arg2))
elif n == THREAD_CREATE:
func_ptr: rawptr = rawptr(arg1)
arg_ptr: rawptr = rawptr(arg2)
cur_pid: int = process.current()
th: sched.Thread* = sched.Scheduler.create_thread(func_ptr, arg_ptr, cur_pid)
if th is None: return uint64(0xFFFFFFFFFFFFFFFF)
p: process.Process* = process.ProcessManager.get_process(cur_pid)
if p:
p.addThread(th.tid)
return uint64(th.tid)
return 0
def init():
efer: uint64 = rdmsr(IA32_EFER)
efer = efer | 1
wrmsr(IA32_EFER, efer)
star_val: uint64 = (uint64(0x08) << 32) | (uint64(0x1B) << 48)
wrmsr(IA32_STAR, star_val)
wrmsr(IA32_LSTAR, uint64(syscall_entry))
wrmsr(IA32_FMASK, 0x200)
serial.puts("[syscall] MSR init done\n")