chore(ViperOS): 落库内核侧进行中的改动(26 文件,+1573/-1805)

内容由用户产出,本次仅代为提交、未做任何语义修改;含 static 修饰符前置迁移等(新增 static 前缀 16 行)。提交消息为中性描述——如需更精确的说明请 amend。
This commit is contained in:
TermiNexus committed 2026-09-28 15:24:52 +08:00
1 parent 1c3fcd6e1e
commit dcb7c5c2c0
26 files changed
+1558 -1790

No files matched your search

+194 -197
View File
@@ -7,53 +7,51 @@ import paging.paging as paging
import sched.process as proc
import sched.sched as sched
import intr.gdt as gdt
import t, c
import viperlib
import string
import asm
# Do NOT import KERN_STACK_SIZE/USER_STACK_SIZE from process - CDefine cross-module import is broken
# Redefine them here to ensure correct values
KERN_STACK_SIZE: t.CDefine = 8192
USER_STACK_SIZE: t.CDefine = 65536
import viperlib
import string
import asm
import t, c
define KERN_STACK_SIZE = 8192
define USER_STACK_SIZE = 65536
ELFMAG0: t.CDefine = 0x7F
ELFMAG1: t.CDefine = 0x45
ELFMAG2: t.CDefine = 0x4C
ELFMAG3: t.CDefine = 0x46
ELFCLASS64: t.CDefine = 2
ELFDATA2LSB: t.CDefine = 1
ET_EXEC: t.CDefine = 2
ET_DYN: t.CDefine = 3
EM_X86_64: t.CDefine = 62
PT_LOAD: t.CDefine = 1
PT_DYNAMIC: t.CDefine = 2
PF_X: t.CDefine = 1
PF_W: t.CDefine = 2
PF_R: t.CDefine = 4
DT_NULL: t.CDefine = 0
DT_HASH: t.CDefine = 4
DT_STRTAB: t.CDefine = 5
DT_SYMTAB: t.CDefine = 6
DT_STRSZ: t.CDefine = 10
DT_SYMENT: t.CDefine = 11
DT_RELA: t.CDefine = 7
DT_RELASZ: t.CDefine = 8
DT_RELAENT: t.CDefine = 9
DT_PLTRELSZ: t.CDefine = 2
DT_JMPREL: t.CDefine = 23
R_X86_64_64: t.CDefine = 1
R_X86_64_GLOB_DAT: t.CDefine = 6
R_X86_64_JUMP_SLOT: t.CDefine = 7
R_X86_64_RELATIVE: t.CDefine = 8
STB_GLOBAL: t.CDefine = 1
STB_WEAK: t.CDefine = 2
define ELFMAG0 = 0x7F
define ELFMAG1 = 0x45
define ELFMAG2 = 0x4C
define ELFMAG3 = 0x46
define ELFCLASS64 = 2
define ELFDATA2LSB = 1
define ET_EXEC = 2
define ET_DYN = 3
define EM_X86_64 = 62
define PT_LOAD = 1
define PT_DYNAMIC = 2
define PF_X = 1
define PF_W = 2
define PF_R = 4
define DT_NULL = 0
define DT_HASH = 4
define DT_STRTAB = 5
define DT_SYMTAB = 6
define DT_STRSZ = 10
define DT_SYMENT = 11
define DT_RELA = 7
define DT_RELASZ = 8
define DT_RELAENT = 9
define DT_PLTRELSZ = 2
define DT_JMPREL = 23
define R_X86_64_64 = 1
define R_X86_64_GLOB_DAT = 6
define R_X86_64_JUMP_SLOT = 7
define R_X86_64_RELATIVE = 8
define STB_GLOBAL = 1
define STB_WEAK = 2
@c.Attribute(t.attr.packed)
@__attribute__(packed)
class Elf64_Ehdr:
e_ident: t.CArray[uint8, 16]
e_ident: [16]uint8
e_type: uint16
e_machine: uint16
e_version: uint32
@@ -68,7 +66,7 @@ class Elf64_Ehdr:
e_shnum: uint16
e_shstrndx: uint16
@c.Attribute(t.attr.packed)
@__attribute__(packed)
class Elf64_Phdr:
p_type: uint32
p_flags: uint32
@@ -79,9 +77,9 @@ class Elf64_Phdr:
p_memsz: uint64
p_align: uint64
MAX_PHDRS: t.CDefine = 16
define MAX_PHDRS = 16
@c.Attribute(t.attr.packed)
@__attribute__(packed)
class Elf64_Shdr:
sh_name: uint32
sh_type: uint32
@@ -94,7 +92,7 @@ class Elf64_Shdr:
sh_addralign: uint64
sh_entsize: uint64
@c.Attribute(t.attr.packed)
@__attribute__(packed)
class Elf64_Sym:
st_name: uint32
st_info: uint8
@@ -103,64 +101,64 @@ class Elf64_Sym:
st_value: uint64
st_size: uint64
@c.Attribute(t.attr.packed)
@__attribute__(packed)
class Elf64_Rela:
r_offset: uint64
r_info: uint64
r_addend: int64
@c.Attribute(t.attr.packed)
@__attribute__(packed)
class Elf64_Dyn:
d_tag: int64
d_val: uint64
MAX_SHDRS: t.CDefine = 64
MAX_DYNS: t.CDefine = 64
MAX_RELAS: t.CDefine = 256
define MAX_SHDRS = 64
define MAX_DYNS = 64
define MAX_RELAS = 256
def load_elf(path: t.CConst | str, do_map: int = 1) -> t.CPtr:
fp: fat32_types.fileobj | t.CPtr = fat32.open(path, fat32_types.FA_READ)
def load_elf(path: const str, do_map: int = 1) -> rawptr:
fp: fat32_types.fileobj* = fat32.open(path, fat32_types.FA_READ)
if fp is None:
err: uint32 = fat32.last_error()
eb: t.CArray[t.CChar, 64]
viperlib.snprintf(c.Addr(eb), 64, "[elf] failed to open file err=%d\n", err)
eb: [64]char
viperlib.snprintf(&eb, 64, "[elf] failed to open file err=%d\n", err)
serial.puts(eb)
return None
ehdr_buf: t.CArray[uint8, 64]
string.memset(c.Addr(ehdr_buf), 0, 64)
read_len: uint32 = fat32.read(fp, c.Addr(ehdr_buf), 64)
ehdr_buf: [64]uint8
string.memset(&ehdr_buf, 0, 64)
read_len: uint32 = fat32.read(fp, &ehdr_buf, 64)
# [DIAG] read_len 实际值 + call 后 RAX 快照:区分"call 返回错"(rl=0 rax=0)
# vs "store 后 RAX 被覆盖"(rl=0 rax=64)
_rax_v2: uint64 = 0
# 读 RAX 未声明输入:至少须声明 CLOBBER_RAX,让编译器知道本块不保留
# RAX(此前只声明 ~{memory},编译器可假设 RAX 存活 → 读到的值不保证是
# 紧邻 call 的返回值)。N16。(本块为 [DIAG] 探针,问题定位后建议删除。)
c.Asm(f"""mov {c.AsmOut(_rax_v2, t.ASM_DESCR.OUTPUT_REG)}, rax""",
op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RAX])
_dbrl: t.CArray[t.CChar, 96]
viperlib.snprintf(c.Addr(_dbrl), 96, "[elf] rl=%lu rax=0x%lx\n", read_len, _rax_v2)
serial.puts(c.Addr(_dbrl))
__asm__(f"""mov {asmout(_rax_v2, ASM_DESCR.OUTPUT_REG)}, rax""",
op=[ASM_DESCR.CLOBBER_MEMORY, ASM_DESCR.CLOBBER_RAX])
_dbrl: [96]char
viperlib.snprintf(&_dbrl, 96, "[elf] rl=%lu rax=0x%lx\n", read_len, _rax_v2)
serial.puts(&_dbrl)
if read_len < 64:
serial.puts("[elf] failed to read ehdr\n")
fat32.close(fp)
return None
ehdr: Elf64_Ehdr | t.CPtr = c.Addr(ehdr_buf)
ehdr: Elf64_Ehdr* = &ehdr_buf
if ehdr.e_ident[0] != ELFMAG0 or ehdr.e_ident[1] != ELFMAG1 or ehdr.e_ident[2] != ELFMAG2 or ehdr.e_ident[3] != ELFMAG3:
serial.puts("[elf] bad magic\n")
# [DIAG] 一次性定位 bad magic:dump ehdr_buf 前 16 字节 + read_len,
# 区分全 0(read 未写)/ 目录数据(sector 错)/ 垃圾(seek 或缓冲错)。
_dbg_mg: t.CArray[t.CChar, 120]
viperlib.snprintf(c.Addr(_dbg_mg), 120,
_dbg_mg: [120]char
viperlib.snprintf(&_dbg_mg, 120,
"[elf] mg=%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x rl=%lu fp=%lu/%lu/%lu/%lu\n",
ehdr_buf[0], ehdr_buf[1], ehdr_buf[2], ehdr_buf[3],
ehdr_buf[4], ehdr_buf[5], ehdr_buf[6], ehdr_buf[7],
ehdr_buf[8], ehdr_buf[9], ehdr_buf[10], ehdr_buf[11],
ehdr_buf[12], ehdr_buf[13], ehdr_buf[14], ehdr_buf[15],
read_len, fp.first_cluster, fp.current_cluster, fp.file_pos, fp.file_size)
serial.puts(c.Addr(_dbg_mg))
serial.puts(&_dbg_mg)
fat32.close(fp)
return None
@@ -182,15 +180,15 @@ def load_elf(path: t.CConst | str, do_map: int = 1) -> t.CPtr:
if ehdr.e_machine != EM_X86_64:
serial.puts("[elf] not x86_64\n")
# [DIAG] e_machine 错:dump ehdr 前 24 字节(read_len=64 正确但内容错)
_dbg_em: t.CArray[t.CChar, 128]
viperlib.snprintf(c.Addr(_dbg_em), 128,
_dbg_em: [128]char
viperlib.snprintf(&_dbg_em, 128,
"[elf] ehdr=%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x rl=%lu\n",
ehdr_buf[0], ehdr_buf[1], ehdr_buf[2], ehdr_buf[3],
ehdr_buf[4], ehdr_buf[5], ehdr_buf[6], ehdr_buf[7],
ehdr_buf[8], ehdr_buf[9], ehdr_buf[10], ehdr_buf[11],
ehdr_buf[12], ehdr_buf[13], ehdr_buf[14], ehdr_buf[15],
ehdr_buf[16], ehdr_buf[17], ehdr_buf[18], ehdr_buf[19], read_len)
serial.puts(c.Addr(_dbg_em))
serial.puts(&_dbg_em)
fat32.close(fp)
return None
@@ -204,17 +202,17 @@ def load_elf(path: t.CConst | str, do_map: int = 1) -> t.CPtr:
fat32.close(fp)
return None
cr: t.CArray[t.CChar, 80]
viperlib.snprintf(c.Addr(cr), 80, "[elf] entry=0x%lx phoff=%lu phentsize=%u phnum=%u\n", entry_point, phoff, phentsize, phnum)
cr: [80]char
viperlib.snprintf(&cr, 80, "[elf] entry=0x%lx phoff=%lu phentsize=%u phnum=%u\n", entry_point, phoff, phentsize, phnum)
serial.puts(cr)
phdr_bufs: t.CArray[Elf64_Phdr, MAX_PHDRS]
string.memset(c.Addr(phdr_bufs), 0, MAX_PHDRS * 56)
phdr_bufs: [MAX_PHDRS]Elf64_Phdr
string.memset(&phdr_bufs, 0, MAX_PHDRS * 56)
for pi in range(phnum):
phdr_off: uint64 = phoff + uint64(pi) * uint64(phentsize)
fat32.seek(fp, uint32(phdr_off))
fat32.read(fp, c.Addr(phdr_bufs[pi]), 56)
fat32.read(fp, &phdr_bufs[pi], 56)
found_load: int = 0
lowest_vaddr: uint64 = 0
@@ -240,13 +238,13 @@ def load_elf(path: t.CConst | str, do_map: int = 1) -> t.CPtr:
total_memsz: uint64 = highest_vaddr_end - lowest_vaddr
total_pages: uint64 = (total_memsz + 0xFFF) // 0x1000
cr2: t.CArray[t.CChar, 80]
viperlib.snprintf(c.Addr(cr2), 80, "[elf] vaddr 0x%lx-0x%lx pages=%lu\n", lowest_vaddr, highest_vaddr_end, total_pages)
cr2: [80]char
viperlib.snprintf(&cr2, 80, "[elf] vaddr 0x%lx-0x%lx pages=%lu\n", lowest_vaddr, highest_vaddr_end, total_pages)
serial.puts(cr2)
raw_alloc: t.CPtr = mm.malloc(total_pages * 0x1000 + 0x1000)
_db_ra: t.CArray[t.CChar, 80]
viperlib.snprintf(c.Addr(_db_ra), 80, "[elf] malloc ret raw_alloc=0x%lx\n", uint64(raw_alloc))
raw_alloc: rawptr = mm.malloc(total_pages * 0x1000 + 0x1000)
_db_ra: [80]char
viperlib.snprintf(&_db_ra, 80, "[elf] malloc ret raw_alloc=0x%lx\n", uint64(raw_alloc))
serial.puts(_db_ra)
if not raw_alloc:
serial.puts("[elf] malloc failed\n")
@@ -254,7 +252,7 @@ def load_elf(path: t.CConst | str, do_map: int = 1) -> t.CPtr:
return None
phys_base_aligned: uint64 = (uint64(raw_alloc) + uint64(0xFFF)) & ~uint64(0xFFF)
phys_base: t.CPtr = t.CPtr(phys_base_aligned)
phys_base: rawptr = rawptr(phys_base_aligned)
string.memset(phys_base, 0, total_pages * 0x1000)
@@ -265,14 +263,14 @@ def load_elf(path: t.CConst | str, do_map: int = 1) -> t.CPtr:
filesz: uint64 = phdr_bufs[pi].p_filesz
memsz: uint64 = phdr_bufs[pi].p_memsz
dest_off: uint64 = vaddr - lowest_vaddr
dest: t.CPtr = t.CPtr(uint64(phys_base) + dest_off)
dest: rawptr = rawptr(uint64(phys_base) + dest_off)
if filesz > 0:
fat32.seek(fp, uint32(file_off))
fat32.read(fp, dest, uint32(filesz))
if memsz > filesz:
bss_start: t.CPtr = t.CPtr(uint64(dest) + filesz)
bss_start: rawptr = rawptr(uint64(dest) + filesz)
bss_len: uint64 = memsz - filesz
string.memset(bss_start, 0, bss_len)
@@ -296,32 +294,32 @@ def load_elf(path: t.CConst | str, do_map: int = 1) -> t.CPtr:
page_flags: uint64 = paging.PTE_PRESENT | paging.PTE_WRITABLE | paging.PTE_USER
paging.MapPage(virt_addr, phys_addr, page_flags)
entry_addr: t.CPtr = t.CPtr(entry_point)
entry_addr: rawptr = rawptr(entry_point)
return entry_addr
def run_elf(path: t.CConst | str) -> int:
entry: t.CPtr = load_elf(path)
def run_elf(path: const str) -> int:
entry: rawptr = load_elf(path)
if entry is None:
serial.puts("[elf] load failed\n")
return -1
serial.puts("[elf] jumping to entry...\n")
# 被调方是任意 ELF 入口(外部代码):`call` 破坏全部 caller-saved 寄存器,
# 除 rax/rcx/rdx/r8~r11 外必须声明 rsi/rdi(N20)。
c.Asm(f"""call {c.AsmInp(entry, t.ASM_DESCR.REG_ANY)}""",
op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RAX,
t.ASM_DESCR.CLOBBER_RCX, t.ASM_DESCR.CLOBBER_RDX,
t.ASM_DESCR.CLOBBER_RSI, t.ASM_DESCR.CLOBBER_RDI,
t.ASM_DESCR.CLOBBER_R8, t.ASM_DESCR.CLOBBER_R9,
t.ASM_DESCR.CLOBBER_R10, t.ASM_DESCR.CLOBBER_R11])
__asm__(f"""call {asminp(entry, ASM_DESCR.REG_ANY)}""",
op=[ASM_DESCR.CLOBBER_MEMORY, ASM_DESCR.CLOBBER_RAX,
ASM_DESCR.CLOBBER_RCX, ASM_DESCR.CLOBBER_RDX,
ASM_DESCR.CLOBBER_RSI, ASM_DESCR.CLOBBER_RDI,
ASM_DESCR.CLOBBER_R8, ASM_DESCR.CLOBBER_R9,
ASM_DESCR.CLOBBER_R10, ASM_DESCR.CLOBBER_R11])
serial.puts("[elf] returned from entry\n")
return 0
MAX_SPAWNED: t.CDefine = 8
_elf_entries: t.CArray[t.CPtr, MAX_SPAWNED]
define MAX_SPAWNED = 8
_elf_entries: [MAX_SPAWNED]rawptr
# User stack virtual address: top of 48-bit user space, 64KB below
USER_STACK_VTOP: t.CDefine = 0x7FFFFFE00000
define USER_STACK_VTOP = 0x7FFFFFE00000
# Globals for ELF mapping info (set by load_elf when do_map=0, used by spawn_elf
# to map ELF pages in the cloned PML4 instead of kernel PML4).
@@ -332,26 +330,26 @@ USER_STACK_VTOP: t.CDefine = 0x7FFFFFE00000
# in the cloned PML4 after clone_for_process.
_last_elf_phys_page_start: uint64 = 0
_last_elf_virt_page_start: uint64 = 0
_last_elf_num_map_pages: uint64 = 0
_last_elf_num_map_pages: uint64 = 0
def _elf_entry_wrapper(arg: t.CPtr) -> int:
def _elf_entry_wrapper(arg: rawptr) -> int:
pid: int = int(uint64(arg))
_db1: t.CArray[t.CChar, 64]
viperlib.snprintf(c.Addr(_db1), 64, "[elf] wrapper pid=%d\n", pid)
_db1: [64]char
viperlib.snprintf(&_db1, 64, "[elf] wrapper pid=%d\n", pid)
serial.puts(_db1)
# Disable interrupts around switch_pid + MapPage + TSS setup: @pml4 is a global
# that switch_pid modifies. A timer interrupt mid-section would make the scheduler
# call switch_pid for another thread, corrupting @pml4 for our MapPage calls.
asm.cli()
proc.switch_pid(pid)
cur_p: proc.Process | t.CPtr = proc.ProcessManager.current()
entry_fn: t.CPtr = cur_p.entry
cur_p: proc.Process* = proc.ProcessManager.current()
entry_fn: rawptr = cur_p.entry
# [DIAG] 定位用户进程首个指令 PF:打印 entry 实际值(PF cr2=ELF 物理区最后一页,
# 疑似 entry 被写成 phys 地址而非虚拟 0x400000)。
_dbw: t.CArray[t.CChar, 160]
viperlib.snprintf(c.Addr(_dbw), 160, "[wrap] pid=%d cur=0x%lx ent=0x%lx ebase=0x%lx ks=0x%lx us=0x%lx\n",
_dbw: [160]char
viperlib.snprintf(&_dbw, 160, "[wrap] pid=%d cur=0x%lx ent=0x%lx ebase=0x%lx ks=0x%lx us=0x%lx\n",
pid, uint64(cur_p), uint64(entry_fn), cur_p.elf_base, cur_p.kern_stack, cur_p.user_stack)
serial.puts(c.Addr(_dbw))
serial.puts(&_dbw)
if entry_fn is not None:
user_stack_vtop: uint64 = USER_STACK_VTOP
us_sz: uint64 = USER_STACK_SIZE
@@ -375,47 +373,46 @@ def _elf_entry_wrapper(arg: t.CPtr) -> int:
# This prevents timer interrupt preemption between TSS setup and iretq.
# Drop to Ring 3 user mode via iretq
proc.drop_to_user_mode(entry_fn, user_stack_vtop, cur_p.kern_stack)
cur: proc.Process | t.CPtr = proc.ProcessManager.current()
cur: proc.Process* = proc.ProcessManager.current()
cur.exit()
return 0
def spawn_elf(path: t.CConst | str) -> int:
def spawn_elf(path: const str) -> int:
fat32.lock()
name_start: int = 0
si: int = 0
while True:
ch: t.CChar = path[si]
if ch == 0: break
if ch == 47:
name_start = si + 1
ch: char = path[si]
if ch == 0: break
if ch == 47: name_start = si + 1
si += 1
lowest_vaddr: uint64 = 0
highest_vaddr_end: uint64 = 0
fp_scan: fat32_types.fileobj | t.CPtr = fat32.open(path, fat32_types.FA_READ)
fp_scan: fat32_types.fileobj* = fat32.open(path, fat32_types.FA_READ)
if fp_scan is None:
serr: uint32 = fat32.last_error()
seb: t.CArray[t.CChar, 64]
viperlib.snprintf(c.Addr(seb), 64, "[elf] spawn scan open failed err=%d\n", serr)
serial.puts(seb)
seb: [64]char
viperlib.snprintf(&seb, 64, "[elf] spawn scan open failed err=%d\n", serr)
serial.puts(&seb)
fat32.unlock()
return -1
if fp_scan is not None:
ehdr_buf_s: t.CArray[uint8, 64]
string.memset(c.Addr(ehdr_buf_s), 0, 64)
fat32.read(fp_scan, c.Addr(ehdr_buf_s), 64)
ehdr_s: Elf64_Ehdr | t.CPtr = c.Addr(ehdr_buf_s)
ehdr_buf_s: [64]uint8
string.memset(&ehdr_buf_s, 0, 64)
fat32.read(fp_scan, &ehdr_buf_s, 64)
ehdr_s: Elf64_Ehdr* = &ehdr_buf_s
if ehdr_s.e_type == ET_EXEC or ehdr_s.e_type == ET_DYN:
phoff_s: uint64 = ehdr_s.e_phoff
phentsize_s: uint16 = ehdr_s.e_phentsize
phnum_s: uint16 = ehdr_s.e_phnum
if phentsize_s > 0 and phnum_s > 0 and phnum_s <= MAX_PHDRS:
phdr_bufs_s: t.CArray[Elf64_Phdr, MAX_PHDRS]
string.memset(c.Addr(phdr_bufs_s), 0, MAX_PHDRS * 56)
phdr_bufs_s: [MAX_PHDRS]Elf64_Phdr
string.memset(&phdr_bufs_s, 0, MAX_PHDRS * 56)
found_load_s: int = 0
for pi_s in range(phnum_s):
fat32.seek(fp_scan, uint32(phoff_s + uint64(pi_s) * uint64(phentsize_s)))
fat32.read(fp_scan, c.Addr(phdr_bufs_s[pi_s]), 56)
fat32.read(fp_scan, &phdr_bufs_s[pi_s], 56)
if phdr_bufs_s[pi_s].p_type == PT_LOAD:
seg_end_s: uint64 = phdr_bufs_s[pi_s].p_vaddr + phdr_bufs_s[pi_s].p_memsz
if found_load_s == 0:
@@ -437,7 +434,7 @@ def spawn_elf(path: t.CConst | str) -> int:
# do_map=0: load_elf stores mapping info in globals for spawn_elf to use.
# ROOT CAUSE FIX: previously load_elf mapped ELF vaddr (e.g. 0x400000) into
# kernel PML4, overwriting identity mapping of buddy memory_block headers.
entry: t.CPtr = load_elf(path, 0)
entry: rawptr = load_elf(path, 0)
if entry is None:
serial.puts("[elf] spawn: load failed\n")
fat32.unlock()
@@ -445,9 +442,9 @@ def spawn_elf(path: t.CConst | str) -> int:
# Clone kernel PML4 (identity mapping intact, no ELF mapping yet)
proc_pml4: uint64 = paging.clone_for_process(isolate_va)
slog1: t.CArray[t.CChar, 80]
viperlib.snprintf(c.Addr(slog1), 80, "[elf] spawn: clone pml4=0x%lx va=0x%lx\n", proc_pml4, isolate_va)
serial.puts(slog1)
slog1: [80]char
viperlib.snprintf(&slog1, 80, "[elf] spawn: clone pml4=0x%lx va=0x%lx\n", proc_pml4, isolate_va)
serial.puts(&slog1)
if proc_pml4 == 0:
serial.puts("[elf] spawn: clone_for_process failed\n")
fat32.unlock()
@@ -460,22 +457,22 @@ def spawn_elf(path: t.CConst | str) -> int:
# interrupt mid-section would call switch_pid, corrupting @pml4.
asm.cli()
_kernel_cr3: uint64 = 0
c.Asm(f"""mov {c.AsmOut(_kernel_cr3, t.ASM_DESCR.OUTPUT_REG)}, cr3""", op=[t.ASM_DESCR.CLOBBER_MEMORY])
c.Asm(f"mov cr3, {c.AsmInp(proc_pml4, t.ASM_DESCR.REG_ANY)}", op=[t.ASM_DESCR.CLOBBER_MEMORY])
__asm__(f"""mov {asmout(_kernel_cr3, ASM_DESCR.OUTPUT_REG)}, cr3""", op=[ASM_DESCR.CLOBBER_MEMORY])
__asm__(f"mov cr3, {asminp(proc_pml4, ASM_DESCR.REG_ANY)}", op=[ASM_DESCR.CLOBBER_MEMORY])
paging.set_active_pml4(proc_pml4)
mi: uint64
for mi in range(_last_elf_num_map_pages):
_va: uint64 = _last_elf_virt_page_start + mi * 0x1000
_pa: uint64 = _last_elf_phys_page_start + mi * 0x1000
paging.MapPage(_va, _pa, paging.PTE_PRESENT | paging.PTE_WRITABLE | paging.PTE_USER)
c.Asm(f"mov cr3, {c.AsmInp(_kernel_cr3, t.ASM_DESCR.REG_ANY)}", op=[t.ASM_DESCR.CLOBBER_MEMORY])
__asm__(f"mov cr3, {asminp(_kernel_cr3, ASM_DESCR.REG_ANY)}", op=[ASM_DESCR.CLOBBER_MEMORY])
paging.set_active_pml4(_kernel_cr3)
asm.sti()
# path[name_start:] 切片表达式 translate_subscript 不支持 Slice(返回 None)→
# 作为实参丢 name、entry 错位成第一参数(TPV 已修,此处指针算术双保险)
nm_ptr: t.CConst | t.CChar | t.CPtr = t.CConst(uint64(path) + uint64(name_start), t.CPtr)
p: proc.Process | t.CPtr = proc.ProcessManager.create_process(nm_ptr, entry)
nm_ptr: const str = str(uint64(path) + uint64(name_start))
p: proc.Process* = proc.ProcessManager.create_process(nm_ptr, entry)
if p is None:
serial.puts("[elf] spawn: create_process failed\n")
fat32.unlock()
@@ -485,7 +482,7 @@ def spawn_elf(path: t.CConst | str) -> int:
if p.pid >= 0 and p.pid < MAX_SPAWNED:
_elf_entries[p.pid] = entry
th: sched.Thread | t.CPtr = sched.Scheduler.create_thread(t.CPtr(_elf_entry_wrapper), t.CPtr(uint64(p.pid)), p.pid)
th: sched.Thread* = sched.Scheduler.create_thread(&_elf_entry_wrapper, rawptr(uint64(p.pid)), p.pid)
if th is None:
serial.puts("[elf] spawn: create_thread failed\n")
p.exit()
@@ -493,26 +490,26 @@ def spawn_elf(path: t.CConst | str) -> int:
return -3
tid: int = th.tid
p.addThread(tid)
slog: t.CArray[t.CChar, 80]
viperlib.snprintf(c.Addr(slog), 80, "[elf] spawn: pid=%d tid=%d entry=0x%lx pml4=0x%lx\n", p.pid, tid, uint64(entry), p.pml4_root)
serial.puts(slog)
slog: [80]char
viperlib.snprintf(&slog, 80, "[elf] spawn: pid=%d tid=%d entry=0x%lx pml4=0x%lx\n", p.pid, tid, uint64(entry), p.pml4_root)
serial.puts(&slog)
# [DIAG] 确认 return p.pid 的实际值(main 收到 pid=0 而此处打印 3)
_dbw2: t.CArray[t.CChar, 64]
viperlib.snprintf(c.Addr(_dbw2), 64, "[elf] spawn ret pid=%d\n", p.pid)
serial.puts(c.Addr(_dbw2))
_dbw2: [64]char
viperlib.snprintf(&_dbw2, 64, "[elf] spawn ret pid=%d\n", p.pid)
serial.puts(&_dbw2)
fat32.unlock()
return p.pid
def _resolve_symbol(name: t.CConst | t.CChar | t.CPtr) -> t.CPtr:
def _resolve_symbol(name: const str) -> rawptr:
nm: int = 0
while c.Deref(name + nm) != 0:
while name[nm] != 0:
nm += 1
cmp_name: t.CConst | t.CChar | t.CPtr = name
cmp_name: const str = name
cmp_len: int = nm
if nm > 9:
sha1_len2: int = 0
for si2 in range(nm):
ch2: t.CChar = c.Deref(name + si2)
ch2: char = name[si2]
if ch2 == 46:
if sha1_len2 >= 8:
cmp_name = str(uint64(name) + si2 + 1)
@@ -527,35 +524,35 @@ def _resolve_symbol(name: t.CConst | t.CChar | t.CPtr) -> t.CPtr:
if cmp_len == 11:
match: int = 1
for i in range(cmp_len):
if c.Deref(cmp_name + i) != c.Deref("serial_puts" + i):
if cmp_name[i] != "serial_puts"[i]:
match = 0
if match:
return c.Addr(serial.puts)
return &serial.puts
return None
_so_strtab: t.CPtr
_so_symtab: t.CPtr
_so_strtab: rawptr
_so_symtab: rawptr
_so_syment: uint64
_so_sym_count: int
def load_so(path: t.CConst | str) -> t.CPtr:
def load_so(path: const str) -> rawptr:
fat32.lock()
fp: fat32_types.fileobj | t.CPtr = fat32.open(path, fat32_types.FA_READ)
fp: fat32_types.fileobj* = fat32.open(path, fat32_types.FA_READ)
if fp is None:
serial.puts("[so] failed to open file\n")
fat32.unlock()
return None
ehdr_buf: t.CArray[uint8, 64]
string.memset(c.Addr(ehdr_buf), 0, 64)
read_len: uint32 = fat32.read(fp, c.Addr(ehdr_buf), 64)
ehdr_buf: [64]uint8
string.memset(&ehdr_buf, 0, 64)
read_len: uint32 = fat32.read(fp, &ehdr_buf, 64)
if read_len < 64:
serial.puts("[so] failed to read ehdr\n")
fat32.close(fp)
fat32.unlock()
return None
ehdr: Elf64_Ehdr | t.CPtr = c.Addr(ehdr_buf)
ehdr: Elf64_Ehdr* = &ehdr_buf
if ehdr.e_ident[0] != ELFMAG0 or ehdr.e_ident[1] != ELFMAG1 or ehdr.e_ident[2] != ELFMAG2 or ehdr.e_ident[3] != ELFMAG3:
serial.puts("[so] bad magic\n")
fat32.close(fp)
@@ -588,12 +585,12 @@ def load_so(path: t.CConst | str) -> t.CPtr:
fat32.unlock()
return None
phdr_bufs: t.CArray[Elf64_Phdr, MAX_PHDRS]
string.memset(c.Addr(phdr_bufs), 0, MAX_PHDRS * 56)
phdr_bufs: [MAX_PHDRS]Elf64_Phdr
string.memset(&phdr_bufs, 0, MAX_PHDRS * 56)
for pi in range(phnum):
phdr_off: uint64 = phoff + uint64(pi) * uint64(phentsize)
fat32.seek(fp, uint32(phdr_off))
fat32.read(fp, c.Addr(phdr_bufs[pi]), 56)
fat32.read(fp, &phdr_bufs[pi], 56)
found_load: int = 0
lowest_vaddr: uint64 = 0
@@ -621,7 +618,7 @@ def load_so(path: t.CConst | str) -> t.CPtr:
total_pages: uint64 = (total_memsz + 0xFFF) // 0x1000
so_load_addr: uint64 = 0x600000
raw_alloc: t.CPtr = mm.malloc(total_pages * 0x1000 + 0x1000)
raw_alloc: rawptr = mm.malloc(total_pages * 0x1000 + 0x1000)
if not raw_alloc:
serial.puts("[so] malloc failed\n")
fat32.close(fp)
@@ -629,7 +626,7 @@ def load_so(path: t.CConst | str) -> t.CPtr:
return None
phys_base_aligned: uint64 = (uint64(raw_alloc) + 0xFFF) & ~uint64(0xFFF)
phys_base: t.CPtr = t.CPtr(phys_base_aligned)
phys_base: rawptr = rawptr(phys_base_aligned)
string.memset(phys_base, 0, total_pages * 0x1000)
for pi in range(phnum):
@@ -639,12 +636,12 @@ def load_so(path: t.CConst | str) -> t.CPtr:
filesz: uint64 = phdr_bufs[pi].p_filesz
memsz: uint64 = phdr_bufs[pi].p_memsz
dest_off: uint64 = vaddr - lowest_vaddr
dest: t.CPtr = t.CPtr(uint64(phys_base) + dest_off)
dest: rawptr = rawptr(uint64(phys_base) + dest_off)
if filesz > 0:
fat32.seek(fp, uint32(file_off))
fat32.read(fp, dest, uint32(filesz))
if memsz > filesz:
bss_start: t.CPtr = t.CPtr(uint64(dest) + filesz)
bss_start: rawptr = rawptr(uint64(dest) + filesz)
bss_len: uint64 = memsz - filesz
string.memset(bss_start, 0, bss_len)
@@ -660,8 +657,8 @@ def load_so(path: t.CConst | str) -> t.CPtr:
base_vaddr: uint64 = so_load_addr + lowest_vaddr
dyn_buf: t.CArray[Elf64_Dyn, MAX_DYNS]
string.memset(c.Addr(dyn_buf), 0, MAX_DYNS * 16)
dyn_buf: [MAX_DYNS]Elf64_Dyn
string.memset(&dyn_buf, 0, MAX_DYNS * 16)
dyn_count: int = 0
for pi in range(phnum):
if phdr_bufs[pi].p_type == PT_DYNAMIC:
@@ -671,7 +668,7 @@ def load_so(path: t.CConst | str) -> t.CPtr:
max_dyn_bytes: uint32 = uint32(MAX_DYNS * 16)
if filesz_d > max_dyn_bytes:
filesz_d = max_dyn_bytes
dyn_read: uint32 = fat32.read(fp, c.Addr(dyn_buf), filesz_d)
dyn_read: uint32 = fat32.read(fp, &dyn_buf, filesz_d)
dyn_count = int(dyn_read) // 16
strtab_vaddr: uint64 = 0
@@ -693,51 +690,51 @@ def load_so(path: t.CConst | str) -> t.CPtr:
elif dyn_buf[di].d_tag == DT_JMPREL: jmprel_vaddr = dyn_buf[di].d_val
elif dyn_buf[di].d_tag == DT_PLTRELSZ: pltrelsz = dyn_buf[di].d_val
strtab_ptr: t.CPtr = t.CPtr(strtab_vaddr + so_load_addr)
symtab_ptr: t.CPtr = t.CPtr(symtab_vaddr + so_load_addr)
strtab_ptr: rawptr = rawptr(strtab_vaddr + so_load_addr)
symtab_ptr: rawptr = rawptr(symtab_vaddr + so_load_addr)
if rela_vaddr != 0 and relasz > 0:
rela_count: uint64 = relasz // 24
for ri in range(rela_count):
rela: Elf64_Rela | t.CPtr = t.CPtr(uint64(rela_vaddr) + so_load_addr + ri * 24)
rela: Elf64_Rela* = Elf64_Rela*(uint64(rela_vaddr) + so_load_addr + ri * 24)
r_type: uint32 = uint32(rela.r_info & 0xFFFFFFFF)
r_sym: uint32 = uint32(rela.r_info >> 32)
target_addr: t.CPtr = t.CPtr(rela.r_offset + so_load_addr)
target_addr: rawptr = rawptr(rela.r_offset + so_load_addr)
if r_type == R_X86_64_RELATIVE:
val: uint64 = uint64(rela.r_addend) + so_load_addr
string.memcpy(target_addr, c.Addr(val), 8)
string.memcpy(target_addr, &val, 8)
elif r_type == R_X86_64_64 or r_type == R_X86_64_GLOB_DAT or r_type == R_X86_64_JUMP_SLOT:
sym: Elf64_Sym | t.CPtr = t.CPtr(uint64(symtab_ptr) + uint64(r_sym) * syment)
sym_name: t.CConst | str = t.CPtr(uint64(strtab_ptr) + sym.st_name)
resolved: t.CPtr = _resolve_symbol(sym_name)
sym: Elf64_Sym* = Elf64_Sym*(uint64(symtab_ptr) + uint64(r_sym) * syment)
sym_name: const str = str(uint64(strtab_ptr) + sym.st_name)
resolved: rawptr = _resolve_symbol(sym_name)
if resolved is not None:
val2: uint64 = uint64(resolved) + uint64(rela.r_addend)
string.memcpy(target_addr, c.Addr(val2), 8)
string.memcpy(target_addr, &val2, 8)
elif sym.st_value != 0:
val3: uint64 = sym.st_value + so_load_addr + uint64(rela.r_addend)
string.memcpy(target_addr, c.Addr(val3), 8)
string.memcpy(target_addr, &val3, 8)
if jmprel_vaddr != 0 and pltrelsz > 0:
jmprel_count: uint64 = pltrelsz // 24
for ji in range(jmprel_count):
rela2: Elf64_Rela | t.CPtr = t.CPtr(jmprel_vaddr + so_load_addr + ji * 24)
rela2: Elf64_Rela* = Elf64_Rela*(jmprel_vaddr + so_load_addr + ji * 24)
r_type2: uint32 = uint32(rela2.r_info & 0xFFFFFFFF)
r_sym2: uint32 = uint32(rela2.r_info >> 32)
target2: t.CPtr = t.CPtr(rela2.r_offset + so_load_addr)
target2: rawptr = rawptr(rela2.r_offset + so_load_addr)
if r_type2 == R_X86_64_JUMP_SLOT or r_type2 == R_X86_64_GLOB_DAT:
sym2: Elf64_Sym | t.CPtr = t.CPtr(uint64(symtab_ptr) + uint64(r_sym2) * syment)
sym_name2: t.CConst | str = t.CPtr(uint64(strtab_ptr) + sym2.st_name)
resolved2: t.CPtr = _resolve_symbol(sym_name2)
sym2: Elf64_Sym* = Elf64_Sym*(uint64(symtab_ptr) + uint64(r_sym2) * syment)
sym_name2: const str = str(uint64(strtab_ptr) + sym2.st_name)
resolved2: rawptr = _resolve_symbol(sym_name2)
if resolved2 is not None:
val4: uint64 = uint64(resolved2) + uint64(rela2.r_addend)
string.memcpy(target2, c.Addr(val4), 8)
string.memcpy(target2, &val4, 8)
elif sym2.st_value != 0:
val5: uint64 = sym2.st_value + so_load_addr + uint64(rela2.r_addend)
string.memcpy(target2, c.Addr(val5), 8)
string.memcpy(target2, &val5, 8)
else:
cr3: t.CArray[t.CChar, 80]
viperlib.snprintf(c.Addr(cr3), 80, "[so] WARN: unresolved PLT sym offset=%lu\n", sym2.st_name)
serial.puts(cr3)
cr3: [80]char
viperlib.snprintf(&cr3, 80, "[so] WARN: unresolved PLT sym offset=%lu\n", sym2.st_name)
serial.puts(&cr3)
fat32.close(fp)
@@ -748,37 +745,37 @@ def load_so(path: t.CConst | str) -> t.CPtr:
_so_syment = syment
_so_sym_count = 0
if hash_vaddr != 0:
hash_ptr: t.CPtr = t.CPtr(hash_vaddr + so_load_addr)
# 宽度只由指针的元素类型决定:nchain 是 4 字节字段,必须给出 u32*
# (i8* 现在恒读 1 字节)。地址口径不变(hash_ptr + 4 字节)。
nchain: uint32 = c.Deref(uint32(uint64(hash_ptr) + 4, t.CPtr))
hash_ptr: rawptr = rawptr(hash_vaddr + so_load_addr)
# 宽度只由指针的元素类型决定:nchain 是 4 字节字段,必须给出 u32*
# (i8* 现在恒读 1 字节)。地址口径不变(hash_ptr + 4 字节)。
nchain: uint32 = *(uint32*(uint64(hash_ptr) + 4))
_so_sym_count = int(nchain)
elif syment > 0 and strtab_vaddr > symtab_vaddr and symtab_vaddr != 0:
sym_tab_size: uint64 = strtab_vaddr - symtab_vaddr
_so_sym_count = int(sym_tab_size // syment)
cr: t.CArray[t.CChar, 80]
viperlib.snprintf(c.Addr(cr), 80, "[so] loaded at 0x%lx\n", base_vaddr)
cr: [80]char
viperlib.snprintf(&cr, 80, "[so] loaded at 0x%lx\n", base_vaddr)
serial.puts(cr)
fat32.unlock()
return t.CPtr(base_vaddr)
return rawptr(base_vaddr)
def get_so_symbol(so_base: t.CPtr, name: t.CConst | str, so_path: t.CConst | t.CChar | t.CPtr) -> t.CPtr:
def get_so_symbol(so_base: rawptr, name: const str, so_path: const str) -> rawptr:
if _so_symtab is None or _so_strtab is None or _so_syment == 0:
return None
if name is None:
return None
for symi in range(_so_sym_count):
sb2: Elf64_Sym | t.CPtr = t.CPtr(uint64(_so_symtab) + uint64(symi) * _so_syment)
sb2: Elf64_Sym* = Elf64_Sym*(uint64(_so_symtab) + uint64(symi) * _so_syment)
if sb2.st_value != 0 and sb2.st_shndx != 0:
sym_name_off2: uint32 = sb2.st_name
cmp_off2: uint32 = sym_name_off2
match2: int = 0
ni2: int = 0
while True:
sc3: t.CChar = c.Deref(t.CPtr(uint64(_so_strtab) + cmp_off2 + ni2))
nc3: t.CChar = c.Deref(name + ni2)
sc3: char = *(char*(uint64(_so_strtab) + cmp_off2 + ni2))
nc3: char = *(name + ni2)
if sc3 != nc3:
break
if sc3 == 0:
@@ -790,7 +787,7 @@ def get_so_symbol(so_base: t.CPtr, name: t.CConst | str, so_path: t.CConst | t.C
is_sha1_2: int = 0
sha1_len_2: uint32 = 0
while True:
dc4: t.CChar = c.Deref(t.CPtr(uint64(_so_strtab) + dot_pos3))
dc4: char = *(char*(uint64(_so_strtab) + dot_pos3))
if dc4 == 46:
if sha1_len_2 >= 8:
is_sha1_2 = 1
@@ -807,8 +804,8 @@ def get_so_symbol(so_base: t.CPtr, name: t.CConst | str, so_path: t.CConst | t.C
match2 = 1
ni2 = 0
while True:
sc4: t.CChar = c.Deref(t.CPtr(uint64(_so_strtab) + cmp_off2 + ni2))
nc4: t.CChar = c.Deref(name + ni2)
sc4: char = *(char*(uint64(_so_strtab) + cmp_off2 + ni2))
nc4: char = *(name + ni2)
if sc4 != nc4:
match2 = 0
break
@@ -817,9 +814,9 @@ def get_so_symbol(so_base: t.CPtr, name: t.CConst | str, so_path: t.CConst | t.C
ni2 += 1
if match2:
result_addr: uint64 = uint64(so_base) + sb2.st_value
dbg2: t.CArray[t.CChar, 80]
viperlib.snprintf(c.Addr(dbg2), 80, "[so] found '%s' at 0x%lx\n", t.CPtr(uint64(_so_strtab) + sym_name_off2), result_addr)
serial.puts(dbg2)
return t.CPtr(result_addr)
dbg2: [80]char
viperlib.snprintf(&dbg2, 80, "[so] found '%s' at 0x%lx\n", rawptr(uint64(_so_strtab) + sym_name_off2), result_addr)
serial.puts(&dbg2)
return rawptr(result_addr)
serial.puts("[so] symbol not found\n")
return None