import vpsdk.fs as fs import vpsdk.syscall as syscall import string from stdint import * # ============================================================================ # devfs 设备层:设备节点路径 + 各设备的专用读写/控制助手。 # # 设备节点由内核在启动时注册(见 VKernel/Kernel/main.vp 的 devfs_register_*), # 用户态用普通 open/read/write/ioctl 访问 —— 不再有"设备专用 syscall"。 # ============================================================================ # 路径必须与内核注册名逐字一致 define DEV_SERIAL0 = "/dev/serial0" define DEV_SERIAL1 = "/dev/serial1" define DEV_FB0 = "/dev/fb0" define DEV_KBD = "/dev/input/keyboard" define DEV_MOUSE = "/dev/input/mouse" define DEV_DESK = "/dev/desk" # ioctl 命令与返回结构:必须与 VKernel/Kernel/drivers/devfs/devfs.vp 的 # FB_GET_INFO / FbInfo 逐字段一致(packed;4×u32 + 2×u64 = 32 字节)。 define FB_GET_INFO = 0x4600 define FB_WAIT_VBLANK = 0x4601 @__attribute__(packed) class FbInfo: width: uint32 height: uint32 pitch: uint32 format: uint32 size: uint64 phys: uint64 def fb_open() -> int: return fs.open(DEV_FB0, uint32(0)) def fb_get_info(fd: int, out: FbInfo*) -> int: """查 framebuffer 几何 / 格式 / 物理区间,写进调用者给出的 out。 返回 ioctl 的返回码(0 = 成功,非 0 = 失败,此时 out 内容不可信 —— 调用方必须判失败)。 为什么改为**出参**而不是按值返回 FbInfo:按值返回 32 字节结构体在现场表现为 "前 16 字节对、后 16 字节是调用方栈残留"(size/phys 打出 1802724708 / 0x130c30 这类值), 即结构体返回值只回传了一部分。出参写内存不依赖该 ABI,稳定可靠。 """ if not out: return -1 string.memset(out, 0, FbInfo.__sizeof__()) return fs.ioctl(fd, uint32(FB_GET_INFO), out) def fb_wait_vblank(fd: int) -> int: """等一次垂直回扫(合成前调用,减轻 tearing)。用户态无 IO 权限,由内核代做。""" return fs.ioctl(fd, uint32(FB_WAIT_VBLANK), None) def fb_map(fd: int, size: uint64) -> uint64: """把 framebuffer 映射进本进程,返回线性地址(0 = 失败)。""" return syscall.mmap(0, size, uint64(syscall.PROT_READ | syscall.PROT_WRITE), uint64(syscall.MAP_SHARED), uint64(fd), 0) def kbd_open() -> int: return fs.open(DEV_KBD, uint32(0)) def mouse_open() -> int: return fs.open(DEV_MOUSE, uint32(0)) def shm_map(fd: int, size: uint64) -> uint64: """把共享内存设备映射进本进程,返回线性起始地址(0 = 失败)。 与 fb_map 同一机制(设备 mmap_info 给出的物理区间);不同点在于 /dev/desk 的区间对**所有**打开者都是同一块物理内存,因此天然可跨进程共享。 """ return syscall.mmap(0, size, uint64(syscall.PROT_READ | syscall.PROT_WRITE), uint64(syscall.MAP_SHARED), uint64(fd), 0) # /dev/serial0 的 fd 惰性打开一次(-1 = 还没开;-2 = 开失败过,不再重试) _serial_fd: int = -1 def serial_puts(msg: const str) -> int: """把字符串写到 /dev/serial0 —— 替代已删除的 SERIAL_PUTS syscall。 内核侧 serial0 设备的 write 按 C 字符串输出(内部就是 serial.puts), 所以这里只需把指针与长度递下去。 """ global _serial_fd if _serial_fd == -1: _serial_fd = fs.open(DEV_SERIAL0, uint32(0)) if _serial_fd < 0: _serial_fd = -2 if _serial_fd < 0: return -1 if msg is None: return -1 return fs.write(_serial_fd, msg, uint32(string.strlen(msg)))