Files
TermiNexus 0919a058a8 fix(vkernel): 预留内核 .bss 与栈区,修堆 arena 覆盖未预留内核内存
根因:bootloader 只按 kernel 文件大小 AllocatePages(.bss 不占文件),于是 .bss
尾部(ticks/_perf_* 等全局量)与主线程栈区(0x60000~0x80000)在 memmap 里仍是
EfiConventionalMemory,被内核 mm 的堆 arena 当作空闲内存占用 → 内核全局量被写坏、
堆元数据被反向破坏,最终桌面线程栈上的 va_list 被改坏,vsnprintf 读 %d 变参时
#GP(rip=0x130d45, err=0x0)。

- linker.ld: .bss 末尾加 LONG(0) 强制 PROGBITS,使 kernel.bin 的 FileSize 涵盖
  .bss,bootloader 的 PagesNeeded 得以预留整块内核镜像(含 .bss)
- mm.init: 新增 KernelAddr/KernelEnd,挑 arena 时把与内核镜像 [kernel_PhysAddr,
  __bss_end) 重叠的 region 起点抬到镜像末端(不整段丢弃)
- main.vp: 取 __bss_end 并传入 mm.init
- boot.c: ExitBootServices 前用 AllocatePages(AllocateAddress, EfiLoaderData)
  占位内核栈区 0x60000~0x80000,使其在 memmap 中标记已用

另含在途整理:多处补显式收窄转换(uint8()/uint16() 等)、kbd_svc 构造改为
kbd_svc.__init__() 等。
2026-10-14 12:54:43 +08:00

376 lines
14 KiB
Plaintext
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import intr.gdt as gdt
import string
import asm
define IA32_KERNEL_GS_BASE = 0xC0000102
define KERN_STACK_SIZE = 8192
define CPU_FEATURE_FPU = (1 << 0)
define CPU_FEATURE_PSE = (1 << 1)
define CPU_FEATURE_MSR = (1 << 2)
define CPU_FEATURE_PAE = (1 << 3)
define CPU_FEATURE_MCE = (1 << 4)
define CPU_FEATURE_CX8 = (1 << 5)
define CPU_FEATURE_APIC = (1 << 6)
define CPU_FEATURE_SEP = (1 << 7)
define CPU_FEATURE_MTRR = (1 << 8)
define CPU_FEATURE_PGE = (1 << 9)
define CPU_FEATURE_MCA = (1 << 10)
define CPU_FEATURE_CMOV = (1 << 11)
define CPU_FEATURE_PAT = (1 << 12)
define CPU_FEATURE_PSE36 = (1 << 13)
define CPU_FEATURE_PSN = (1 << 14)
define CPU_FEATURE_CLFSH = (1 << 15)
define CPU_FEATURE_DS = (1 << 16)
define CPU_FEATURE_ACPI = (1 << 17)
define CPU_FEATURE_MMX = (1 << 18)
define CPU_FEATURE_FXSR = (1 << 19)
define CPU_FEATURE_SSE = (1 << 20)
define CPU_FEATURE_SSE2 = (1 << 21)
define CPU_FEATURE_SS = (1 << 22)
define CPU_FEATURE_HTT = (1 << 23)
define CPU_FEATURE_TM = (1 << 24)
define CPU_FEATURE_PBE = (1 << 25)
class cpu_info:
vendor_id: [13]char
brand_string: [48]char
features: uint32
family: uint32
model: uint32
stepping: uint32
cpu_type: uint32
ext_model: uint32
ext_family: uint32
cpu_freq: uint64
@__attribute__(packed)
class _tss:
# x86_64 TSS 布局:偏移 0 为 4 字节保留字段(对齐 gdt.vp:32 的
# "reserved0(4) rsp0(8) ..." 与 tss_buf: t.CArray[uint8, 104])。
# 此前写作 uint64 使 RSP0 落在偏移 8、结构体 108B —— 与硬件 104B 布局
# 及 gdt 的 tss_buf(104B) 不一致(N6)。
reserved0: uint32
rsp0: uint64
rsp1: uint64
rsp2: uint64
reserved1: uint64
ist1: uint64
ist2: uint64
ist3: uint64
ist4: uint64
ist5: uint64
ist6: uint64
ist7: uint64
reserved2: uint64
reserved3: uint16
io_map_base: uint16
class cpuid_result:
eax: uint32
ebx: uint32
ecx: uint32
edx: uint32
@__attribute__(packed)
def _rdmsr_naked():
__asm__(f"""rdmsr
shl rdx, 32
or rax, rdx
ret""",
op=[ASM_DESCR.CLOBBER_RDX])
@__attribute__(packed)
def _wrmsr_naked():
# msr_write sets ecx=msr, r8=value. wrmsr needs ECX=msr, EDX:EAX=value.
# Old code did `mov rax,rcx` (rax=msr) which wrote (value>>32):msr to MSR,
# corrupting IA32_KERNEL_GS_BASE -> swapgs -> #GP on gs:[0]. Fixed below.
__asm__(f"""mov rax, r8
mov rdx, r8
shr rdx, 32
wrmsr
ret""",
op=[ASM_DESCR.CLOBBER_RAX, ASM_DESCR.CLOBBER_RDX])
def msr_read(msr: uint32) -> uint64:
result: uint64 = 0
func: callable = _rdmsr_naked
__asm__(f"""mov ecx, {asminp(msr, ASM_DESCR.REG_ANY)}
call {asminp(func, ASM_DESCR.REG_ANY)}
mov {asmout(result, ASM_DESCR.OUTPUT_REG)}, rax""",
op=[ASM_DESCR.CLOBBER_RAX, ASM_DESCR.CLOBBER_RCX, ASM_DESCR.CLOBBER_RDX])
return result
def msr_write(msr: uint32, value: uint64):
func: callable = _wrmsr_naked
__asm__(f"""mov ecx, {asminp(msr, ASM_DESCR.REG_ANY)}
mov r8, {asminp(value, ASM_DESCR.REG_ANY)}
call {asminp(func, ASM_DESCR.REG_ANY)}""",
op=[ASM_DESCR.CLOBBER_RAX, ASM_DESCR.CLOBBER_RCX, ASM_DESCR.CLOBBER_RDX, ASM_DESCR.CLOBBER_R8])
@__attribute__(packed)
def _cpuid_naked():
__asm__(f"""push rbx
mov eax, ecx
cpuid
mov dword ptr [rdx], eax
mov dword ptr [rdx + 4], ebx
mov dword ptr [rdx + 8], ecx
mov dword ptr [rdx + 12], edx
pop rbx
ret""",
op=[ASM_DESCR.CLOBBER_RAX, ASM_DESCR.CLOBBER_RCX,
ASM_DESCR.CLOBBER_RDX])
@__attribute__(packed)
def _cpuid_sub_naked():
__asm__(f"""push rbx
mov eax, ecx
mov ecx, r8d
cpuid
mov dword ptr [rdx], eax
mov dword ptr [rdx + 4], ebx
mov dword ptr [rdx + 8], ecx
mov dword ptr [rdx + 12], edx
pop rbx
ret""",
op=[ASM_DESCR.CLOBBER_RAX, ASM_DESCR.CLOBBER_RCX,
ASM_DESCR.CLOBBER_RDX])
@__attribute__(noinline)
def cpuid(leaf: uint32, out: cpuid_result*):
func: callable = _cpuid_naked
__asm__(f"""mov ecx, {asminp(leaf, ASM_DESCR.REG_ANY)}
mov rdx, {asminp(out, ASM_DESCR.REG_ANY)}
call {asminp(func, ASM_DESCR.REG_ANY)}""",
op=[ASM_DESCR.CLOBBER_RAX, ASM_DESCR.CLOBBER_RCX,
ASM_DESCR.CLOBBER_RDX, ASM_DESCR.CLOBBER_R8,
ASM_DESCR.CLOBBER_R9, ASM_DESCR.CLOBBER_R10,
ASM_DESCR.CLOBBER_R11])
@__attribute__(noinline)
def cpuid_sub(leaf: uint32, sub: uint32, out: cpuid_result*):
func: callable = _cpuid_sub_naked
__asm__(f"""mov ecx, {asminp(leaf, ASM_DESCR.REG_ANY)}
mov r8d, {asminp(sub, ASM_DESCR.REG_ANY)}
mov rdx, {asminp(out, ASM_DESCR.REG_ANY)}
call {asminp(func, ASM_DESCR.REG_ANY)}""",
op=[ASM_DESCR.CLOBBER_RAX, ASM_DESCR.CLOBBER_RCX,
ASM_DESCR.CLOBBER_RDX, ASM_DESCR.CLOBBER_R8,
ASM_DESCR.CLOBBER_R9, ASM_DESCR.CLOBBER_R10,
ASM_DESCR.CLOBBER_R11])
@__attribute__(noinline)
def detect_features_static() -> uint32:
features: uint32 = 0
res: cpuid_result
cpuid(1, &res)
if res.edx & (1 << 0): features |= CPU_FEATURE_FPU
if res.edx & (1 << 3): features |= CPU_FEATURE_PSE
if res.edx & (1 << 5): features |= CPU_FEATURE_MSR
if res.edx & (1 << 6): features |= CPU_FEATURE_PAE
if res.edx & (1 << 7): features |= CPU_FEATURE_MCE
if res.edx & (1 << 8): features |= CPU_FEATURE_CX8
if res.edx & (1 << 9): features |= CPU_FEATURE_APIC
if res.edx & (1 << 11): features |= CPU_FEATURE_SEP
if res.edx & (1 << 12): features |= CPU_FEATURE_MTRR
if res.edx & (1 << 13): features |= CPU_FEATURE_PGE
if res.edx & (1 << 14): features |= CPU_FEATURE_MCA
if res.edx & (1 << 15): features |= CPU_FEATURE_CMOV
if res.edx & (1 << 16): features |= CPU_FEATURE_PAT
if res.edx & (1 << 17): features |= CPU_FEATURE_PSE36
if res.edx & (1 << 18): features |= CPU_FEATURE_PSN
if res.edx & (1 << 19): features |= CPU_FEATURE_CLFSH
if res.edx & (1 << 21): features |= CPU_FEATURE_DS
if res.edx & (1 << 22): features |= CPU_FEATURE_ACPI
if res.edx & (1 << 23): features |= CPU_FEATURE_MMX
if res.edx & (1 << 24): features |= CPU_FEATURE_FXSR
if res.edx & (1 << 25): features |= CPU_FEATURE_SSE
if res.edx & (1 << 26): features |= CPU_FEATURE_SSE2
if res.edx & (1 << 27): features |= CPU_FEATURE_SS
if res.edx & (1 << 28): features |= CPU_FEATURE_HTT
if res.edx & (1 << 29): features |= CPU_FEATURE_TM
if res.edx & (1 << 30): features |= CPU_FEATURE_PBE
return features
@__attribute__(packed)
class per_cpu_data:
user_rsp: uint64
kernel_rsp0: uint64
current_pid: int
_pad0: uint32
_pad1: uint64
_per_cpu: per_cpu_data
class _CPUObject:
tss: _tss
features: uint32
def __init__(self):
self.__init_tss__()
def __init_tss__(self):
global _per_cpu
string.memset(&self.tss, 0, self.tss.__sizeof__())
self.tss.io_map_base = self.tss.__sizeof__()
string.memset(&_per_cpu, 0, per_cpu_data.__sizeof__())
gdt.setTSS64(5, uint64(&self.tss), int(self.tss.__sizeof__() - 1))
gdt.flush()
# IA32_KERNEL_GS_BASE holds the per_cpu address for swapgs.
# When entering from Ring 3, swapgs swaps IA32_GS_BASE (0) with
# IA32_KERNEL_GS_BASE (_per_cpu), making gs: accessible in kernel.
# When returning to Ring 3, swapgs swaps back, restoring GS base to 0.
msr_write(IA32_KERNEL_GS_BASE, uint64(&_per_cpu))
def getInfo(self, info: cpu_info*):
if not info: return
res: cpuid_result
cpuid(0, &res)
uint32*(info.vendor_id)[0] = res.ebx
uint32*(info.vendor_id)[1] = res.edx
uint32*(info.vendor_id)[2] = res.ecx
info.vendor_id[12] = '\0'
info.features = self.detectFeatures()
cpuid(1, &res)
info.stepping = (res.eax >> 0) & 0x0F
info.model = (res.eax >> 4) & 0x0F
info.family = (res.eax >> 8) & 0x0F
info.cpu_type = (res.eax >> 12) & 0x03
info.ext_model = (res.eax >> 16) & 0x0F
info.ext_family = (res.eax >> 20) & 0xFF
# CPUID 品牌串:0x80000002..0x80000004 共 3 个叶 × 16 字节 = 48,
# 与 brand_string[48] 等长(此前 range(4) 会写 64 字节 → 越界 16 字节)。
# 逐 u32 按字节地址显式写入,避免 uint32|t.CPtr 被降级为 i8* 后
# 下标按字节偏移且被截断为 i8(只写低字节、偏移不乘 4)。
brand_addr: uint64 = uint64(uint32*(info.brand_string))
for i in range(3):
cpuid(int(0x80000002 + i), &res)
off_b: uint64 = uint64(i) * 16
*(uint32*(brand_addr + off_b + 0)) = res.eax
*(uint32*(brand_addr + off_b + 4)) = res.ebx
*(uint32*(brand_addr + off_b + 8)) = res.ecx
*(uint32*(brand_addr + off_b + 12)) = res.edx
info.brand_string[47] = '\0'
info.cpu_freq = 2000000000
def detectFeatures(self) -> uint32:
features: int32 = 0
res: cpuid_result
cpuid(1, &res)
if res.edx & (1 << 0): features |= CPU_FEATURE_FPU
if res.edx & (1 << 3): features |= CPU_FEATURE_PSE
if res.edx & (1 << 5): features |= CPU_FEATURE_MSR
if res.edx & (1 << 6): features |= CPU_FEATURE_PAE
if res.edx & (1 << 7): features |= CPU_FEATURE_MCE
if res.edx & (1 << 8): features |= CPU_FEATURE_CX8
if res.edx & (1 << 9): features |= CPU_FEATURE_APIC
if res.edx & (1 << 11): features |= CPU_FEATURE_SEP
if res.edx & (1 << 12): features |= CPU_FEATURE_MTRR
if res.edx & (1 << 13): features |= CPU_FEATURE_PGE
if res.edx & (1 << 14): features |= CPU_FEATURE_MCA
if res.edx & (1 << 15): features |= CPU_FEATURE_CMOV
if res.edx & (1 << 16): features |= CPU_FEATURE_PAT
if res.edx & (1 << 17): features |= CPU_FEATURE_PSE36
if res.edx & (1 << 18): features |= CPU_FEATURE_PSN
if res.edx & (1 << 19): features |= CPU_FEATURE_CLFSH
if res.edx & (1 << 21): features |= CPU_FEATURE_DS
if res.edx & (1 << 22): features |= CPU_FEATURE_ACPI
if res.edx & (1 << 23): features |= CPU_FEATURE_MMX
if res.edx & (1 << 24): features |= CPU_FEATURE_FXSR
if res.edx & (1 << 25): features |= CPU_FEATURE_SSE
if res.edx & (1 << 26): features |= CPU_FEATURE_SSE2
if res.edx & (1 << 27): features |= CPU_FEATURE_SS
if res.edx & (1 << 28): features |= CPU_FEATURE_HTT
if res.edx & (1 << 29): features |= CPU_FEATURE_TM
if res.edx & (1 << 30): features |= CPU_FEATURE_PBE
return features
def enableInterrupts(self):
__asm__("sti", [ASM_DESCR.CLOBBER_MEMORY])
def disableInterrupts(self):
__asm__("cli", [ASM_DESCR.CLOBBER_MEMORY])
def enableNmis(self):
current: uint8 = asm.inb(0x70)
asm.outb(0x70, current & 0x7F)
def disableNmis(self):
current: uint8 = asm.inb(0x70)
asm.outb(0x70, current | 0x80)
def readCR0(self) -> uint64:
cr0: uint64
__asm__(f"""mov rax, cr0
mov {asmout(cr0, ASM_DESCR.OUTPUT_REG)}, rax""",
[ASM_DESCR.CLOBBER_RAX])
return cr0
def writeCR0(self, value: uint64):
__asm__(f"""mov rax, {asminp(value, ASM_DESCR.REG_ANY)}
mov cr0, rax""",
[ASM_DESCR.CLOBBER_RAX])
def readCR3(self) -> uint64:
cr3: uint64
__asm__(f"""mov rax, cr3
mov {asmout(cr3, ASM_DESCR.OUTPUT_REG)}, rax""",
[ASM_DESCR.CLOBBER_RAX])
return cr3
def writeCR3(self, value: uint64):
__asm__(f"""mov rax, {asminp(value, ASM_DESCR.REG_ANY)}
mov cr3, rax""",
[ASM_DESCR.CLOBBER_RAX])
def readCR4(self) -> uint64:
cr4: uint64
__asm__(f"""mov rax, cr4
mov {asmout(cr4, ASM_DESCR.OUTPUT_REG)}, rax""",
[ASM_DESCR.CLOBBER_RAX])
return cr4
def writeCR4(self, value: uint64):
__asm__(f"""mov rax, {asminp(value, ASM_DESCR.REG_ANY)}
mov cr4, rax""",
[ASM_DESCR.CLOBBER_RAX])
def readMSR(self, msr: uint32) -> uint64:
return msr_read(msr)
def writeMSR(self, msr: uint32, value: uint64):
msr_write(msr, value)
def setTSSRSP0(self, rsp0: uint64):
global _per_cpu
self.tss.rsp0 = rsp0
_per_cpu.kernel_rsp0 = rsp0
def set_kernel_rsp0(rsp0: uint64):
global _per_cpu
_per_cpu.kernel_rsp0 = rsp0
# 启用 SSE/FPU:CR4.OSFXSR(bit9)|OSXMMEXCPT(bit10) 置位、CR0 清 EM(bit2) 置 MP(bit1)。
# OVMF/UEFI 启动后 CR4.OSFXSR 未置位,任何 movaps 都 #GP(err=0)——变参函数
# 传 float/double 时保存 xmm 寄存器触发(serial.printf / snprintf("%.2f") 崩溃根因)。
def enable_sse():
cr0_v: uint64 = 0
__asm__(f"""mov rax, cr0
mov {asmout(cr0_v, ASM_DESCR.OUTPUT_REG)}, rax""",
op=[ASM_DESCR.CLOBBER_RAX])
cr0_v = cr0_v & ~uint64(4) # 清 EM(禁止 FPU 仿真)
cr0_v = cr0_v | uint64(2) # 置 MP(监控协处理器)
__asm__(f"""mov rax, {asminp(cr0_v, ASM_DESCR.REG_ANY)}
mov cr0, rax""",
op=[ASM_DESCR.CLOBBER_RAX])
cr4_v: uint64 = 0
__asm__(f"""mov rax, cr4
mov {asmout(cr4_v, ASM_DESCR.OUTPUT_REG)}, rax""",
op=[ASM_DESCR.CLOBBER_RAX])
cr4_v = cr4_v | uint64(0x600) # OSFXSR | OSXMMEXCPT
__asm__(f"""mov rax, {asminp(cr4_v, ASM_DESCR.REG_ANY)}
mov cr4, rax""",
op=[ASM_DESCR.CLOBBER_RAX])
__asm__("fninit", op=[ASM_DESCR.CLOBBER_MEMORY])