المرحلة 4b: أول عملية User Space — Hello from Ring 3!
هذه لحظة تاريخية في تطوير النواة: أول كود يعمل في وضع المستخدم (Ring 3) ويتواصل مع النواة عبر syscall حقيقي.
ما تم إنجازه
1. إطلاق عملية User Space (kernel/sched/user_init.rs)
- تخصيص صفحة كود (4KB) وصفحة مكدس (4KB) عند عنوان 2GB (فوق منطقة الكيرنل)
- ربط الصفحات مع
PTE_USER | PTE_WRITABLEعبر VMM - كتابة برنامج المستخدم كـ machine code مباشر (40 بايت) مع رسالة نصية
- القفز لـ Ring 3 عبر
iretqمع CS=0x23 (User Code) و SS=0x1B (User Data)
2. Syscall يعمل بالكامل
التسلسل الكامل يعمل:
User (Ring 3): syscall → SFMASK يعطل IF
→ CPU: RIP→rcx, RFLAGS→r11, CS→KernelCode, SS→KernelData
→ syscall_entry.asm:
→ swapgs (GS يشير لـ PerCpu)
→ حفظ user RSP في [gs:8]
→ تحميل kernel RSP من [gs:0]
→ حفظ كل المسجلات على مكدس النواة
→ تدوير المعاملات بالترتيب العكسي
→ call syscall_dispatch (Rust)
→ استعادة المسجلات
→ pop r10 (user RSP مؤقت — ليس pop rsp!)
→ pop r11, pop rcx (لسه على مكدس النواة)
→ mov rsp, r10 (آخر شيء)
→ swapgs عكسي
→ sysretq
→ User (Ring 3): يكمل التنفيذ3. خطأ حرج 11: نشر PTE_USER عبر جداول الصفحات
المشكلة: map_page كانت تضع PTE_PRESENT | PTE_WRITABLE فقط على المستويات الوسيطة (PML4 → PDP → PD). عندما يمشي المعالج في جداول الصفحات من Ring 3، يتحقق من PTE_USER في كل مستوى — إذا أي مستوى يفتقده، يطلق Page Fault.
مضاعفة المشكلة: PML4[0] موجود أصلاً من Assembly بدون PTE_USER، وensure_table كانت ترجع العنوان الموجود بدون تحديث الـ flags.
الحل (إصلاحان):
map_pageتحسبintermediate_flags— إذا الصفحة فيهاPTE_USER، كل المستويات الوسيطة تحصل عليه أيضاًensure_tableتتحقق من flags المفقودة وتضيفها (OR) على entries الموجودة
الأمان محفوظ: PTE_USER في PML4[0] يسمح بالمرور للـ 512GB كاملة، لكن PDP[0] و PDP[1] (الكيرنل) لا تحتوي PTE_USER، فتبقى محمية.
النتيجة
Spawning user process [PID 1]...
Hello from Ring 3!
[PID 1] sys_exit(0)إثبات شامل: iretq ✅ | syscall ✅ | swapgs ✅ | stack switch ✅ | SYS_WRITE ✅ | SYS_EXIT ✅ | PTE_USER propagation ✅