المرحلة 5: Context Switch — عمليتان مستقلتان في Ring 3
ما تم إنجازه
1. context_switch.asm
- حفظ callee-saved registers (rbx, rbp, r12-r15, rflags)
- تبديل CR3 مع تجنب TLB flush غير ضروري
- استعادة سياق العملية الجديدة
2. إدارة العمليات
- Idle Task (PID 0): kernel_main نفسه مسجل كعملية — يعطي context_switch مكان لحفظ RSP
- spawn_user_task: يبني machine code داخلياً بالعنوان الافتراضي الصحيح لكل عملية
- Guard Pages: صفحة غير مربوطة تحت كل مكدس نواة — stack overflow = Page Fault بدل corruption
- Kernel Stack Zeroing: كل مكدس نواة يُصفّر عند الإنشاء لمنع تسريب بيانات
3. enter_usermode Trampoline
- دالة
#[unsafe(naked)]تستقبل RIP في r12 وRSP في r13 - تبني iretq frame وتقفز لـ Ring 3
4. تحديثات أمنية عند كل Context Switch
- TSS.rsp0 → مكدس نواة العملية الجديدة (لولاه: المقاطعة تستخدم مكدس خاطئ)
- percpu.kernel_rsp → نفس القيمة (لولاها: syscall يستخدم مكدس خاطئ)
5. SYS_EXIT + yield
exit_current_task()يغير حالة العملية لـ Exitedyield_now()يبدّل فوراً للعملية التالية بدون انتظار Timer
النتيجة
[PID 1] Hello from Ring 3!
[exit:0]
[PID 2] Hello from Ring 3!
[exit:0]الأخطاء المكتشفة أثناء التطوير
- ترتيب fake stack frame معكوس — context_switch يعمل popfq أولاً ثم pop r15..rbx ثم ret، لكن الكود كان يكتب بترتيب خاطئ → jump to NULL
- عنوان رسالة المستخدم خاطئ — build_user_program يستخدم عنوان ثابت بينما spawn_user_task يحسب عنوان حسب الـ slot → Page Fault at 0x80000100
- PID 2 لا يعمل — SYS_EXIT كان يعمل hlt بدون تغيير حالة العملية → الجدولة تعتبرها Running وما تبدّل