内核 MMAP(addr,length,prot,flags,fd,offset):fd=-1 + MAP_ANONYMOUS 走匿名映射(分配物理页、清零后映射到本进程新 VA,对齐 Linux"匿名必为零"语义);fd 是带 mmap_info 的 devfs 设备(当前仅 /dev/fb0)则把 [phys+offset, phys+offset+len) 按页映射进调用者地址空间(PTE_USER|WRITE)。addr/MAP_FIXED 暂未实现,一律由内核挑 VA 并返回真实起始地址。新增 PROT_*/MAP_*/MMAP_FD_ANON 常量。 参数次序与 Linux mmap 完全一致(rdi/rsi/rdx/r10/r8/r9),syscall_entry 的搬运顺序本就是这个约定,SDK 侧 vpsdk/syscall.vp 加 mmap() 助手走 _syscall6。stdlib.malloc 随之改为匿名映射调用(fd=-1、MAP_PRIVATE|MAP_ANONYMOUS、PROT_READ|PROT_WRITE),行为与原 MMAP(size) 一致且多一层清零。
601 lines
24 KiB
Plaintext
601 lines
24 KiB
Plaintext
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
|
||
import drivers.devfs.devfs as devfs
|
||
|
||
|
||
# ============================================================================
|
||
# 系统调用号表(唯一权威来源)。与 Linux x86-64 ABI **同名同号**:
|
||
# · Linux 有同名调用 → 直接用它的号;Linux 有而我们未实现的**留空不占号**
|
||
# (12 brk / 39 getpid / 84 rmdir / 217 getdents64 / 257 openat … 需要时按号补上);
|
||
# · 我们独有的能力**不再新增 syscall**,一律走 devfs 设备文件(open/read/write)
|
||
# 或下沉到用户层(见下面「临时私有段」的逐条迁移标注)。
|
||
# 注意:vpsdk/syscall.vp 有一份逐字对应的镜像(vpsdk 不允许依赖 VKernel),
|
||
# 增删/改号/改名必须两边同步。
|
||
# ============================================================================
|
||
enum Syscall:
|
||
# ---- Linux 对齐段(号 = Linux x86-64 的号)----
|
||
READ = 0 # read(fd, buf, count)
|
||
WRITE = 1 # write(fd, buf, count)
|
||
OPEN = 2 # open(path, flags)
|
||
CLOSE = 3 # close(fd)
|
||
STAT = 4 # stat(path, info)(结构体仍是本系统的 fileinfo)
|
||
SEEK = 8 # lseek(fd, offset, whence)(whence 目前恒 0 = SEEK_SET)
|
||
MMAP = 9 # mmap(size) → VA(ABI 待向 Linux 的 addr/len/prot/flags/fd/off 靠拢)
|
||
MUNMAP = 11 # munmap(ptr, size)(目前空实现)
|
||
IOCTL = 16 # ioctl(fd, request, arg):设备控制(当前用于 /dev/fb0 查几何)
|
||
YIELD = 24 # sched_yield()
|
||
THREAD_CREATE = 56 # clone():建用户线程,返回 tid
|
||
SPAWN = 59 # execve():加载并运行新 ELF,返回 pid
|
||
THREAD_EXIT = 60 # exit():退役当前线程
|
||
MKDIR = 83 # mkdir(path)
|
||
REMOVE = 87 # unlink(path)
|
||
EXIT = 231 # exit_group():退役当前线程 + 拆掉本 pid 的窗口
|
||
# ---- 临时私有段(0x1000+):Linux 无对应,且**逐条都会被消掉** ----
|
||
# 目标形态:私有能力不占 syscall 号 → 改 devfs 设备文件;UI 11 个 → 由用户态
|
||
# explorer(图形壳)接管 framebuffer 与输入后删除。当前保留只为让现有 app 还能跑。
|
||
SERIAL_PUTS = 0x1000 # TODO(devfs):改为 write(/dev/serial0)
|
||
TELL = 0x1001 # TODO(linux):可由 lseek(fd, 0, SEEK_CUR) 表达
|
||
SIZE = 0x1002 # TODO(linux):可由 fstat 表达
|
||
OPENDIR = 0x1003 # TODO(linux):openat(O_DIRECTORY) + getdents64
|
||
READDIR = 0x1004 # TODO(linux):getdents64
|
||
CLOSEDIR = 0x1005 # TODO(linux):close
|
||
LOAD_SO = 0x1006 # TODO(用户层):动态库加载下沉
|
||
SO_CALL1 = 0x1007 # TODO(用户层):同上
|
||
WAIT_WINDOW = 0x1008 # TODO(explorer):UI
|
||
CREATE_WINDOW = 0x1009 # TODO(explorer):UI
|
||
DRAW_TEXT = 0x100A # TODO(explorer):UI
|
||
GET_WINBUF = 0x100B # TODO(explorer):UI
|
||
WIN_FLUSH = 0x100C # TODO(explorer):UI
|
||
POLL_EVENT = 0x100D # TODO(explorer):UI
|
||
SET_CURSOR = 0x100E # TODO(explorer):UI
|
||
SET_TITLE = 0x100F # TODO(explorer):UI
|
||
SET_GEOMETRY = 0x1010 # TODO(explorer):UI
|
||
SET_RESIZABLE = 0x1011 # TODO(explorer):UI
|
||
GET_WIN_SIZE = 0x1012 # TODO(explorer):UI
|
||
|
||
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())
|
||
# 真正的退出:退役本线程并让出,**绝不返回用户态**。
|
||
# 只 destroy 窗口不够:app 的 _start 在 process.exit(0) 之后还有 `return 0`,而内核是以
|
||
# rsp = USER_STACK_VTOP 进入 _start 的(elf.vp:379),VTOP 正是用户栈映射
|
||
# [VTOP-64K, VTOP) 的上界之外那一字节 ⇒ 一旦 _start 收尾 `ret` 就会去读 [VTOP]:
|
||
# #PF cr2=rsp=0x7fffffe00000,rip 在 _start 内,rbp=0,rax=退出码(实测现场)。
|
||
# 口径与异常终止路径一致(idt.vp 的 free_user_thread + state=THREAD_DONE + 不再回用户态)。
|
||
sched.Scheduler.exit_current_thread()
|
||
# 【硬保护】这里绝不允许返回:一旦返回就会沿调用链回到 app 的 _start 末尾,那里 `ret`
|
||
# 会弹到一个 0 返回地址并去 0 取指(现场:[0E] rip=0x0 err=0x15 = 用户态取指缺页,
|
||
# 紧随 [syscall] exit called,tid=5)。停留在此让调度器彻底不再调度本线程。
|
||
while True:
|
||
sched.Scheduler._yield()
|
||
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 _is_dev_path(path: const str) -> int:
|
||
"""路径是否以 "/dev/" 开头(走 devfs 设备节点而不是 FAT32)。逐字符比较,不引 str 库。"""
|
||
if path[0] != 47: return 0 # '/'
|
||
if path[1] != 100: return 0 # 'd'
|
||
if path[2] != 101: return 0 # 'e'
|
||
if path[3] != 118: return 0 # 'v'
|
||
if path[4] != 47: return 0 # '/'
|
||
return 1
|
||
|
||
def OPEN(path_ptr: str, mode: uint32) -> int:
|
||
p: process.Process* = _current_proc()
|
||
path: const str = path_ptr
|
||
# /dev/* 走 devfs 设备节点(serial / 输入 / fb…),其余仍走 FAT32 文件系统。
|
||
# 判据用逐字符比较(不引 str 库函数):"/dev/" = 47 '/'、100 'd'、101 'e'、118 'v'、47 '/'。
|
||
if _is_dev_path(path):
|
||
dfd: int = devfs.devfs_open(path, int(mode))
|
||
if dfd < 0:
|
||
return -1
|
||
fd: int = _fd_alloc(p)
|
||
if fd < 0:
|
||
devfs.devfs_close(dfd)
|
||
return -1
|
||
# 存 devfs_fd+1:devfs fd 0 是合法值,直接用会与"空槽位"混淆
|
||
p.fd_table[fd] = rawptr(uint64(dfd + 1))
|
||
p.fd_kind[fd] = process.FD_KIND_DEVFS
|
||
return fd
|
||
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
|
||
p.fd_kind[fd] = process.FD_KIND_FAT32
|
||
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)
|
||
if p.fd_kind[fd] == process.FD_KIND_DEVFS:
|
||
res_dev: int = devfs.devfs_close(int(uint64(fp)) - 1)
|
||
_fd_free(p, fd)
|
||
return res_dev
|
||
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
|
||
if p.fd_kind[fd] == process.FD_KIND_DEVFS:
|
||
return devfs.devfs_read(int(uint64(fp)) - 1, buf_ptr, count)
|
||
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
|
||
if p.fd_kind[fd] == process.FD_KIND_DEVFS:
|
||
return devfs.devfs_write(int(uint64(fp)) - 1, buf_ptr, count)
|
||
fat32.lock()
|
||
bw: uint32 = fat32.write(fp, buf_ptr, count)
|
||
fat32.unlock()
|
||
return int(bw)
|
||
|
||
def IOCTL(fd: int, request: uint32, arg: rawptr) -> int:
|
||
"""设备控制(Linux ioctl 的子集):当前只有 devfs 设备支持,用于 /dev/fb0 查几何。"""
|
||
p: process.Process* = _current_proc()
|
||
if fd < 0 or fd >= process.PROC_MAX_FDS:
|
||
return -1
|
||
if not p.fd_used[fd]:
|
||
return -1
|
||
if p.fd_kind[fd] != process.FD_KIND_DEVFS:
|
||
return -1
|
||
return devfs.devfs_ioctl(int(uint64(p.fd_table[fd])) - 1, request, arg)
|
||
|
||
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
|
||
|
||
# ---- mmap 的 prot / flags(值与 Linux 同名常量一致)----
|
||
define PROT_NONE = 0x0
|
||
define PROT_READ = 0x1
|
||
define PROT_WRITE = 0x2
|
||
define PROT_EXEC = 0x4
|
||
define MAP_SHARED = 0x01
|
||
define MAP_PRIVATE = 0x02
|
||
define MAP_FIXED = 0x10
|
||
define MAP_ANONYMOUS = 0x20
|
||
# fd = -1(Linux 匿名映射约定)
|
||
define MMAP_FD_ANON: uint64 = 0xFFFFFFFFFFFFFFFF
|
||
|
||
def MMAP(addr: uint64, length: uint64, prot: uint64, flags: uint64, fd: uint64, offset: uint64) -> uint64:
|
||
"""mmap(addr, length, prot, flags, fd, offset):与 Linux 同名同参。
|
||
|
||
· fd == MMAP_FD_ANON(-1) 且带 MAP_ANONYMOUS:匿名映射 —— 分配物理页、清零后映射到
|
||
本进程新 VA(对齐 Linux 的"匿名映射必为 0"语义);
|
||
· fd 是带 mmap_info 的 devfs 设备 fd(当前仅 /dev/fb0):把设备物理区间
|
||
[phys+offset, phys+offset+length) 按页映射进来(用户可读写)。
|
||
addr 与 MAP_FIXED 暂未实现:一律由内核挑 VA,返回真实起始地址。失败返回 0。
|
||
"""
|
||
p: process.Process* = _current_proc()
|
||
if length == 0: return 0
|
||
aligned: uint64 = (length + 4095) & ~uint64(4095)
|
||
if p.heap_start == 0:
|
||
p.heap_start = USER_HEAP_BASE
|
||
va: uint64 = p.heap_start + p.heap_size
|
||
if fd == MMAP_FD_ANON:
|
||
if (flags & MAP_ANONYMOUS) == 0: return 0
|
||
for off in range(0, aligned, 4096):
|
||
phys_page: rawptr = mm.malloc(4096)
|
||
if phys_page is None: return 0
|
||
string.memset(phys_page, 0, 4096)
|
||
paging.MapPage(va + off, uint64(phys_page),
|
||
paging.PTE_PRESENT | paging.PTE_WRITABLE | paging.PTE_USER)
|
||
else:
|
||
fdi: int = int(fd)
|
||
if fdi < 0 or fdi >= process.PROC_MAX_FDS: return 0
|
||
if not p.fd_used[fdi]: return 0
|
||
if p.fd_kind[fdi] != process.FD_KIND_DEVFS: return 0
|
||
dev_phys: uint64 = 0
|
||
dev_size: uint64 = 0
|
||
if devfs.devfs_get_mmap_info(int(uint64(p.fd_table[fdi])) - 1, &dev_phys, &dev_size) != 0:
|
||
return 0
|
||
if offset + aligned > dev_size: return 0
|
||
for off in range(0, aligned, 4096):
|
||
paging.MapPage(va + off, dev_phys + offset + off,
|
||
paging.PTE_PRESENT | paging.PTE_WRITABLE | paging.PTE_USER)
|
||
p.heap_size = p.heap_size + aligned
|
||
return va
|
||
|
||
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 == int(Syscall.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 == int(Syscall.DRAW_TEXT):
|
||
text_ptr: str = str(arg4)
|
||
return uint64(DRAW_TEXT(int(arg1), int(arg2), int(arg3), text_ptr, uint32(arg5)))
|
||
elif n == int(Syscall.EXIT):
|
||
return uint64(EXIT(int(arg1)))
|
||
elif n == int(Syscall.OPEN):
|
||
path_ptr: str = str(arg1)
|
||
return uint64(OPEN(path_ptr, uint32(arg2)))
|
||
elif n == int(Syscall.CLOSE):
|
||
return uint64(CLOSE(int(arg1)))
|
||
elif n == int(Syscall.READ):
|
||
buf_ptr: rawptr = rawptr(arg2)
|
||
return uint64(READ(int(arg1), buf_ptr, uint32(arg3)))
|
||
elif n == int(Syscall.WRITE):
|
||
buf_ptr: rawptr = rawptr(arg2)
|
||
return uint64(WRITE(int(arg1), buf_ptr, uint32(arg3)))
|
||
elif n == int(Syscall.IOCTL):
|
||
return uint64(IOCTL(int(arg1), uint32(arg2), rawptr(arg3)))
|
||
elif n == int(Syscall.SEEK):
|
||
return uint64(SEEK(int(arg1), uint32(arg2)))
|
||
elif n == int(Syscall.TELL):
|
||
return uint64(TELL(int(arg1)))
|
||
elif n == int(Syscall.SIZE):
|
||
return uint64(fsize(int(arg1)))
|
||
elif n == int(Syscall.MKDIR):
|
||
path_ptr: str = str(arg1)
|
||
return uint64(MKDIR(path_ptr))
|
||
elif n == int(Syscall.REMOVE):
|
||
path_ptr: str = str(arg1)
|
||
return uint64(REMOVE(path_ptr))
|
||
elif n == int(Syscall.OPENDIR):
|
||
path_ptr: str = str(arg1)
|
||
return uint64(OPENdir(path_ptr))
|
||
elif n == int(Syscall.READDIR):
|
||
info_ptr: rawptr = rawptr(arg2)
|
||
return uint64(READdir(int(arg1), info_ptr))
|
||
elif n == int(Syscall.CLOSEDIR):
|
||
return uint64(CLOSEdir(int(arg1)))
|
||
elif n == int(Syscall.STAT):
|
||
path_ptr: str = str(arg1)
|
||
info_ptr: rawptr = rawptr(arg2)
|
||
return uint64(STAT(path_ptr, info_ptr))
|
||
elif n == int(Syscall.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 == int(Syscall.SERIAL_PUTS):
|
||
str_ptr_sp: str = str(arg1)
|
||
return uint64(SERIAL_PUTS(str_ptr_sp))
|
||
elif n == int(Syscall.LOAD_SO):
|
||
path_ptr_so: rawptr = rawptr(arg1)
|
||
return LOAD_SO(path_ptr_so)
|
||
elif n == int(Syscall.SO_CALL1):
|
||
sym_ptr: rawptr = rawptr(arg1)
|
||
return uint64(SO_CALL1(sym_ptr, rawptr(arg2)))
|
||
elif n == int(Syscall.GET_WINBUF):
|
||
return GET_WINBUF(int(arg1))
|
||
elif n == int(Syscall.WIN_FLUSH):
|
||
return uint64(WIN_FLUSH(int(arg1), rawptr(arg2)))
|
||
elif n == int(Syscall.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 == int(Syscall.SET_CURSOR):
|
||
desktop.set_cursor_type(int(arg1), int(arg2))
|
||
return 0
|
||
elif n == int(Syscall.YIELD):
|
||
sched.Scheduler.try_reschedule()
|
||
return 0
|
||
elif n == int(Syscall.SET_TITLE):
|
||
title_ptr_st: rawptr = rawptr(arg2)
|
||
return uint64(desktop.set_title(int(arg1), title_ptr_st))
|
||
elif n == int(Syscall.SET_GEOMETRY):
|
||
return uint64(desktop.set_geometry(int(arg1), int(arg2), int(arg3), int(arg4), int(arg5)))
|
||
elif n == int(Syscall.SET_RESIZABLE):
|
||
return uint64(desktop.set_resizable(int(arg1), int(arg2), int(arg3)))
|
||
elif n == int(Syscall.GET_WIN_SIZE):
|
||
return uint64(desktop.get_size(int(arg1)))
|
||
elif n == int(Syscall.SPAWN):
|
||
path_ptr_sp: rawptr = rawptr(arg1)
|
||
return uint64(SPAWN(path_ptr_sp, int(arg2)))
|
||
elif n == int(Syscall.MMAP):
|
||
return MMAP(arg1, arg2, arg3, arg4, arg5, arg6)
|
||
elif n == int(Syscall.MUNMAP):
|
||
return uint64(MUNMAP(arg1, arg2))
|
||
elif n == int(Syscall.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 == int(Syscall.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")
|