From 7d5380148babbfdd3ced4c2fd82b1040cf50188a Mon Sep 17 00:00:00 2001 From: TermiNexus Date: Fri, 16 Oct 2026 18:40:14 +0800 Subject: [PATCH] =?UTF-8?q?feat(mmap):=20S1c=20=E2=80=94=E2=80=94=20MMAP?= =?UTF-8?q?=20=E6=94=B9=20Linux=20=E5=85=AD=E5=8F=82=E5=BD=A2=E6=80=81?= =?UTF-8?q?=E5=B9=B6=E6=94=AF=E6=8C=81=E6=98=A0=E5=B0=84=20/dev/fb0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 内核 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) 一致且多一层清零。 --- VKernel/Kernel/intr/syscall.vp | 60 +++++++++++++++++++++++++++------- vpsdk/stdlib.vp | 4 ++- vpsdk/syscall.vp | 21 ++++++++++++ 3 files changed, 72 insertions(+), 13 deletions(-) diff --git a/VKernel/Kernel/intr/syscall.vp b/VKernel/Kernel/intr/syscall.vp index d16e6d3..dee31a8 100644 --- a/VKernel/Kernel/intr/syscall.vp +++ b/VKernel/Kernel/intr/syscall.vp @@ -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): diff --git a/vpsdk/stdlib.vp b/vpsdk/stdlib.vp index d6bc534..a0ecbcc 100644 --- a/vpsdk/stdlib.vp +++ b/vpsdk/stdlib.vp @@ -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, diff --git a/vpsdk/syscall.vp b/vpsdk/syscall.vp index ccfaf15..df604e2 100644 --- a/vpsdk/syscall.vp +++ b/vpsdk/syscall.vp @@ -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)