Files
ViperOS/VKernel/Kernel/sched/coroutine.vp
T
TermiNexus 6a54373c26 fix(vkernel): 补 ISR/调度 call 的 rsi/rdi clobber、rep stosb 内存 clobber,修 mm 别名笔误
N8  paging.vp:AllocPage 的 rep stosb 写 4096B 补 CLOBBER_MEMORY,避免优化器
    重排/消除其前后的内存读写
N9  coroutine.vp / sched.vp:_coro_entry/_thread_entry 的 call rax 补
    CLOBBER_RSI/CLOBBER_RDI(RSP 由 sub rsp,8 / add rsp,8 配对抵消,无需声明)
N15 process.vp:mm_mm.malloc/free → mm.malloc/free(该文件只有 import mm.mm as mm)
N16 elf.vp:读 RAX 的 c.Asm 补 CLOBBER_RAX([DIAG] 探针)
N20 elf.vp / idt.vp(12 处):外部 ELF 入口 / ISR handler 的 call 补
    CLOBBER_RSI/CLOBBER_RDI(被调方破坏全部 caller-saved 寄存器)
2026-09-11 17:40:21 +08:00

212 lines
7.2 KiB
Plaintext
Raw 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 mm.mm as mm
import drivers.serial.uart.serial as serial
import asm
import t, c
CORO_READY: t.CDefine = 0
CORO_RUNNING: t.CDefine = 1
CORO_YIELDED: t.CDefine = 2
CORO_DONE: t.CDefine = 3
MAX_COROUTINES: t.CDefine = 32
CORO_STACK_SIZE: t.CDefine = 8192
@t.Object
class Coroutine:
rsp: uint64
stack: t.CPtr
stack_size: uint64
func: t.CPtr
arg: t.CPtr
state: int
cid: int
caller_rsp: uint64
ret_val: int
def resume(self) -> int:
global _coro_old_rsp, _coro_new_rsp
m: CoroutineManager | t.CPtr = _coro_mgr_ptr
if self.state == CORO_DONE: return self.ret_val
if self.state != CORO_READY and self.state != CORO_YIELDED: return -1
prev_cid: int = m.current_cid
m.current_cid = self.cid
self.state = CORO_RUNNING
_coro_old_rsp = c.Addr(m.coroutines[prev_cid].rsp)
_coro_new_rsp = c.Addr(self.rsp)
self.caller_rsp = uint64(_coro_old_rsp)
_coro_switch()
if self.state == CORO_DONE:
return self.ret_val
return 0
@staticmethod
def _yield():
global _coro_old_rsp, _coro_new_rsp
m: CoroutineManager | t.CPtr = _coro_mgr_ptr
cid: int = m.current_cid
if cid < 0: return
m.coroutines[cid].state = CORO_YIELDED
prev_cid: int = -1
i: int
for i in range(m.count):
if m.coroutines[i].state == CORO_RUNNING and m.coroutines[i].caller_rsp != 0:
prev_cid = i
break
if prev_cid < 0: return
m.current_cid = prev_cid
_coro_old_rsp = c.Addr(m.coroutines[cid].rsp)
_coro_new_rsp = c.Addr(m.coroutines[prev_cid].rsp)
_coro_switch()
@property
def is_done(self) -> int:
if self.state == CORO_DONE:
return 1
return 0
@property
def is_yielded(self) -> int:
if self.state == CORO_YIELDED:
return 1
return 0
@property
def retval(self) -> int:
return self.ret_val
@t.Object
class CoroutineManager:
coroutines: t.CArray[Coroutine, MAX_COROUTINES]
current_cid: int
count: int
def __init__(self):
global _coro_mgr_ptr
_coro_mgr_ptr = c.Addr(_coro_mgr)
m: CoroutineManager | t.CPtr = _coro_mgr_ptr
m.current_cid = 0
m.count = 1
m.coroutines[0].state = CORO_RUNNING
m.coroutines[0].cid = 0
m.coroutines[0].caller_rsp = 0
m.coroutines[0].ret_val = 0
m.coroutines[0].rsp = 0
m.coroutines[0].stack = None
m.coroutines[0].stack_size = 0
m.coroutines[0].func = None
m.coroutines[0].arg = None
main_rsp_ptr: t.CPtr = c.Addr(m.coroutines[0].rsp)
c.Asm(f"""mov qword ptr [{c.AsmInp(main_rsp_ptr, t.ASM_DESCR.REG_ANY)}], rsp""",
op=[t.ASM_DESCR.CLOBBER_MEMORY])
@staticmethod
def current() -> Coroutine | t.CPtr:
m: CoroutineManager | t.CPtr = _coro_mgr_ptr
return c.Addr(m.coroutines[m.current_cid])
@staticmethod
def get_coroutine(cid: int) -> Coroutine | t.CPtr:
m: CoroutineManager | t.CPtr = _coro_mgr_ptr
if cid < 0 or cid >= m.count: return None
return c.Addr(m.coroutines[cid])
@staticmethod
def create(func: t.CPtr, arg: t.CPtr) -> Coroutine | t.CPtr:
m: CoroutineManager | t.CPtr = _coro_mgr_ptr
if m.count >= MAX_COROUTINES: return None
cid: int = m.count
m.count += 1
co: Coroutine | t.CPtr = c.Addr(m.coroutines[cid])
co.state = CORO_READY
co.cid = cid
co.func = func
co.arg = arg
co.caller_rsp = 0
co.ret_val = 0
stack_ptr: t.CPtr = mm.malloc(CORO_STACK_SIZE)
if not stack_ptr: return None
co.stack = stack_ptr
co.stack_size = CORO_STACK_SIZE
stack_top: uint64 = uint64(stack_ptr) + CORO_STACK_SIZE - 16
stack_top = stack_top & ~uint64(0xF)
entry_addr: uint64 = uint64(c.Addr(_coro_entry))
sp: t.CPtr = t.CPtr(stack_top)
c.Asm(f"""mov rax, {c.AsmInp(sp, t.ASM_DESCR.REG_ANY)}
mov qword ptr [rax - 56], 0
mov qword ptr [rax - 48], 0
mov qword ptr [rax - 40], 0
mov qword ptr [rax - 32], 0
mov qword ptr [rax - 24], 0
mov qword ptr [rax - 16], 0
mov qword ptr [rax - 8], 0
mov qword ptr [rax], {c.AsmInp(entry_addr, t.ASM_DESCR.REG_ANY)}""",
op=[t.ASM_DESCR.CLOBBER_MEMORY, t.ASM_DESCR.CLOBBER_RAX])
stack_top = stack_top - 56
co.rsp = stack_top
return co
_coro_mgr: CoroutineManager = CoroutineManager()
_coro_mgr_ptr: CoroutineManager | t.CPtr | t.CExport = c.Addr(_coro_mgr)
_coro_old_rsp: t.CPtr | t.CExport
_coro_new_rsp: t.CPtr | t.CExport
@c.Attribute(t.attr.naked)
def _coro_switch():
c.Asm(f"""push rax
push rbx
push rbp
push r12
push r13
push r14
push r15
mov rax, qword ptr [rip + _coro_old_rsp]
mov qword ptr [rax], rsp
mov rax, qword ptr [rip + _coro_new_rsp]
mov rsp, qword ptr [rax]
pop r15
pop r14
pop r13
pop r12
pop rbp
pop rbx
pop rax
ret""",
op=[t.ASM_DESCR.CLOBBER_MEMORY])
@c.Attribute(t.attr.naked)
def _coro_entry():
# 结构体布局(以 stub.ll 为权威):
# Coroutine = {rsp@0, stack@8, stack_size@16, func@24, arg@32,
# state@40, cid@44, caller_rsp@48, ret_val@56}, sizeof=64
# CoroutineManager= {coroutines[32]@0 (32*64=2048), current_cid@2048, count@2052}
# 取 func/arg 入口,写 state=CORO_DONE(3)、ret_val。
c.Asm(f"""sub rsp, 8
mov rax, qword ptr [rip + _coro_mgr_ptr]
mov ecx, dword ptr [rax + 2048]
movsxd rcx, ecx
shl rcx, 6
mov rdi, qword ptr [rax + rcx + 32]
mov rax, qword ptr [rax + rcx + 24]
call rax
mov rax, qword ptr [rip + _coro_mgr_ptr]
mov ecx, dword ptr [rax + 2048]
movsxd rcx, ecx
shl rcx, 6
mov dword ptr [rax + rcx + 40], 3
mov dword ptr [rax + rcx + 56], eax
add rsp, 8""",
# `call rax` 破坏全部 caller-saved 寄存器(x64 SysV):除 RAX/RCX/RDX/
# R8-R11 外,RSI 与 RDI 也必须声明,否则编译器可能假设其值存活(N9)。
# RSP 由 `sub rsp,8` / `add rsp,8` 配对抵消,净变化为 0,无需声明。
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])
Coroutine._yield()
while True:
asm.sti()
asm.hlt()