feat(mmap): S1c —— MMAP 改 Linux 六参形态并支持映射 /dev/fb0

内核 MMAP(addr,length,prot,flags,fd,offset):fd=-1 + MAP_ANONYMOUS 走匿名映射(分配物理页、清零后映射到本进程新 VA,对齐 Linux"匿名必为零"语义);fd 是带 mmap_info 的 devfs 设备(当前仅 /dev/fb0)则把 [phys+offset, phys+offset+len) 按页映射进调用者地址空间(PTE_USER|WRITE)。addr/MAP_FIXED 暂未实现,一律由内核挑 VA 并返回真实起始地址。新增 PROT_*/MAP_*/MMAP_FD_ANON 常量。

参数次序与 Linux mmap 完全一致(rdi/rsi/rdx/r10/r8/r9),syscall_entry 的搬运顺序本就是这个约定,SDK 侧 vpsdk/syscall.vp 加 mmap() 助手走 _syscall6。stdlib.malloc 随之改为匿名映射调用(fd=-1、MAP_PRIVATE|MAP_ANONYMOUS、PROT_READ|PROT_WRITE),行为与原 MMAP(size) 一致且多一层清零。
This commit is contained in:
TermiNexus committed 2026-10-16 18:40:14 +08:00
1 parent f4c653958e
commit 7d5380148b
3 files changed
+72 -13

No files matched your search

+48 -12
View File
@@ -422,20 +422,56 @@ def SPAWN(path_ptr: str, blocking: int) -> int:
define USER_HEAP_BASE = 0x20000000
def MMAP(size: uint64) -> uint64:
# ---- mmap 的 prot / flags(值与 Linux 同名常量一致)----
define PROT_NONE = 0x0
define PROT_READ = 0x1
define PROT_WRITE = 0x2
define PROT_EXEC = 0x4
define MAP_SHARED = 0x01
define MAP_PRIVATE = 0x02
define MAP_FIXED = 0x10
define MAP_ANONYMOUS = 0x20
# fd = -1(Linux 匿名映射约定)
define MMAP_FD_ANON: uint64 = 0xFFFFFFFFFFFFFFFF
def MMAP(addr: uint64, length: uint64, prot: uint64, flags: uint64, fd: uint64, offset: uint64) -> uint64:
"""mmap(addr, length, prot, flags, fd, offset):与 Linux 同名同参。
· fd == MMAP_FD_ANON(-1) 且带 MAP_ANONYMOUS:匿名映射 —— 分配物理页、清零后映射到
本进程新 VA(对齐 Linux 的"匿名映射必为 0"语义);
· fd 是带 mmap_info 的 devfs 设备 fd(当前仅 /dev/fb0):把设备物理区间
[phys+offset, phys+offset+length) 按页映射进来(用户可读写)。
addr 与 MAP_FIXED 暂未实现:一律由内核挑 VA,返回真实起始地址。失败返回 0。
"""
p: process.Process* = _current_proc()
if size == 0: return 0
aligned_size: uint64 = (size + 4095) & ~uint64(4095)
if length == 0: return 0
aligned: uint64 = (length + 4095) & ~uint64(4095)
if p.heap_start == 0:
p.heap_start = USER_HEAP_BASE
heap_end: uint64 = p.heap_start + p.heap_size
new_end: uint64 = heap_end + aligned_size
for va in range(heap_end, new_end, 4096):
phys_page: rawptr = mm.malloc(4096)
if phys_page is None: return 0
paging.MapPage(va, uint64(phys_page), paging.PTE_PRESENT | paging.PTE_WRITABLE | paging.PTE_USER)
p.heap_size = p.heap_size + aligned_size
return heap_end
va: uint64 = p.heap_start + p.heap_size
if fd == MMAP_FD_ANON:
if (flags & MAP_ANONYMOUS) == 0: return 0
for off in range(0, aligned, 4096):
phys_page: rawptr = mm.malloc(4096)
if phys_page is None: return 0
string.memset(phys_page, 0, 4096)
paging.MapPage(va + off, uint64(phys_page),
paging.PTE_PRESENT | paging.PTE_WRITABLE | paging.PTE_USER)
else:
fdi: int = int(fd)
if fdi < 0 or fdi >= process.PROC_MAX_FDS: return 0
if not p.fd_used[fdi]: return 0
if p.fd_kind[fdi] != process.FD_KIND_DEVFS: return 0
dev_phys: uint64 = 0
dev_size: uint64 = 0
if devfs.devfs_get_mmap_info(int(uint64(p.fd_table[fdi])) - 1, &dev_phys, &dev_size) != 0:
return 0
if offset + aligned > dev_size: return 0
for off in range(0, aligned, 4096):
paging.MapPage(va + off, dev_phys + offset + off,
paging.PTE_PRESENT | paging.PTE_WRITABLE | paging.PTE_USER)
p.heap_size = p.heap_size + aligned
return va
def MUNMAP(ptr: uint64, size: uint64) -> int:
return 0
@@ -532,7 +568,7 @@ export def syscall_handler(num: uint64, arg1: uint64, arg2: uint64, arg3: uint64
path_ptr_sp: rawptr = rawptr(arg1)
return uint64(SPAWN(path_ptr_sp, int(arg2)))
elif n == int(Syscall.MMAP):
return MMAP(arg1)
return MMAP(arg1, arg2, arg3, arg4, arg5, arg6)
elif n == int(Syscall.MUNMAP):
return uint64(MUNMAP(arg1, arg2))
elif n == int(Syscall.THREAD_CREATE):
+3 -1
View File
@@ -20,7 +20,9 @@ export def malloc(size: sizet) -> rawptr:
if _heap_inited == 0: _heap_init()
hdr_size: sizet = _heap_hdr.__sizeof__()
total: sizet = hdr_size + size
ptr: uint64 = _sc._syscall1(uint64(_sc.Syscall.MMAP), uint64(total))
# mmap 已按 Linux 六参形态对齐:匿名映射 = fd -1 + MAP_ANONYMOUS + PROT_READ|WRITE
ptr: uint64 = _sc.mmap(0, uint64(total), uint64(_sc.PROT_READ | _sc.PROT_WRITE),
uint64(_sc.MAP_PRIVATE | _sc.MAP_ANONYMOUS), _sc.MMAP_FD_ANON, 0)
if ptr == 0: return None
# 块头必须落在**映射区内部**(映射起点 ptr 处),不能写 ptr - hdr_size:
# 那 8 字节在映射之外 —— 第一次 malloc 时 mmap 返回的正是用户堆起点 0x20000000,
+21
View File
@@ -45,6 +45,18 @@ enum Syscall:
SET_RESIZABLE = 0x1011 # TODO(explorer):UI
GET_WIN_SIZE = 0x1012 # TODO(explorer):UI
# ---- mmap 的 prot / flags(与内核 VKernel/intr/syscall.vp 及各 Linux 同名常量一致)----
define PROT_NONE = 0x0
define PROT_READ = 0x1
define PROT_WRITE = 0x2
define PROT_EXEC = 0x4
define MAP_SHARED = 0x01
define MAP_PRIVATE = 0x02
define MAP_FIXED = 0x10
define MAP_ANONYMOUS = 0x20
# fd = -1(Linux 匿名映射约定)
define MMAP_FD_ANON: uint64 = 0xFFFFFFFFFFFFFFFF
def _syscall0(num: uint64) -> uint64:
ret: uint64
__asm__(f"""mov rax, {asminp(num, ASM_DESCR.REG_ANY)}
@@ -122,3 +134,12 @@ def _syscall6(num: uint64, a1: uint64, a2: uint64, a3: uint64, a4: uint64, a5: u
ASM_DESCR.CLOBBER_R10, ASM_DESCR.CLOBBER_R8,
ASM_DESCR.CLOBBER_R9])
return ret
def mmap(addr: uint64, length: uint64, prot: uint64, flags: uint64, fd: uint64, offset: uint64) -> uint64:
"""mmap(addr, length, prot, flags, fd, offset):返回映射起始 VA,失败返回 0。
匿名映射:fd = MMAP_FD_ANON(-1) 且 flags 带 MAP_ANONYMOUS;
映射设备(如 /dev/fb0):fd 传该设备的 fd。addr / MAP_FIXED 由内核挑地址。
(定义放在 _syscall6 之后,避免同模块内前向引用。)
"""
return _syscall6(uint64(Syscall.MMAP), addr, length, prot, flags, fd, offset)