6.7 - פסיקות ו-exceptions - תרגול
תרגיל 1 - בדיקת interrupts במערכת חיה¶
-
הריצו את הפקודה הבאה:
-
ענו על השאלות הבאות:
- כמה שורות interrupts חומרה (מספריות) יש?
- מצאו את שורת הטיימר (timer). על איזו ליבה רוב הinterrupts של הטיימר טופלו?
- מצאו את השורה של LOC (Local timer interrupts). מה ההבדל בין הטיימר הגלובלי לLOC?
-
האם יש כרטיס רשת רשום? מה שם הדרייבר שלו?
-
הריצו:
ולחצו מקשים במקלדת. איזה מספר IRQ עולה כשלוחצים?
תרגיל 2 - המסע של לחיצת מקש¶
תארו בפירוט מה קורה מהרגע שמשתמש לוחץ על מקש במקלדת ועד שהתו מופיע על המסך. עברו על כל השלבים:
1. מה קורה ברמת החומרה?
2. איך הinterrupt מגיעה למעבד? (דרך מי?)
3. מה המעבד עושה כשהוא מקבל את הinterrupt?
4. מה הtop half של הhandler עושה?
5. מה הbottom half עושה?
6. איך המידע מגיע בסופו של דבר לprocess (לטרמינל)?
תרגיל 3 - דיבאגר ו-breakpoints¶
-
הסבירו מה ההבדל בין hardware breakpoint ל-software breakpoint.
-
כשGDB שם software breakpoint בכתובת מסוימת, הוא כותב את הבית
0xCC(הopcode שלint3) במקום הפקודה המקורית.
ענו:
- למה GDB צריך לשמור את הבית המקורי שהיה שם?
- מה קורה כשהמעבד מגיע לint3? תארו את השרשרת: exception -> IDT -> handler -> סיגנל -> ptrace -> GDB
- כשGDB מחליט להמשיך (continue), מה הוא צריך לעשות לפני שהתוכנה ממשיכה?
- בפרק 5.4 למדנו על סיגנלים. הסבירו למה דווקא SIGTRAP הוא הסיגנל שנבחר לbreakpoints ולא סיגנל אחר.
תרגיל 4 - חצי עליון מול חצי תחתון¶
לפניכם שלושה תרחישים. לכל תרחיש, החליטו איזה מנגנון bottom half הכי מתאים (softirq, tasklet, או workqueue) והסבירו למה:
-
דרייבר של כרטיס רשת שצריך לעבד חבילות בקצב של מיליון חבילות בשנייה. העיבוד לא דורש גישה לדיסק.
-
דרייבר של מקלדת USB שצריך לעבד לחיצות מקשים. הקצב נמוך (כמה עשרות לחיצות בשנייה לכל היותר) והעיבוד פשוט.
-
דרייבר של דיסק שצריך לעדכן מטא-דאטה של מערכת הקבצים אחרי כל כתיבה. העדכון דורש allocation זיכרון ועשוי לדרוש גישה לדיסק.
תרגיל 5 - חריגות וסיגנלים¶
- לפניכם קטע קוד ב-C. לכל שורה מסומנת, ציינו: איזו חריגה (exception) תיגרם, מה המספר שלה, ואיזה סיגנל יישלח לprocess.
#include <stdio.h>
#include <signal.h>
int main() {
// line A
int x = 1 / 0;
// line B
int *ptr = (int *)0xDEADBEEF;
*ptr = 42;
// line C
void (*func)() = (void (*)())0x12345678;
func();
return 0;
}
-
כתבו תוכנה ב-C שרושמת signal handler לSIGFPE, ובhandler מדפיסה הודעה ואז יוצאת מהתוכנה. אחרי רישום הhandler, גרמו בכוונה לחלוקה באפס.
-
הסבירו: למה exception #PF (page fault) לא תמיד גורם לSIGSEGV? תנו שתי דוגמאות שבהן page fault הוא "רגיל" והקרנל מטפל בו בלי לשלוח סיגנל.