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 THREAD_EXIT = 34 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, src: rawptr) -> int: """把 app 的**用户缓冲**内容拷进窗口的内核后备缓冲,再上屏。 旧设计由 GET_WINBUF 把内核缓冲地址直接交给用户态,而那片页 U=0 → app 一画就 #PF(err=0x7)。 现在 app 画在自己的用户缓冲(MMAP 分配)里,由这里 memcpy 进窗口缓冲。 """ if src is None: return -1 dst: rawptr = desktop.get_fb(win_id) # 可能按 resize 重建 → 先取指针 n: int = desktop.get_fb_bytes(win_id) # 再取尺寸,保证与刚取的指针一致 if dst is None or n <= 0: return -1 string.memcpy(dst, src, n) 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), rawptr(arg2))) 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() # app 传进来的是**用户地址**:必须用 create_user_thread(独立用户栈 + 独立内核栈、 # 走 drop_to_user_mode 进 Ring 3),不能用 create_thread 在 Ring 0 直接 call。 th: sched.Thread* = sched.Scheduler.create_user_thread(cur_pid, func_ptr, arg_ptr) 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) elif n == THREAD_EXIT: # 用户线程显式退出(回收用户栈等资源后让出,永不返回)。 sched.Scheduler.exit_current_thread() return 0 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")