7#define STACKFRAME_DEPTH 2089externconststruct stab __STAB_BEGIN__[];// beginning of stabs table10externconststruct stab __STAB_END__[];// end of stabs table11externconstchar __STABSTR_BEGIN__[];// beginning of string table12externconstchar __STABSTR_END__[];// end of string table1314/* debug information about a particular instruction pointer */15struct eipdebuginfo {16constchar*eip_file;// source code filename for eip17int eip_line;// source code line number for eip18constchar*eip_fn_name;// name of function containing eip19int eip_fn_namelen;// length of function's name20uintptr_t eip_fn_addr;// start address of function21int eip_fn_narg;// number of function arguments22};9/* Entries in the STABS table are formatted as follows. */8struct stab {7uint32_t n_strx;// index into string table of name6uint8_t n_type;// type of symbol5uint8_t n_other;// misc info (usually empty)4uint16_t n_desc;// description field3uintptr_t n_value;// value of symbol2};
66 static void
1 stab_binsearch(const struct stab *stabs, int *region_left, int *region_right,
2 int type, uintptr_t addr) {
3 int l = *region_left, r = *region_right, any_matches = 0;
4
5 while (l <= r) {
6 int true_m = (l + r) / 2, m = true_m;
7
8 // search for earliest stab with right type
9 // when fail at the end, l will become bigger than r.
10 // The logic here is simply to find the first m that suitable for our type.
11 while (m >= l && stabs[m].n_type != type) {
12 m --;
13 }
14 if (m < l) { // no match in [l, m]
15 l = true_m + 1;
16 continue;
17 }
18
19 // actual binary search
20 // For this while loop:
21 // 1. We assure the m is of right type. -> that will be computed for region_left or region_right.
22 // 2. We use binsearch to accelerate the speed to find m, we ensure at least one is smaller than addr,
23 // one is bigger than addr, but not ensure this m is the closest to the addr. When we are using binsearch,
24 // we implicitly omit some l and some r values. What we do here is simply found the right&left bounds.
25 any_matches = 1;
26 if (stabs[m].n_value < addr) {
27 *region_left = m;
28 l = true_m + 1;
29 } else if (stabs[m].n_value > addr) {
30 *region_right = m - 1;
31 r = m - 1;
32 } else {
33 // exact match for 'addr', but continue loop to find
34 // *region_right
35 *region_left = m;
36 l = m;
37 addr ++;
38 }
39 }
107 if (!any_matches) {
1 *region_right = *region_left - 1;
2 }
3 else {
4 // find rightmost region containing 'addr'
5 // Now we want to have a closer result.
6 l = *region_right;
7 for (; l > *region_left && stabs[l].n_type != type; l --)
8 /* do nothing */;
9 *region_left = l;
10 }
11 }
31 void
30 print_stackframe(void) {
29 /* LAB1 YOUR CODE : STEP 1 */
28 /* (1) call read_ebp() to get the value of ebp. the type is (uint32_t);
27 * (2) call read_eip() to get the value of eip. the type is (uint32_t);
26 * (3) from 0 .. STACKFRAME_DEPTH
25 * (3.1) printf value of ebp, eip
24 * (3.2) (uint32_t)calling arguments [0..4] = the contents in address (uint32_t)ebp +2 [0..4]
23 * (3.3) cprintf("\n");
22 * (3.4) call print_debuginfo(eip-1) to print the C calling function name and line number, etc.
21 * (3.5) popup a calling stackframe
20 * NOTICE: the calling funciton's return addr eip = ss:[ebp+4]
19 * the calling funciton's ebp = ss:[ebp]
18 */
17 int time = 0;
16 uint32_t ebp = read_ebp(); // | return address | <-- caller's eip. read_ebp will simply return ebp value.
15 // - - - - - - - - - -
14 uint32_t eip = read_eip(); // | last ebp | <-- ebp point to this position. read_eip will load the memory 4(%%ebp).
13 // BTW: the read_eip function here is very tricky!! Understand this thing is of great fun!
12
11 // End point: when ebp is equal to 0, then our stackframe chain ends.
10 while (ebp != 0 && time < STACKFRAME_DEPTH) {
9 cprintf("ebp:%08x eip:%08x ", ebp, eip);
8 uint32_t* args = (uint32_t*) ebp + 2;
7 cprintf("args:%08x %08x %08x %08x\n", args[0], args[1], args[2], args[3]);
6 // eip - 1 is sufficient for us to use binsearch to locate the line.
5 print_debuginfo(eip - 1);
4 eip = *((uint32_t*) ebp + 1);
3 ebp = *((uint32_t*) ebp);
2 time++;
1 }
331 }
15 int
16 kern_init(void) {
17 extern char edata[], end[];
18 memset(edata, 0, end - edata);
19
20 cons_init(); // init the console
21
22 const char *message = "(THU.CST) os is loading ...";
23 cprintf("%s\n\n", message);
24
25 print_kerninfo();
26
27 grade_backtrace();
28
29 pmm_init(); // init physical memory management
30
31 pic_init(); // init interrupt controller
32 idt_init(); // init interrupt descriptor table
33
34 clock_init(); // init clock interrupt
35 intr_enable(); // enable irq interrupt
36
37 //LAB1: CAHLLENGE 1 If you try to do it, uncomment lab1_switch_test()
38 // user/kernel mode switch test
39 //lab1_switch_test();
40
41 /* do nothing */
42 while (1);
43 }
12 /* *
13 * Set up a normal interrupt/trap gate descriptor
14 * - istrap: 1 for a trap (= exception) gate, 0 for an interrupt gate
15 * - sel: Code segment selector for interrupt/trap handler
16 * - off: Offset in code segment for interrupt/trap handler
17 * - dpl: Descriptor Privilege Level - the privilege level required
18 * for software to invoke this interrupt/trap gate explicitly
19 * using an int instruction.
20 * */
27 #define SETGATE(gate, istrap, sel, off, dpl) { \
26 (gate).gd_off_15_0 = (uint32_t)(off) & 0xffff; \
25 (gate).gd_ss = (sel); \
24 (gate).gd_args = 0; \
23 (gate).gd_rsv1 = 0; \
22 (gate).gd_type = (istrap) ? STS_TG32 : STS_IG32; \
21 (gate).gd_s = 0; \
20 (gate).gd_dpl = (dpl); \
19 (gate).gd_p = 1; \
18 (gate).gd_off_31_16 = (uint32_t)(off) >> 16; \
17 }
9 #ifndef __KERN_MM_MEMLAYOUT_H__
8 #define __KERN_MM_MEMLAYOUT_H__
7
6 /* This file contains the definitions for memory management in our OS. */
5
4 /* global segment number */
3 #define SEG_KTEXT 1
2 #define SEG_KDATA 2
1 #define SEG_UTEXT 3
10 #define SEG_UDATA 4
1 #define SEG_TSS 5
2
3 /* global descriptor numbers */
4 #define GD_KTEXT ((SEG_KTEXT) << 3) // kernel text
5 #define GD_KDATA ((SEG_KDATA) << 3) // kernel data
6 #define GD_UTEXT ((SEG_UTEXT) << 3) // user text
7 #define GD_UDATA ((SEG_UDATA) << 3) // user data
8 #define GD_TSS ((SEG_TSS) << 3) // task segment selector
/* idt_init - initialize IDT to each of the entry points in kern/trap/vectors.S */
4 void
5 idt_init(void) {
6 /* LAB1 YOUR CODE : STEP 2 */
7 /* (1) Where are the entry addrs of each Interrupt Service Routine (ISR)?
8 * All ISR's entry addrs are stored in __vectors. where is uintptr_t __vectors[] ?
9 * __vectors[] is in kern/trap/vector.S which is produced by tools/vector.c
10 * (try "make" command in lab1, then you will find vector.S in kern/trap DIR)
11 * You can use "extern uintptr_t __vectors[];" to define this extern variable which will be used later.
12 * (2) Now you should setup the entries of ISR in Interrupt Description Table (IDT).
13 * Can you see idt[256] in this file? Yes, it's IDT! you can use SETGATE macro to setup each item of IDT
14 * (3) After setup the contents of IDT, you will let CPU know where is the IDT by using 'lidt' instruction.
15 * You don't know the meaning of this instruction? just google it! and check the libs/x86.h to know more.
16 * Notice: the argument of lidt is idt_pd. try to find it!
17 */
18
19 // call extern global variabels __vectors.
20 extern uintptr_t __vectors[];
21
22 // use __vectors to initialize the idt entry.
23 for (int i = 0; i < 256; i++) {
24 SETGATE(idt[i], 0, GD_KTEXT, __vectors[i], 0);
25 }
26
27 // lidt instruction to set the IDT with IDTR.
28 lidt(&idt_pd);
29 }