diff --git a/VKernel/Kernel/mm/mm.vp b/VKernel/Kernel/mm/mm.vp index 3dba149..0c8fb78 100644 --- a/VKernel/Kernel/mm/mm.vp +++ b/VKernel/Kernel/mm/mm.vp @@ -193,7 +193,12 @@ class _BuddySystemObject: if self.buddy.free_lists[i]: found_order = i break - if found_order == -1: return None + if found_order == -1: + # [DIAG] 池面耗尽/链表坏:打印请求大小与所需阶数 + _adb: [128]char + viperlib.snprintf(&_adb, 128, "[mm] allocate_block(size=%lu) need order=%d -> NO FREE BLOCK\n", size, order) + serial.puts(&_adb) + return None # 取出空闲块 block: memory_block* = self.buddy.free_lists[found_order] # 从空闲链表中移除块 @@ -287,7 +292,12 @@ class _SlabAllocator: obj_size: uint16 = _slab_obj_size(size_class) aligned_size: uint16 = uint16((obj_size + 15) & ~15) block: memory_block* = BuddySystemObject.allocate_block(4096 + memory_block.__sizeof__()) - if not block: return None + if not block: + # [DIAG] slab 建页拿不到伙伴块 + _cpb: [96]char + viperlib.snprintf(&_cpb, 96, "[mm] slab _create_page(sc=%d) allocate_block(4128) -> NULL\n", size_class) + serial.puts(&_cpb) + return None hdr_off: uint64 = memory_block.__sizeof__() page: slab_page* = slab_page*(uint64(block) + hdr_off) page.magic = SLAB_MAGIC @@ -353,6 +363,11 @@ export def malloc(size: uint64) -> rawptr: sc: int = _slab_size_class(size) if sc >= 0: result: rawptr = SlabAllocator.alloc(sc) + if result is None: + # [DIAG] slab 分配失败(缓存链与建页都失败) + _mb: [96]char + viperlib.snprintf(&_mb, 96, "[mm] malloc(%lu) slab sc=%d -> NULL\n", size, sc) + serial.puts(&_mb) return result hdr: uint64 = memory_block.__sizeof__() if size >= 4096: diff --git a/build.py b/build.py index 02d8868..e441b7b 100644 --- a/build.py +++ b/build.py @@ -3,7 +3,6 @@ import os import sys import subprocess import threading -import glob # 解析参数 @@ -23,19 +22,30 @@ os.system(cmd) shutil.copy("VKernel/__vpcbuild__/output/kernel.bin", "./disk/sys/kernel/x86_64/kernel.bin") -# 额外链接一份带符号的 kernel.elf(仅供分析:objdump / nm / readelf 定位崩溃 rip)。 -# kernel.bin 是 --oformat binary --strip-all 的裸镜像,无符号表,不便把日志里的 -# rip=0x130d45 映射回函数。这里用同一批 .obj + 同一 linker.ld 再链一次(只去掉 -# --oformat binary/--strip-all),段布局与 kernel.bin 一致 → ELF 里的地址可直接对上运行镜像。 +# 额外产出带符号的 kernel.elf(仅供分析:objdump / nm / readelf 定位崩溃 rip)。 +# kernel.bin 是 --oformat binary --strip-all 的裸镜像、无符号表,不便把日志里的 +# rip 映射回函数。要点:**对象顺序决定段内布局**,自行 glob 一组 .obj 去链会得到 +# 与 kernel.bin 不同的地址(实测前 247KB 里 230KB 不同),没法对上日志。 +# 因此用 viperc 自己的 --phase2command:它把 llc/链接命令按“精确顺序”写进 .bat, +# 我们只把该链接行里的 --oformat binary/--strip-all 去掉、输出改为 kernel.elf 再执行。 kernel_elf = "VKernel/__vpcbuild__/output/kernel.elf" -kernel_objs = sorted(glob.glob("VKernel/__vpcbuild__/output/*/*.obj")) -if kernel_objs: - print(f"[build] linking {kernel_elf} for analysis ({len(kernel_objs)} objects)...") - link_rc = subprocess.call(["ld.lld.exe", "-m", "elf_x86_64", "-T", "VKernel/linker.ld", "-o", kernel_elf] + kernel_objs) - if link_rc != 0: +p2c_bat = "VKernel/__vpcbuild__/phase2cmd.bat" +os.system(r'..\..\ViperC\output\viperc.exe --project ./VKernel/project.vpj --phase2command ' + p2c_bat) +link_line = None +if os.path.exists(p2c_bat): + with open(p2c_bat, "r", encoding="utf-8", errors="replace") as f: + for line in f: + low = line.lower() + if "ld.lld" in low and (".bin" in low or "output" in low): + link_line = line.rstrip("\r\n") +if link_line is not None: + elf_line = link_line.replace("--oformat binary", "").replace("--strip-all", "") + elf_line = elf_line.replace("kernel.bin", "kernel.elf") + print("[build] linking kernel.elf for analysis ...") + if os.system(elf_line) != 0: print("[build] 警告: kernel.elf 链接失败(不影响 kernel.bin)") else: - print("[build] 警告: 未找到 kernel 目标文件,跳过 kernel.elf") + print("[build] 警告: 未从 phase2command 取到链接命令,跳过 kernel.elf") # --noapp 优先级高于 --kernel-only:只编译内核,不编译所有库和应用