מנגנון הPaging – מיפוי זיכרון חכם¶
1. למה אנחנו צריכים Paging?¶
ישנם כמה בעיות במצב הנוכחי של המערכת שלנו מבחינת הזכרון של תוכנות יוזר מודיות.
כרגע, כל התוכנות היוזר מודיות חולקות אותו מרחב זכרון.
גם אם נגדיר לכל התוכנות היוזר מודיות שלנו בGDT המון סלקטורים, בסופו של דבר הם עדיין נמצאים באותו "מרחב זכרון".
כל התוכנות היוזר מודיות יכולות לגשת לסקלטורים של תוכנות יוזר מודיות אחרות, וזה בעייתי.
אומנם עכשיו, תוכנה יוזרמודית לא תוכל להקריס את כל המערכת (את הקרנל), אך היא תוכל להרוס את כל התוכנות שרצות במקביל איתה- וזה גם בעייתי!
הפתרון לזה? Paging – מנגנון מיפוי של כתובות זיכרון וירטואליות לכתובות פיזיות.
2. מה זה בכלל Paging?¶
מנגנון Paging = מנגנון של תירגום אוטומטי ע"י המעבד מכתובות ש־התוכנה רואה, לכתובות האמיתיות ב־RAM.
דמיינו, שכל תוכנה יוזר מודית שרצה במערכת, חושבת שהיא רצה לבד במערכת.
כלומר, היא יכולה לגשת לכל המרחב כתובות- מ0x00000000 עד ל- 0xffffffff
המנגון דואג שכל תוכנה תרוץ במרחב כתובות משלה, לבד לגמרי- וכך היא לא תוכל לגשת או לדעת על זכרון של תוכנה אחרת במערכת.
איך זה עובד?¶
המרחב כתובות הזה של כל תוכנה הוא וירטואלי, כלומר כאשר תוכנה ניגשת לאיזשהי כתובת במרחב הכתובות שלה- למשל 0x12345678, היא לא באמת תיגש לכתובת 0x12345678 בRAM.
המעבד חומרתית יתרגם את הכתובת הוירטואלית 0x12345678 לכתובת פיזית בRAM. ובכך, המעבד הוא זה שמנהל את הRAM ולא התוכנות היוזר מודיות.
- כל תוכנה חושבת שהיא מתחילה בכתובת
0x00000000. - המעבד יודע, לפי טבלאות שהוא טוען מראש, איך לתרגם את הכתובת הזו לכתובת האמיתית ב־RAM.
- לכל תוכנה יש טבלאות משלה – וכך היא לא רואה את האחרות, כלומר לתוכנה A הכתובת הוירטואלית
0x12345678יכולה להיות הכתובת הפיזית0xDEADBEEFולתוכנה B הכתובת הוירטואלית0x12345678יכולה להיות הכתובות הפיזית0x87654321
3. כתובת וירטואלית לעומת כתובת פיזית¶
| מושג | הסבר |
|---|---|
| Virtual Address | מה שהתוכנה רואה – לדוגמה: 0x00400000 |
| Physical Address | מה שבאמת קיים ב־RAM – לדוגמה: 0x0013A000 |
4. טבלאות Paging – Page Directory ו־Page Tables¶
למעבד יש טבלאות שדרכים הוא יודע כיצד להמיר כתובת וירטואלית של תוכנה מסוימת לכתובת פיזית.
לכל תוכנה יוזר מודית שרצה במערכת, יש העתק של הטבלאות הבאות בקרנל- המעבד משתמש בטבלאות הבאות שיש לכל תוכנה כדי לתרגם את הכתובת הוירטואלית לכתובת פיזית בRAM.
טבלאת הPage Directory:¶
- גודל: 4KB
- מכיל 1024 רשומות (כל אחת בגודל 4 בתים)
- כל רשומה מצביעה על Page Table
טבלאת Page Table:¶
- גודל: 4KB
- מכיל 1024 רשומות (כל אחת בגודל 4 בתים)
- כל רשומה מצביעה על מסגרת זיכרון אמיתית (Page Frame)
ומה זה Page Frame?¶
- הFrame היא מסגרת של זכרון בRAM האמיתי, שאילו כל עמודה בpage table מצביעה.
- גודל המסגרת: בדיוק 4KB
כלומר:
כדי להמיר כתובת וירטואלית של תוכנה מסוימת, על פי הטבלאות שמוגדרות בקרנל שיש לכל תוכנה- המעבד יודע למיר את הכתובת הוירטואלית לפיזית.
5. חלוקת כתובת וירטואלית (32 ביט)¶
איך זה קורה?
כל כתובת מתחלקת כך:
+---------------+-----------+------+
|Directory Index|Table Index|Offset|
| 31.........22 | 21.....12 |11...0|
+---------------+-----------+------+
כך, שאת הכתובות הוירטואלית אנחנו מחלקים למצביע בטבלת הpage directory, (שמצביע על הpage table הרלוונטי ) ולמצביע בטבלת הpage table (שמציין את הframe הפיזי) ולבסוף, offset של 12 ביטים בתוך הframe הפיזי.
-
10 ביטים: מצביעים על קלט בטבלת ה־Directory
-
10 ביטים: מצביעים על קלט בטבלת ה־Page Table
-
12 ביטים: Offset בתוך ה־Page בגודל 4KB
כאשר תוכנה יוזר מודית מנסה לגשת לכתובת וירטואלית מסוימת, המעבד לוקח את טבלת הpage directory ועל פי הindex שיש בכתובת, הוא פונה לטבלת page table ההכרחית, ועל פי הindex שיש בכתובת, הוא ניגש בRAM הפיזי לframe שמוגדר בטבלה- ומוסיף לframe את הoffset שמוגדר בכתובת- וכך המעבד המיר כתובת וירטואלית של תוכנה מסוימת לכתובת פיזית.
6. דף¶
לכל מסגרת פיזית שמוגדרת בpage table (כל frame) אנחנו נקרא גם "page" או בתרגום, דף.
כלומר, אפשר להגיד שהRAM הפיזי מחולק להמון מסגרות, ואפשר גם להגיד שהוא מחולק להמון דפים.
כל מסגרת היא "דף".
למעשה, אנחנו לא יכולים באמת להקצות לכל תוכנה את כל המרחב כתובות שלה, 0x00000000 עד 0xffffffff- כי אז יגמר לנו הזכרון במחשב.
מערכת ההפעלה אחראית לנהל ולהקצות דפים לתוכנות, היא יכולה להוסיף דפים ולמחוק דפים לכל תוכנה.
אבל מה ההבדל בין דף למסגרת?
מסגרת (frame כמו שאמרנו קודם) בזכרון היא הדף ה"פיזי" שנמצא בRAM (בכתובת פיזית), ולעומת זאת כשאנחנו אומרים "דף" אנחנו מתכוונים למסגרת עם עוד כמה פרמטרים של מערכת ההפעלה (אובייקט של מערכת ההפעלה שמדמה מסגרת).
כלומר, מערכת ההפעלה יכולה להקצות דפים (להוסיף), למחוק דפים, לשנות הגדרות של דפים לכל תוכנה- ומאחורי הקלעים, כל דף היא מסגרת פיזית בRAM.
דף שמוגדר בטבלת הpage table נראה כך:
+----+---+---+---+----------------------------+
| P | R | U | W |כתובת פיזית של המסגרת(20bit)|
+----+---+---+---+----------------------------+
- כתובת פיזית של המסגרת = כתובת פיזית של ה־Page
- P = Present – האם הדף קיים בזיכרון? (כלומר האם הקצנו את הדף לתוכנה)
- R/W = האם מותר לתוכנה לקרוא או לכתוב לדף?
- U/S = האם הדף רץ בהרשאות קרנל או יוזרמוד
7. הפעלת Paging במעבד¶
שלב 1: יצירת Page Directory ו־Page Tables בזיכרון¶
קודם ניצור טבלת page directory ריקה לכל תוכנה יוזר מודית.
בעתיד, נאפשר לתוכנות להקצות page-ים באמצעות פסיקות וכאשר הם יעשו זאת מערכת ההפעלה תיצור page directory רלוונטי ( על סמך הpage שנרצה ליצור לתוכנה ), ותוסיף את השורות הרלוונטיות בטבלה על פי הpage-ים שנרצה להביא לתוכנה.
שלב 2: טוענים את כתובת ה־Page Directory לרגיסטר CR3¶
כדי לגרום למעבד להתחיל להמיר כתובות עם מנגנון הpaging- עלינו לשים את כתובת הpage directory ברגיסטר "cr3"
שלב 3: מפעילים את Paging¶
ולהפעיל את paging עם הדלקת ביט מסוים בcr0.
ברגע שעשינו זאת – המעבד יתחיל לתרגם כתובות וירטואליות דרך הטבלאות שהצבענו להן.
8. שגיאת page fault¶
מה יקרה אם תוכנה תנסה לגשת לpage שמערכת ההפעלה לא הגדירה לה?
בתהליך הpaging, אם המעבד לא ימצה page table בpage directory, או שבpage table לא ימצא page עם present דולק- אז תתרחש שגיאת "page fault", ואיתה תקרה הפסיקה "interrupt 14h"
מערכת ההפעלה יכולה להגיב לזה (לכתוב handler).
9. למה המנגנון הזה כל כך שימושי?¶
| שימוש | הסבר |
|---|---|
| ריבוי משימות בטוח | כל תוכנה רואה רק את הזיכרון שלה |
| הפרדת קרנל מיוזר מוד | הקרנל מוגדר בpage-ים ייחודיים שלא נגישים למשתמש |
| תמיכה ב־Virtual Memory | לא חייבים ש־RAM יכיל את הכל הזכרון, אפשר גם שהאחסון – נדבר על זה בהמשך (Swapping) |
| כתובות אחידות | תוכנה תמיד נטענת לאותו מקום וירטואלי (לאותה כתובת מוגדרת מראש) – אפילו אם פיזית זה במקום אחר |
10. שינוי ידני של הטבלאות¶
לצורך הבנה של הטבלה בצד הקרנל, הנה דוגמה לאיך ניתן לשנות את הטבלה ידנית כדי להוסיף Page.
נניח שיש לנו תוכנה שרצה מכתובת 0x00400000
אנחנו רוצים למפות את זה ל־RAM אמיתי, לדוגמה 0x00120000. (כלומר שpage ב0x00400000 יכוון על הכתובת הפיזית 0x00120000)
mov eax, page_table
or eax, 0x3 ; Present, RW
mov [page_directory + 4*1], eax ; כי index=1 (0x00400000)
mov dword [page_table + 4*0], 0x00120000 | 0x3
11. איפה זה משתלב ב־Scheduler?¶
כל תוכנה שמריצים – יש לה Page Directory משלה
כל פעם ש־Scheduler עובר תוכנה (עושה context switch) – הוא טוען ל־CR3 (האוגר שמכיל את הכתובת הקרנלית של הpage directory של התוכנה) את ה־Directory שלה
כך המעבד "חושב" שהתוכנה היא היחידה שרצה בזיכרון – לא רואה תוכנות אחרות בכלל
כמובן שהcr3 של כל תוכנה גם נשמר בpcb, והScheduler משתמש בו בcontext switch.
12. סיכום¶
- מנגנון הPaging הוא מנגנון תרגום כתובות – מה שהתוכנה רואה ≠ מה שקיים בפועל בRAM
- מאפשר הפרדת תוכנות, הגנה, ואשליית זיכרון גדול
- מופעל ע"י הגדרת טבלאות – Page Directory ו־Page Table
- כל תוכנה מקבלת מפת זיכרון משלה – מתוחזקת ע"י הקרנל
- המעבד עושה את התרגום אוטומטית, אחרי שנפעיל את ה־PG ב־CR0 והאוגר CR3 יכיל את כתובת הטבלה שנגדיר.
שאלות למחשבה¶
- מה קורה אם תוכנה מנסה לכתוב לדף שלא קיים? (קורה page fault)
- איך נוכל לטעון דפים רק כשצריך אותם? כלומר- איך נפתח פסיקה של מערכת ההפעלה שטוענת page-ים חדשים לתוכנה שקורת לפסיקה שהגדרנו?
- איך ניתן לממש מערכת עם יותר RAM מהכמות האמיתית? (רמז: swap)
אם תרצה, נוכל להמשיך בהרצאה הבאה לעסוק ב־Page Faults, demand paging, ואיך זה משתלב בניהול זיכרון מתקדם.