Files
ViperOS/vpsdk/devfs.vp
T
TermiNexus 0fd1bf7567 fix(fb0): 几何登记为 0 + FbInfo 按值返回只回传一半 —— explorer 拿不到 framebuffer 几何
现场(serial.log 330-339):[fb0] ioctl fd=6 req=0x4600 arg=0x7fffffdffb78 w=0 h=0 ⇒ request 与 arg 传递都正常、写入回读也正常,真正的问题是设备对象里的 fb_w/fb_h/fb_pitch/fb_format/fb_phys/fb_size 全为 0;随后 explorer 以 pitch=0 调 mmap 失败退出。两个独立缺陷:① 内核侧——devfs_register_fb0 收到的是被清零的 width/height/pitch/fb_format/fb_size(main.vp 顶部注释记录的"__init__ 的 fb/width/height/pitch 局部量被偶发写坏"同类问题:这些长寿命局部量在 L121 之后、L304 之前被写坏,而 L366+ 的 _CheckFrameLocals 又不报,属时点相关),改为在调用点直接从 BootInfo 重取几何并补一条 _CheckFrameLocals(pre_devfs_fb0);② SDK 侧——fb_get_info 按值返回 32 字节 FbInfo,现场表现为只有前 16 字节有效、后 16 字节是调用方栈残留(size=1802724708 phys=0x130c30),改为出参 out + 返回 ioctl 返回码;③ explorer 侧改为判返回码与 pitch/size 非 0,失败即 _dbg 说明原因后 fail-fast 退出,不再带着 0 几何继续。
2026-10-16 20:20:36 +08:00

93 lines
3.6 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 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
@__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_map(fd: int, size: uint64) -> uint64:
"""把 framebuffer 映射进本进程,返回线性起始地址(0 = 失败),之后可直接写像素。
走通用 mmap(fd = 该设备 fd):内核按设备的 mmap_info 把物理区间按页映射进来。
"""
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)))