🚀 نفق الانطلاق: تشريح arch/syscall.rs
في الأنظمة القديمة (مثل Windows XP أو Linux القديم)، كانت البرامج تطلب خدمات من النواة باستخدام المقاطعة int 0x80. هذه الطريقة آمنة ولكنها بطيئة جداً جداً لأنها تمر عبر جداول وتتحقق من صلاحيات كثيرة. في المعالجات الحديثة (x86_64)، تم اختراع تعليمة مخصصة وصاروخية تسمى syscall.
كيف تعمل تعليمة syscall؟
بدلاً من البحث في الجداول، المعالج يقرأ عنوان النواة من مسجل خاص ومخبأ يسمى MSR (Model Specific Register) ويقفز إليه مباشرة بسرعة الضوء!
تجهيز مسجلات الـ MSR
هذا الملف يقوم بإخبار المعالج: "عندما يكتب أي برنامج كلمة syscall، اقفز فوراً إلى هذه الدالة".
rust
pub unsafe fn init() {
// 1. تفعيل الميزة عتادياً في مسجل EFER (تفعيل الإضافة الممتدة)
let mut efer = Msr::new(0xC000_0080);
efer.write(efer.read() | 1); // SCE (Syscall Enable) bit
// 2. تحديد عنوان الدالة التي سيقفز إليها المعالج (نقطة الهبوط)
let mut lstar = Msr::new(0xC000_0082);
lstar.write(syscall_entry as u64); // syscall_entry مكتوبة بالأسمبلي!
// 3. تحديد الصلاحيات (Ring 0 و Ring 3) التي صممناها في الـ GDT
let mut star = Msr::new(0xC000_0081);
let kernel_cs = 1; // Segment 1
let user_cs = 3; // Segment 3
star.write(((user_cs << 16) | kernel_cs) << 32);
}نقطة الهبوط syscall_entry (الأسمبلي السحري)
عندما يقفز المعالج، هو لا يحفظ مكدس المستخدم (Stack). لو استخدمنا لغة Rust فوراً، ستنهار الذاكرة! لذلك النواة تحتوي على كود أسمبلي صغير وظيفته:
- تبديل مكدس المستخدم (User Stack) بمكدس النواة (Kernel Stack).
- حفظ جميع مسجلات المستخدم (كي لا تضيع بياناته).
- استدعاء دالة
syscall_dispatchالمكتوبة بلغة Rust للتعامل مع الطلب. - إعادة المسجلات، ثم إطلاق تعليمة
sysretللعودة السريعة!