לדלג לתוכן

הרצאה מסכמת: איך מערכת ההפעלה באמת עולה – מהבוט ועד להרצת תוכנה


בהרצאה זו נסכם את כל מה שלמדנו ונסביר כיצד מערכת הפעלה מודרנית פועלת במעבדי אינטל 32 ביט.

1. מבוא: הכל מתחיל כשהמחשב נדלק

ברגע שלוחצים על כפתור ההפעלה, המעבד מתחיל לרוץ מכתובת קבועה מראש ב־ROM (באחסון שצרוב בלוח האם של המחשב) (לרוב בכתובת 0xFFFF0) ושם נמצא ה־BIOS – תוכנה בסיסית שמובנית בלוח האם.

מטרת ה־BIOS: לבצע בדיקות בסיסיות (POST), לזהות חומרה (דיסק, זיכרון, מקלדת), להגדיר פסיקות בסיסיות ואז – לטעון את ה־bootloader.
הbootloader הוא הקטע קוד הראשון של מערכת ההפעלה שלנו שנמצאת בדיסק הקשיח, כאשר קטע קוד זה נטען לזכרון- מתחיל לרוץ קטע קוד קטן של מערכת ההפעלה שלנו, הקטע הזה אחראי להרים את כל המערכת.


2. שלב ראשון: טעינת ה־Bootloader

איך זה עובד?

  1. ה־BIOS קורא את 512 הבייטים הראשונים מהדיסק הקשיח (קטע זה נקרא גם ה־MBR).

  2. טוען אותם לכתובת 0x7C00 ב־RAM.

  3. קופץ להריץ את הקוד משם.


3. מה עושה ה־Bootloader?

ה־bootloader רץ ב־Real Mode (בדיוק כמו 8086), ולכן הוא מוגבל:

  • גישה רק לזיכרון עד 1MB

  • בלי הגנות

  • בלי Paging

  • גישה ישירה ל־BIOS

למרות המגבלות, המשימה שלו קריטית:

  1. לטעון את קרנל מערכת ההפעלה לזיכרון.

  2. לעבור מ־Real Mode ל־Protected Mode.

  3. להריץ את כל הקרנל שלנו.


4. טעינת הקרנל

נניח שהקרנל שלך נשמר אחרי ה־bootloader בדיסק.
ה־bootloader:

  • משתמש ב־INT 13h של ה־BIOS כדי לקרוא סקטורים מדיסק. (כלומר, הוא מתקשר עם הדיסק כדי לטעון את כל שאר החלקים של הקרנל מהדיסק לזכרון)

  • טוען את הקרנל לזיכרון (למשל לכתובת 0x100000 וקופץ אליה.)

  • מכין טבלת GDT

  • עובר ל־Protected Mode


5. מעבר ל־Protected Mode

כמו שלמדנו:

  1. הגדרת טבלת GDT עם תיאור ל־Kernel Code ו־Kernel Data.

  2. טעינה של GDTR באמצעות lgdt.

  3. כיבוי פסיקות (cli)

  4. הדלקת ביט PE ב־CR0.

  5. קפיצה ל־Protected Mode (jmp far לסלקטור של Kernel Code)

mov eax, cr0
or eax, 1
mov cr0, eax
jmp 0x08:protected_mode_entry

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

mov eax, page_directory
mov cr3, eax
mov eax, cr0
or eax, 0x80000000
mov cr0, eax

7. Scheduler והקצאת תהליכים

בשלב זה הקרנל מוכן להריץ תוכנות:

הקרנל מגדיר:

  • רשימת תהליכים (PCB)

  • לכל תהליך: page directory נפרד, stack, תיאור הרשאות

Scheduler

  • כל כמה מילי-שניות (timer interrupt) מתבצעת פסיקה

  • הקרנל שומר context של התהליך הנוכחי (pusha, mov esp)

  • טוען context של תהליך אחר

  • מחליף cr3 לדפים שלו

  • מחזיר את הבקרה באמצעות iret


8. User Mode – הרצת תוכנה

בשלב מסוים, הקרנל טוען תוכנית יוזר מוד מהדיסק,

  1. יוצר page directory לתוכנית

  2. ממפה קוד לכתובות וירטואליות (למשל 0x00400000)

  3. ממפה stack

  4. מציב את EIP להתחלה של קוד התוכנית

  5. משנה את ה־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 ודרך אוגרים- תלוי בקונבנצית קריאה.

mov eax, 1      ; write
mov ebx, msg
int 0x80

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 – הקצאת זיכרון חכמה רק כשצריך