现场:main.vp 探针读模块级 fb0_file 得 w=1360 h=768 pitch=5440(注册正确),而 explorer 侧 [fb0] ioctl 的 self 读得 w=0 h=0 pitch=0 fmt=0。IR 证据(devfs 编译单元 .text.ll 的 create_file):files[file_count] = *file_ptr 被生成成 llvm.load/llvm.store 整个 devfs_file 结构体(88 字节基类布局),派生字段 fb_phys/fb_size/fb_w/fb_h/fb_pitch/fb_format 从未被写入,保持 __init__ 的 memset 0;vptr 一并拷过去所以虚调用仍能进 framebuffer_device.ioctl,但读到的派生字段全是 0。这是对象切片而非编译器缺陷。 改法:files 由 [MAX_DEVICE_FILES]devfs_file 改为 devfs_file* 指针数组,create_file 只登记指针(设备对象由 devfs_register_* 以模块级实例持有,生命周期贯穿内核运行期);find_in_dir/list_in_dir 相应去掉取址;__init__ 的 memset 长度改为指针数组真实大小 8*MAX_DEVICE_FILES(原来按 devfs_file.__sizeof__() 清会越界清掉后面全局量)。顺带修好同样依赖派生字段的 /dev/desk(shm_device.shm_phys/shm_size)。
600 lines
22 KiB
Plaintext
600 lines
22 KiB
Plaintext
import drivers.serial.uart.serial as serial
|
||
import string
|
||
import viperlib
|
||
|
||
|
||
define MAX_FILE_DESCRIPTORS = 64
|
||
define MAX_DEVICE_FILES = 32
|
||
define MAX_DIRECTORIES = 16
|
||
define PATH_BUFFER_SIZE = 256
|
||
|
||
directories: [MAX_DIRECTORIES]devfs_directory = [0]
|
||
directory_count: int = 0
|
||
|
||
# 存**指针**而不是基类值:按值数组会把设备对象**切片**成 devfs_file(只拷 88 字节基类部分),
|
||
# 派生字段(framebuffer_device.fb_w/fb_h/fb_phys…、shm_device.shm_phys…)全部丢失 ——
|
||
# 现场表现为 [main] fb0 reg w=1360(读的是模块级对象)而 [fb0] ioctl w=0(读的是数组里的切片)。
|
||
# IR 证据:create_file 里生成的是 llvm.load/llvm.store 整个 devfs_file 结构体,不含派生字段。
|
||
files: [MAX_DEVICE_FILES]devfs_file* = [0]
|
||
file_count: int = 0
|
||
|
||
|
||
class _fd_table:
|
||
file: devfs_file*
|
||
flags: int
|
||
|
||
fd_table: [MAX_FILE_DESCRIPTORS]_fd_table = [0]
|
||
|
||
|
||
class devfs_directory:
|
||
name: [64]char
|
||
parent: devfs_directory*
|
||
|
||
@staticmethod
|
||
def find(path: const str, root_directory: devfs_directory*) -> devfs_directory*:
|
||
if not path or string.strchr(path, '/') != path: return None
|
||
if not root_directory: return None
|
||
|
||
current_dir: devfs_directory* = root_directory
|
||
result: [PATH_BUFFER_SIZE]str
|
||
token = string.split(path, "/", result, PATH_BUFFER_SIZE)
|
||
|
||
# `for i in result` 按 NULL 终止语义遍历(i8* 元素,split 尾哨兵 NULL 停):
|
||
# 编译器 _handle_array_iter 已实现"长度上限 + 解引用为空提前终止"。
|
||
for i in result:
|
||
found: bool = False
|
||
for d in range(directory_count):
|
||
dirp: devfs_directory* = &directories[d]
|
||
if dirp.parent == current_dir and string.samestr(dirp.name, i):
|
||
current_dir = dirp
|
||
found = True
|
||
break
|
||
if not found: return None
|
||
|
||
return current_dir
|
||
|
||
@staticmethod
|
||
def find_child(name: const str, parent: devfs_directory*) -> devfs_directory*:
|
||
for d in range(directory_count):
|
||
dirp: devfs_directory* = &directories[d]
|
||
if dirp.parent == parent and string.samestr(dirp.name, name):
|
||
return dirp
|
||
return None
|
||
|
||
@staticmethod
|
||
def list_subdirs(dir_ptr: devfs_directory*, buffer: str, size: uint32, pos: int) -> int:
|
||
for d in range(directory_count):
|
||
dirp: devfs_directory* = &directories[d]
|
||
if dirp.parent == dir_ptr:
|
||
name_len: int = int(string.strlen(dirp.name))
|
||
if pos + name_len + 1 > size:
|
||
break
|
||
string.strcpy(buffer + pos, dirp.name)
|
||
pos += name_len
|
||
buffer[pos] = '\n'
|
||
pos += 1
|
||
return pos
|
||
|
||
|
||
virtual class devfs_file:
|
||
name: [64]char
|
||
private_data: rawptr
|
||
parent_dir: devfs_directory*
|
||
|
||
@staticmethod
|
||
def find_in_dir(file_name: const str, dir_ptr: devfs_directory*) -> devfs_file*:
|
||
for f in range(file_count):
|
||
fp: devfs_file* = files[f]
|
||
if fp.parent_dir == dir_ptr and string.samestr(fp.name, file_name):
|
||
return fp
|
||
return None
|
||
|
||
@staticmethod
|
||
def list_in_dir(dir_ptr: devfs_directory*, buffer: str, size: uint32, pos: int) -> int:
|
||
for f in range(file_count):
|
||
filep: devfs_file* = files[f]
|
||
if filep.parent_dir == dir_ptr:
|
||
name_len: int = int(string.strlen(filep.name))
|
||
if pos + name_len + 1 > size:
|
||
break
|
||
string.strcpy(buffer + pos, filep.name)
|
||
pos += name_len
|
||
buffer[pos] = '\n'
|
||
pos += 1
|
||
return pos
|
||
|
||
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 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:
|
||
root_directory: devfs_directory*
|
||
|
||
def __init__(self):
|
||
global directory_count, file_count
|
||
self.root_directory = None
|
||
directory_count = 0
|
||
file_count = 0
|
||
string.memset(&directories, 0, devfs_directory.__sizeof__() * MAX_DIRECTORIES)
|
||
# files 是指针数组(8 字节/项),不能再用 devfs_file.__sizeof__() —— 那会越界清掉后面的全局量。
|
||
string.memset(&files, 0, 8 * MAX_DEVICE_FILES)
|
||
string.memset(&fd_table, 0, _fd_table.__sizeof__() * MAX_FILE_DESCRIPTORS)
|
||
|
||
def create_single_dir(self, parent: devfs_directory*, dir_name: const str) -> devfs_directory*:
|
||
global directory_count
|
||
if not parent or not dir_name: return None
|
||
if directory_count >= MAX_DIRECTORIES: return None
|
||
if string.strlen(dir_name) >= 64: return None
|
||
|
||
new_dir: devfs_directory* = &directories[directory_count]
|
||
directory_count += 1
|
||
|
||
string.strcpy(new_dir.name, dir_name)
|
||
new_dir.parent = parent
|
||
|
||
return new_dir
|
||
|
||
def find_or_create_directory(self, path: const str) -> devfs_directory*:
|
||
global directory_count
|
||
if not path or string.samestr(path, "/"): return None
|
||
|
||
if not self.root_directory:
|
||
self.root_directory = &directories[directory_count]
|
||
directory_count += 1
|
||
string.strcpy(self.root_directory.name, "")
|
||
self.root_directory.parent = None
|
||
current: devfs_directory* = self.root_directory
|
||
buf: [PATH_BUFFER_SIZE]char
|
||
string.memset(&buf, 0, PATH_BUFFER_SIZE)
|
||
buf_idx: int = 0
|
||
p: int = 0
|
||
if path[p] == '/': p += 1
|
||
while path[p] != '\0':
|
||
if path[p] == '/':
|
||
if buf_idx > 0:
|
||
found_child: devfs_directory* = devfs_directory.find_child(buf, current)
|
||
if not found_child:
|
||
found_child = self.create_single_dir(current, buf)
|
||
if not found_child: return None
|
||
current = found_child
|
||
string.memset(&buf, 0, PATH_BUFFER_SIZE)
|
||
buf_idx = 0
|
||
p += 1
|
||
else:
|
||
buf[buf_idx] = path[p]
|
||
buf_idx += 1
|
||
p += 1
|
||
if buf_idx > 0:
|
||
found_child: devfs_directory* = devfs_directory.find_child(buf, current)
|
||
if not found_child:
|
||
found_child = self.create_single_dir(current, buf)
|
||
if not found_child: return None
|
||
current = found_child
|
||
return current
|
||
|
||
def init(self) -> int:
|
||
self.create_directory("/dev")
|
||
self.create_directory("/dev/input")
|
||
return 0
|
||
|
||
def create_directory(self, path: const str) -> int:
|
||
dir_ptr: devfs_directory* = self.find_or_create_directory(path)
|
||
return 0 if dir_ptr else -1
|
||
|
||
def create_file(self, path: const str, file_ptr: devfs_file*, private_data: rawptr) -> int:
|
||
global file_count
|
||
path_copy: [PATH_BUFFER_SIZE]char
|
||
string.memset(&path_copy, 0, PATH_BUFFER_SIZE)
|
||
string.strcpy(&path_copy, path)
|
||
|
||
last_slash: str = string.strrchr(path_copy, '/')
|
||
|
||
if not last_slash: return -1
|
||
|
||
last_slash[0] = '\0'
|
||
dir_path = path_copy
|
||
file_name: str = last_slash + 1
|
||
|
||
dir_ptr: devfs_directory* = self.find_or_create_directory(dir_path)
|
||
if not dir_ptr: return -1
|
||
if devfs_file.find_in_dir(file_name, dir_ptr): return -1
|
||
if file_count >= MAX_DEVICE_FILES: return -1
|
||
|
||
if file_ptr:
|
||
string.strcpy(file_ptr.name, file_name)
|
||
file_ptr.private_data = private_data
|
||
file_ptr.parent_dir = dir_ptr
|
||
# 只登记指针。设备对象由调用方(devfs_register_*)以模块级实例持有,
|
||
# 生命周期贯穿内核运行期,因此指针引用安全且能看见派生字段。
|
||
files[file_count] = file_ptr
|
||
else:
|
||
# 调用方没给对象时自建基类实例(无派生字段,方法即基类默认实现)。
|
||
new_file: devfs_file* = devfs_file()
|
||
string.strcpy(new_file.name, file_name)
|
||
new_file.private_data = private_data
|
||
new_file.parent_dir = dir_ptr
|
||
files[file_count] = new_file
|
||
|
||
file_count += 1
|
||
return 0
|
||
|
||
def open(self, path: const str, flags: int) -> int:
|
||
path_copy: [PATH_BUFFER_SIZE]char
|
||
string.memset(&path_copy, 0, PATH_BUFFER_SIZE)
|
||
string.strcpy(&path_copy, path)
|
||
|
||
last_slash: str = string.strrchr(path_copy, '/')
|
||
|
||
if not last_slash: return -1
|
||
|
||
last_slash[0] = '\0'
|
||
dir_path = path_copy
|
||
file_name: str = last_slash + 1
|
||
|
||
dir_ptr: devfs_directory* = devfs_directory.find(dir_path, self.root_directory)
|
||
if not dir_ptr: return -1
|
||
|
||
file_ptr: devfs_file* = devfs_file.find_in_dir(file_name, dir_ptr)
|
||
if not file_ptr: return -1
|
||
|
||
fd: int = -1
|
||
for i in range(MAX_FILE_DESCRIPTORS):
|
||
if not fd_table[i].file:
|
||
fd = i
|
||
break
|
||
if fd == -1: return -1
|
||
|
||
ret: int = file_ptr.open(path, flags)
|
||
if ret != 0: return ret
|
||
|
||
fd_table[fd].file = file_ptr
|
||
fd_table[fd].flags = flags
|
||
return fd
|
||
|
||
def close(self, fd: int) -> 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
|
||
file_ptr.close(fd)
|
||
fd_table[fd].file = None
|
||
fd_table[fd].flags = 0
|
||
return 0
|
||
|
||
def read(self, fd: int, buffer: rawptr, size: uint32) -> 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.read(fd, buffer, size)
|
||
|
||
def write(self, fd: int, buffer: const rawptr, size: uint32) -> 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.write(fd, buffer, size)
|
||
|
||
def ioctl(self, fd: int, cmd: uint32, arg: rawptr) -> 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.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:
|
||
dir_ptr: devfs_directory* = devfs_directory.find(path, self.root_directory)
|
||
if not dir_ptr or not buffer or size == 0: return -1
|
||
|
||
pos: int = devfs_directory.list_subdirs(dir_ptr, buffer, size, 0)
|
||
pos = devfs_file.list_in_dir(dir_ptr, buffer, size, pos)
|
||
|
||
return pos
|
||
|
||
DevFSObject: _DevFSObject* = _DevFSObject()
|
||
|
||
|
||
def devfs_init() -> int:
|
||
global DevFSObject
|
||
DevFSObject.__init__()
|
||
DevFSObject.init()
|
||
return 0
|
||
|
||
def devfs_create_directory(path: const str) -> int:
|
||
return DevFSObject.create_directory(path)
|
||
|
||
def devfs_create_file(path: const str, file_ptr: devfs_file*, private_data: rawptr) -> int:
|
||
return DevFSObject.create_file(path, file_ptr, private_data)
|
||
|
||
def devfs_open(path: const str, flags: int) -> int:
|
||
return DevFSObject.open(path, flags)
|
||
|
||
def devfs_close(fd: int) -> int:
|
||
return DevFSObject.close(fd)
|
||
|
||
def devfs_read(fd: int, buffer: rawptr, size: uint32) -> int:
|
||
return DevFSObject.read(fd, buffer, size)
|
||
|
||
def devfs_write(fd: int, buffer: const rawptr, size: uint32) -> int:
|
||
return DevFSObject.write(fd, buffer, size)
|
||
|
||
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)
|
||
|
||
serial0_file: devfs_file* = devfs_file()
|
||
|
||
def serial0_open(self: rawptr, path: const str, flags: int) -> int:
|
||
serial.puts("[serial0] open: ")
|
||
serial.puts(path)
|
||
serial.puts("\n")
|
||
return 0
|
||
|
||
def serial0_close(self: rawptr, fd: int) -> int:
|
||
serial.puts("[serial0] close\n")
|
||
return 0
|
||
|
||
def serial0_read(self: rawptr, fd: int, buffer: rawptr, size: uint32) -> int:
|
||
serial.puts("[serial0] read\n")
|
||
return 0
|
||
|
||
def serial0_write(self: rawptr, fd: int, buffer: const rawptr, size: uint32) -> int:
|
||
serial.puts("[serial0] write\n")
|
||
serial.puts(buffer)
|
||
serial.puts("\n")
|
||
return size
|
||
|
||
def devfs_register_serial0() -> int:
|
||
global serial0_file
|
||
serial0_file.__init__()
|
||
serial0_file.open = serial0_open
|
||
serial0_file.close = serial0_close
|
||
serial0_file.read = serial0_read
|
||
serial0_file.write = serial0_write
|
||
return devfs_create_file("/dev/serial0", serial0_file, None)
|
||
|
||
|
||
virtual class serial1_device(devfs_file):
|
||
def open(self, path: const str, flags: int) -> int:
|
||
serial.puts("[serial1] open: ")
|
||
serial.puts(path)
|
||
serial.puts("\n")
|
||
return 0
|
||
|
||
def close(self, fd: int) -> int:
|
||
serial.puts("[serial1] close\n")
|
||
return 0
|
||
|
||
def read(self, fd: int, buffer: rawptr, size: uint32) -> int:
|
||
serial.puts("[serial1] read\n")
|
||
return 0
|
||
|
||
def write(self, fd: int, buffer: const rawptr, size: uint32) -> int:
|
||
serial.puts("[serial1] write\n")
|
||
serial.puts(str(buffer))
|
||
serial.puts("\n")
|
||
return size
|
||
|
||
serial1_file: serial1_device* = serial1_device()
|
||
|
||
def devfs_register_serial1() -> int:
|
||
global serial1_file
|
||
serial1_file.__init__()
|
||
return devfs_create_file("/dev/serial1", serial1_file, None)
|
||
|
||
import drivers.input.keyboard.keyboard as keyboard
|
||
import drivers.input.mouse.mouse as mouse
|
||
|
||
|
||
virtual class keyboard_device(devfs_file):
|
||
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:
|
||
count: uint32 = 0
|
||
while count < size and keyboard.has_data():
|
||
sc: uint8 = keyboard.read_scancode()
|
||
ch: char = keyboard.scancode_to_ascii(sc)
|
||
if ch != '\0':
|
||
char*(buffer)[count] = ch
|
||
count += 1
|
||
return count
|
||
|
||
def write(self, fd: int, buffer: const rawptr, size: uint32) -> int:
|
||
return -1
|
||
|
||
def ioctl(self, fd: int, request: int, arg: rawptr) -> int:
|
||
return 0
|
||
|
||
kbd_file: keyboard_device* = keyboard_device()
|
||
|
||
def devfs_register_keyboard() -> int:
|
||
global kbd_file
|
||
kbd_file.__init__()
|
||
keyboard.init()
|
||
return devfs_create_file("/dev/input/keyboard", kbd_file, None)
|
||
|
||
|
||
virtual class mouse_device(devfs_file):
|
||
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:
|
||
if not mouse.has_data(): return 0
|
||
pkt: mouse.mouse_packet
|
||
mouse.read_packet(&pkt)
|
||
if size >= 1:
|
||
uint8*(buffer)[0] = pkt.buttons
|
||
|
||
if size >= 9:
|
||
buf: uint32* = uint32*(uint64(buffer) + 1)
|
||
int32*(buf)[0] = mouse.get_x()
|
||
int32*(buf)[1] = mouse.get_y()
|
||
return 9
|
||
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:
|
||
return 0
|
||
|
||
mse_file: mouse_device* = mouse_device()
|
||
|
||
def devfs_register_mouse() -> int:
|
||
global mse_file
|
||
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:
|
||
# 【诊断·临时】确认 request/arg 是否真的到达内核、以及写入的目标 VA。
|
||
# 若这里打印的 request 不是 0x4600,说明 syscall 派发把请求号传错了(app 会读到未写入的残留)。
|
||
_io_b: [128]char
|
||
viperlib.snprintf(&_io_b, 128, "[fb0] ioctl fd=%d req=0x%lx arg=0x%lx w=%lu h=%lu\n",
|
||
fd, uint64(request), uint64(arg), uint64(self.fb_w), uint64(self.fb_h))
|
||
serial.puts(&_io_b)
|
||
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
|
||
# 【诊断·临时】回读刚写的 6 个字段:能读到新值说明写入确实落到了 arg 指向的内存。
|
||
_io_b2: [128]char
|
||
viperlib.snprintf(&_io_b2, 128, "[fb0] ioctl wrote w=%lu h=%lu pitch=%lu fmt=%lu\n",
|
||
uint64(info.width), uint64(info.height),
|
||
uint64(info.pitch), uint64(info.format))
|
||
serial.puts(&_io_b2)
|
||
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)
|
||
|
||
|
||
# ============================================================================
|
||
# /dev/desk:图形壳 explorer 与各 app 之间的**共享内存通道**。
|
||
#
|
||
# 内核只做两件事:启动时分配一块物理内存、让每个 open 者 mmap 到**同一**物理区间。
|
||
# 区间内部的布局(窗口表 / 各窗口像素缓冲 / 请求与事件环形队列)完全由用户态协议
|
||
# 约定,见 vpsdk/desk.vp —— 内核不解析其内容,也不参与窗口语义。
|
||
#
|
||
# 为什么用 devfs 而不是新 syscall:syscall 表已对齐 Linux 且不留私有段;
|
||
# "共享一块内存给多方"正好能用 设备 + mmap 表达(Linux 用 shm/memfd + MAP_SHARED,
|
||
# 这里用 devfs 设备 + mmap 达到同样效果)。
|
||
# ============================================================================
|
||
# 共享区大小:vpsdk/desk.vp 里有一份同名同值的镜像(用户在 mmap 时必须先知道长度)。
|
||
define DESK_SHM_SIZE = 8388608
|
||
|
||
virtual class shm_device(devfs_file):
|
||
shm_phys: uint64
|
||
shm_size: uint64
|
||
|
||
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 mmap_info(self, fd: int, out_phys: uint64*, out_size: uint64*) -> int:
|
||
if out_phys: *out_phys = self.shm_phys
|
||
if out_size: *out_size = self.shm_size
|
||
return 0
|
||
|
||
desk_file: shm_device* = shm_device()
|
||
|
||
def devfs_register_desk(shm: rawptr, size: uint64) -> int:
|
||
"""登记 /dev/desk。shm 是内核启动时 mm.malloc 出来的共享区;所有 open 者映射同一区间。"""
|
||
global desk_file
|
||
if not shm or size == 0:
|
||
serial.puts("[devfs] desk shm register skipped (no memory)\n")
|
||
return -1
|
||
desk_file.__init__()
|
||
desk_file.shm_phys = uint64(shm)
|
||
desk_file.shm_size = size
|
||
return devfs_create_file("/dev/desk", desk_file, None)
|