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