键盘只收到一个残留字节(ch=50)后就没有数据,符合'数据上报被关掉'。keyboard.init() 被调了两次:devfs_register_keyboard() 与 services/keyboard.vp 的 start()。init() 会读-改-写 8042 CCB 并安装 IRQ1,二次读改写可能把键盘时钟/数据上报关掉。改为只在 service 层初始化一次。
613 lines
23 KiB
Plaintext
613 lines
23 KiB
Plaintext
import drivers.serial.uart.serial as serial
|
||
import string
|
||
import asm
|
||
|
||
|
||
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: static 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: static 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:
|
||
# 不再自建节点:`devfs_file()` 在函数内构造的是**栈实例**,登记进全局 files[] 会悬垂,
|
||
# 编译器 LifetimeError 已按"栈地址逃逸"拦截。设备节点只能由调用方以长寿命实例
|
||
# (模块级 / 堆)提供;缺对象一律失败,不静默造一个假的占位对象。
|
||
return -1
|
||
|
||
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
|
||
# 以 read_scancode() 的返回值为准(0 = 队列空):每轮要么取到一个字节并前进,
|
||
# 要么立即退出,不再依赖第二个计数量做循环条件(那次混合计数会自旋)。
|
||
while count < size:
|
||
sc: uint8 = keyboard.read_scancode()
|
||
if sc == uint8(0): break
|
||
ch: char = keyboard.scancode_to_ascii(sc)
|
||
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():初始化(含 8042 CCB 读改写与 IRQ1 安装)由
|
||
# services/keyboard.vp 的 start() 统一负责。两处都调会二次读改写 CCB,
|
||
# 第二次可能把键盘时钟/数据上报关掉 —— 表现为"设备能开、只收到一个残留字节"。
|
||
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:
|
||
# 布局:[0] = 按键,[1..4] = dx(int32),[5..8] = dy(int32)。
|
||
# 【重要】dx/dy 是 PS/2 包里的**相对位移**,不是绝对坐标 —— 光标位置由 explorer
|
||
# 持有并做边界钳制,内核只负责设备语义。旧写法填的是 mouse.get_x()/get_y(),
|
||
# 而那两个静态量从未被更新(irq_handler 只把包入队),恒为 0 ⇒ 用户一动鼠标,
|
||
# explorer 就把光标设到 (0,0),现场表现为"立马跑到左上角"。
|
||
buf: uint32* = uint32*(uint64(buffer) + 1)
|
||
dx: int = int(pkt.dx)
|
||
dy: int = int(pkt.dy)
|
||
# uint8 原始字节 → 有符号增量(-128..127);不依赖 int8 转换的语义,直接判借位。
|
||
if dx >= 128: dx = dx - 256
|
||
if dy >= 128: dy = dy - 256
|
||
# PS/2 协议的 Y 正方向是**向上**,而屏幕坐标 Y 向下为正 —— 在这里统一取反成屏幕
|
||
# 方向,消费方直接累加即可(与历史 desktop.vp 里 pkt_dy 的用法一致)。
|
||
dy = 0 - dy
|
||
int32*(buf)[0] = int32(dx)
|
||
int32*(buf)[1] = int32(dy)
|
||
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
|
||
# 等一次垂直回扫:用户态(explorer)没有 IO 端口权限,不能自己 inb 0x3DA,由内核代做。
|
||
define FB_WAIT_VBLANK = 0x4601
|
||
|
||
@__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_WAIT_VBLANK:
|
||
# 等进入垂直回扫期(0x3DA bit3)。返回等待消耗的迭代数:到上限即超时
|
||
#(当前没有 VGA 回扫信号),调用方可据此判断同步是否真的生效。
|
||
t: int = 100000
|
||
while (asm.inb(0x3DA) & 0x08) != 0 and t > 0: t -= 1
|
||
t2: int = 100000
|
||
while (asm.inb(0x3DA) & 0x08) == 0 and t2 > 0: t2 -= 1
|
||
return 100000 - t2
|
||
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)
|
||
|
||
|
||
# ============================================================================
|
||
# /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)
|