diff --git a/VKernel/Kernel/drivers/devfs/devfs.vp b/VKernel/Kernel/drivers/devfs/devfs.vp index 4c96c43..d89c253 100644 --- a/VKernel/Kernel/drivers/devfs/devfs.vp +++ b/VKernel/Kernel/drivers/devfs/devfs.vp @@ -104,6 +104,9 @@ virtual class devfs_file: def read(self, fd: int, buffer: rawptr, size: uint32) -> int: return 0 def write(self, fd: int, buffer: const rawptr, size: uint32) -> int: return 0 def ioctl(self, fd: int, request: int, arg: rawptr) -> int: return 0 + # mmap 支持:默认不可映射(返回 -1)。可映射设备(/dev/fb0)覆写它, + # 把自己的物理区间交给内核 mmap 去映射进用户地址空间。 + def mmap_info(self, fd: int, out_phys: uint64*, out_size: uint64*) -> int: return -1 class _DevFSObject: @@ -272,6 +275,12 @@ class _DevFSObject: file_ptr: devfs_file* = fd_table[fd].file return file_ptr.ioctl(fd, cmd, arg) + def get_mmap_info(self, fd: int, out_phys: uint64*, out_size: uint64*) -> int: + if fd < 0 or fd >= MAX_FILE_DESCRIPTORS or not fd_table[fd].file: + return -1 + file_ptr: devfs_file* = fd_table[fd].file + return file_ptr.mmap_info(fd, out_phys, out_size) + def list_directory(self, path: const str, buffer: str, size: uint32) -> int: @@ -313,6 +322,9 @@ def devfs_write(fd: int, buffer: const rawptr, size: uint32) -> int: def devfs_ioctl(fd: int, cmd: uint32, arg: rawptr) -> int: return DevFSObject.ioctl(fd, cmd, arg) +def devfs_get_mmap_info(fd: int, out_phys: uint64*, out_size: uint64*) -> int: + return DevFSObject.get_mmap_info(fd, out_phys, out_size) + def devfs_list_directory(path: const str, buffer: str, size: uint32) -> int: return DevFSObject.list_directory(path, buffer, size) @@ -446,3 +458,72 @@ def devfs_register_mouse() -> int: mse_file.__init__() mouse.init() return devfs_create_file("/dev/input/mouse", mse_file, None) + + +# ============================================================================ +# /dev/fb0:framebuffer 设备(供用户态图形壳 explorer 接管桌面绘制)。 +# · read/write 不支持(-1):像素由用户态经 mmap 取到线性地址后直接写; +# · ioctl(FB_GET_INFO):把几何/格式/物理区间回填进用户缓冲(FbInfo); +# · mmap_info:把本设备的物理区间交给内核 mmap 映射进用户地址空间。 +# 本节点只记录 BootInfo 里的物理地址与几何,不自己持有 framebuffer 映射。 +# ============================================================================ +define FB_GET_INFO = 0x4600 + +@__attribute__(packed) +class FbInfo: + width: uint32 + height: uint32 + pitch: uint32 + format: uint32 + size: uint64 + phys: uint64 + +virtual class framebuffer_device(devfs_file): + fb_phys: uint64 + fb_size: uint64 + fb_w: uint32 + fb_h: uint32 + fb_pitch: uint32 + fb_format: uint32 + + def open(self, path: const str, flags: int) -> int: + return 0 + + def close(self, fd: int) -> int: + return 0 + + def read(self, fd: int, buffer: rawptr, size: uint32) -> int: + return -1 + + def write(self, fd: int, buffer: const rawptr, size: uint32) -> int: + return -1 + + def ioctl(self, fd: int, request: int, arg: rawptr) -> int: + if request != FB_GET_INFO or not arg: + return -1 + info: FbInfo* = FbInfo*(uint64(arg)) + info.width = self.fb_w + info.height = self.fb_h + info.pitch = self.fb_pitch + info.format = self.fb_format + info.size = self.fb_size + info.phys = self.fb_phys + return 0 + + def mmap_info(self, fd: int, out_phys: uint64*, out_size: uint64*) -> int: + if out_phys: *out_phys = self.fb_phys + if out_size: *out_size = self.fb_size + return 0 + +fb0_file: framebuffer_device* = framebuffer_device() + +def devfs_register_fb0(fb: rawptr, width: int, height: int, pitch: int, format: int, size: uint64) -> int: + global fb0_file + fb0_file.__init__() + fb0_file.fb_phys = uint64(fb) + fb0_file.fb_size = size + fb0_file.fb_w = uint32(width) + fb0_file.fb_h = uint32(height) + fb0_file.fb_pitch = uint32(pitch) + fb0_file.fb_format = uint32(format) + return devfs_create_file("/dev/fb0", fb0_file, None) diff --git a/VKernel/Kernel/intr/syscall.vp b/VKernel/Kernel/intr/syscall.vp index aa29a1f..d16e6d3 100644 --- a/VKernel/Kernel/intr/syscall.vp +++ b/VKernel/Kernel/intr/syscall.vp @@ -9,6 +9,7 @@ import string import mm.mm as mm import paging.paging as paging import execrunner.elf as elf +import drivers.devfs.devfs as devfs # ============================================================================ @@ -29,7 +30,8 @@ enum Syscall: 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)(目前空实现) + 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 @@ -209,9 +211,32 @@ 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: @@ -223,6 +248,7 @@ def OPEN(path_ptr: str, mode: uint32) -> int: fat32.unlock() return -1 p.fd_table[fd] = fp + p.fd_kind[fd] = process.FD_KIND_FAT32 fat32.unlock() return fd @@ -233,6 +259,10 @@ def CLOSE(fd: int) -> int: 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() @@ -246,6 +276,8 @@ def READ(fd: int, buf_ptr: rawptr, count: uint32) -> int: 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() @@ -258,11 +290,24 @@ def WRITE(fd: int, buf_ptr: rawptr, count: uint32) -> int: 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: @@ -418,6 +463,8 @@ export def syscall_handler(num: uint64, arg1: uint64, arg2: uint64, arg3: uint64 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): diff --git a/VKernel/Kernel/main.vp b/VKernel/Kernel/main.vp index da61a7e..7bf493f 100644 --- a/VKernel/Kernel/main.vp +++ b/VKernel/Kernel/main.vp @@ -284,6 +284,9 @@ class ViperKernel: devfs.devfs_register_serial1() devfs.devfs_register_keyboard() devfs.devfs_register_mouse() + # /dev/fb0:把 framebuffer 的物理区间与几何登记成设备节点,供用户态图形壳 + # explorer 经 open + ioctl(FB_GET_INFO) + mmap 接管屏幕绘制(S1)。 + devfs.devfs_register_fb0(fb, width, height, pitch, fb_format, fb_size) serial.puts("[main] sched started\n") diff --git a/VKernel/Kernel/sched/process.vp b/VKernel/Kernel/sched/process.vp index 2d23c2f..4898758 100644 --- a/VKernel/Kernel/sched/process.vp +++ b/VKernel/Kernel/sched/process.vp @@ -14,7 +14,12 @@ define PROC_BLOCKED = 2 define PROC_DONE = 3 define MAX_PROCESSES = 8 define MAX_PROC_THREADS = 8 -define PROC_MAX_FDS = 16 +define PROC_MAX_FDS = 16 +# fd 种类(process.fd_kind[])。定义放这里、由 intr/syscall.vp 以 process.FD_KIND_* 引用, +# 这样 process.vp 不必 import devfs —— devfs → keyboard/mouse → intr.idt → sched → process +# 会形成环,不能让 process 反向依赖 devfs。 +define FD_KIND_FAT32 = 0 +define FD_KIND_DEVFS = 1 define PROC_MAX_DIRS = 8 define KERN_STACK_SIZE = 8192 define USER_STACK_SIZE = 65536 @@ -39,6 +44,10 @@ class Process: name: [32]char fd_table: [PROC_MAX_FDS]rawptr fd_used: [PROC_MAX_FDS]uint8 + # 0 = FAT32 文件(fd_table[i] 里是 fileobj*);1 = devfs 设备(fd_table[i] 里是 + # devfs_fd+1,+1 只为避开"devfs fd 0"与空指针的歧义)。READ/WRITE/CLOSE/IOCTL 与 + # Process.exit 都必须按它分派 —— 把 devfs fd 当 fileobj* 解引用会直接跑飞。 + fd_kind: [PROC_MAX_FDS]uint8 dir_table: [PROC_MAX_DIRS]rawptr dir_used: [PROC_MAX_DIRS]uint8 dir_pool: [PROC_MAX_DIRS]fat32_types.dirobj @@ -56,10 +65,15 @@ class Process: for i in range(PROC_MAX_FDS): if self.fd_used[i]: fp: rawptr = self.fd_table[i] - if fp: + # devfs 设备 fd 绝不能当 fileobj* 交给 fat32.close —— 那会把 devfs_fd+1 + # 当指针解引用而跑飞。devfs 的 fd 表是独立的另一张;正规退出路径本来就不 + # 回收 fd(见 intr/syscall.vp 的 EXIT 不调 Process.exit),这里只清槽位, + # app 自己调 CLOSE 时才走 devfs_close。 + if fp and self.fd_kind[i] == FD_KIND_FAT32: fat32.close(fp) self.fd_used[i] = 0 self.fd_table[i] = None + self.fd_kind[i] = 0 for i in range(PROC_MAX_DIRS): if self.dir_used[i]: dp: rawptr = self.dir_table[i] @@ -117,6 +131,7 @@ class ProcessManager: for j in range(PROC_MAX_FDS): p.fd_used[j] = 0 p.fd_table[j] = None + p.fd_kind[j] = 0 for j in range(PROC_MAX_DIRS): p.dir_used[j] = 0 p.dir_table[j] = None @@ -179,6 +194,7 @@ class ProcessManager: for j in range(PROC_MAX_FDS): p.fd_used[j] = 0 p.fd_table[j] = None + p.fd_kind[j] = 0 for j in range(PROC_MAX_DIRS): p.dir_used[j] = 0 p.dir_table[j] = None diff --git a/vpsdk/fs.vp b/vpsdk/fs.vp index 873604d..bb26b0d 100644 --- a/vpsdk/fs.vp +++ b/vpsdk/fs.vp @@ -55,6 +55,10 @@ def closedir(dd: int) -> int: def stat(path: const str, info: rawptr) -> int: return int(syscall._syscall3(uint64(syscall.Syscall.STAT), uint64(path), uint64(info), 0)) +def ioctl(fd: int, request: uint32, arg: rawptr) -> int: + """设备控制(Linux ioctl 子集)。当前只有 devfs 设备(如 /dev/fb0)实现了它。""" + return int(syscall._syscall3(uint64(syscall.Syscall.IOCTL), uint64(fd), uint64(request), uint64(arg))) + class FileIO: _fd: int _pos: uint32 diff --git a/vpsdk/syscall.vp b/vpsdk/syscall.vp index 0fadc63..ccfaf15 100644 --- a/vpsdk/syscall.vp +++ b/vpsdk/syscall.vp @@ -13,7 +13,8 @@ enum Syscall: 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)(目前空实现) + 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