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 寄存器)
212 lines
7.2 KiB
Plaintext
212 lines
7.2 KiB
Plaintext
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()
|