3 #include <inc/assert.h>
7 #include <kern/console.h>
8 #include <kern/monitor.h>
10 #include <kern/syscall.h>
11 #include <kern/sched.h>
12 #include <kern/kclock.h>
13 #include <kern/picirq.h>
15 static struct Taskstate ts
;
17 /* Interrupt descriptor table. (Must be built at run time because
18 * shifted function addresses can't be represented in relocation records.)
20 struct Gatedesc idt
[256] = { { 0 } };
21 struct Pseudodesc idt_pd
= {
22 sizeof(idt
) - 1, (uint32_t) idt
26 static const char *trapname(int trapno
)
28 static const char * const excnames
[] = {
31 "Non-Maskable Interrupt",
34 "BOUND Range Exceeded",
36 "Device Not Available",
38 "Coprocessor Segment Overrun",
40 "Segment Not Present",
45 "x87 FPU Floating-Point Error",
48 "SIMD Floating-Point Exception"
51 if (trapno
< (int) (sizeof(excnames
)/sizeof(excnames
[0])))
52 return excnames
[trapno
];
53 if (trapno
== T_SYSCALL
)
55 if (trapno
>= IRQ_OFFSET
&& trapno
< IRQ_OFFSET
+ 16)
56 return "Hardware Interrupt";
57 return "(unknown trap)";
64 extern struct Segdesc gdt
[];
66 // LAB 2: Your code here.
68 // Set a gate for the system call interrupt.
69 // Hint: Must this gate be accessible from userlevel?
71 // LAB 3 (Exercise 4): Your code here.
73 // Setup a TSS so that we get the right stack
74 // when we trap to the kernel.
75 ts
.ts_esp0
= KSTACKTOP
;
78 // Initialize the TSS field of the gdt.
79 gdt
[GD_TSS
>> 3] = SEG16(STS_T32A
, (uint32_t) (&ts
),
80 sizeof(struct Taskstate
), 0);
81 gdt
[GD_TSS
>> 3].sd_s
= 0;
87 asm volatile("lidt idt_pd");
92 print_trapframe(struct Trapframe
*tf
, bool trap_just_happened
)
94 cprintf("Trap frame at %p\n", tf
);
95 print_regs(&tf
->tf_regs
);
96 cprintf(" es 0x----%04x\n", tf
->tf_es
);
97 cprintf(" ds 0x----%04x\n", tf
->tf_ds
);
98 cprintf(" trap 0x%08x %s", tf
->tf_trapno
, trapname(tf
->tf_trapno
));
99 // If this trap was a page fault that just happened
100 // (so %cr2 is meaningful), print the faulting linear address.
101 if (trap_just_happened
&& tf
->tf_trapno
== T_PGFLT
)
102 cprintf(" [la 0x%08x]", rcr2());
103 cprintf("\n err 0x%08x", tf
->tf_err
);
104 // For page faults, print unparsed fault error code:
105 // U=fault occurred in user mode (K=kernel),
106 // WR=a write caused the fault (R=read),
107 // PR=a protection violation caused the fault (NP=page not present).
108 if (tf
->tf_trapno
== T_PGFLT
)
109 cprintf(" [fault err %s,%s,%s]",
110 tf
->tf_err
& 4 ? "U" : "K",
111 tf
->tf_err
& 2 ? "W" : "R",
112 tf
->tf_err
& 1 ? "PR" : "NP");
113 cprintf("\n eip 0x%08x\n", tf
->tf_eip
);
114 cprintf(" cs 0x----%04x\n", tf
->tf_cs
);
115 cprintf(" flag 0x%08x\n", tf
->tf_eflags
);
116 cprintf(" esp 0x%08x\n", tf
->tf_esp
);
117 cprintf(" ss 0x----%04x\n", tf
->tf_ss
);
121 print_regs(struct PushRegs
*regs
)
123 cprintf(" edi 0x%08x\n", regs
->reg_edi
);
124 cprintf(" esi 0x%08x\n", regs
->reg_esi
);
125 cprintf(" ebp 0x%08x\n", regs
->reg_ebp
);
126 cprintf(" oesp 0x%08x\n", regs
->reg_oesp
);
127 cprintf(" ebx 0x%08x\n", regs
->reg_ebx
);
128 cprintf(" edx 0x%08x\n", regs
->reg_edx
);
129 cprintf(" ecx 0x%08x\n", regs
->reg_ecx
);
130 cprintf(" eax 0x%08x\n", regs
->reg_eax
);
134 trap_dispatch(struct Trapframe
*tf
)
136 // Handle the breakpoint exception.
137 // LAB 2: Your code here.
139 // Handle page faults by calling page_fault_handler.
141 // LAB 3 (Exercise 3): Your code here.
143 // Handle system calls.
144 // Extract the system call number and arguments from 'tf',
145 // call 'syscall', and arrange for the return value to be passed
146 // back to the caller.
147 // LAB 3 (Exercise 4): Your code here.
149 // Handle clock interrupts.
150 // LAB 4: Your code here.
153 // Handle keyboard interrupts.
154 // LAB 5: Your code here.
156 // Handle spurious interrupts
157 // The hardware sometimes raises these because of noise on the
158 // IRQ line or other reasons. We don't care.
159 if (tf
->tf_trapno
== IRQ_OFFSET
+ IRQ_SPURIOUS
) {
160 cprintf("Spurious interrupt on irq 7\n");
161 print_trapframe(tf
, true);
166 // Unexpected trap: The user process or the kernel has a bug.
167 print_trapframe(tf
, true);
168 if (tf
->tf_cs
== GD_KT
)
169 panic("unhandled trap in kernel");
177 trap(struct Trapframe
*tf
)
179 // The environment may have set DF and some versions
180 // of GCC rely on DF being clear
181 asm volatile("cld" : : : "cc");
183 // Check that interrupts are disabled. If this assertion
184 // fails, DO NOT be tempted to fix it by inserting a "cli" in
185 // the interrupt path.
186 assert(!(read_eflags() & FL_IF
));
188 if ((tf
->tf_cs
& 3) == 3) {
189 // Trapped from user mode.
190 // Copy trap frame (which is currently on the stack)
191 // into 'curenv->env_tf', so that running the environment
192 // will restart at the trap point.
194 curenv
->env_tf
= *tf
;
195 // The trapframe on the stack should be ignored from here on.
196 tf
= &curenv
->env_tf
;
199 // Dispatch based on what type of trap occurred
202 // If we made it to this point, then no other environment was
203 // scheduled, so we should return to the current environment
204 // if doing so makes sense.
205 if (curenv
&& curenv
->env_status
== ENV_RUNNABLE
)
213 page_fault_handler(struct Trapframe
*tf
)
217 // Read processor's CR2 register to find the faulting address
220 // Page faults in the kernel should cause a panic.
221 // LAB 3 (Exercise 8): Your code here.
223 // If we get here, the page fault happened in user mode.
225 // Call the environment's page fault upcall, if one exists. Set up a
226 // page fault stack frame on the user exception stack (below
227 // UXSTACKTOP), then branch to curenv->env_pgfault_upcall.
229 // The page fault upcall might cause another page fault, in which case
230 // we branch to the page fault upcall recursively, pushing another
231 // page fault stack frame on top of the user exception stack.
233 // The trap handler needs one word of scratch space at the top of the
234 // trap-time stack in order to return. In the non-recursive case, we
235 // don't have to worry about this because the top of the regular user
236 // stack is free. In the recursive case, this means we have to leave
237 // an extra word between the current top of the exception stack and
238 // the new stack frame because the exception stack _is_ the trap-time
241 // If there's no page fault upcall, the environment didn't allocate a
242 // page for its exception stack, the environment can't write to its
243 // exception stack page, or the exception stack overflows, then destroy
244 // the environment that caused the fault.
245 // The grade script assumes you will first check for the page fault
246 // upcall and print the "user fault va" message below if there is
249 // Note that when this function runs, 'tf == &curenv->env_tf'.
251 // LAB 4: Your code here.
253 // Destroy the environment that caused the fault.
254 cprintf("[%08x] user fault va %08x ip %08x\n",
255 curenv
->env_id
, fault_va
, tf
->tf_eip
);
256 print_trapframe(tf
, true);