יישום
המערך sys_imp כולל את כל המידע הנדרש לפסיקות XINU.
לכל פסיקה מוקצאת
רשומה הכוללת את המידע הבא:
- פקודת המכונה call intcom.
- כתובת קוד ה-BIOS שהוצבע במקור מווקטור הפסיקות.
- כתובת פונקצית הפסיקה של XINU.
- מספר הפסיקה בווקטור הפסיקות.
- זיהוי פנימי של ההתקן.
- דגל המסמן האם לקרוא לקוד ה-BIOS לפני הקריאה לקוד ה-XINU.
- גודל כל רשומה מסוג intmap הינו 14 בתים.
מבנה רשומה:
struct intmap { /* device-to-interrupt routine
mapping */
char ivec; /* interrupt number */
char callinst; /* the call instruction */
word intcom; /* common interrupt code */
word oldisr_off; /* old int. service routine
offset */
word oldisr_seg; /* old int. service routine
segment */
int (*newisr)(); /* pointer to the new int. ser.
routine */
word mdevno; /* minor device number */
word iflag; /* if nonzero, call the old isr */
};
קבועים והגדרות
הקשורים לטבלה זו:
extern struct intmap far *sys_imp; /* pointer to intmap
table */
extern int nmaps; /* number of active
intmap entries*/
#define isbaddev(f) ( (f)<0 || (f)>=NDEVS )
/* In-line I/O procedures */
#define getchar() getc(CONSOLE)
#define putchar(ch) putc(CONSOLE,(ch))
#define fgetc(unit) getc((unit))
#define fputc(unit,ch) putc((unit),(ch))
extern int _doprnt(); /* output formatter */
- ווקטור הפסיקות מצביע על פקודת call intcom שברשומה
המתאימה במערך sys_imp. לכן בעת פסיקה תקרא intcom כפונקציה מתוך הפסיקה.
- intcom היא פונקציה כללית המשרתת את כל הפסיקות. אנו יודעים לאיזו פסיקה לקרוא לפי
המיקום של intcom. הבית שאחרי פקודה זו נמצא
על המחסנית ככתובת החזרה,
בכתובת ss:bp+2.
- על ידי ביצוע mov bx,
[bp+2], אנו מקבלים ב-bx את "כתובת החזרה" המצביעה לתוך רשומת הפסיקה. כתובת שגרת הפסיקה המקורית נמצאת ב-.
- כתובת שגרת הפסיקה של XINU היא cs:[bx+4]. כתובת
mdevno היא cs:[bx+6].
- כתובת iflag המציין האם לקרוא לשגרה המקורית היא cs:[bx+8].
- בסוף פעולתה, intcom מוציאה את כתובת החזרה מהמחסנית, ומשתמשת ב-iret כדי לחזור לנקודה בה הייתה לפני הקפיצה לטבלה.
- טבלת הפסיקות נמצאת בסגמנט התוכנית, cs, שהינו
לא נגיש עבור תוכניות C
רגילות. מכיוון שאנו רוצים לאתחל
את המערך מתוך C, מוגדר המשתנה sys_imp המכיל מצביע (סגמנט + offset) אל
הטבלה.
intcom()
- קוראת לקוד הפסיקה הישן במידה ש-iflag דולק.
- מכבה את דגל הפסיקות, כדי לוודא שקוד הפסיקה הישן לא
הדליק אותו.
- שומרת את ערכי כל הרגיסטרים.
- אם הפסיקה ארעה כאשר התבצע קוד של XINU:
- אם הפסיקה ארעה מתוך קוד שאינו של XINU
(למשל בזמן
ביצוע פסיקתBIOS - ROM כאשר דגל הפסיקות דולק):
- נמנעת החלפת תהליכים ע”י
איפוס pcxflag.
- נקרא קוד הפסיקה של XINU.
- משוחזרים pcxflag והמחסנית הישנה.
- משוחזרים כל הרגיסטרים.
- כתובת החזרה מ-
intcom מוצאת
מהמחסנית ומתבצע iret.
הערה: ב-intcom, קביעת ה-pcxflag ל-0 נעשית אחרי החלפת המחסנית ולא
לפני, אולם זו איננה בעיה מכיוון
שהפסיקות מכובות בקטע זה, ולכן לא תתכן החלפת תהליכים.
מבנה המחסנית
בזמן הקריאה ל-intcom
Stack Offset |
Stack Contents |
0 |
es |
1 |
ds |
2 |
di |
3 |
si |
4 |
dx |
5 |
cx |
6 |
bx |
7 |
ax |
8 |
bp |
9 |
ret
address to intmap table, offset 4 |
10 |
IRET
offset address |
11 |
IRET
segment address |
12 |
IRET flags |
13 |
user code |
- intcom מתחילה את פעולתה בדחיפת bp, ax, bx אל המחסנית.
תודה
הסברתם את זה, כמו שאר הנושאים, באופן הכי ברור שיש.