|
|
- #include <defs.h>
- #include <mmu.h>
- #include <memlayout.h>
- #include <clock.h>
- #include <trap.h>
- #include <x86.h>
- #include <stdio.h>
- #include <assert.h>
- #include <console.h>
- #include <vmm.h>
- #include <swap.h>
- #include <kdebug.h>
- #include <unistd.h>
- #include <syscall.h>
- #include <error.h>
- #include <sched.h>
- #include <sync.h>
- #include <proc.h>
-
- #define TICK_NUM 100
-
- static void print_ticks() {
- cprintf("%d ticks\n",TICK_NUM);
- #ifdef DEBUG_GRADE
- cprintf("End of Test.\n");
- panic("EOT: kernel seems ok.");
- #endif
- }
-
- /* *
- * Interrupt descriptor table:
- *
- * Must be built at run time because shifted function addresses can't
- * be represented in relocation records.
- * */
- static struct gatedesc idt[256] = {{0}};
-
- static struct pseudodesc idt_pd = {
- sizeof(idt) - 1, (uintptr_t)idt
- };
-
- /* idt_init - initialize IDT to each of the entry points in kern/trap/vectors.S */
- void
- idt_init(void) {
- /* LAB1 YOUR CODE : STEP 2 */
- /* (1) Where are the entry addrs of each Interrupt Service Routine (ISR)?
- * All ISR's entry addrs are stored in __vectors. where is uintptr_t __vectors[] ?
- * __vectors[] is in kern/trap/vector.S which is produced by tools/vector.c
- * (try "make" command in lab1, then you will find vector.S in kern/trap DIR)
- * You can use "extern uintptr_t __vectors[];" to define this extern variable which will be used later.
- * (2) Now you should setup the entries of ISR in Interrupt Description Table (IDT).
- * Can you see idt[256] in this file? Yes, it's IDT! you can use SETGATE macro to setup each item of IDT
- * (3) After setup the contents of IDT, you will let CPU know where is the IDT by using 'lidt' instruction.
- * You don't know the meaning of this instruction? just google it! and check the libs/x86.h to know more.
- * Notice: the argument of lidt is idt_pd. try to find it!
- */
- /* LAB5 YOUR CODE */
- //you should update your lab1 code (just add ONE or TWO lines of code), let user app to use syscall to get the service of ucore
- //so you should setup the syscall interrupt gate in here
- extern uintptr_t __vectors[];
- int i;
- for (i = 0; i < sizeof(idt) / sizeof(struct gatedesc); i ++) {
- SETGATE(idt[i], 0, GD_KTEXT, __vectors[i], DPL_KERNEL);
- }
- SETGATE(idt[T_SYSCALL], 1, GD_KTEXT, __vectors[T_SYSCALL], DPL_USER);
- lidt(&idt_pd);
- }
-
- static const char *
- trapname(int trapno) {
- static const char * const excnames[] = {
- "Divide error",
- "Debug",
- "Non-Maskable Interrupt",
- "Breakpoint",
- "Overflow",
- "BOUND Range Exceeded",
- "Invalid Opcode",
- "Device Not Available",
- "Double Fault",
- "Coprocessor Segment Overrun",
- "Invalid TSS",
- "Segment Not Present",
- "Stack Fault",
- "General Protection",
- "Page Fault",
- "(unknown trap)",
- "x87 FPU Floating-Point Error",
- "Alignment Check",
- "Machine-Check",
- "SIMD Floating-Point Exception"
- };
-
- if (trapno < sizeof(excnames)/sizeof(const char * const)) {
- return excnames[trapno];
- }
- if (trapno >= IRQ_OFFSET && trapno < IRQ_OFFSET + 16) {
- return "Hardware Interrupt";
- }
- return "(unknown trap)";
- }
-
- /* trap_in_kernel - test if trap happened in kernel */
- bool
- trap_in_kernel(struct trapframe *tf) {
- return (tf->tf_cs == (uint16_t)KERNEL_CS);
- }
-
- static const char *IA32flags[] = {
- "CF", NULL, "PF", NULL, "AF", NULL, "ZF", "SF",
- "TF", "IF", "DF", "OF", NULL, NULL, "NT", NULL,
- "RF", "VM", "AC", "VIF", "VIP", "ID", NULL, NULL,
- };
-
- void
- print_trapframe(struct trapframe *tf) {
- cprintf("trapframe at %p\n", tf);
- print_regs(&tf->tf_regs);
- cprintf(" ds 0x----%04x\n", tf->tf_ds);
- cprintf(" es 0x----%04x\n", tf->tf_es);
- cprintf(" fs 0x----%04x\n", tf->tf_fs);
- cprintf(" gs 0x----%04x\n", tf->tf_gs);
- cprintf(" trap 0x%08x %s\n", tf->tf_trapno, trapname(tf->tf_trapno));
- cprintf(" err 0x%08x\n", tf->tf_err);
- cprintf(" eip 0x%08x\n", tf->tf_eip);
- cprintf(" cs 0x----%04x\n", tf->tf_cs);
- cprintf(" flag 0x%08x ", tf->tf_eflags);
-
- int i, j;
- for (i = 0, j = 1; i < sizeof(IA32flags) / sizeof(IA32flags[0]); i ++, j <<= 1) {
- if ((tf->tf_eflags & j) && IA32flags[i] != NULL) {
- cprintf("%s,", IA32flags[i]);
- }
- }
- cprintf("IOPL=%d\n", (tf->tf_eflags & FL_IOPL_MASK) >> 12);
-
- if (!trap_in_kernel(tf)) {
- cprintf(" esp 0x%08x\n", tf->tf_esp);
- cprintf(" ss 0x----%04x\n", tf->tf_ss);
- }
- }
-
- void
- print_regs(struct pushregs *regs) {
- cprintf(" edi 0x%08x\n", regs->reg_edi);
- cprintf(" esi 0x%08x\n", regs->reg_esi);
- cprintf(" ebp 0x%08x\n", regs->reg_ebp);
- cprintf(" oesp 0x%08x\n", regs->reg_oesp);
- cprintf(" ebx 0x%08x\n", regs->reg_ebx);
- cprintf(" edx 0x%08x\n", regs->reg_edx);
- cprintf(" ecx 0x%08x\n", regs->reg_ecx);
- cprintf(" eax 0x%08x\n", regs->reg_eax);
- }
-
- static inline void
- print_pgfault(struct trapframe *tf) {
- /* error_code:
- * bit 0 == 0 means no page found, 1 means protection fault
- * bit 1 == 0 means read, 1 means write
- * bit 2 == 0 means kernel, 1 means user
- * */
- cprintf("page fault at 0x%08x: %c/%c [%s].\n", rcr2(),
- (tf->tf_err & 4) ? 'U' : 'K',
- (tf->tf_err & 2) ? 'W' : 'R',
- (tf->tf_err & 1) ? "protection fault" : "no page found");
- }
-
- static int
- pgfault_handler(struct trapframe *tf) {
- extern struct mm_struct *check_mm_struct;
- if(check_mm_struct !=NULL) { //used for test check_swap
- print_pgfault(tf);
- }
- struct mm_struct *mm;
- if (check_mm_struct != NULL) {
- assert(current == idleproc);
- mm = check_mm_struct;
- }
- else {
- if (current == NULL) {
- print_trapframe(tf);
- print_pgfault(tf);
- panic("unhandled page fault.\n");
- }
- mm = current->mm;
- }
- return do_pgfault(mm, tf->tf_err, rcr2());
- }
-
- static volatile int in_swap_tick_event = 0;
- extern struct mm_struct *check_mm_struct;
-
- static void
- trap_dispatch(struct trapframe *tf) {
- char c;
-
- int ret=0;
-
- switch (tf->tf_trapno) {
- case T_PGFLT: //page fault
- if ((ret = pgfault_handler(tf)) != 0) {
- print_trapframe(tf);
- if (current == NULL) {
- panic("handle pgfault failed. ret=%d\n", ret);
- }
- else {
- if (trap_in_kernel(tf)) {
- panic("handle pgfault failed in kernel mode. ret=%d\n", ret);
- }
- cprintf("killed by kernel.\n");
- panic("handle user mode pgfault failed. ret=%d\n", ret);
- do_exit(-E_KILLED);
- }
- }
- break;
- case T_SYSCALL:
- syscall();
- break;
- case IRQ_OFFSET + IRQ_TIMER:
- #if 0
- LAB3 : If some page replacement algorithm(such as CLOCK PRA) need tick to change the priority of pages,
- then you can add code here.
- #endif
- /* LAB1 YOUR CODE : STEP 3 */
- /* handle the timer interrupt */
- /* (1) After a timer interrupt, you should record this event using a global variable (increase it), such as ticks in kern/driver/clock.c
- * (2) Every TICK_NUM cycle, you can print some info using a funciton, such as print_ticks().
- * (3) Too Simple? Yes, I think so!
- */
- /* LAB5 YOUR CODE */
- /* you should upate you lab1 code (just add ONE or TWO lines of code):
- * Every TICK_NUM cycle, you should set current process's current->need_resched = 1
- */
- /* LAB6 YOUR CODE */
- /* IMPORTANT FUNCTIONS:
- * run_timer_list
- *----------------------
- * you should update your lab5 code (just add ONE or TWO lines of code):
- * Every tick, you should update the system time, iterate the timers, and trigger the timers which are end to call scheduler.
- * You can use one funcitons to finish all these things.
- */
- ticks ++;
- assert(current != NULL);
- run_timer_list();
- break;
- case IRQ_OFFSET + IRQ_COM1:
- c = cons_getc();
- cprintf("serial [%03d] %c\n", c, c);
- break;
- case IRQ_OFFSET + IRQ_KBD:
- c = cons_getc();
- cprintf("kbd [%03d] %c\n", c, c);
- break;
- //LAB1 CHALLENGE 1 : YOUR CODE you should modify below codes.
- case T_SWITCH_TOU:
- case T_SWITCH_TOK:
- panic("T_SWITCH_** ??\n");
- break;
- case IRQ_OFFSET + IRQ_IDE1:
- case IRQ_OFFSET + IRQ_IDE2:
- /* do nothing */
- break;
- default:
- print_trapframe(tf);
- if (current != NULL) {
- cprintf("unhandled trap.\n");
- do_exit(-E_KILLED);
- }
- // in kernel, it must be a mistake
- panic("unexpected trap in kernel.\n");
-
- }
- }
-
- /* *
- * trap - handles or dispatches an exception/interrupt. if and when trap() returns,
- * the code in kern/trap/trapentry.S restores the old CPU state saved in the
- * trapframe and then uses the iret instruction to return from the exception.
- * */
- void
- trap(struct trapframe *tf) {
- // dispatch based on what type of trap occurred
- // used for previous projects
- if (current == NULL) {
- trap_dispatch(tf);
- }
- else {
- // keep a trapframe chain in stack
- struct trapframe *otf = current->tf;
- current->tf = tf;
-
- bool in_kernel = trap_in_kernel(tf);
-
- trap_dispatch(tf);
-
- current->tf = otf;
- if (!in_kernel) {
- if (current->flags & PF_EXITING) {
- do_exit(-E_KILLED);
- }
- if (current->need_resched) {
- schedule();
- }
- }
- }
- }
-
|