diff --git a/VKernel/Kernel/intr/idt.vp b/VKernel/Kernel/intr/idt.vp index a369e45..f5af2cb 100644 --- a/VKernel/Kernel/intr/idt.vp +++ b/VKernel/Kernel/intr/idt.vp @@ -238,7 +238,11 @@ export def isr28_handler(): isrCommonhandler(28) export def isr29_handler(): isrCommonhandler(29) export def isr30_handler(): isrCommonhandler(30) export def isr31_handler(): isrCommonhandler(31) -export def isr32_handler(): timer.timer_handler() +export def isr32_handler(from_user: int): + timer.timer_handler() + # 定时 IRQ 已 EOI,处理完毕;仅在返回用户态时消费时间片,内核态不抢占。 + if from_user != 0: + sched.Scheduler.try_reschedule() export def isr33_handler(): handler: irq_handler_t = irqGetHandler(1) diff --git a/VKernel/Kernel/intr/isr.s b/VKernel/Kernel/intr/isr.s index 3e88b07..3a3906a 100644 --- a/VKernel/Kernel/intr/isr.s +++ b/VKernel/Kernel/intr/isr.s @@ -134,6 +134,8 @@ isr\num\()_frame_ready: push r13 push r14 push r15 + # is_user 作为第 1 个参数(rdi)传给处理函数,供其判断"返回用户态"时是否抢占 + mov rdi, rcx call isr\num\()_handler pop r15 pop r14 @@ -332,6 +334,8 @@ isr\num\()_frame_ready: push r13 push r14 push r15 + # is_user 作为第 1 个参数(rdi)传给处理函数,供其判断"返回用户态"时是否抢占 + mov rdi, rcx call isr\num\()_handler pop r15 pop r14 diff --git a/VKernel/Kernel/sched/sched.vp b/VKernel/Kernel/sched/sched.vp index 43b6d97..b1c1fba 100644 --- a/VKernel/Kernel/sched/sched.vp +++ b/VKernel/Kernel/sched/sched.vp @@ -16,6 +16,10 @@ define SCHED_QUANTUM = 10 _yield_cnt: uint32 = 0 _yield_lock: int = 0 +# ISR scratch 是全局槽(isr.s);抢占后一个 ISR 会跨越其它线程的 ISR,故切换时按线程保存/恢复。 +export _isr_scratch_tbl: [MAX_THREADS * 6]uint64 +export _switch_old_tid: int = 0 +export _switch_new_tid: int = 0 class Thread: @@ -92,7 +96,8 @@ class Scheduler: @staticmethod def _yield(): - global _switch_old_rsp, _switch_new_rsp, _yield_cnt, _yield_lock + global _switch_old_rsp, _switch_new_rsp, _yield_cnt, _yield_lock + global _switch_old_tid, _switch_new_tid _if_saved: int = 0 __asm__(f"""pushfq pop rax @@ -147,6 +152,8 @@ class Scheduler: if next_ks != 0: gdt.set_tss_rsp0(next_ks) cpu.set_kernel_rsp0(next_ks) + _switch_old_tid = old_tid + _switch_new_tid = next_tid _yield_lock = 0 _do_switch() if _if_saved: @@ -304,10 +311,44 @@ def _do_switch(): push r14 push r15 pushfq + # 按线程保存 ISR scratch(被抢占的 ISR 会跨越其它线程的 ISR) + mov eax, dword ptr [rip + _switch_old_tid] + imul rax, rax, 48 + lea rdx, [rip + _isr_scratch_tbl] + add rdx, rax + mov rcx, qword ptr [rip + _isr_scratch] + mov qword ptr [rdx], rcx + mov rcx, qword ptr [rip + _isr_scratch + 8] + mov qword ptr [rdx + 8], rcx + mov rcx, qword ptr [rip + _isr_scratch + 16] + mov qword ptr [rdx + 16], rcx + mov rcx, qword ptr [rip + _isr_scratch + 24] + mov qword ptr [rdx + 24], rcx + mov rcx, qword ptr [rip + _isr_scratch + 32] + mov qword ptr [rdx + 32], rcx + mov rcx, qword ptr [rip + _isr_scratch + 40] + mov qword ptr [rdx + 40], rcx mov rax, qword ptr [rip + _switch_old_rsp] mov qword ptr [rax], rsp mov rax, qword ptr [rip + _switch_new_rsp] mov rsp, qword ptr [rax] + # 恢复切入线程的 scratch(不在 ISR 中时内容无意义,覆盖无害) + mov eax, dword ptr [rip + _switch_new_tid] + imul rax, rax, 48 + lea rdx, [rip + _isr_scratch_tbl] + add rdx, rax + mov rcx, qword ptr [rdx] + mov qword ptr [rip + _isr_scratch], rcx + mov rcx, qword ptr [rdx + 8] + mov qword ptr [rip + _isr_scratch + 8], rcx + mov rcx, qword ptr [rdx + 16] + mov qword ptr [rip + _isr_scratch + 16], rcx + mov rcx, qword ptr [rdx + 24] + mov qword ptr [rip + _isr_scratch + 24], rcx + mov rcx, qword ptr [rdx + 32] + mov qword ptr [rip + _isr_scratch + 32], rcx + mov rcx, qword ptr [rdx + 40] + mov qword ptr [rip + _isr_scratch + 40], rcx popfq pop r15 pop r14 @@ -317,7 +358,7 @@ def _do_switch(): pop rbx pop rax ret""", - op=[ASM_DESCR.CLOBBER_MEMORY]) + op=[ASM_DESCR.CLOBBER_MEMORY, ASM_DESCR.CLOBBER_RCX, ASM_DESCR.CLOBBER_RDX]) # Thread 布局:rsp0/stack8/stack_size16/func24/arg32/state40/tid44/pid48/kern_stack56 # ⇒ sizeof(Thread) = 64,Scheduler.threads[16] 占 1024 字节 ⇒ current_tid 在 +1024。