Skip to content

المرحلة 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() يغير حالة العملية لـ Exited
  • yield_now() يبدّل فوراً للعملية التالية بدون انتظار Timer

النتيجة ​

[PID 1] Hello from Ring 3!
[exit:0]
[PID 2] Hello from Ring 3!
[exit:0]

الأخطاء المكتشفة أثناء التطوير ​

  1. ترتيب fake stack frame معكوس — context_switch يعمل popfq أولاً ثم pop r15..rbx ثم ret، لكن الكود كان يكتب بترتيب خاطئ → jump to NULL
  2. عنوان رسالة المستخدم خاطئ — build_user_program يستخدم عنوان ثابت بينما spawn_user_task يحسب عنوان حسب الـ slot → Page Fault at 0x80000100
  3. PID 2 لا يعمل — SYS_EXIT كان يعمل hlt بدون تغيير حالة العملية → الجدولة تعتبرها Running وما تبدّل

تم تطويره بحب بواسطة مجتمع Qtoom.