void page_fault_handler(struct Trapframe *tf) { uint32_t fault_va; // Read processor's CR2 register to find the faulting address fault_va = rcr2(); // Handle kernel-mode page faults. if(tf->tf_cs && 0x01 == 0) { panic("page_fault in kernel mode, fault address %d\n", fault_va); } // LAB 3: Your code here. // We've already handled kernel-mode exceptions, so if we get here, // the page fault happened in user mode. // Destroy the environment that caused the fault. cprintf("[%08x] user fault va %08x ip %08x\n", curenv->env_id, fault_va, tf->tf_eip); print_trapframe(tf); env_destroy(curenv); }
void syscall(void) { assert(current != NULL); struct trapframe *tf = current->tf; uint32_t arg[5]; int num = tf->tf_regs.reg_r[MIPS_REG_V0]; //num -= T_SYSCALL; //kprintf("$ %d %d\n",current->pid, num); if (num >= 0 && num < NUM_SYSCALLS) { if (syscalls[num] != NULL) { arg[0] = tf->tf_regs.reg_r[MIPS_REG_A0]; arg[1] = tf->tf_regs.reg_r[MIPS_REG_A1]; arg[2] = tf->tf_regs.reg_r[MIPS_REG_A2]; arg[3] = tf->tf_regs.reg_r[MIPS_REG_A3]; arg[4] = tf->tf_regs.reg_r[MIPS_REG_T0]; tf->tf_regs.reg_r[MIPS_REG_V0] = syscalls[num] (arg); return; } } print_trapframe(tf); panic("undefined syscall %d, pid = %d, name = %s.\n", num, current->pid, current->name); }
static void unhandled_trap(struct hw_trapframe *state, const char* name) { static spinlock_t screwup_lock = SPINLOCK_INITIALIZER; spin_lock(&screwup_lock); if(in_kernel(state)) { print_trapframe(state); panic("Unhandled trap in kernel!\nTrap type: %s", name); } else { char tf_buf[1024]; format_trapframe(state, tf_buf, sizeof(tf_buf)); warn("Unhandled trap in user!\nTrap type: %s\n%s", name, tf_buf); backtrace(); spin_unlock(&screwup_lock); assert(current); proc_destroy(current); } }
static void trap_dispatch(struct Trapframe *tf) { // Handle processor exceptions. // LAB 3: Your code here. int32_t ret; switch (tf->tf_trapno){ case T_PGFLT:{ //14 page_fault_handler(tf); return; } case T_BRKPT:{ //3 breakpoint_handler(tf); return; } case T_DEBUG:{ breakpoint_handler(tf); return; } case T_SYSCALL:{ ret = system_call_handler(tf); tf->tf_regs.reg_eax = ret; return; } case IRQ_OFFSET+IRQ_TIMER:{ lapic_eoi(); time_tick(); sched_yield(); return; } case IRQ_OFFSET+IRQ_KBD:{ kbd_intr(); return; } case IRQ_OFFSET+IRQ_SERIAL:{ serial_intr(); return; } case IRQ_OFFSET+IRQ_E1000:{ e1000_trap_handler(); return; } } // Handle spurious interrupts // The hardware sometimes raises these because of noise on the // IRQ line or other reasons. We don't care. if (tf->tf_trapno == IRQ_OFFSET + IRQ_SPURIOUS) { cprintf("Spurious interrupt on irq 7\n"); print_trapframe(tf); return; } // Handle clock interrupts. Don't forget to acknowledge the // interrupt using lapic_eoi() before calling the scheduler! // LAB 4: Your code here. // Add time tick increment to clock interrupts. // Be careful! In multiprocessors, clock interrupts are // triggered on every CPU. // LAB 6: Your code here. // Handle keyboard and serial interrupts. // LAB 5: Your code here. // Unexpected trap: The user process or the kernel has a bug. print_trapframe(tf); if (tf->tf_cs == GD_KT) panic("unhandled trap in kernel"); else { env_destroy(curenv); return; } }
static void trap_dispatch(struct trapframe *tf) { char c; int ret; static int counter = 0; switch (tf->tf_trapno) { case T_PGFLT: //page fault if ((ret = pgfault_handler(tf)) != 0) { print_trapframe(tf); panic("handle pgfault failed. %e\n", ret); } 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 2010011358: 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! */ if (++counter == TICK_NUM){ counter = 0; print_ticks(); } 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: asm volatile( "cli;"); tf->tf_ds = 0x23; tf->tf_es = 0x23; tf->tf_fs = 0x23; tf->tf_gs = 0x23; tf->tf_eflags = tf->tf_eflags | 0x200; tf->tf_eflags = tf->tf_eflags | 0x3000; tf->tf_ss = 0x23; tf->tf_cs = 0x1B; tf->tf_esp = tf->tf_regs.reg_eax; break; case T_SWITCH_TOK: asm volatile( "cli;"); tf->tf_ds = 0x10; tf->tf_es = 0x10; tf->tf_fs = 0x10; tf->tf_gs = 0x10; tf->tf_eflags = tf->tf_eflags | 0x200; tf->tf_eflags = tf->tf_eflags & ~0x3000U | 0x1000U; tf->tf_ss = 0x10; tf->tf_cs = 0x8; break; case IRQ_OFFSET + IRQ_IDE1: case IRQ_OFFSET + IRQ_IDE2: /* do nothing */ break; default: // in kernel, it must be a mistake if ((tf->tf_cs & 3) == 0) { print_trapframe(tf); panic("unexpected trap in kernel.\n"); } } }
void page_fault_handler(struct Trapframe *tf) { u_int fault_va; // Read processor's CR2 register to find the faulting address fault_va = rcr2(); if(!(tf->tf_cs & 0x3)) { // This happens in kernel mode if(page_fault_mode == PFM_NONE) { int i; u_long ebp = tf->tf_ebp; for(i = 0; i < 3; i++) { ebp = backtrace_intrap(ebp); } panic("Aiee, page fault in kernel mode va %08x ip %08x\n", fault_va, tf->tf_eip); } else { Pte *pte; u_long va = fault_va; printf("[%08x] PFM_KILL va %08x ip %08x\n", curenv->env_id, fault_va, tf->tf_eip); printf("curenv->env_pgdir[PDX(va)] = %08x\n", curenv->env_pgdir[PDX(va)]); pte = KADDR(PTE_ADDR(curenv->env_pgdir[PDX(va)])); printf("pte[PTX(va)] = %08x\n", pte[PTX(va)]); page_fault_mode = PFM_NONE; env_destroy(curenv); } return; } if(curenv->env_pgfault_entry) { u_int newsp; struct user_stack_frame *us; if(tf->tf_esp > UXSTACKTOP-BY2PG && tf->tf_esp < UXSTACKTOP) { //Page fault within UXSTACKTOP newsp = tf->tf_esp - 8; // Reserve 2 words for eip and eflags } else { newsp = UXSTACKTOP; } if(newsp < UXSTACKTOP-BY2PG) goto fail; //printf("Trap env[%08x] va %08x ip %08x\n", curenv->env_id, fault_va, tf->tf_eip); //print_trapframe(tf); //printf("newsp = %08x, tf->tf_esp = %08x\n", newsp, tf->tf_esp); us = (struct user_stack_frame *)(newsp - sizeof(struct user_stack_frame)); us->fault_va = fault_va; us->tf_err = tf->tf_err; us->esp = tf->tf_esp; us->eip = tf->tf_eip; us->eflags = tf->tf_eflags; tf->tf_esp = newsp; tf->tf_eip = curenv->env_pgfault_entry; return; } fail: // User-mode exception - destroy the environment. printf("[%08x] user fault va %08x ip %08x\n", curenv->env_id, fault_va, tf->tf_eip); print_trapframe(tf); env_destroy(curenv); }
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 2011010312 : 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 2011010312 */ /* 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 */ ticks++; if(ticks == TICK_NUM) { ticks = 0; current->need_resched = 1; } 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"); } }
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 ++; 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 : 13307130148 you should modify below codes. case T_SWITCH_TOU: cprintf("To user mode\n"); if (tf->tf_cs != USER_CS) { tfk2u = *tf; tfk2u.tf_cs = USER_CS; tfk2u.tf_ds = tfk2u.tf_es = tfk2u.tf_ss = USER_DS; tfk2u.tf_esp = (uint32_t)tf + sizeof(struct trapframe) - 8; tfk2u.tf_eflags |= (3 << 12); *((uint32_t *)tf - 1) = (uint32_t)&tfk2u; } break; case T_SWITCH_TOK: cprintf("To kernel mode\n"); //panic("T_SWITCH_** ??\n"); struct trapframe *tfu2k; if (tf->tf_cs != KERNEL_CS) { tf->tf_cs = KERNEL_CS; tf->tf_ds = tf->tf_es = KERNEL_DS; tf->tf_eflags &= ~(3 << 12); tfu2k = (struct trapframe*)((uint32_t)tf->tf_esp - sizeof(struct trapframe) + 8); memmove(tfu2k, tf, sizeof(struct trapframe)-8); *((uint32_t *)tf - 1) = (uint32_t)tfu2k; } 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"); } }
static void trap_dispatch(struct Trapframe *tf) { // Handle processor exceptions. // LAB 3: Your code here. if (tf->tf_trapno == T_BRKPT) { print_trapframe(tf); // cprintf("Breakpoint!\n"); while (1) monitor(NULL); } else if (tf->tf_trapno == T_PGFLT) { page_fault_handler(tf); return; } else if (tf->tf_trapno == T_SYSCALL) { uint32_t syscallno; uint32_t a1, a2, a3, a4, a5; syscallno = tf->tf_regs.reg_eax; a1 = tf->tf_regs.reg_edx; a2 = tf->tf_regs.reg_ecx; a3 = tf->tf_regs.reg_ebx; a4 = tf->tf_regs.reg_edi; a5 = tf->tf_regs.reg_esi; int32_t ret = syscall(syscallno, a1, a2, a3, a4, a5); tf->tf_regs.reg_eax = ret; return; } // Handle spurious interrupts // The hardware sometimes raises these because of noise on the // IRQ line or other reasons. We don't care. if (tf->tf_trapno == IRQ_OFFSET + IRQ_SPURIOUS) { cprintf("Spurious interrupt on irq 7\n"); print_trapframe(tf); return; } // Handle clock interrupts. Don't forget to acknowledge the // interrupt using lapic_eoi() before calling the scheduler! // LAB 4: Your code here. if (tf->tf_trapno == IRQ_OFFSET + IRQ_TIMER) { time_tick(); lapic_eoi(); /* what's that? */ sched_yield(); } // Handle keyboard and serial interrupts. // LAB 5: Your code here. if (tf->tf_trapno == IRQ_OFFSET + IRQ_KBD) { kbd_intr(); return; } if (tf->tf_trapno == IRQ_OFFSET + IRQ_SERIAL) { serial_intr(); return; } // Unexpected trap: The user process or the kernel has a bug. print_trapframe(tf); if (tf->tf_cs == GD_KT) panic("unhandled trap in kernel"); else { env_destroy(curenv); return; } }
static void trap_dispatch(struct trapframe *tf) { char c; int ret; switch (tf->tf_trapno) { case T_PGFLT: //page fault if ((ret = pgfault_handler(tf)) != 0) { print_trapframe(tf); panic("handle pgfault failed. %e\n", ret); } 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! */ ticks ++; if (ticks % TICK_NUM == 0) print_ticks(); 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); if (c == '0') { user2kernel(tf); } if (c == '3') { kernel2user(tf); } print_trapframe(tf); break; //LAB1 CHALLENGE 1 : YOUR CODE you should modify below codes. case T_SWITCH_TOU: kernel2user(tf); /* if (tf->tf_cs != USER_CS) { switchk2u = *tf; switchk2u.tf_cs = USER_CS; switchk2u.tf_ds = switchk2u.tf_es = switchk2u.tf_ss = USER_DS; switchk2u.tf_esp = (uint32_t)tf + sizeof(struct trapframe)-8; switchk2u.tf_eflags |= FL_IOPL_MASK; *((uint32_t *)tf -1) = (uint32_t)&switchk2u; }*/ break; case T_SWITCH_TOK: //panic("T_SWITCH_** ??\n"); user2kernel(tf); /* if (tf->tf_cs != KERNEL_CS) { tf->tf_cs = KERNEL_CS; tf->tf_ds = tf->tf_es = KERNEL_DS; tf->tf_eflags &= ~FL_IOPL_MASK; switchu2k = (struct trapframe *)(tf->tf_esp - (sizeof(struct trapframe)-8)); memmove(switchu2k, tf, sizeof(struct trapframe)-8); *((uint32_t*)tf-1) = (uint32_t)switchu2k; }*/ break; case IRQ_OFFSET + IRQ_IDE1: case IRQ_OFFSET + IRQ_IDE2: /* do nothing */ break; default: // in kernel, it must be a mistake if ((tf->tf_cs & 3) == 0) { print_trapframe(tf); panic("unexpected trap in kernel.\n"); } } }
void page_fault_handler(struct Trapframe *tf) { uint32_t fault_va; // Read processor's CR2 register to find the faulting address fault_va = rcr2(); // Handle kernel-mode page faults. // LAB 3: Your code here. if (tf->tf_cs == GD_KT) { print_trapframe(tf); panic("kernel page fault va %08x ip %08x env %x\n", fault_va, tf->tf_eip, curenv->env_id); } // We've already handled kernel-mode exceptions, so if we get here, // the page fault happened in user mode. // Call the environment's page fault upcall, if one exists. Set up a // page fault stack frame on the user exception stack (below // UXSTACKTOP), then branch to curenv->env_pgfault_upcall. // // The page fault upcall might cause another page fault, in which case // we branch to the page fault upcall recursively, pushing another // page fault stack frame on top of the user exception stack. // // The trap handler needs one word of scratch space at the top of the // trap-time stack in order to return. In the non-recursive case, we // don't have to worry about this because the top of the regular user // stack is free. In the recursive case, this means we have to leave // an extra word between the current top of the exception stack and // the new stack frame because the exception stack _is_ the trap-time // stack. // // If there's no page fault upcall, the environment didn't allocate a // page for its exception stack or can't write to it, or the exception // stack overflows, then destroy the environment that caused the fault. // Note that the grade script assumes you will first check for the page // fault upcall and print the "user fault va" message below if there is // none. The remaining three checks can be combined into a single test. // // Hints: // user_mem_assert() and env_run() are useful here. // To change what the user environment runs, modify 'curenv->env_tf' // (the 'tf' variable points at 'curenv->env_tf'). // LAB 4: Your code here. if (!curenv->env_pgfault_upcall) { goto destroy; } // Check that exception stack is allocated user_mem_assert(curenv, (void *)(UXSTACKTOP - 4), 4, 0); uintptr_t exstack; struct UTrapframe *utf; // Figure out top where trapframe should end, leaving 1 word scratch space if (tf->tf_esp >= UXSTACKTOP-PGSIZE && tf->tf_esp <= UXSTACKTOP-1) { exstack = tf->tf_esp - 4; // recursive } else { exstack = UXSTACKTOP; // non-recursive } // Check if enough space to copy trapframe if ((exstack - sizeof(struct UTrapframe)) < UXSTACKTOP-PGSIZE) { goto destroy; } // Set up UTrapframe on exception stack utf = (struct UTrapframe *) (exstack - sizeof(struct UTrapframe)); utf->utf_fault_va = fault_va; utf->utf_err = tf->tf_err; utf->utf_regs = tf->tf_regs; utf->utf_eip = tf->tf_eip; utf->utf_eflags = tf->tf_eflags; utf->utf_esp = tf->tf_esp; // Fix trapframe to return to user handler tf->tf_esp = (uintptr_t) utf; tf->tf_eip = (uintptr_t) curenv->env_pgfault_upcall; env_run(curenv); panic("Unreachable code!\n"); destroy: // Destroy the environment that caused the fault. cprintf("[%08x] user fault va %08x ip %08x\n", curenv->env_id, fault_va, tf->tf_eip); print_trapframe(tf); env_destroy(curenv); }
static void trap_dispatch(struct Trapframe *tf) { // Handle processor exceptions. // LAB 3: Your code here. switch(tf->tf_trapno) { case T_PGFLT: page_fault_handler(tf); return; case T_BRKPT: case T_DEBUG: monitor(tf); return; case T_SYSCALL: tf->tf_regs.reg_eax = syscall(tf->tf_regs.reg_eax, // syscall # tf->tf_regs.reg_edx, // arg1 tf->tf_regs.reg_ecx, // arg2 tf->tf_regs.reg_ebx, // arg3 tf->tf_regs.reg_edi, // arg4 tf->tf_regs.reg_esi);// arg5 return; } // Handle spurious interrupts // The hardware sometimes raises these because of noise on the // IRQ line or other reasons. We don't care. if (tf->tf_trapno == IRQ_OFFSET + IRQ_SPURIOUS) { cprintf("Spurious interrupt on irq 7\n"); print_trapframe(tf); return; } // Handle clock interrupts. Don't forget to acknowledge the // interrupt using lapic_eoi() before calling the scheduler! // Add time tick increment to clock interrupts. // Be careful! In multiprocessors, clock interrupts are // triggered on every CPU. // LAB 4: Your code here. // LAB 6: Your code here. if (tf->tf_trapno == IRQ_OFFSET + IRQ_TIMER) { time_tick(); lapic_eoi(); sched_yield(); return; } // Handle keyboard and serial interrupts. // LAB 7: Your code here. if (tf->tf_trapno == IRQ_OFFSET + IRQ_SERIAL) { serial_intr(); return; } if (tf->tf_trapno == IRQ_OFFSET + IRQ_KBD) { kbd_intr(); return; } // Unexpected trap: The user process or the kernel has a bug. print_trapframe(tf); if (tf->tf_cs == GD_KT) panic("unhandled trap in kernel"); else { env_destroy(curenv); return; } }
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 2014011421 */ /* 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 2014011421 */ /* you should upate you lab5 code * IMPORTANT FUNCTIONS: * sched_class_proc_tick */ /* LAB7 2014011421 */ /* you should upate you lab6 code * IMPORTANT FUNCTIONS: * run_timer_list */ ticks++; 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: // There are user level shell in LAB8, so we need change COM/KBD interrupt processing. c = cons_getc(); { extern void dev_stdin_write(char c); dev_stdin_write(c); } break; //LAB1 CHALLENGE 1 : YOUR CODE you should modify below codes. case T_SWITCH_TOU: if (tf->tf_cs != USER_CS) { switchk2u = *tf; switchk2u.tf_cs = USER_CS; switchk2u.tf_ds = switchk2u.tf_es = switchk2u.tf_ss = USER_DS; switchk2u.tf_esp = (uint32_t)tf + sizeof(struct trapframe) - 8; // set eflags, make sure ucore can use io under user mode. // if CPL > IOPL, then cpu will generate a general protection. switchk2u.tf_eflags |= FL_IOPL_MASK; // set temporary stack // then iret will jump to the right stack *((uint32_t *)tf - 1) = (uint32_t)&switchk2u; } break; case T_SWITCH_TOK: if (tf->tf_cs != KERNEL_CS) { tf->tf_cs = KERNEL_CS; tf->tf_ds = tf->tf_es = KERNEL_DS; tf->tf_eflags &= ~FL_IOPL_MASK; switchu2k = (struct trapframe *)(tf->tf_esp - (sizeof(struct trapframe) - 8)); memmove(switchu2k, tf, sizeof(struct trapframe) - 8); *((uint32_t *)tf - 1) = (uint32_t)switchu2k; } 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"); } }
static void trap_dispatch(struct trapframe *tf) { char c; switch (tf->tf_trapno) { case IRQ_OFFSET + IRQ_TIMER: /* 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! */ ticks++; if (ticks >= TICK_NUM) { print_ticks(); ticks = 0; } 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: if (tf->tf_cs != USER_CS) { k2u = *tf; k2u.tf_cs = USER_CS; k2u.tf_ds = k2u.tf_es = k2u.tf_ss = USER_DS; k2u.tf_esp = (uint32_t)tf + sizeof(struct trapframe) - 8; k2u.tf_eflags |= FL_IOPL_MASK; *((uint32_t *)tf - 1) = (uint32_t)&k2u; } break; case T_SWITCH_TOK: if (tf->tf_cs != KERNEL_CS) { tf->tf_cs = KERNEL_CS; tf->tf_ds = tf->tf_es = KERNEL_DS; tf->tf_eflags = tf->tf_eflags & ~FL_IOPL_MASK; u2k = *((struct trapframe*)(tf->tf_esp - (sizeof(struct trapframe) - 8))); memmove(&u2k, tf, sizeof(struct trapframe) - 8); *((uint32_t *)tf - 1) = (uint32_t)&u2k; } //panic("T_SWITCH_** ??\n"); break; case IRQ_OFFSET + IRQ_IDE1: case IRQ_OFFSET + IRQ_IDE2: /* do nothing */ break; default: // in kernel, it must be a mistake if ((tf->tf_cs & 3) == 0) { print_trapframe(tf); panic("unexpected trap in kernel.\n"); } } }
static void trap_dispatch(struct Trapframe *tf) { // Handle processor exceptions. // LAB 3: Your code here. //---------------------------------------- Lab3 ------------------------------------------------------------ if (tf->tf_trapno == T_PGFLT) { //cprintf("pagefault!\n"); page_fault_handler(tf); return; } if (tf->tf_trapno == T_BRKPT) { //cprintf("brkpt!\n"); monitor(tf); return; } if (tf->tf_trapno == T_DEBUG) { my_monitor(tf); return; } if (tf->tf_trapno == T_SYSCALL) { //cprintf("Syscall!\n"); tf->tf_regs.reg_eax = syscall(tf->tf_regs.reg_eax, tf->tf_regs.reg_edx, tf->tf_regs.reg_ecx, tf->tf_regs.reg_ebx, tf->tf_regs.reg_edi, tf->tf_regs.reg_esi); if (tf->tf_regs.reg_eax < 0) panic("syscall failed: %e\n", tf->tf_regs.reg_eax); return; } //---------------------------------------- Lab3 ------------------------------------------------------------ // Handle spurious interrupts // The hardware sometimes raises these because of noise on the // IRQ line or other reasons. We don't care. if (tf->tf_trapno == IRQ_OFFSET + IRQ_SPURIOUS) { cprintf("Spurious interrupt on irq 7\n"); print_trapframe(tf); return; } // Handle clock interrupts. Don't forget to acknowledge the // interrupt using lapic_eoi() before calling the scheduler! // LAB 4: Your code here. //------------ Lab4 ---------------------------------------------------------------------------------------- if (tf->tf_trapno == IRQ_OFFSET + IRQ_TIMER) { // cprintf("clock interrupt!\n"); lapic_eoi(); sched_yield(); return; } //------------ Lab4 ---------------------------------------------------------------------------------------- // Unexpected trap: The user process or the kernel has a bug. print_trapframe(tf); if (tf->tf_cs == GD_KT) panic("unhandled trap in kernel"); else { env_destroy(curenv); return; } }
void page_fault_handler(struct Trapframe *tf) { uint32_t fault_va; // Read processor's CR2 register to find the faulting address fault_va = rcr2(); // Handle kernel-mode page faults. // LAB 3: Your code here. //cprintf("SUNUS : tf eip = %08x\n",tf->tf_eip); //sunus_dbg(0,3,page_fault_handler); if((tf->tf_cs & 0x3) != 0x3) panic("page_fault_handler @ %08x\n",fault_va); // We've already handled kernel-mode exceptions, so if we get here, // the page fault happened in user mode. // Call the environment's page fault upcall, if one exists. Set up a // page fault stack frame on the user exception stack (below // UXSTACKTOP), then branch to curenv->env_pgfault_upcall. // // The page fault upcall might cause another page fault, in which case // we branch to the page fault upcall recursively, pushing another // page fault stack frame on top of the user exception stack. // // The trap handler needs one word of scratch space at the top of the // trap-time stack in order to return. In the non-recursive case, we // don't have to worry about this because the top of the regular user // stack is free. In the recursive case, this means we have to leave // an extra word between the current top of the exception stack and // the new stack frame because the exception stack _is_ the trap-time // stack. // // If there's no page fault upcall, the environment didn't allocate a // page for its exception stack or can't write to it, or the exception // stack overflows, then destroy the environment that caused the fault. // Note that the grade script assumes you will first check for the page // fault upcall and print the "user fault va" message below if there is // none. The remaining three checks can be combined into a single test. // // Hints: // user_mem_assert() and env_run() are useful here. // To change what the user environment runs, modify 'curenv->env_tf' // (the 'tf' variable points at 'curenv->env_tf'). // LAB 4: Your code here. // JAN,10,SUNUS if(curenv->env_pgfault_upcall) { struct UTrapframe utf; utf.utf_fault_va =fault_va; utf.utf_err = tf->tf_err; utf.utf_regs = tf->tf_regs; utf.utf_eip = tf->tf_eip; utf.utf_eip = tf->tf_eip; utf.utf_eflags = tf->tf_eflags; utf.utf_esp = tf->tf_esp; if(tf->tf_esp >= (UXSTACKTOP - PGSIZE) && tf->tf_esp <= UXSTACKTOP) /* check if it's in another PGFLT */ { //LINE 277-279 tf->tf_esp -= 4; user_mem_assert(curenv, (const void *)(tf->tf_esp - sizeof(utf) - 4), sizeof(utf), PTE_W|PTE_U);// -4 is the extra 32bit } else { tf->tf_esp = UXSTACKTOP; user_mem_assert(curenv, (const void *)(tf->tf_esp - sizeof(utf)), sizeof(utf), PTE_W|PTE_U); } tf->tf_esp -= sizeof(utf); if(tf->tf_esp < (UXSTACKTOP - PGSIZE)) { cprintf("tf->tf_esp < UXSTACKTOP - PGSIZE!\n"); env_destroy(curenv); return; } memmove((void *)(tf->tf_esp), &utf, sizeof(struct UTrapframe)); tf->tf_eip = (uintptr_t)curenv->env_pgfault_upcall; env_run(curenv); } // Destroy the environment that caused the fault. cprintf("[%08x] user fault va %08x ip %08x\n",curenv->env_id, fault_va, tf->tf_eip); print_trapframe(tf); env_destroy(curenv); }
static void trap_dispatch(struct Trapframe *tf) { // Handle processor exceptions. // LAB 3: Your code here. // dec 15,2010 sunus switch(tf->tf_trapno) { case T_PGFLT : { page_fault_handler(tf); break; } case T_DEBUG : cprintf("encounter a breakpoint!\n"); /*fall through*/ case T_BRKPT : { monitor(tf); break; } case T_SYSCALL : { (tf->tf_regs).reg_eax = syscall( (tf->tf_regs).reg_eax, (tf->tf_regs).reg_edx, (tf->tf_regs).reg_ecx, (tf->tf_regs).reg_ebx, (tf->tf_regs).reg_edi, (tf->tf_regs).reg_esi); return ; } default : ; /* do nothing */ } // Handle clock interrupts. // LAB 4: Your code here. // JAN 30,2011,SUNUS if(tf->tf_trapno == IRQ_OFFSET + IRQ_TIMER) { sched_yield(); return; } // Handle spurious interrupts // The hardware sometimes raises these because of noise on the // IRQ line or other reasons. We don't care. if (tf->tf_trapno == IRQ_OFFSET + IRQ_SPURIOUS) { cprintf("Spurious interrupt on irq 7\n"); print_trapframe(tf); return; } // Unexpected trap: The user process or the kernel has a bug. print_trapframe(tf); if (tf->tf_cs == GD_KT) panic("unhandled trap in kernel"); else { env_destroy(curenv); return; } }
static void trap_dispatch(struct Trapframe *tf) { static int page_to_age = 0; int page_to_age_first = page_to_age; int num_page_updates = NPAGEUPDATES_FACTOR*NPAGESFREE_LOW_THRESHOLD; struct PteChain *pp_refs_chain; char page_accessed; // Handle processor exceptions. // LAB 3: Your code here. if (tf->tf_trapno == T_PGFLT) { page_fault_handler(tf); return; } else if (tf->tf_trapno == T_BRKPT) { monitor(tf); // breakpoint exceptions invoke the kernel monitor return; } else if (tf->tf_trapno == T_SYSCALL) { tf->tf_regs.reg_eax = syscall(tf->tf_regs.reg_eax, tf->tf_regs.reg_edx, tf->tf_regs.reg_ecx, tf->tf_regs.reg_ebx, tf->tf_regs.reg_edi, tf->tf_regs.reg_esi); return; } // Handle spurious interrupts // The hardware sometimes raises these because of noise on the // IRQ line or other reasons. We don't care. if (tf->tf_trapno == IRQ_OFFSET + IRQ_SPURIOUS) { cprintf("Spurious interrupt on irq 7\n"); print_trapframe(tf); return; } // Handle clock interrupts. Don't forget to acknowledge the // interrupt using lapic_eoi() before calling the scheduler! // LAB 4: Your code here. if (tf->tf_trapno == IRQ_OFFSET + IRQ_TIMER) { lapic_eoi(); // Update the age of some physical pages // If we fall below the thresholds, update more pages than usual // This is somewhat arbitrary, we can tweak these numbers // We also might want to increase the order of magnitude of the number of pages we update per clock tick // This will require some testing and profiling // There is also no reason why num_page_updates is based on the threshold values, it can be incremented by its own macros if (num_free_pages <= NPAGESFREE_LOW_THRESHOLD) { num_page_updates += NPAGEUPDATES_FACTOR*NPAGESFREE_HIGH_THRESHOLD; } if (num_free_pages <= NPAGESFREE_HIGH_THRESHOLD) { num_page_updates += NPAGEUPDATES_FACTOR*NPAGESFREE_LOW_THRESHOLD; } for ( ; num_page_updates >= 0; --num_page_updates) { // Find the next page that is currently mapped in user space, by finding one with a nonzero pp_ref while (!pages[page_to_age].pp_ref) { // If we wrap around to where we started, stop updating page ages if ((page_to_age=(page_to_age+1)%npages) == page_to_age_first) { goto end_of_page_age_updates; } } // Iterate through all of the user space PTEs that map to this page // If any of them have been accessed, increment the age, and then clear the PTE_A bit in all of the PTEs page_accessed = 0; for (pp_refs_chain = pages[page_to_age].pp_refs_chain; pp_refs_chain; pp_refs_chain = pp_refs_chain->pc_link) { if (*pp_refs_chain->pc_pte & PTE_A) { page_accessed = 1; pages[page_to_age].age += PAGE_AGE_INCREMENT_ON_ACCESS; for ( ; pp_refs_chain; pp_refs_chain = pp_refs_chain->pc_link) { *(pp_refs_chain->pc_pte) &= ~PTE_A; } break; } } pages[page_to_age].age = (pages[page_to_age].age > MAX_PAGE_AGE ? MAX_PAGE_AGE : pages[page_to_age].age); if (!page_accessed) { if (pages[page_to_age].age >= (uint8_t)PAGE_AGE_DECREMENT_ON_CLOCK) { pages[page_to_age].age -= (uint8_t)PAGE_AGE_DECREMENT_ON_CLOCK; } else { pages[page_to_age].age = 0; } } // If we wrap around to where we started, stop updating page ages if ((page_to_age=(page_to_age+1)%npages) == page_to_age_first) { goto end_of_page_age_updates; } } end_of_page_age_updates: sched_yield(); } // Handle keyboard and serial interrupts. // LAB 5: Your code here. if (tf->tf_trapno == IRQ_OFFSET + IRQ_KBD) { lapic_eoi(); kbd_intr(); return; } if (tf->tf_trapno == IRQ_OFFSET + IRQ_SERIAL) { lapic_eoi(); serial_intr(); return; } // Unexpected trap: The user process or the kernel has a bug. print_trapframe(tf); if (tf->tf_cs == GD_KT) panic("unhandled trap in kernel"); else { env_destroy(curenv); return; } }
void page_fault_handler(struct Trapframe *tf) { uint32_t fault_va; struct PageInfo *pp = NULL; // Read processor's CR2 register to find the faulting address fault_va = rcr2(); // Handle kernel-mode page faults. // LAB 3: Your code here. if ((tf->tf_cs & 3) == 0) { panic("page_fault_handler: kernel-mode page fault"); } // We've already handled kernel-mode exceptions, so if we get here, // the page fault happened in user mode. // Call the environment's page fault upcall, if one exists. Set up a // page fault stack frame on the user exception stack (below // UXSTACKTOP), then branch to curenv->env_pgfault_upcall. // // The page fault upcall might cause another page fault, in which case // we branch to the page fault upcall recursively, pushing another // page fault stack frame on top of the user exception stack. // // The trap handler needs one word of scratch space at the top of the // trap-time stack in order to return. In the non-recursive case, we // don't have to worry about this because the top of the regular user // stack is free. In the recursive case, this means we have to leave // an extra word between the current top of the exception stack and // the new stack frame because the exception stack _is_ the trap-time // stack. // // If there's no page fault upcall, the environment didn't allocate a // page for its exception stack or can't write to it, or the exception // stack overflows, then destroy the environment that caused the fault. // Note that the grade script assumes you will first check for the page // fault upcall and print the "user fault va" message below if there is // none. The remaining three checks can be combined into a single test. // // Hints: // user_mem_assert() and env_run() are useful here. // To change what the user environment runs, modify 'curenv->env_tf' // (the 'tf' variable points at 'curenv->env_tf'). // LAB 4: Your code here. // utf is a pointer to the UTrapframe in the user exception stack. // If this is the first fault, then the pointer is right below UXSTACKTOP. // Otherwise, the pointer is right below tf->tf_esp, with a 32-bit word offset. // If UXSTACKTOP-PGSIZE <= tf->tf_esp <= UXSTACKTOP-1, then it is a recursive trap, the latter case. struct UTrapframe *utf = (struct UTrapframe *)( (((UXSTACKTOP-PGSIZE)<=(tf->tf_esp))&&((tf->tf_esp)<=(UXSTACKTOP-1))) ? ((tf->tf_esp)-(sizeof(struct UTrapframe)+sizeof(uint32_t))) : (UXSTACKTOP-sizeof(struct UTrapframe)) ); if (!(curenv->env_pgfault_upcall)) { // Destroy the environment that caused the fault. cprintf("[%08x] user fault va %08x ip %08x\n", curenv->env_id, fault_va, tf->tf_eip); print_trapframe(tf); env_destroy(curenv); } // If the environment didn't allocate a // page for its exception stack or can't write to it, or the exception // stack overflows, then destroy the environment that caused the fault. // We can do this with user_mem_assert on the portion of the stack where *utf is stored. // This obviously covers the first two cases. // It also takes care of the third case because the region below UXSTACKTOP-PGSIZE is unmapped. user_mem_assert(curenv, (void *)utf, sizeof(struct UTrapframe), PTE_W|PTE_U|PTE_P); utf->utf_fault_va = fault_va; // Copy values from the Trapframe to the UTrapframe. utf->utf_err = tf->tf_err; utf->utf_regs = tf->tf_regs; utf->utf_eip = tf->tf_eip; utf->utf_eflags = tf->tf_eflags; utf->utf_esp = tf->tf_esp; // Set the Trapframe to return to env_pgfault_upcall, with an exception stack at utf. // NOTE I am not confident that this code is correct. // TODO Test that this is correct, and correct it if necessary. tf->tf_eip = (uintptr_t)curenv->env_pgfault_upcall; tf->tf_esp = (uintptr_t)utf; }
/* trap_dispatch - dispatch based on what type of trap occurred */ static void trap_dispatch(struct trapframe *tf) { char c; switch (tf->tf_trapno) { case IRQ_OFFSET + IRQ_TIMER: /* 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! */ ticks++; if ((ticks % TICK_NUM) == 0){ print_ticks(); } 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: asm volatile( "cli;"); tf->tf_ds = USER_DS; tf->tf_es = USER_DS; tf->tf_fs = USER_DS; tf->tf_gs = USER_DS; tf->tf_eflags = tf->tf_eflags | 0x200; tf->tf_eflags = tf->tf_eflags | 0x3000; tf->tf_ss = USER_DS; tf->tf_cs = USER_CS; tf->tf_esp = tf->tf_regs.reg_eax; break; case T_SWITCH_TOK: // panic("T_SWITCH_** ??\n"); asm volatile( "cli;"); tf->tf_ds = KERNEL_DS; tf->tf_es = KERNEL_DS; tf->tf_fs = KERNEL_DS; tf->tf_gs = KERNEL_DS; tf->tf_eflags = tf->tf_eflags | 0x200; tf->tf_eflags = tf->tf_eflags & ~0x3000U | 0x1000U; tf->tf_ss = KERNEL_DS; tf->tf_cs = KERNEL_CS; tf->tf_esp = tf->tf_regs.reg_eax; cprintf("%08x\n",tf->tf_esp); break; case IRQ_OFFSET + IRQ_IDE1: case IRQ_OFFSET + IRQ_IDE2: /* do nothing */ break; default: // in kernel, it must be a mistake if ((tf->tf_cs & 3) == 0) { print_trapframe(tf); panic("unexpected trap in kernel.\n"); } } }
static void trap_dispatch(struct Trapframe *tf) { int32_t res; // Handle processor exceptions. // LAB 3: Your code here. // Handle spurious interrupts // The hardware sometimes raises these because of noise on the // IRQ line or other reasons. We don't care. if (tf->tf_trapno == IRQ_OFFSET + IRQ_SPURIOUS) { cprintf("Spurious interrupt on irq 7\n"); print_trapframe(tf); return; } // Handle clock interrupts. Don't forget to acknowledge the // interrupt using lapic_eoi() before calling the scheduler! // LAB 4: Your code here. // Add time tick increment to clock interrupts. // Be careful! In multiprocessors, clock interrupts are // triggered on every CPU. // LAB 6: Your code here. // Handle keyboard and serial interrupts. // LAB 5: Your code here. //if(tf->tf_trapno == 48 && tf->tf_regs.reg_eax==7) //{ //cprintf("trap no = %d at cpu %d env %x\n",tf->tf_trapno,cpunum(),curenv->env_id); //print_trapframe(tf); //} switch(tf->tf_trapno) { case IRQ_OFFSET + IRQ_TIMER: //cprintf("clock interrupt on irq 7 on cpu %d\n",cpunum()); //print_trapframe(tf); //cprintf(" eip 0x%08x\n", tf->tf_eip); //cprintf(" esp 0x%08x\n", tf->tf_esp); lapic_eoi(); time_tick(); sched_yield(); break; case IRQ_OFFSET + IRQ_SERIAL: serial_intr(); break; case IRQ_OFFSET + IRQ_KBD: kbd_intr(); break; case T_DIVIDE: tf->tf_regs.reg_ecx = 1; break; case T_PGFLT: page_fault_handler(tf); goto err; case T_SYSCALL: res = syscall(tf->tf_regs.reg_eax,tf->tf_regs.reg_edx,tf->tf_regs.reg_ecx,tf->tf_regs.reg_ebx,tf->tf_regs.reg_edi,tf->tf_regs.reg_esi); tf->tf_regs.reg_eax = res; break; case T_BRKPT:print_trapframe(tf);monitor(NULL);break; default: goto err; } return; err: // Unexpected trap: The user process or the kernel has a bug. print_trapframe(tf); if (tf->tf_cs == GD_KT) panic("unhandled trap in kernel"); else { env_destroy(curenv); return; } }
void page_fault_handler(struct Trapframe *tf) { uint32_t fault_va; // Read processor's CR2 register to find the faulting address fault_va = rcr2(); // Handle kernel-mode page faults. if ((tf->tf_cs & 3) != 3) { panic("Page fault in kernel mode.\n"); } // LAB 3: Your code here. // We've already handled kernel-mode exceptions, so if we get here, // the page fault happened in user mode. // Call the environment's page fault upcall, if one exists. Set up a // page fault stack frame on the user exception stack (below // UXSTACKTOP), then branch to curenv->env_pgfault_upcall. // // The page fault upcall might cause another page fault, in which case // we branch to the page fault upcall recursively, pushing another // page fault stack frame on top of the user exception stack. // // The trap handler needs one word of scratch space at the top of the // trap-time stack in order to return. In the non-recursive case, we // don't have to worry about this because the top of the regular user // stack is free. In the recursive case, this means we have to leave // an extra word between the current top of the exception stack and // the new stack frame because the exception stack _is_ the trap-time // stack. // // If there's no page fault upcall, the environment didn't allocate a // page for its exception stack or can't write to it, or the exception // stack overflows, then destroy the environment that caused the fault. // Note that the grade script assumes you will first check for the page // fault upcall and print the "user fault va" message below if there is // none. The remaining three checks can be combined into a single test. // // Hints: // user_mem_assert() and env_run() are useful here. // To change what the user environment runs, modify 'curenv->env_tf' // (the 'tf' variable points at 'curenv->env_tf'). // LAB 4: Your code here. // Destroy the environment that caused the fault. if (!curenv->env_pgfault_upcall) { cprintf("[%08x] user fault va %08x ip %08x\n", curenv->env_id, fault_va, tf->tf_eip); print_trapframe(tf); env_destroy(curenv); return; } uint32_t* user_stack; if (tf->tf_esp >= UXSTACKTOP - PGSIZE && tf->tf_esp <= UXSTACKTOP - 1) { if (tf->tf_esp - sizeof(struct UTrapframe) < UXSTACKTOP - PGSIZE) { cprintf("Crossing User Stack boundaries.\n"); } tf->tf_esp = tf->tf_esp - 4; lcr3(PADDR(curenv->env_pgdir)); *((uint32_t*)tf->tf_esp) = 0; lcr3(PADDR(kern_pgdir)); user_stack = (uint32_t*)tf->tf_esp; tf->tf_esp = tf->tf_esp + 4; user_stack -= 13; user_mem_assert(curenv, (void*)user_stack, sizeof(struct UTrapframe) + 4, PTE_U | PTE_P); } else { user_stack = (uint32_t*)(UXSTACKTOP); user_stack -= 13; user_mem_assert(curenv, (void*)user_stack, sizeof(struct UTrapframe), PTE_U | PTE_P); } uint32_t user_stack_start = (uint32_t)user_stack; lcr3(PADDR(curenv->env_pgdir)); *((uint32_t*)user_stack) = fault_va; user_stack++; *((uint32_t*)user_stack) = tf->tf_err; user_stack++; *((uint32_t*)user_stack) = tf->tf_regs.reg_edi; user_stack++; *((uint32_t*)user_stack) = tf->tf_regs.reg_esi; user_stack++; *((uint32_t*)user_stack) = tf->tf_regs.reg_ebp; user_stack++; *((uint32_t*)user_stack) = tf->tf_esp; user_stack++; *((uint32_t*)user_stack) = tf->tf_regs.reg_ebx; user_stack++; *((uint32_t*)user_stack) = tf->tf_regs.reg_edx; user_stack++; *((uint32_t*)user_stack) = tf->tf_regs.reg_ecx; user_stack++; *((uint32_t*)user_stack) = tf->tf_regs.reg_eax; user_stack++; *((uint32_t*)user_stack) = tf->tf_eip; user_stack++; *((uint32_t*)user_stack) = tf->tf_eflags; user_stack++; *((uint32_t*)user_stack) = tf->tf_esp; lcr3(PADDR(kern_pgdir)); curenv->env_tf.tf_eip = (uint32_t)(curenv->env_pgfault_upcall); curenv->env_tf.tf_esp = (uint32_t)(user_stack_start); env_run(curenv); }
void page_fault_handler(struct Trapframe *tf) { uint32_t fault_va; // Read processor's CR2 register to find the faulting address fault_va = rcr2(); // Handle kernel-mode page faults. // LAB 3: Your code here. if ((tf->tf_cs & 3) == 0) { panic("kernel-mode page fault!\n"); } // We've already handled kernel-mode exceptions, so if we get here, // the page fault happened in user mode. // Call the environment's page fault upcall, if one exists. Set up a // page fault stack frame on the user exception stack (below // UXSTACKTOP), then branch to curenv->env_pgfault_upcall. // // The page fault upcall might cause another page fault, in which case // we branch to the page fault upcall recursively, pushing another // page fault stack frame on top of the user exception stack. // // The trap handler needs one word of scratch space at the top of the // trap-time stack in order to return. In the non-recursive case, we // don't have to worry about this because the top of the regular user // stack is free. In the recursive case, this means we have to leave // an extra word between the current top of the exception stack and // the new stack frame because the exception stack _is_ the trap-time // stack. // // If there's no page fault upcall, the environment didn't allocate a // page for its exception stack, or the exception stack overflows, // then destroy the environment that caused the fault. // // Hints: // user_mem_assert() and env_run() are useful here. // To change what the user environment runs, modify 'curenv->env_tf' // (the 'tf' variable points at 'curenv->env_tf'). // LAB 4: Your code here. if (curenv->env_pgfault_upcall != NULL){ struct UTrapframe *utf; if (UXSTACKTOP - PGSIZE <= tf->tf_esp && tf->tf_esp < UXSTACKTOP){ utf = (struct UTrapframe *)(tf->tf_esp - sizeof(struct UTrapframe) - 4); } else { utf = (struct UTrapframe *)(UXSTACKTOP - sizeof(struct UTrapframe)); } user_mem_assert(curenv, (void *)utf, sizeof(struct UTrapframe), PTE_U | PTE_W); utf->utf_eflags = tf->tf_eflags; utf->utf_eip = tf->tf_eip; utf->utf_err = tf->tf_err; utf->utf_esp = tf->tf_esp; utf->utf_fault_va = fault_va; utf->utf_regs = tf->tf_regs; curenv->env_tf.tf_eip = (uint32_t)curenv->env_pgfault_upcall; curenv->env_tf.tf_esp = (uint32_t)utf; env_run(curenv); } // Destroy the environment that caused the fault. cprintf("[%08x] user fault va %08x ip %08x\n", curenv->env_id, fault_va, tf->tf_eip); print_trapframe(tf); env_destroy(curenv); }
void page_fault_handler(struct Trapframe *tf) { // Read processor's CR2 register to find the faulting address int ret; uint32_t fault_va = rcr2(); uint8_t * curr_stack; struct UTrapframe curr_frame; // Handle kernel-mode page faults. //deal with softint in which case error is not pushed to stack if(!(tf->tf_cs & 3)) { print_trapframe(tf); panic("page fault occurs in kernel mode\n"); } if(!curenv->env_pgfault_upcall) goto no_page_fault_handler; // We've already handled kernel-mode exceptions, so if we get here, // the page fault happened in user mode. // Call the environment's page fault upcall, if one exists. Set up a // page fault stack frame on the user exception stack (below // UXSTACKTOP), then branch to curenv->env_pgfault_upcall. // The page fault upcall might cause another page fault, in which case // we branch to the page fault upcall recursively, pushing another // page fault stack frame on top of the user exception stack. // Jie's Note : x86 first dec stack pointer and then store the value user_mem_assert(curenv,(void *)(UXSTACKTOP-PGSIZE),PGSIZE,PTE_U|PTE_W|PTE_P); if(tf->tf_esp < USTACKTOP) { curr_stack = (uint8_t *)UXSTACKTOP; } else { curr_stack = (uint8_t *) tf->tf_esp; curr_stack-=sizeof(uint32_t); memset(curr_stack,0,sizeof(uint32_t)); } if((uint32_t)curr_stack <= UXSTACKTOP-PGSIZE+sizeof(struct UTrapframe)+sizeof(uint32_t)) panic("exception stack overflow"); curr_stack-=sizeof(struct UTrapframe); // The trap handler needs one word of scratch space at the top of the // trap-time stack in order to return. In the non-recursive case, we // don't have to worry about this because the top of the regular user // stack is free. In the recursive case, this means we have to leave // an extra word between the current top of the exception stack and // the new stack frame because the exception stack _is_ the trap-time // stack. curr_frame.utf_fault_va = fault_va; curr_frame.utf_err = tf->tf_err; curr_frame.utf_eip = tf->tf_eip; curr_frame.utf_esp = tf->tf_esp; curr_frame.utf_eflags = tf->tf_eflags; memcpy(&(curr_frame.utf_regs),&(tf->tf_regs),sizeof(struct PushRegs)); memcpy(curr_stack,&curr_frame,sizeof(struct UTrapframe)); // If there's no page fault upcall, the environment didn't allocate a // page for its exception stack or can't write to it, or the exception // stack overflows, then destroy the environment that caused the fault. // Note that the grade script assumes you will first check for the page // fault upcall and print the "user fault va" message below if there is // none. The remaining three checks can be combined into a single test. // // Hints: // user_mem_assert() and env_run() are useful here. // To change what the user environment runs, modify 'curenv->env_tf' // (the 'tf' variable points at 'curenv->env_tf'). // LAB 4: Your code here. curenv->env_tf.tf_eip = (uintptr_t)curenv->env_pgfault_upcall; curenv->env_tf.tf_esp = (uintptr_t)curr_stack; env_run(curenv); // Destroy the environment that caused the fault. no_page_fault_handler: cprintf("[%08x] user fault va %08x ip %08x\n", curenv->env_id, fault_va, tf->tf_eip); print_trapframe(tf); env_destroy(curenv); }
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 2013011365 : 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 */ if(++ticks % TICK_NUM == 0) { //print_ticks(); current->need_resched = 1; } 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: if(tf->tf_cs != USER_CS) { user_stack = *tf; user_stack.tf_cs = USER_CS; user_stack.tf_ds = USER_DS; user_stack.tf_ss = USER_DS; user_stack.tf_es = USER_DS; user_stack.tf_esp = (uint32_t)tf + sizeof(struct trapframe) - 8; user_stack.tf_eflags |= FL_IOPL_MASK; *((uint32_t *)tf - 1) = (uint32_t)&user_stack; } break; case T_SWITCH_TOK: if(tf->tf_cs != KERNEL_CS) { tf->tf_cs = KERNEL_CS; tf->tf_ds = KERNEL_DS; tf->tf_es = KERNEL_DS; tf->tf_eflags &= ~FL_IOPL_MASK; struct trapframe* k = (struct trapframe*)(tf->tf_esp - (sizeof(struct trapframe) - 8)); memmove(k, tf, sizeof(struct trapframe) -8); *((uint32_t *)tf - 1) = (uint32_t)k; } 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"); } }
static void trap_dispatch(struct Trapframe *tf) { // Handle processor exceptions. // LAB 3: Your code here. // TODO: chky int r; switch (tf->tf_trapno) { case T_PGFLT: page_fault_handler(tf); break; case T_BRKPT: // TODO: lab3 ex6 challenge monitor(tf); break; case T_SYSCALL: r = syscall(tf->tf_regs.reg_eax, // syscallno tf->tf_regs.reg_edx, // a1 tf->tf_regs.reg_ecx, // a2 tf->tf_regs.reg_ebx, // a3 tf->tf_regs.reg_edi, // a4 tf->tf_regs.reg_esi // a5 ); tf->tf_regs.reg_eax = r; return; default: break; } // Handle spurious interrupts // The hardware sometimes raises these because of noise on the // IRQ line or other reasons. We don't care. if (tf->tf_trapno == IRQ_OFFSET + IRQ_SPURIOUS) { cprintf("Spurious interrupt on irq 7\n"); print_trapframe(tf); return; } // Handle clock interrupts. Don't forget to acknowledge the // interrupt using lapic_eoi() before calling the scheduler! // LAB 4: Your code here. // TODO: chky if (tf->tf_trapno == IRQ_OFFSET + IRQ_TIMER) { lapic_eoi(); sched_yield(); return; } // chky end // Handle keyboard and serial interrupts. // LAB 5: Your code here. // TODO: chky if (tf->tf_trapno == IRQ_OFFSET + IRQ_KBD) { kbd_intr(); return; } if (tf->tf_trapno == IRQ_OFFSET + IRQ_SERIAL) { serial_intr(); return; } // chky end // Unexpected trap: The user process or the kernel has a bug. print_trapframe(tf); if (tf->tf_cs == GD_KT) panic("unhandled trap in kernel"); else { env_destroy(curenv); return; } }
void page_fault_handler(struct Trapframe *tf) { uint32_t fault_va; // Read processor's CR2 register to find the faulting address fault_va = rcr2(); // Handle kernel-mode page faults. // LAB 3: Your code here. if ((tf->tf_cs&3) == 0) panic("Kernel page fault!"); // We've already handled kernel-mode exceptions, so if we get here, // the page fault happened in user mode. // Call the environment's page fault upcall, if one exists. Set up a // page fault stack frame on the user exception stack (below // UXSTACKTOP), then branch to curenv->env_pgfault_upcall. // // The page fault upcall might cause another page fault, in which case // we branch to the page fault upcall recursively, pushing another // page fault stack frame on top of the user exception stack. // // The trap handler needs one word of scratch space at the top of the // trap-time stack in order to return. In the non-recursive case, we // don't have to worry about this because the top of the regular user // stack is free. In the recursive case, this means we have to leave // an extra word between the current top of the exception stack and // the new stack frame because the exception stack _is_ the trap-time // stack. // // If there's no page fault upcall, the environment didn't allocate a // page for its exception stack or can't write to it, or the exception // stack overflows, then destroy the environment that caused the fault. // Note that the grade script assumes you will first check for the page // fault upcall and print the "user fault va" message below if there is // none. The remaining three checks can be combined into a single test. // // Hints: // user_mem_assert() and env_run() are useful here. // To change what the user environment runs, modify 'curenv->env_tf' // (the 'tf' variable points at 'curenv->env_tf'). // LAB 4: Your code here. if( curenv->env_pgfault_upcall ) { //cprintf("in trap.c: page_fault_handler\n"); //the curenv->env_pgfault_upcall is set. struct UTrapframe *utf; uintptr_t utf_addr; //check if the tf->tf_esp is on the exception stack if (UXSTACKTOP-PGSIZE<=tf->tf_esp && tf->tf_esp<=UXSTACKTOP-1) utf_addr = tf->tf_esp - sizeof(struct UTrapframe) - 4; else utf_addr = UXSTACKTOP - sizeof(struct UTrapframe); user_mem_assert(curenv, (void*)utf_addr, 1, PTE_W); utf = (struct UTrapframe *) utf_addr; utf->utf_fault_va = fault_va; utf->utf_err = tf->tf_err; utf->utf_regs = tf->tf_regs; utf->utf_eip = tf->tf_eip; utf->utf_eflags = tf->tf_eflags; utf->utf_esp = tf->tf_esp; // curenv->env_tf.env_tf //set the function running curenv->env_tf.tf_eip = (uintptr_t)curenv->env_pgfault_upcall; curenv->env_tf.tf_esp = utf_addr; env_run(curenv); } // Destroy the environment that caused the fault. cprintf("[%08x] user fault va %08x ip %08x\n", curenv->env_id, fault_va, tf->tf_eip); print_trapframe(tf); env_destroy(curenv); }
/* trap_dispatch - dispatch based on what type of trap occurred */ static void trap_dispatch(struct trapframe *tf) { char c; int ret; //kprintf("Trap [%03d %03d]\n", tf->tf_trapno, tf->tf_trapsubno); switch (tf->tf_trapno) { // Prefetch Abort service routine // Data Abort service routine case T_PABT: case T_DABT: if ((ret = pgfault_handler(tf)) != 0) { print_pgfault(tf); print_trapframe(tf); if (pls_read(current) == NULL) { panic("handle pgfault failed. %e\n", ret); } else { if (trap_in_kernel(tf)) { panic ("handle pgfault failed in kernel mode. %e\n", ret); } killed_by_kernel(); } } break; case T_SWI: syscall(); break; // IRQ Service Routine /* case IRQ_OFFSET + INT_TIMER4: ticks ++; if (ticks % TICK_NUM == 0) { print_ticks(); //print_trapframe(tf); } break; case IRQ_OFFSET + INT_UART0: c = cons_getc(); kprintf("serial [%03d] %c\n", c, c); break; */ // SWI Service Routine #if 0 case T_SWITCH_TOK: // a random System call kprintf("Random system call\n"); print_cur_status(); //print_stackframe(); break; #endif case T_IRQ: __irq_level++; #if 0 if (!trap_in_kernel(tf)) { uint32_t sp; asm volatile ("mov %0, sp":"=r" (sp)); kprintf("### iRQnotK %08x\n", sp); } #endif irq_handler(); __irq_level--; break; #if 0 case T_PANIC: print_cur_status(); //print_stackframe(); break; #endif /* for debugging */ case T_UNDEF: udef_handler(tf); break; default: print_trapframe(tf); if (pls_read(current) != NULL) { kprintf("unhandled trap.\n"); do_exit(-E_KILLED); } panic("unexpected trap in kernel.\n"); }
/* trap_dispatch - dispatch based on what type of trap occurred */ static void trap_dispatch(struct trapframe *tf) { char c; switch (tf->tf_trapno) { case IRQ_OFFSET + IRQ_TIMER: /* LAB1 2012011363 : 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! */ ticks ++; if (ticks % TICK_NUM == 0) { print_ticks(); } 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 : 2012011363 you should modify below codes. case T_SWITCH_TOU: if (tf->tf_cs != USER_CS) { switchk2u = *tf; switchk2u.tf_cs = USER_CS; switchk2u.tf_ds = switchk2u.tf_es = switchk2u.tf_ss = USER_DS; switchk2u.tf_esp = (uint32_t)tf + sizeof(struct trapframe) - 8; // set eflags, make sure ucore can use io under user mode. // if CPL > IOPL, then cpu will generate a general protection. switchk2u.tf_eflags |= FL_IOPL_MASK; // set temporary stack // then iret will jump to the right stack *((uint32_t *)tf - 1) = (uint32_t)&switchk2u; } break; case T_SWITCH_TOK: if (tf->tf_cs != KERNEL_CS) { tf->tf_cs = KERNEL_CS; tf->tf_ds = tf->tf_es = KERNEL_DS; tf->tf_eflags &= ~FL_IOPL_MASK; switchu2k = (struct trapframe *)(tf->tf_esp - (sizeof(struct trapframe) - 8)); memmove(switchu2k, tf, sizeof(struct trapframe) - 8); *((uint32_t *)tf - 1) = (uint32_t)switchu2k; } break; case IRQ_OFFSET + IRQ_IDE1: case IRQ_OFFSET + IRQ_IDE2: /* do nothing */ break; default: // in kernel, it must be a mistake if ((tf->tf_cs & 3) == 0) { print_trapframe(tf); panic("unexpected trap in kernel.\n"); } } }
void page_fault_handler(struct Trapframe *tf) { uint64_t fault_va; uintptr_t stktop; uint64_t arr[20]; // Read processor's CR2 register to find the faulting address fault_va = rcr2(); // Handle kernel-mode page faults. // Ashish if ((tf->tf_cs & 0x03) == 0) panic("ERROR: Page fault occurred in kernel mode : Fault va=%x\n",fault_va); // We've already handled kernel-mode exceptions, so if we get here, // the page fault happened in user mode. // Call the environment's page fault upcall, if one exists. Set up a // page fault stack frame on the user exception stack (below // UXSTACKTOP), then branch to curenv->env_pgfault_upcall. // // The page fault upcall might cause another page fault, in which case // we branch to the page fault upcall recursively, pushing another // page fault stack frame on top of the user exception stack. // // The trap handler needs one word of scratch space at the top of the // trap-time stack in order to return. In the non-recursive case, we // don't have to worry about this because the top of the regular user // stack is free. In the recursive case, this means we have to leave // an extra word between the current top of the exception stack and // the new stack frame because the exception stack _is_ the trap-time // stack. // // // If there's no page fault upcall, the environment didn't allocate a // page for its exception stack or can't write to it, or the exception // stack overflows, then destroy the environment that caused the fault. // Note that the grade script assumes you will first check for the page // fault upcall and print the "user fault va" message below if there is // none. The remaining three checks can be combined into a single test. // // Hints: // user_mem_assert() and env_run() are useful here. // To change what the user environment runs, modify 'curenv->env_tf' // (the 'tf' variable points at 'curenv->env_tf'). // Ashish if (!curenv->env_pgfault_upcall) { // Destroy the environment that caused the fault. cprintf("[%08x] user fault va %08x ip %08x\n", curenv->env_id, fault_va, tf->tf_rip); print_trapframe(tf); env_destroy(curenv); } user_mem_assert(curenv, (void*)UXSTACKTOP-1, 1, PTE_P|PTE_W|PTE_U); if (tf->tf_rsp-sizeof(arr)-8 >= UXSTACKTOP) { cprintf("Exception stack overflow for env:\n", curenv->env_id); print_trapframe(tf); env_destroy(curenv); } //Store the trapframe memcpy(&(curenv->env_tf), tf, sizeof(struct Trapframe)); //Assign stacktop appropriately. In non-recursive case, stack top is UXSTACKTOP-sizeof(UTrapframe) //In recursive case, stack top will point to tf->tf_rsp-sizeof(UTrapframe)-8. Note that 8 is scratch space. if (tf->tf_rsp < UXSTACKTOP && tf->tf_rsp > UXSTACKTOP - PGSIZE) stktop = tf->tf_rsp-sizeof(arr)-8; else stktop = UXSTACKTOP-sizeof(arr); //Prepare reverse-UTrapframe arr[0]=fault_va; arr[1]=tf->tf_err; arr[2]=tf->tf_regs.reg_r15; arr[3]=tf->tf_regs.reg_r14; arr[4]=tf->tf_regs.reg_r13; arr[5]=tf->tf_regs.reg_r12; arr[6]=tf->tf_regs.reg_r11; arr[7]=tf->tf_regs.reg_r10; arr[8]=tf->tf_regs.reg_r9; arr[9]=tf->tf_regs.reg_r8; arr[10]=tf->tf_regs.reg_rsi; arr[11]=tf->tf_regs.reg_rdi; arr[12]=tf->tf_regs.reg_rbp; arr[13]=tf->tf_regs.reg_rdx; arr[14]=tf->tf_regs.reg_rcx; arr[15]=tf->tf_regs.reg_rbx; arr[16]=tf->tf_regs.reg_rax; arr[17]=tf->tf_rip; arr[18]=tf->tf_eflags; arr[19]=tf->tf_rsp; //Copy these values on the stack. memcpy((void*)(stktop), (void*)arr, sizeof(arr)); tf->tf_rsp = stktop; //Force the env to execute _pgfault_upcall from pgfault.S curenv->env_tf.tf_rip = (uintptr_t)curenv->env_pgfault_upcall; env_run(curenv); }