הרצאה מסכמת: איך מערכת ההפעלה באמת עולה – מהבוט ועד להרצת תוכנה¶
בהרצאה זו נסכם את כל מה שלמדנו ונסביר כיצד מערכת הפעלה מודרנית פועלת במעבדי אינטל 32 ביט.
1. מבוא: הכל מתחיל כשהמחשב נדלק¶
ברגע שלוחצים על כפתור ההפעלה, המעבד מתחיל לרוץ מכתובת קבועה מראש ב־ROM (באחסון שצרוב בלוח האם של המחשב) (לרוב בכתובת 0xFFFF0) ושם נמצא ה־BIOS – תוכנה בסיסית שמובנית בלוח האם.
מטרת ה־BIOS: לבצע בדיקות בסיסיות (POST), לזהות חומרה (דיסק, זיכרון, מקלדת), להגדיר פסיקות בסיסיות ואז – לטעון את ה־bootloader.
הbootloader הוא הקטע קוד הראשון של מערכת ההפעלה שלנו שנמצאת בדיסק הקשיח, כאשר קטע קוד זה נטען לזכרון- מתחיל לרוץ קטע קוד קטן של מערכת ההפעלה שלנו, הקטע הזה אחראי להרים את כל המערכת.
2. שלב ראשון: טעינת ה־Bootloader¶
איך זה עובד?¶
-
ה־BIOS קורא את 512 הבייטים הראשונים מהדיסק הקשיח (קטע זה נקרא גם ה־MBR).
-
טוען אותם לכתובת
0x7C00ב־RAM. -
קופץ להריץ את הקוד משם.
3. מה עושה ה־Bootloader?¶
ה־bootloader רץ ב־Real Mode (בדיוק כמו 8086), ולכן הוא מוגבל:
-
גישה רק לזיכרון עד 1MB
-
בלי הגנות
-
בלי Paging
-
גישה ישירה ל־BIOS
למרות המגבלות, המשימה שלו קריטית:
-
לטעון את קרנל מערכת ההפעלה לזיכרון.
-
לעבור מ־Real Mode ל־Protected Mode.
-
להריץ את כל הקרנל שלנו.
4. טעינת הקרנל¶
נניח שהקרנל שלך נשמר אחרי ה־bootloader בדיסק.
ה־bootloader:
-
משתמש ב־INT 13h של ה־BIOS כדי לקרוא סקטורים מדיסק. (כלומר, הוא מתקשר עם הדיסק כדי לטעון את כל שאר החלקים של הקרנל מהדיסק לזכרון)
-
טוען את הקרנל לזיכרון (למשל לכתובת
0x100000וקופץ אליה.) -
מכין טבלת GDT
-
עובר ל־Protected Mode
5. מעבר ל־Protected Mode¶
כמו שלמדנו:
-
הגדרת טבלת GDT עם תיאור ל־Kernel Code ו־Kernel Data.
-
טעינה של GDTR באמצעות
lgdt. -
כיבוי פסיקות (
cli) -
הדלקת ביט
PEב־CR0. -
קפיצה ל־Protected Mode (
jmp farלסלקטור של Kernel Code)
6. שלב הקרנל: אתחול המערכת¶
הקרנל שלנו עכשיו רץ ב־32 ביט עם הרשאות גבוהות (Ring 0).
זה הזמן לבנות את התשתיות:
1. טעינת GDT מלאה¶
- כולל סגמנטים ליוזר מוד
2. טעינת IDT¶
-
טבלת פסיקות, כולל int 0x80 לפסיקות מערכת
-
כולל int 14h לטיפול ב־Page Fault
3. הגדרת TSS¶
- הגדרת מחסנית לקרנל לשימוש בזמן פסיקות מיוזר מוד
4. הגדרת Paging¶
-
הגדרת Page Directory ו־Page Tables
-
טעינה ל־CR3
-
הדלקת Paging בביט 31 של CR0
7. Scheduler והקצאת תהליכים¶
בשלב זה הקרנל מוכן להריץ תוכנות:
הקרנל מגדיר:¶
-
רשימת תהליכים (
PCB) -
לכל תהליך: page directory נפרד, stack, תיאור הרשאות
Scheduler¶
-
כל כמה מילי-שניות (timer interrupt) מתבצעת פסיקה
-
הקרנל שומר context של התהליך הנוכחי (
pusha,mov esp) -
טוען context של תהליך אחר
-
מחליף
cr3לדפים שלו -
מחזיר את הבקרה באמצעות
iret
8. User Mode – הרצת תוכנה¶
בשלב מסוים, הקרנל טוען תוכנית יוזר מוד מהדיסק,
-
יוצר page directory לתוכנית
-
ממפה קוד לכתובות וירטואליות (למשל
0x00400000) -
ממפה stack
-
מציב את EIP להתחלה של קוד התוכנית
-
משנה את ה־CS ל־Ring 3 (
jmp far 0x23:user_entry)
9. קריאות מערכת – Syscalls¶
ביוזר מוד, לתוכנה אין הרשאות לבצע פעולות כמו:
-
כתיבה למסך
-
גישה לזיכרון קרנל
-
הקצאת זיכרון
במקום זה, היא קוראת לפסיקות מוגדרות מראש – int 0x80.
המעבד:
-
עובר אוטומטית ל־Ring 0
-
שומר את context
-
משתמש ב־TSS כדי לבחור מחסנית קרנלית
-
קופץ לפונקציית syscall בקרנל שלך
הכדי להגדיר המון קריאות מערכת (syscall-ים) תחת פסיקת 0x80, נהוג לסמן את סוג הקריאה על פי אוגר eax.
הקרנל בודק את המספר (למשל eax = 1 לפעולה מסוימת) ומבצע את הפעולה.
דוגמה: אפשר לממש קוד קרנלי שיודע להתממשק עם הדיסק- ליצור קבצים, למחוק, לשנות, ולפתוח.
אחרכך אפשר להנגיש את הפונקצונליות למשתמש באמצעות יצירת syscall-ים תחת הפסיקה 0x80.
שזה אומר בקצרה להוסיף לif else הארוך בפסיקה, שeax שווה ל123, תקרה פעולת יצירת קובץ, או שeax שווה ל3242 תקרה פעולת מחיקת קובץ.
וכמובן, להעביר פרמטרים אפשר דרך הstack ודרך אוגרים- תלוי בקונבנצית קריאה.
10. Page Fault¶
אם תוכנה ניגשת לדף שלא הוקצה לה – תתרחש פסיקת Page Fault (int 14h)
המעבד:
-
שומר EIP
-
שומר error code
-
טוען את הכתובת ב־CR2
הקרנל:
-
קופץ ל־handler שהגדרת
-
קורא את הכתובת מה־CR2
-
מקצה לה Page חדש ומעדכן את טבלת ה־Page Table
-
ממשיך את התהליך מהנקודה שעצר
כך ניתן להקצות זיכרון רק כשצריך, ולא מראש – זהו demand paging.
11. איך הכל מתחבר?¶
| שלב | תיאור |
|---|---|
| BIOS | טוען את ה־bootloader ל־0x7C00 ומעביר שליטה |
| Bootloader | טוען את הקרנל, עובר ל־Protected Mode |
| קרנל | מאתחל GDT, IDT, TSS, Paging, Scheduler |
| תהליך יוזר | נטען לזיכרון עם Page Directory נפרד |
| קריאות מערכת | דרך int 0x80, המעבד מחליף הרשאות ומריץ קוד קרנל |
| פסיקות | פסיקות חומרה (טיימר, מקלדת), פסיקות Page Fault נלכדות בקרנל |
| החלפת תהליכים | Scheduler עובר בין תהליכים כל כמה זמן |
12. סיכום¶
יצרנו מערכת הפעלה מודרנית – אמיתית, שמבוססת על עקרונות כמו:
-
Protected Mode – הבדלה בין קרנל ליוזר
-
Paging – כתובות וירטואליות עם בידוד מלא
-
Interrupts & Syscalls – מנגנון תקשורת מאובטח בין יוזר לקרנל
-
Context Switch – ריבוי משימות אמיתי
-
Page Fault – הקצאת זיכרון חכמה רק כשצריך