void show_regs(struct pt_regs * regs) { unsigned long cr0 = 0L, cr2 = 0L, cr3 = 0L, cr4 = 0L; printk("\n"); printk("Pid: %d, comm: %20s\n", current->pid, current->comm); printk("EIP: %04x:[<%08lx>] CPU: %d\n",0xffff & regs->xcs,regs->eip, smp_processor_id()); print_symbol("EIP is at %s\n", regs->eip); if (user_mode_vm(regs)) printk(" ESP: %04x:%08lx",0xffff & regs->xss,regs->esp); printk(" EFLAGS: %08lx %s (%s %.*s)\n", regs->eflags, print_tainted(), system_utsname.release, (int)strcspn(system_utsname.version, " "), system_utsname.version); printk("EAX: %08lx EBX: %08lx ECX: %08lx EDX: %08lx\n", regs->eax,regs->ebx,regs->ecx,regs->edx); printk("ESI: %08lx EDI: %08lx EBP: %08lx", regs->esi, regs->edi, regs->ebp); printk(" DS: %04x ES: %04x\n", 0xffff & regs->xds,0xffff & regs->xes); cr0 = read_cr0(); cr2 = read_cr2(); cr3 = read_cr3(); cr4 = read_cr4_safe(); printk("CR0: %08lx CR2: %08lx CR3: %08lx CR4: %08lx\n", cr0, cr2, cr3, cr4); show_trace(NULL, regs, ®s->esp); }
/*H:040 * This is the i386-specific code to setup and run the Guest. Interrupts * are disabled: we own the CPU. */ void lguest_arch_run_guest(struct lg_cpu *cpu) { /* * Remember the awfully-named TS bit? If the Guest has asked to set it * we set it now, so we can trap and pass that trap to the Guest if it * uses the FPU. */ if (cpu->ts && user_has_fpu()) stts(); /* * SYSENTER is an optimized way of doing system calls. We can't allow * it because it always jumps to privilege level 0. A normal Guest * won't try it because we don't advertise it in CPUID, but a malicious * Guest (or malicious Guest userspace program) could, so we tell the * CPU to disable it before running the Guest. */ if (boot_cpu_has(X86_FEATURE_SEP)) wrmsr(MSR_IA32_SYSENTER_CS, 0, 0); /* * Now we actually run the Guest. It will return when something * interesting happens, and we can examine its registers to see what it * was doing. */ run_guest_once(cpu, lguest_pages(raw_smp_processor_id())); /* * Note that the "regs" structure contains two extra entries which are * not really registers: a trap number which says what interrupt or * trap made the switcher code come back, and an error code which some * traps set. */ /* Restore SYSENTER if it's supposed to be on. */ if (boot_cpu_has(X86_FEATURE_SEP)) wrmsr(MSR_IA32_SYSENTER_CS, __KERNEL_CS, 0); /* Clear the host TS bit if it was set above. */ if (cpu->ts && user_has_fpu()) clts(); /* * If the Guest page faulted, then the cr2 register will tell us the * bad virtual address. We have to grab this now, because once we * re-enable interrupts an interrupt could fault and thus overwrite * cr2, or we could even move off to a different CPU. */ if (cpu->regs->trapnum == 14) cpu->arch.last_pagefault = read_cr2(); /* * Similarly, if we took a trap because the Guest used the FPU, * we have to restore the FPU it expects to see. * math_state_restore() may sleep and we may even move off to * a different CPU. So all the critical stuff should be done * before this. */ else if (cpu->regs->trapnum == 7 && !user_has_fpu()) math_state_restore(); }
static void __save_processor_state(struct saved_context *ctxt) { mtrr_save_fixed_ranges(NULL); kernel_fpu_begin(); /* * descriptor tables */ store_gdt(&ctxt->gdt); store_idt(&ctxt->idt); store_tr(ctxt->tr); /* * segment registers */ savesegment(es, ctxt->es); savesegment(fs, ctxt->fs); savesegment(gs, ctxt->gs); savesegment(ss, ctxt->ss); /* * control registers */ ctxt->cr0 = read_cr0(); ctxt->cr2 = read_cr2(); ctxt->cr3 = read_cr3(); ctxt->cr4 = read_cr4_safe(); }
void do_page_fault(struct pt_regs *regs, unsigned int vector) { /* Kernel space exception fixup check */ if (fixup_exception(regs)) return; unsigned long cr2 = read_cr2(); #ifdef CONFIG_KGDB kgdb_breakpoint(); #endif struct siginfo s; memset(&s, 0, sizeof(struct siginfo)); s.si_signo = SIGSEGV; s.si_errno = 0; s.si_addr = (void *)cr2; s.si_code = SEGV_ACCERR; // SEGV_MAPERR; int i = sigsend(current->aspace->id, ANY_ID, SIGSEGV, &s); printk(">> PAGE FAULT! Sent signal %d. CR2 is %p, cpu %d\n", i, (void *)cr2, this_cpu); show_registers(regs); /* If the fault occurred in kernel space, or the init_task, go down */ if ( (regs->rip >= PAGE_OFFSET) || (current->aspace->id == INIT_ASPACE_ID)) { local_irq_disable(); halt(); } }
void PageTable::handle_fault(REGS * _r) { /* Page fault handler */ //Console::puts("Page Fault Handler Called\n"); unsigned long addr = 0, page_dir_index = 0, page_table_index = 0, page_offset = 0; unsigned long page_fault_dir = read_cr2(); //Console::puts("Virtual Address = "); Console::putui(page_fault_dir); /* Page directory index is stored in the first 10 bits of the virtual address */ page_dir_index = SHIFT_RIGHT (page_fault_dir, PAGE_DIR_SHIFT) & 0x3FF; /* Page table index is stored in the second 10 bits of the virtual address */ page_table_index = SHIFT_RIGHT (page_fault_dir, PAGE_TABLE_SHIFT) & 0x3FF; /* Page offset is stored in the first 12 bits of the virtual address */ page_offset = page_fault_dir & 0xFFF; if ((current_page_table->page_directory[page_dir_index] & 0x1) == 0) /* The page table is not present in the page directory. * So allocate a frame from the kernel frame pool and mark the page as present. */ { current_page_table->page_directory[page_dir_index] = ((PageTable::kernel_mem_pool->get_frame()) * PageTable::PAGE_SIZE ) | 3; } ((unsigned long*)((current_page_table->page_directory[page_dir_index]) & 0xFFFFF000) )[page_table_index] = ( (PageTable::process_mem_pool->get_frame()) * (PageTable::PAGE_SIZE)) | 3; }
void PageTable::handle_fault(REGS * _r) { if(!(_r->err_code & 0x2)) Console::puts("It's read only.\n"); if(!(_r->err_code & 0x1)) //if the requested page is not in memory { unsigned long virtualaddr=read_cr2(); unsigned long pdindex=virtualaddr>>22; //we need first 10bit unsigned long * pd=(unsigned long *)read_cr3(); //get physical memory address which is also vm address of page directory Console::putui((unsigned int)pd[pdindex]); if((pd[pdindex] & 0x1)==0) //pagetable is not present { pd[pdindex]=(kernel_mem_pool->get_frame()*4096) | 3; //request frame address for storing page table, //by calling kernel_mem_pool, we assume pagetable for a process reside in kernel memory /*pt=(unsigned long *)(pd[pdindex] & 0xFFFFF000); for(unsigned long i;i<=1023;i++) pt[i]=2;*/ } unsigned long * pt=(unsigned long *)(pd[pdindex] & 0xFFFFF000); //Console::putui((unsigned int)pd[pdindex]); unsigned long ptindex=(virtualaddr>>12) & 0x03FF; //we need next 10bit in the middle pt[ptindex]=(process_mem_pool->get_frame()*4096) | 3; //request frame address for storing the page //Console::putui((unsigned int)pt[ptindex]); //for(;;); }
/*------------------------------------------------------------------------- * pfint - paging fault ISR *------------------------------------------------------------------------- */ SYSCALL pfint() { kprintf("---------ISR----------\n"); unsigned int pfaddr = read_cr2();// faulted address //Check that pfaddr is a legal address ???? unsigned int pdbaddr = read_cr3()&(~0xfff); //page directory base address unsigned int p = pfaddr >> 22; // upper ten bits of faulted address unsigned int q = (pfaddr >> 12)&0x3ff; // middle ten bits of faulted address unsigned int offset = pfaddr & 0xfff; // last twelve bits pd_t * pt = (pd_t *)pdbaddr + p ; //pth page table //kprintf("%x\n",*pt); if(pt->pd_pres == 0) // if page table is not present { int frm_num = get_frm(1,FR_TBL,pfaddr>>12); //kprintf("%d\n",frm_num); if(frm_num == SYSERR) return SYSERR; pt->pd_base = (0x00400000 + frm_num*4096) >> 12; pt->pd_pres = 1; write_cr3(pdbaddr); kprintf("faulted addr: %x xth page table: %x, content: %x\n",pfaddr,pt,p); return OK; }
/** @brief Page fault handler */ asmregparm void do_page_fault(struct pt_regs * regs, long error_code) { unsigned long error_address = read_cr2(); bool in_user = address_in_user(error_address); struct ko_thread *current; //printk("PAGE fault: eip %x addr %x code %x\n", regs->ip, error_address, error_code); /* Access violation. 读、写和u/s异常 如果是用户模式,那么访问核心层空间时崩溃,其他地方尝试修复 如果是特权模式,都尝试修复 */ if (error_code & PAGE_FAULT_U) { if (in_user == false) goto die_cur; } current = kt_current(); if (unlikely(false == ks_exception(current, error_address, error_code))) goto die_cur; return; die_cur: printk("TODO: Thread deing :eip %x addr %x code %x\n", regs->ip, error_address, error_code); //TODO kill thread //fak_arch_x86_dump_register(regs); kt_delete_current(); }
void do_page_fault(struct pt_regs *regs, unsigned long error_code) { unsigned long addr = read_cr2(); struct sched_shutdown sched_shutdown = { .reason = SHUTDOWN_crash }; if ((error_code & TRAP_PF_WRITE) && handle_cow(addr)) return; /* If we are already handling a page fault, and got another one that means we faulted in pagetable walk. Continuing here would cause a recursive fault */ if(handling_pg_fault == 1) { printk("Page fault in pagetable walk (access to invalid memory?).\n"); HYPERVISOR_sched_op(SCHEDOP_shutdown, &sched_shutdown); } handling_pg_fault++; barrier(); printk("Page fault at linear address %p, rip %p, regs %p, sp %p, our_sp %p, code %lx\n", addr, regs->rip, regs, regs->rsp, &addr, error_code); dump_regs(regs); //do_stack_walk(regs->rbp); dump_mem(regs->rsp); dump_mem(regs->rbp); dump_mem(regs->rip); page_walk(addr); HYPERVISOR_sched_op(SCHEDOP_shutdown, &sched_shutdown); /* We should never get here ... but still */ handling_pg_fault--; }
void do_page_fault(struct pt_regs *regs, unsigned int vector) { /* Kernel space exception fixup check */ if (fixup_exception(regs)) return; unsigned long cr2 = read_cr2(); #ifdef CONFIG_KGDB kgdb_breakpoint(); #endif struct siginfo s; memset(&s, 0, sizeof(struct siginfo)); s.si_signo = SIGSEGV; s.si_errno = 0; s.si_addr = (void *)cr2; s.si_code = SEGV_ACCERR; // SEGV_MAPERR; int i = sigsend(current->aspace->id, ANY_ID, SIGSEGV, &s); printk(">> PAGE FAULT! Sent signal %d: CR2 is %p\n", i, s.si_addr); show_registers(regs); while (1) {} }
void __show_registers(struct pt_regs *regs, int all) { unsigned long cr0 = 0L, cr2 = 0L, cr3 = 0L, cr4 = 0L; unsigned long d0, d1, d2, d3, d6, d7; unsigned long sp; unsigned short ss, gs; if (user_mode_vm(regs)) { sp = regs->sp; ss = regs->ss & 0xffff; savesegment(gs, gs); } else { sp = (unsigned long) (®s->sp); savesegment(ss, ss); savesegment(gs, gs); } printk("\n"); printk("Pid: %d, comm: %s %s (%s %.*s)\n", task_pid_nr(current), current->comm, print_tainted(), init_utsname()->release, (int)strcspn(init_utsname()->version, " "), init_utsname()->version); printk("EIP: %04x:[<%08lx>] EFLAGS: %08lx CPU: %d\n", (u16)regs->cs, regs->ip, regs->flags, smp_processor_id()); print_symbol("EIP is at %s\n", regs->ip); printk("EAX: %08lx EBX: %08lx ECX: %08lx EDX: %08lx\n", regs->ax, regs->bx, regs->cx, regs->dx); printk("ESI: %08lx EDI: %08lx EBP: %08lx ESP: %08lx\n", regs->si, regs->di, regs->bp, sp); printk(" DS: %04x ES: %04x FS: %04x GS: %04x SS: %04x\n", (u16)regs->ds, (u16)regs->es, (u16)regs->fs, gs, ss); if (!all) return; cr0 = read_cr0(); cr2 = read_cr2(); cr3 = read_cr3(); cr4 = read_cr4_safe(); printk("CR0: %08lx CR2: %08lx CR3: %08lx CR4: %08lx\n", cr0, cr2, cr3, cr4); get_debugreg(d0, 0); get_debugreg(d1, 1); get_debugreg(d2, 2); get_debugreg(d3, 3); printk("DR0: %08lx DR1: %08lx DR2: %08lx DR3: %08lx\n", d0, d1, d2, d3); get_debugreg(d6, 6); get_debugreg(d7, 7); printk("DR6: %08lx DR7: %08lx\n", d6, d7); }
void __show_regs(struct pt_regs *regs, int all) { #ifdef NOT_FOR_L4 unsigned long cr0 = 0L, cr2 = 0L, cr3 = 0L, cr4 = 0L; unsigned long d0, d1, d2, d3, d6, d7; #endif unsigned long sp; unsigned short ss, gs; if (user_mode_vm(regs)) { sp = regs->sp; ss = regs->ss & 0xffff; gs = get_user_gs(regs); } else { sp = kernel_stack_pointer(regs); savesegment(ss, ss); savesegment(gs, gs); } show_regs_common(); printk(KERN_DEFAULT "EIP: %04x:[<%08lx>] EFLAGS: %08lx CPU: %d\n", (u16)regs->cs, regs->ip, regs->flags, smp_processor_id()); print_symbol("EIP is at %s\n", regs->ip); printk(KERN_DEFAULT "EAX: %08lx EBX: %08lx ECX: %08lx EDX: %08lx\n", regs->ax, regs->bx, regs->cx, regs->dx); printk(KERN_DEFAULT "ESI: %08lx EDI: %08lx EBP: %08lx ESP: %08lx\n", regs->si, regs->di, regs->bp, sp); printk(KERN_DEFAULT " DS: %04x ES: %04x FS: %04x GS: %04x SS: %04x\n", (u16)regs->ds, (u16)regs->es, (u16)regs->fs, gs, ss); if (!all) return; #ifdef NOT_FOR_L4 cr0 = read_cr0(); cr2 = read_cr2(); cr3 = read_cr3(); cr4 = read_cr4_safe(); printk(KERN_DEFAULT "CR0: %08lx CR2: %08lx CR3: %08lx CR4: %08lx\n", cr0, cr2, cr3, cr4); get_debugreg(d0, 0); get_debugreg(d1, 1); get_debugreg(d2, 2); get_debugreg(d3, 3); printk(KERN_DEFAULT "DR0: %08lx DR1: %08lx DR2: %08lx DR3: %08lx\n", d0, d1, d2, d3); get_debugreg(d6, 6); get_debugreg(d7, 7); printk(KERN_DEFAULT "DR6: %08lx DR7: %08lx\n", d6, d7); #endif }
void fault(struct tcb *tcb, struct ccb *ccb) { if (tcb->ivect == 32) { ccb->lapic->eoi = 0; scheduler_schedule(); return; } if (tcb->ivect == 0x100) { if (tcb->rdi == 0 && tcb->state != TCB_STATE_RUNNING) { ccb_unload_tcb(); } scheduler_schedule(); return; } if (tcb->ivect == 14) { extern uint64_t read_cr2(void); log(ERROR, "page fault at addr %p (ip %p, sp %p, id %d)", read_cr2(), tcb->rip, tcb->rsp, tcb->id); log(ERROR, "translation: %p %p", pcx_get_trans(NULL, read_cr2()), pcx_get_flags(NULL, read_cr2())); queue_pagefault(ccb_unload_tcb()); interrupt_vector_fire(__PINION_INTERRUPT_PAGEFAULT); scheduler_schedule(); return; } if (tcb->ivect == 8) { log(ERROR, "PANIC: double fault"); for(;;); } if (tcb->ivect < 32) { queue_miscfault(ccb_unload_tcb()); interrupt_vector_fire(__PINION_INTERRUPT_MISCFAULT); scheduler_schedule(); return; } }
void __show_regs(struct pt_regs *regs, int all) { unsigned long cr0 = 0L, cr2 = 0L, cr3 = 0L, cr4 = 0L; unsigned long d0, d1, d2, d3, d6, d7; unsigned long sp; unsigned short ss, gs; if (user_mode(regs)) { sp = regs->sp; ss = regs->ss & 0xffff; gs = get_user_gs(regs); } else { sp = kernel_stack_pointer(regs); savesegment(ss, ss); savesegment(gs, gs); } printk(KERN_DEFAULT "EIP: %04x:[<%08lx>] EFLAGS: %08lx CPU: %d\n", (u16)regs->cs, regs->ip, regs->flags, smp_processor_id()); print_symbol("EIP is at %s\n", regs->ip); printk(KERN_DEFAULT "EAX: %08lx EBX: %08lx ECX: %08lx EDX: %08lx\n", regs->ax, regs->bx, regs->cx, regs->dx); printk(KERN_DEFAULT "ESI: %08lx EDI: %08lx EBP: %08lx ESP: %08lx\n", regs->si, regs->di, regs->bp, sp); printk(KERN_DEFAULT " DS: %04x ES: %04x FS: %04x GS: %04x SS: %04x\n", (u16)regs->ds, (u16)regs->es, (u16)regs->fs, gs, ss); if (!all) return; cr0 = read_cr0(); cr2 = read_cr2(); cr3 = read_cr3(); cr4 = __read_cr4_safe(); printk(KERN_DEFAULT "CR0: %08lx CR2: %08lx CR3: %08lx CR4: %08lx\n", cr0, cr2, cr3, cr4); get_debugreg(d0, 0); get_debugreg(d1, 1); get_debugreg(d2, 2); get_debugreg(d3, 3); get_debugreg(d6, 6); get_debugreg(d7, 7); /* Only print out debug registers if they are in their non-default state. */ if ((d0 == 0) && (d1 == 0) && (d2 == 0) && (d3 == 0) && (d6 == DR6_RESERVED) && (d7 == 0x400)) return; printk(KERN_DEFAULT "DR0: %08lx DR1: %08lx DR2: %08lx DR3: %08lx\n", d0, d1, d2, d3); printk(KERN_DEFAULT "DR6: %08lx DR7: %08lx\n", d6, d7); }
void FH_page_fault(struct fault_ctx *fctx) { uintptr_t fault_addr, fixup_addr; struct intr_stack_frame *stack_frame = fctx->istack_frame; fault_addr = read_cr2(); fixup_addr = fixup_fault_address(stack_frame->rip); if (IS_KERNEL_FAULT(fctx) && !fixup_addr) { display_unhandled_pf_info(fctx, fault_addr); goto stop_cpu; } else { vmm_t *vmm = current_task()->task_mm; uint32_t errmask = 0; int ret = -EFAULT; if (!PFAULT_READ(fctx->errcode)) errmask |= PFLT_WRITE; if (PFAULT_NXE(fctx->errcode)) errmask |= PFLT_NOEXEC; if (PFAULT_PROTECT(fctx->errcode)) errmask |= PFLT_PROTECT; else errmask |= PFLT_NOT_PRESENT; ret = vmm_handle_page_fault(vmm, fault_addr, errmask); if (!ret) { return; } if (fixup_addr) { goto handle_fixup; } display_unhandled_pf_info(fctx, fault_addr); #ifdef CONFIG_DUMP_VMM_ON_FAULT kprintf_fault("========= [Vrages Tree] ========="); vmranges_print_tree_dbg(vmm); #endif /* CONFIG_DUMP_VMM_ON_FAULT */ #ifdef CONFIG_SEND_SIGSEGV_ON_FAULTS send_sigsegv(fault_addr, ret); return; #endif /* CONFIG_SEND_SIGSEGV_ON_FAULTS */ } stop_cpu: __stop_cpu(); handle_fixup: kprintf_fault("FIXUP = %p\n", fixup_addr); stack_frame->rip = fixup_addr; return; }
dotraplinkage void do_page_fault(struct pt_regs *regs, long error_code) { unsigned long address = read_cr2(); __do_page_fault(regs, error_code, address); printk("BUG: unable to handle kernel paging request at %#lx\n", address); printk("CPU: %d PID: %u Comm: %s\n", smp_processor_id(), current->pid, current->comm); show_regs(regs); panic("panic at #PF"); }
void dump_regs(struct irq_regs *regs) { unsigned long cr0 = 0L, cr2 = 0L, cr3 = 0L, cr4 = 0L; unsigned long d0, d1, d2, d3, d6, d7; unsigned long sp; printf("EIP: %04x:[<%08lx>] EFLAGS: %08lx\n", (u16)regs->xcs, regs->eip, regs->eflags); printf("EAX: %08lx EBX: %08lx ECX: %08lx EDX: %08lx\n", regs->eax, regs->ebx, regs->ecx, regs->edx); printf("ESI: %08lx EDI: %08lx EBP: %08lx ESP: %08lx\n", regs->esi, regs->edi, regs->ebp, regs->esp); printf(" DS: %04x ES: %04x FS: %04x GS: %04x SS: %04x\n", (u16)regs->xds, (u16)regs->xes, (u16)regs->xfs, (u16)regs->xgs, (u16)regs->xss); cr0 = read_cr0(); cr2 = read_cr2(); cr3 = read_cr3(); cr4 = read_cr4(); printf("CR0: %08lx CR2: %08lx CR3: %08lx CR4: %08lx\n", cr0, cr2, cr3, cr4); d0 = get_debugreg(0); d1 = get_debugreg(1); d2 = get_debugreg(2); d3 = get_debugreg(3); printf("DR0: %08lx DR1: %08lx DR2: %08lx DR3: %08lx\n", d0, d1, d2, d3); d6 = get_debugreg(6); d7 = get_debugreg(7); printf("DR6: %08lx DR7: %08lx\n", d6, d7); printf("Stack:\n"); sp = regs->esp; sp += 64; while (sp > (regs->esp - 16)) { if (sp == regs->esp) printf("--->"); else printf(" "); printf("0x%8.8lx : 0x%8.8lx\n", sp, (ulong)readl(sp)); sp -= 4; } }
void page_fault(unsigned int n, istate_t *istate) { uintptr_t badvaddr = read_cr2(); if (istate->error_word & PFERR_CODE_RSVD) panic("Reserved bit set in page table entry."); pf_access_t access; if (istate->error_word & PFERR_CODE_RW) access = PF_ACCESS_WRITE; else if (istate->error_word & PFERR_CODE_ID) access = PF_ACCESS_EXEC; else access = PF_ACCESS_READ; (void) as_page_fault(badvaddr, access, istate); }
void PageTable::handle_fault(REGS* _r) { /* check what exception? */ unsigned long faulting_addr = read_cr2(); /* compute the index of the page dir and page table */ int page_dir_index = faulting_addr >> 22; int page_table_index = (faulting_addr >> 12) & MASK; /* Perform the recursive page dir trick */ unsigned long* virt_page_directory = (unsigned long*)0xFFFFF000; unsigned long* virt_page_table = 0; /* check the present bit of the dir */ if(virt_page_directory[page_dir_index] == 2) { /* create page table, assign new frame for the faulting address */ unsigned long frame = process_mem_pool->get_frame(); // mark as present virt_page_directory[page_dir_index] = frame | 3; frame = process_mem_pool->get_frame(); virt_page_table = (unsigned long*)(0xFFC00000 | (page_dir_index << 12)); for(int i = 0; i < 1024; i++) // mark as absent virt_page_table[i] = 0 | 2; // mark as present the page containing the faulting addr virt_page_table[page_table_index] = frame | 3; } else { // page table present, assign page unsigned long new_frame = process_mem_pool->get_frame_address(process_mem_pool->get_frame()); // unsigned long new_frame = process_mem_pool->get_frame(); virt_page_table = (unsigned long*)(0xFFC00000 | (page_dir_index << 12)); // page containing the faulting address to be marked present virt_page_table[page_table_index] = new_frame | 3; } }
void lguest_arch_run_guest(struct lg_cpu *cpu) { if (cpu->ts) unlazy_fpu(current); if (boot_cpu_has(X86_FEATURE_SEP)) wrmsr(MSR_IA32_SYSENTER_CS, 0, 0); run_guest_once(cpu, lguest_pages(raw_smp_processor_id())); if (boot_cpu_has(X86_FEATURE_SEP)) wrmsr(MSR_IA32_SYSENTER_CS, __KERNEL_CS, 0); if (cpu->regs->trapnum == 14) cpu->arch.last_pagefault = read_cr2(); else if (cpu->regs->trapnum == 7) math_state_restore(); }
/* All of our Exception handling Interrupt Service Routines will * point to this function. This will tell us what exception has * happened! Right now, we simply halt the system by hitting an * endless loop. All ISRs disable interrupts while they are being * serviced as a 'locking' mechanism to prevent an IRQ from * happening and messing up kernel data structures */ extern "C" void fault_handler(struct cpu_state *r) { if (r->int_no < 32) { bool handled = false; switch( r->int_no ) { case 14: // Page fault handled = paging_handle_fault( r, read_cr2() ); break; default: debug_bochs_printf( "EXCEPTION!" ); debug_bochs_printf( " (%x) (err_code = %x)\n", r->int_no, r->err_code ); debug_bochs_printf( "%s Exception\n", exception_messages[r->int_no] ); break; } if( !handled ) { debug_bochs_printf( "\nRegister dump:\n" ); /* unsigned int gs, fs, es, ds; unsigned int edi, esi, ebp, esp, ebx, edx, ecx, eax; unsigned int int_no, err_code; unsigned int eip, cs, eflags, useresp, ss; */ debug_bochs_printf( "EAX = %x EBX = %x ECX = %x EDX = %x\n", r->eax, r->ebx, r->ecx, r->edx ); debug_bochs_printf( "ESP = %x EBP = %x ESI = %x EDI = %x\n", r->esp, r->ebp, r->esi, r->edi ); debug_bochs_printf( "GS = %x FS = %x ES = %x DS = %x\n", r->gs, r->fs, r->es, r->ds ); debug_bochs_printf( "EIP = %x CS = %x EFLAGS = %x SS = %x\n", r->eip, r->cs, r->eflags, r->ss ); debug_bochs_printf( "System Halted!\n" ); for (;;); } } }
/*------------------------------------------------------------------------- * pfint - paging fault ISR *------------------------------------------------------------------------- */ SYSCALL pfint() { STATWORD ps; disable(ps); int vp, p, q; int i; unsigned long fault_addr; int store, pageth; int new_frame, m_frame = -1; pt_t *ptr_pt; fault_addr = read_cr2(); vp = (fault_addr & ~(NBPG - 1)) >> 12; //If process tries to access bs that it has not got using getbs. if (bsm_lookup(currpid, fault_addr, &store, &pageth) == SYSERR) { kill(currpid); } pd_t *ptr_pd = (pd_t *) (proctab[currpid].pdbr); p = (fault_addr & 0xFFC00000) >> 22; q = (fault_addr & 0x003FF000) >> 12; ptr_pd = ptr_pd + p; if (ptr_pd->pd_pres == 0) { get_frm(&new_frame); frm_tab[new_frame].fr_pid = currpid; frm_tab[new_frame].fr_type = FR_TBL; new_frame = new_frame + FRAME0; add_page_dir(ptr_pd, new_frame, ((proctab[currpid].pdbr & ~(NBPG - 1)) >> 12) - FRAME0); } else
void dump_regs(struct irq_regs *regs) { unsigned long cr0 = 0L, cr2 = 0L, cr3 = 0L, cr4 = 0L; unsigned long d0, d1, d2, d3, d6, d7; printf("EIP: %04x:[<%08lx>] EFLAGS: %08lx\n", (u16)regs->xcs, regs->eip, regs->eflags); printf("EAX: %08lx EBX: %08lx ECX: %08lx EDX: %08lx\n", regs->eax, regs->ebx, regs->ecx, regs->edx); printf("ESI: %08lx EDI: %08lx EBP: %08lx ESP: %08lx\n", regs->esi, regs->edi, regs->ebp, regs->esp); printf(" DS: %04x ES: %04x FS: %04x GS: %04x SS: %04x\n", (u16)regs->xds, (u16)regs->xes, (u16)regs->xfs, (u16)regs->xgs, (u16)regs->xss); cr0 = read_cr0(); cr2 = read_cr2(); cr3 = read_cr3(); cr4 = read_cr4(); printf("CR0: %08lx CR2: %08lx CR3: %08lx CR4: %08lx\n", cr0, cr2, cr3, cr4); d0 = get_debugreg(0); d1 = get_debugreg(1); d2 = get_debugreg(2); d3 = get_debugreg(3); printf("DR0: %08lx DR1: %08lx DR2: %08lx DR3: %08lx\n", d0, d1, d2, d3); d6 = get_debugreg(6); d7 = get_debugreg(7); printf("DR6: %08lx DR7: %08lx\n", d6, d7); }
SYSCALL pfint() { unsigned long cr2,physical_addr; virt_addr_t * vaddr; int vp,s,o,avail,*store,*pageth; unsigned int p,q,pt; pd_t *pd; pt_t *new_pt; STATWORD ps; // Disable interrupts disable(ps); if(GDB) kprintf("\n*************pfint is running!************\n"); // Get the faulted address. The processor loads the CR2 register // with the 32-bit address that generated the exception. /* 1. Get the faulted address. */ cr2 = read_cr2(); vaddr = (virt_addr_t *)(&cr2); if(GDB) kprintf("&cr2=%x, cr2=%x, &vaddr=%x, vaddr=%x\n",&cr2,cr2,&vaddr,vaddr); /* 2. Let 'vp' be the virtual page number of the page containing of the faulted address */ vp = a2pno(cr2); if(GDB) kprintf("vp=%d,\n",vp); /* 3. Let pd point to the current page directory. */ pd = proctab[currpid].pdbr; if(GDB) kprintf("pd=%x,\n",pd); /* 4. Check that a is a legal address (i.e., it has been mapped). If it is not, print an error message and kill the process. */ pageth = getmem( sizeof(int *) ); store = getmem( sizeof(int *) ); if( SYSERR == bsm_lookup(currpid, vp, store, pageth)){ kprintf("ERROR: This virtual address hasn't been mapped!\n"); kill(currpid); } /* 5. Let p be the upper ten bits of a. [p represents page dirctory offset] */ /* 6. Let q be the bits [21:12] of a. [p represents page table offset.] /* 7.1 Let pt point to the pth page table.*/ p = vaddr->pd_offset; q = vaddr->pt_offset; pt = vaddr->pg_offset; if(GDB) kprintf("p=%d,q=%d,pt=%d\n",p,q,pt); /* 7.2 If the pth page table does not exist obtain a frame for it and initialize it. */ if(pd[p].pd_pres != 1){ if(GDB) kprintf("**obtain a frame for the new page table. \n"); avail = get_frm(); //get the id of a new frame from frm_tab[]; if (avail == -1) { if(GDB) kprintf("Could not create page table!\n"); restore(ps); return SYSERR; } //initialize frame[avail], update the process_id and frame_type of this frame. init_frm(avail, currpid, FR_TBL); frm_tab[avail].fr_upper_t = pa2frid((unsigned long) pd); if(GDB) kprintf("upper page table @frame[%d] pd=%x, a2pno(pd)=%d\n",frm_tab[avail].fr_upper_t, pd, a2pno((unsigned long) pd)); new_pt = frid2pa(avail); init_pt(new_pt); //update this page_table_entry in the page_directory. pd[p].pd_pres = 1; pd[p].pd_write = 1; pd[p].pd_user = 0; // not sure about the usage; pd[p].pd_pwt = 0; pd[p].pd_pcd = 0; pd[p].pd_acc = 0; pd[p].pd_mbz = 0; pd[p].pd_fmb = 0; pd[p].pd_global = 0; pd[p].pd_avail = 0; // not in use right now. pd[p].pd_base = a2pno((unsigned long) new_pt); /* location of page table */ if(GDB) kprintf("New page_table(%x)@frame[%d] updated in page_directory[%d]@(frame[%d])\n", new_pt, avail, p, frm_tab[avail].fr_upper_t); if(GDB) kprintf("q=%d, new_pt[q]=%x, new_pt=%x, pd[p].pd_base=%d\n", q, new_pt[q], new_pt, pd[p].pd_base); } //if the page table has already existed, just need to refcnt++; else { int avail = pd[p].pd_base -1024; frm_tab[avail].fr_refcnt++; if(GDB) kprintf("frm_tab[%d].fr_refcnt = %d, frame_type: %d\n",avail, frm_tab[avail].fr_refcnt, frm_tab[avail].fr_type); } /* 8.1 Using the backing store map, find the store s and page offset o which correspond to vp. */ //already saved in 'store' and 'pageth' s = *store; o = *pageth; /* 8.2 In the inverted page table increment the reference count of the frame which holds pt. This indicates that one more of pt's entries is marked "present." */ avail = find_frm(currpid,vp); if (avail == -1) { if(GDB) kprintf("allocating a page for the page fault\n"); avail = get_frm(); if(avail == -1) { if(GDB) kprintf("ATTENTION! Frames full. ###Replacement NEEDED!###\n"); int frame_number = proctab[currpid].nframes-1; int frame_id = proc_frames[currpid][0]; //update_proc_frames(pid,frame_number); int i; for (i = 0; i+1 < frame_number; ++i) { proc_frames[currpid][i] = proc_frames[currpid][i+1]; } proctab[currpid].nframes = frame_number; int pid = frm_tab[frame_id].fr_pid; int upper_id = frm_tab[frame_id].fr_upper_t; vp = frm_tab[frame_id].fr_vpno; if(GDB) kprintf("currpid=%d, frame[%d].pid=%d .vpno=%d, upper_frame[%d].ref=%d\n",currpid,frame_id,pid,vp,upper_id,frm_tab[upper_id].fr_refcnt); p = vp>>10; q = vp &0x003ff; new_pt = vp2pa(pd[p].pd_base); new_pt[q].pt_pres = 0; new_pt[q].pt_write = 1; new_pt[q].pt_base = 0; if(GDB) kprintf("pd_offset=%d, pt_offset=%d, pt_dirty=%d\n",p,q,new_pt[q].pt_dirty); if(new_pt[q].pt_dirty == 1) { //write back and pageth = getmem( sizeof(int *) ); store = getmem( sizeof(int *) ); if( SYSERR == bsm_lookup(currpid, vp, store, pageth)){ kprintf("ERROR: This virtual address hasn't been mapped!\n"); kill(currpid); } if(GDB) kprintf("maping found: {pid: %d, vpno: %d, store: %d, pageth: %d}\n",currpid,vp,*store,*pageth); write_bs((char *)new_pt, *store, *pageth); } init_pt(new_pt); reset_frm(frame_id); frm_tab[upper_id].fr_refcnt -= 2; //it is 2, not 1. if(frm_tab[upper_id].fr_refcnt <= 0){ //mark the appropriate entry in pd as being not present, and free pt. } //invalidate the TLB entry for the page vp using the invlpg instruction if(pid == currpid) { set_PDBR(currpid); } } else { init_frm(avail, currpid, FR_PAGE); frm_tab[avail].fr_upper_t = pd[p].pd_base-FRAME0; if(GDB) kprintf("upper page table @frame[%d]\n",frm_tab[avail].fr_upper_t); frm_tab[avail].fr_vpno = vp; int counter = proctab[currpid].nframes; proc_frames[currpid][counter] = frm_tab[avail].fr_id; proctab[currpid].nframes++; if(GDB) kprintf("proc_frames[%d][%d] = frame[%d]\n",currpid,counter,avail); // Add this frame to head of the frame list within the bs of this process //(frm_tab[avail].bs_next)->fr_vpno //, proctab[currpid].bsmap[s].frames->bs_next if(GDB) kprintf("&frm_tab[avail].bs_next = %x\n",frm_tab[avail].bs_next, &frm_tab[avail].bs_next); if(GDB) kprintf("proctab[%d].bsmap[%d].frames = %x, ->vpno=%d, ->bs_next=%x\n",currpid, s, proctab[currpid].bsmap[s].frames, proctab[currpid].bsmap[s].frames->fr_vpno, proctab[currpid].bsmap[s].frames->bs_next); frm_tab[avail].bs_next = getmem(sizeof(fr_map_t *)); frm_tab[avail].bs_next = proctab[currpid].bsmap[s].frames; proctab[currpid].bsmap[s].frames = &frm_tab[avail]; fr_map_t *frame = proctab[currpid].bsmap[s].frames; int i = frame->fr_vpno; if(GDB) kprintf("i = %d\n",i); if(GDB) kprintf("~~~frame[%d] linked to frame[%d]\n", avail, frame->bs_next==NULL?-1:frame->bs_next->fr_id); if(GDB) kprintf("frame[%d].bs_next = %x, &**=%x\n",avail,frm_tab[avail].bs_next, &frm_tab[avail].bs_next); if(GDB) kprintf("proctab[%d].bsmap[%d].frames = %x, ->vpno=%d, ->bs_next=%x\n",currpid, s, proctab[currpid].bsmap[s].frames, proctab[currpid].bsmap[s].frames->fr_vpno, proctab[currpid].bsmap[s].frames->bs_next); if(GDB) kprintf("Mapping frame[%d](ppno[%d]) to {pid[%d], vpno[%d]} -> {bs[%d],offset:%d}\n", avail,frid2vpno(avail),currpid,vp,s,o); physical_addr = frid2pa(avail); read_bs(physical_addr,s,o); if(GDB) kprintf("copied from bs[%d]:offset[%d] to vp[%d]@(%x)\n",s,o,vp,vp2pa(vp)); } }
/* The page fault handler. */ void PageTable::handle_fault(REGS * _r) { unsigned int err_code = _r->err_code & 1; unsigned long fault_address = read_cr2(); switch(err_code) { case KERNEL_READ_PAGE_NOT_PRESENT: case KERNEL_WRITE_PAGE_NOT_PRESENT: unsigned long page_directory_index = fault_address >> 22; //constify this unsigned long page_table_index = (fault_address & 0x003FFFFF) >> 12; //constify this unsigned long *page_directory = current_page_table->get_page_directory(); if(page_directory[page_directory_index] & 1) { //constify this //page table entry is present in the directory unsigned long *page_table = (unsigned long *)(page_directory[page_directory_index] & (0xFFFFF000)); if(page_table[page_table_index] & 1) { //page entry is present in the page table //why did the page fault occur? :P } else { //constify the 3 - PT entry control bits unsigned long *requested_page_from_framepool; if(fault_address >= shared_size) { requested_page_from_framepool = (unsigned long *)(process_mem_pool->get_frame() * PAGE_SIZE); } else { requested_page_from_framepool = (unsigned long *)(kernel_mem_pool->get_frame() * PAGE_SIZE); } create_page_table_entry(requested_page_from_framepool, page_table, page_table_index, 3); //handle the fault by reading/writing to that location or do what is required } } else { //create page table unsigned long *requested_page_from_framepool = (unsigned long *)(kernel_mem_pool->get_frame() * PAGE_SIZE); create_page_table_entry(requested_page_from_framepool, page_directory, page_directory_index, 3); unsigned long *page_table = (unsigned long *)(page_directory[page_directory_index] & (0xFFFFF000)); if(fault_address >= shared_size) { requested_page_from_framepool = (unsigned long *)(process_mem_pool->get_frame() * PAGE_SIZE); } else { requested_page_from_framepool = (unsigned long *)(kernel_mem_pool->get_frame() * PAGE_SIZE); } create_page_table_entry(requested_page_from_framepool, page_table, page_table_index, 3); //handle the fault by reading/writing to that location or do what is required } break; } /* switch(err_code) { case KERNEL_READ_PAGE_NOT_PRESENT: break; case KERNEL_READ_PROTECTION_FAULT: break; case KERNEL_WRITE_PAGE_NOT_PRESENT: break; case KERNEL_WRITE_PROTECTION_FAULT: break; case USER_READ_PAGE_NOT_PRESENT: break; case USER_READ_PROTECTION_FAULT: break; case USER_WRITE_PAGE_NOT_PRESENT: break; case USER_WRITE_PROTECTION_FAULT: break; }*/ }
/*------------------------------------------------------------------------- * pfint - paging fault ISR *------------------------------------------------------------------------- */ SYSCALL pfint() { STATWORD ps; disable(ps); unsigned long int eip = read_cr2(); unsigned long int pd_offset = eip >> 22; unsigned long int pt_offset = eip >>12; pt_offset = pt_offset & 1023; unsigned long offset = eip; offset = offset & 4095; eip = eip >> 12; //vpno int i = 0, flag = 0; int backing_store_page, bs_id; for(i = 0 ; i < NBS; i++) { if(proctab[currpid].map[i].bs_pid == currpid) { if(proctab[currpid].map[i].next == NULL) { if(proctab[currpid].map[i].bs_vpno == eip) //we found the exact page { backing_store_page = proctab[currpid].map[i].starting_page; flag = 1; } else if(proctab[currpid].map[i].bs_vpno < eip && (proctab[currpid].map[i].bs_vpno+proctab[currpid].map[i].bs_npages) >= eip) { backing_store_page = proctab[currpid].map[i].starting_page + eip - proctab[currpid].map[i].bs_vpno; flag = 1; } } else { bs_map_t *move = &(proctab[currpid].map[i]); while(move != NULL) { if(move->bs_vpno == eip) //we found the exact page { backing_store_page = move->starting_page; flag = 1; break; } else if(move->bs_vpno < eip && (move->bs_npages+move->bs_vpno) >= eip) { backing_store_page = move->starting_page + eip - move->bs_vpno; flag = 1; break; } move = move->next; } } } if(flag==1) { bs_id = i; break; } } unsigned long *bs_addr = (unsigned long *)(backing_store_page*NBPG); //populate page table //checking if page dir is empty pd_t *ptr1 = (pd_t *)(proctab[currpid].pdbr); ptr1 += pd_offset; pt_t *ptr; if(ptr1->pd_pres == 1) //page table exists hence add entry to that { ptr = (pt_t *)((ptr1->pd_base)*NBPG); frm_tab[(ptr1->pd_base)-FRAME0].refcnt++; frm_map[(ptr1->pd_base)-FRAME0].fr_refcnt++; } else //we need to create a page table, add our free_frame entry to it and add the page table entry to the directory { //kprintf("\nin else %d\n",ptr1); int pt_frame = get_frm(); frm_tab[pt_frame-FRAME0].status = FRM_PGT; frm_tab[pt_frame-FRAME0].refcnt++; frm_map[pt_frame-FRAME0].fr_status = FRM_MAPPED; frm_map[pt_frame-FRAME0].fr_pid = currpid; frm_map[pt_frame-FRAME0].fr_refcnt++; frm_map[pt_frame-FRAME0].fr_type = FR_TBL; ptr = (pt_t*)(pt_frame*NBPG); //add the above table to page directory ptr1->pd_pres = 1; ptr1->pd_write = 1; ptr1->pd_user = 0; ptr1->pd_pwt = 0; ptr1->pd_pcd = 0; ptr1->pd_acc = 0; ptr1->pd_mbz = 0; ptr1->pd_fmb = 0; ptr1->pd_global = 0; ptr1->pd_avail = 0; ptr1->pd_base = pt_frame; } //add entry to page table ptr += pt_offset; ptr->pt_pres = 1; ptr->pt_write = 1; ptr->pt_user = 0; ptr->pt_pwt = 0; ptr->pt_pcd = 0; ptr->pt_acc = 0; ptr->pt_dirty = 0; ptr->pt_mbz = 0; ptr->pt_global = 0; ptr->pt_avail = 0; //getting a free frame an setting the frame mappings int free_frame; if(page_table[backing_store_page-total_bs_available] != -1) { free_frame = page_table[backing_store_page-total_bs_available]; frm_map[free_frame-FRAME0].fr_refcnt++; frm_tab[free_frame-FRAME0].refcnt++; fr_map_t *map = (fr_map_t *)getmem(sizeof(fr_map_t)); map->fr_pid = currpid; map->fr_vpno = eip; map->shared = NULL; fr_map_t *next = (fr_map_t *)getmem(sizeof(fr_map_t)); next = &(frm_map[free_frame-FRAME0]); while(next->shared != NULL) next = next->shared; next->shared = map; } else { //obtain free frame free_frame = get_frm(); frm_tab[free_frame-FRAME0].status = FRM_BS; frm_tab[free_frame-FRAME0].refcnt++; frm_tab[free_frame-FRAME0].bs = bs_id; frm_tab[free_frame-FRAME0].bs_page = backing_store_page; frm_tab[free_frame-FRAME0].bs_next = NULL; frm_tab[free_frame-FRAME0].fifo = NULL; frm_tab[free_frame-FRAME0].age = 128; frm_map[free_frame-FRAME0].fr_status = FRM_MAPPED; frm_map[free_frame-FRAME0].fr_pid = currpid; frm_map[free_frame-FRAME0].fr_vpno = eip; frm_map[free_frame-FRAME0].fr_refcnt++; frm_map[free_frame-FRAME0].fr_type = FR_PAGE; frm_map[free_frame-FRAME0].bs_page_num = backing_store_page; page_table[backing_store_page-total_bs_available] = free_frame; //set bs mappings if(bs_tab[bs_id].frm == NULL) bs_tab[bs_id].frm = &frm_tab[free_frame-FRAME0]; else { frame_t *move = (frame_t *)getmem(sizeof(frame_t)); move = bs_tab[bs_id].frm; while(move->bs_next != NULL) { move = move->bs_next; } move->bs_next = &frm_tab[free_frame-FRAME0]; } //adding this frame to the fifo queue if(fifo_head == NULL) { //queue is empty fifo_head = &frm_tab[free_frame-FRAME0]; fifo_tail = fifo_head; } else { fifo_tail->fifo = &frm_tab[free_frame-FRAME0]; fifo_tail = &frm_tab[free_frame-FRAME0]; } } unsigned long *dest_addr = (unsigned long *)(free_frame*NBPG); //copy page from bs to phy for(i = 0; i < NBPG/sizeof(unsigned long); i++) { *dest_addr = *bs_addr; dest_addr++; bs_addr++; } ptr->pt_base = free_frame; restore(ps); return OK; }
static void dump_regs(struct irq_regs *regs) { unsigned long cs, eip, eflags; unsigned long cr0 = 0L, cr2 = 0L, cr3 = 0L, cr4 = 0L; unsigned long d0, d1, d2, d3, d6, d7; unsigned long sp; /* * Some exceptions cause an error code to be saved on the current stack * after the EIP value. We should extract CS/EIP/EFLAGS from different * position on the stack based on the exception number. */ switch (regs->irq_id) { case EXC_DF: case EXC_TS: case EXC_NP: case EXC_SS: case EXC_GP: case EXC_PF: case EXC_AC: cs = regs->context.ctx2.xcs; eip = regs->context.ctx2.eip; eflags = regs->context.ctx2.eflags; /* We should fix up the ESP due to error code */ regs->esp += 4; break; default: cs = regs->context.ctx1.xcs; eip = regs->context.ctx1.eip; eflags = regs->context.ctx1.eflags; break; } printf("EIP: %04x:[<%08lx>] EFLAGS: %08lx\n", (u16)cs, eip, eflags); if (gd->flags & GD_FLG_RELOC) printf("Original EIP :[<%08lx>]\n", eip - gd->reloc_off); printf("EAX: %08lx EBX: %08lx ECX: %08lx EDX: %08lx\n", regs->eax, regs->ebx, regs->ecx, regs->edx); printf("ESI: %08lx EDI: %08lx EBP: %08lx ESP: %08lx\n", regs->esi, regs->edi, regs->ebp, regs->esp); printf(" DS: %04x ES: %04x FS: %04x GS: %04x SS: %04x\n", (u16)regs->xds, (u16)regs->xes, (u16)regs->xfs, (u16)regs->xgs, (u16)regs->xss); cr0 = read_cr0(); cr2 = read_cr2(); cr3 = read_cr3(); cr4 = read_cr4(); printf("CR0: %08lx CR2: %08lx CR3: %08lx CR4: %08lx\n", cr0, cr2, cr3, cr4); d0 = get_debugreg(0); d1 = get_debugreg(1); d2 = get_debugreg(2); d3 = get_debugreg(3); printf("DR0: %08lx DR1: %08lx DR2: %08lx DR3: %08lx\n", d0, d1, d2, d3); d6 = get_debugreg(6); d7 = get_debugreg(7); printf("DR6: %08lx DR7: %08lx\n", d6, d7); printf("Stack:\n"); sp = regs->esp; sp += 64; while (sp > (regs->esp - 16)) { if (sp == regs->esp) printf("--->"); else printf(" "); printf("0x%8.8lx : 0x%8.8lx\n", sp, (ulong)readl(sp)); sp -= 4; } }
/******************************************************************************* * Name: pf_handler * * Desc: High level page fault handling code. The low level page fault * interrupt handler is written in assembly. It'll setup the required * registers (faulted address in CR2) and the stack frame with the * error code. This routine is responsible for the following: * 1. Read the faulted address and lookup BS to find if this address is * mapped. If so, get the BS id and the offset within the BS. If * not, this is an illegal access - kill the process and move on. * 2. Actual paging starts here. Lookup the proctab to find the pid's * pdir base. From the faulted address, we can get the pdir offset. * Using these two, check if a page table exist for the faulted * address. If not create one. * 3. If the page table is presnet, get the ptbl offset from the * faulted vaddr. This points to the location of the page table * entry. Now, check if the frame assoicated with this page is * already present in the memory (shared pages). If so, update the * page table's 'pres' bit to reflect this and increment the * frame's refcount. If not, allocate a new frame and update the * page table entry to reflect that the frame is present. * 4. Processor caches the paging entries (TLB) maintained by software * and uses them whenever possible. When a pgt entry's 'pres' bit * is cleared, we need to flush the entry from the processor * cache so that the proceessor would use the updated software * data. This is described in detail in section 4.8 of Intel IA32 * software developer manual (vol 3). There are many ways to force * the processor to use the software tables, than hardware cache. * One such way is to reload teh CR0 register. So, if any of the * 'pres' bits are modified, we reload the CR0 register. * * Params: None. * * Returns: SYSCALL * OK - on success * SYSERR - on error ******************************************************************************/ SYSCALL pf_handler(void) { int bs_id = EMPTY; int bs_offset = EMPTY; int fr_id = EMPTY; uint32_t pdir_offset = 0; uint32_t ptbl_offset = 0; uint32_t page_offset = 0; uint32_t fault_addr = 0; pd_t *pdir = NULL; pt_t *ptbl = NULL; frm_map_t *frptr = NULL; frm_map_t *pt_frptr = NULL; virt_addr_t *fault_vaddr = NULL; STATWORD ps; disable(ps); DTRACE_START; DTRACE("DBG$ %d %s> inside high-level page fault handler\n", \ currpid, __func__); /* vaddr : pdir_offset : ptbl_offset : page_offset * 32 bits : 10 bits : 10 bits : 12 bits */ fault_addr = read_cr2(); /* The virtual address is 32-bits. So, we directly read the required set of * bits by assigining it to a strcutre with appropriate bit-fields. */ fault_vaddr = (virt_addr_t *) (&fault_addr); pdir_offset = (uint32_t) fault_vaddr->pd_offset; ptbl_offset = (uint32_t) fault_vaddr->pt_offset; page_offset = (uint32_t) fault_vaddr->pg_offset; DTRACE("DBG$ %d %s> faulted vaddr 0x%08x, vpage %d\n", \ currpid, __func__, fault_addr, VADDR_TO_VPAGE(fault_addr)); DTRACE("DBG$ %d %s> pd %d, pt %d, pg %d\n", \ currpid, __func__, pdir_offset, ptbl_offset, page_offset); /* Check the BS for a mapping for the faulted vaddr and the pid. If present, * record the BS id and the offset within the BS. If not present, it's * illeagal memory access. Kill the process and return. */ if (SYSERR == bsm_lookup(currpid, fault_addr, &bs_id, &bs_offset, NULL, NULL)) { DTRACE("DBG$ %d %s> bsm_lookup() failed\n", currpid, __func__); DTRACE("DBG$ %d %s> pid %d will be killed\n", \ currpid, __func__, currpid); kprintf("\n\n"); kprintf("FATAL ERROR: Process '%s' with pid '%d' is trying to access " \ "virtual memory out of its range! \nThe process will be " \ "terminated.\n", P_GET_PNAME(currpid), currpid); kprintf("\n\n"); sleep(9); DTRACE_END; restore(ps); kill(currpid); goto RESTORE_AND_RETURN_ERROR; } /* Get the currpid's page directory and index to the appropriate pgt. If pgt * isn't present, create one. */ pdir = P_GET_PDIR(currpid); if (FALSE == PD_GET_PRES(pdir, pdir_offset)) { DTRACE("DBG$ %d %s> pgt not present for pid %d, pd offset %d, " \ "pt offset %d, pg offset %d, vaddr 0x%08x\n", currpid, \ __func__, currpid, pdir_offset, ptbl_offset, page_offset, \ fault_addr); ptbl = new_pgt(); if (NULL == ptbl) { DTRACE("DBG$ %d %s> new_pgt() failed\n", currpid, __func__); goto RESTORE_AND_RETURN_ERROR; } /* Fill-in few meta-data for the pgt frame just created. */ pt_frptr = FR_GET_FPTR(FR_PA_TO_ID(ptbl)); pt_frptr->fr_pid = currpid; /* Set the 'pres' and 'write' bits alone. Rest would've been zeroed * out by new_pgt(). Also, set the base of the new page table. */ pdir[pdir_offset].pd_pres = 1; pdir[pdir_offset].pd_write = 1; pdir[pdir_offset].pd_base = VADDR_TO_VPAGE((unsigned) ptbl); } else { DTRACE("DBG$ %d %s> ptbl already present at 0x%08x, fr id %d\n", \ currpid, __func__, VPAGE_TO_VADDR(PD_GET_BASE(pdir, pdir_offset)),\ FR_PA_TO_ID(VPAGE_TO_VADDR(PD_GET_BASE(pdir, pdir_offset)))); } ptbl = (pt_t *) VPAGE_TO_VADDR(PD_GET_BASE(pdir, pdir_offset)); DTRACE("DBG$ %d %s> ptbl present at 0x%08x, fr id %d\n", \ currpid, __func__, ptbl, FR_PA_TO_ID(ptbl)); /* Find if a frame representing the same BS id and offset is present in the * memory (shared pages). If so, just update the page table entry and * increment teh refcount. */ if (EMPTY == (fr_id = is_frm_present(bs_id, bs_offset))) { DTRACE("DBG$ %d %s> frame not present.. creating a new frame\n", \ currpid, __func__); frptr = get_frm(FR_PAGE); if (NULL == frptr) { DTRACE("DBG$ %d %s> get_frm() failed\n", currpid, __func__); goto RESTORE_AND_RETURN_ERROR; } fr_id = frptr->fr_id; frm_pidmap_oper(fr_id, getpid(), FR_OP_PMAP_SET); frm_record_details(fr_id, getpid(), VADDR_TO_VPAGE(fault_addr)); /* Read the appropriate page from BS onto the new frame. */ if (SYSERR == read_bs((char *) FR_ID_TO_PA(fr_id), bs_id, bs_offset)) { DTRACE("DBG$ %d %s> read_bs() failed for fr id %d, bs %d, " \ "offset %d\n", currpid, __func__, fr_id, bs_id, bs_offset); goto RESTORE_AND_RETURN_ERROR; } else { DTRACE("DBG$ %d %s> reading for fr id %d, bs %d, offset %d\n", \ currpid, __func__, fr_id, bs_id, bs_offset); } /* Fill-in the new BS details in the frame. */ frptr->fr_type = FR_PAGE; frptr->fr_bs = bs_id; frptr->fr_bsoffset = bs_offset; inc_frm_refcount(fr_id); #ifdef DBG_ON print_frm_id(fr_id); #endif } else { /* A frame representing the same BS and offset is already present in the * memory. So, just increment the refcount of the frame. */ frm_pidmap_oper(fr_id, getpid(), FR_OP_PMAP_SET); frm_record_details(fr_id, getpid(), VADDR_TO_VPAGE(fault_addr)); inc_frm_refcount(fr_id); } /* In both cases (frame present and frame not present), we need to update * the page table entry as at this point, the frame is loaded onto the * memory. Do the following w.r.t. the pgt frame: * 1. Set the 'pres' bit in the page table entry corresponding to the * newly loaded page to reflect that the page is present in the * memory. * 2. Set the 'write' bit (as given in PA3 description). * 3. Update the 'base' of the page entry corresponding to the newly * created page to point to the frame. * 4. Increment the refcount of the pgt frame. Unlike data frames, where * refocunt denotes the # of processes that map to the actual * physical frame, pgt frame's refcount reflects the # of pages * (that are part of this pgt) that are present in the memory. * This will be decremented when a frame is paged out and the * pgt frame will be freed when the refcount reaches zero. */ ptbl[ptbl_offset].pt_pres = 1; ptbl[ptbl_offset].pt_write = 1; ptbl[ptbl_offset].pt_base = FR_ID_TO_VPAGE(fr_id); inc_frm_refcount(FR_PA_TO_ID(ptbl)); /* Reload the CR0 register would force the processor to flush the tables * that the processor maintains in hardware cache and to use the updated * software tables. */ enable_paging(); DTRACE("DBG$ %d %s> returning OK\n", currpid, __func__); DTRACE_END; restore(ps); return OK; RESTORE_AND_RETURN_ERROR: DTRACE("DBG$ %d %s> returning SYSERR\n", currpid, __func__); DTRACE_END; restore(ps); return SYSERR; }
/*------------------------------------------------------------------------- * pfint - paging fault ISR *------------------------------------------------------------------------- */ SYSCALL pfint() { STATWORD ps; disable(ps); unsigned long int eip = read_cr2(); //kprintf("\n\n#PF in %s, cr2:%x",proctab[currpid].pname, eip); unsigned long int pd_offset = eip >> 22; unsigned long int pt_offset = eip >>12; pt_offset = pt_offset & 1023; unsigned long offset = eip; offset = offset & 4095; //kprintf("\nEIP read is %lu\n",eip); eip = eip >> 12; //vpno //kprintf("\nEIP shifted is %lu\n",eip); int i = 0, flag = 0; int backing_store_page, bs_id; for(i = 0 ; i < NBS; i++) { if(proctab[currpid].map[i].pid == currpid) { //kprintf("\nif\n"); if(proctab[currpid].map[i].next == NULL) { //kprintf("\nif if\n"); if(proctab[currpid].map[i].vpno == eip) //we found the exact page { backing_store_page = proctab[currpid].map[i].base_page; flag = 1; //kprintf("\nif if if\n"); } else if(proctab[currpid].map[i].vpno < eip && (proctab[currpid].map[i].vpno+proctab[currpid].map[i].npages) >= eip) //we found the page in the range of base_page - npages { backing_store_page = proctab[currpid].map[i].base_page + eip - proctab[currpid].map[i].vpno; flag = 1; //kprintf("\nif if else if\n"); } } else { //kprintf("\nelse\n"); bs_map_t *jump = &(proctab[currpid].map[i]); while(jump != NULL) { //kprintf("\nwhile\n"); if(jump->vpno == eip) //we found the exact page { backing_store_page = jump->base_page; flag = 1; //kprintf("\nif else if\n"); break; } else if(jump->vpno < eip && (jump->npages+jump->vpno) >= eip) //we found the page in the range of base_page - npages { backing_store_page = jump->base_page + eip - jump->vpno; flag = 1; //kprintf("\nif else else if\n"); break; } jump = jump->next; } } } if(flag) { bs_id = i; break; } } //kprintf("\nin pfint bs %d, bs_page %d",bs_id,backing_store_page); unsigned long *bs_addr = (unsigned long *)(backing_store_page*NBPG); //populate page table //checking if page dir is empty pd_t *ptr1 = (pd_t *)(proctab[currpid].pdbr); //kprintf("\nbefore %d, %lu\n",ptr1,pd_offset); ptr1 += pd_offset; pt_t *ptr; if(ptr1->pd_pres == 1) //page table exists hence add entry to that { ptr = (pt_t *)((ptr1->pd_base)*NBPG); frm_tab[(ptr1->pd_base)-FRAME0].refcnt++; frm_map[(ptr1->pd_base)-FRAME0].fr_refcnt++; } else //we need to create a page table, add our free_frm entry to it and add the page table entry to the directory { //kprintf("\nin else %d\n",ptr1); int pt_frame = get_frm(); frm_tab[pt_frame-FRAME0].status = FRM_PGT; frm_tab[pt_frame-FRAME0].refcnt++; frm_map[pt_frame-FRAME0].fr_status = FRM_MAPPED; frm_map[pt_frame-FRAME0].fr_pid = currpid; frm_map[pt_frame-FRAME0].fr_refcnt++; frm_map[pt_frame-FRAME0].fr_type = FR_TBL; ptr = (pt_t*)(pt_frame*NBPG); //add the above table to page directory ptr1->pd_pres = 1; ptr1->pd_write = 1; ptr1->pd_user = 0; ptr1->pd_pwt = 0; ptr1->pd_pcd = 0; ptr1->pd_acc = 0; ptr1->pd_mbz = 0; ptr1->pd_fmb = 0; ptr1->pd_global = 0; ptr1->pd_avail = 0; ptr1->pd_base = pt_frame; //kprintf("\nget_frm return frame %d. To be page table for process %s",pt_frame, proctab[currpid].pname); } //add entry to page table ptr += pt_offset; ptr->pt_pres = 1; ptr->pt_write = 1; ptr->pt_user = 0; ptr->pt_pwt = 0; ptr->pt_pcd = 0; ptr->pt_acc = 0; ptr->pt_dirty = 0; ptr->pt_mbz = 0; ptr->pt_global = 0; ptr->pt_avail = 0; //getting a free frame an setting the frame mappings int free_frm; if(ni_page_table[backing_store_page-total_bs_left] != -1) // if backing store is already mapped then we share the frame { free_frm = ni_page_table[backing_store_page-total_bs_left]; //kprintf("\nIN NI frm = %d, ni = %d\n",free_frm, ni_page_table[backing_store_page-total_bs_left]); frm_map[free_frm-FRAME0].fr_refcnt++; frm_tab[free_frm-FRAME0].refcnt++; //adding this vpno and pid to the shared frame map list fr_map_t *map = (fr_map_t *)getmem(sizeof(fr_map_t)); map->fr_pid = currpid; map->fr_vpno = eip; map->shared = NULL; fr_map_t *next = (fr_map_t *)getmem(sizeof(fr_map_t)); next = &(frm_map[free_frm-FRAME0]); while(next->shared != NULL) next = next->shared; next->shared = map; //printing the list /*kprintf("\nSHARED VPNO: "); next = &(frm_map[free_frm-FRAME0]); while(next != NULL) { kprintf("%d -> ",next->fr_vpno); next = next->shared; }*/ } else { free_frm = get_frm(); frm_tab[free_frm-FRAME0].status = FRM_BS; frm_tab[free_frm-FRAME0].refcnt++; frm_tab[free_frm-FRAME0].bs = bs_id; frm_tab[free_frm-FRAME0].bs_page = backing_store_page; frm_tab[free_frm-FRAME0].bs_next = NULL; frm_tab[free_frm-FRAME0].fifo = NULL; frm_tab[free_frm-FRAME0].age = 128; frm_map[free_frm-FRAME0].fr_status = FRM_MAPPED; frm_map[free_frm-FRAME0].fr_pid = currpid; frm_map[free_frm-FRAME0].fr_vpno = eip; frm_map[free_frm-FRAME0].fr_refcnt++; frm_map[free_frm-FRAME0].fr_type = FR_PAGE; frm_map[free_frm-FRAME0].bs_page_num = backing_store_page; ni_page_table[backing_store_page-total_bs_left] = free_frm; //set bs mappings if(bs_tab[bs_id].frm == NULL) bs_tab[bs_id].frm = &frm_tab[free_frm-FRAME0]; else { //frame_t *jump = &frm_tab[free_frm-FRAME0]; frame_t *jump = (frame_t *)getmem(sizeof(frame_t)); jump = bs_tab[bs_id].frm; while(jump->bs_next != NULL) { jump = jump->bs_next; //kprintf("\njumping\n"); } jump->bs_next = &frm_tab[free_frm-FRAME0]; } //adding this frame to the fifo queue if(fifo_head == NULL) { //queue is empty fifo_head = &frm_tab[free_frm-FRAME0]; fifo_tail = fifo_head; } else { fifo_tail->fifo = &frm_tab[free_frm-FRAME0]; fifo_tail = &frm_tab[free_frm-FRAME0]; } } //kprintf("\nget_frm return frame %d.", free_frm); unsigned long *dst_addr = (unsigned long *)(free_frm*NBPG); //kprintf("\n\n Virtual page %d mapped to bs page %d, bs id %d, mapped to frame %d, %lu",eip, backing_store_page, bs_id, free_frm,dst_addr); /*frame_t *next = fifo_head; kprintf("\nFIFO : "); while(next != NULL) { kprintf("%d-> ",next->frame_num); next = next->fifo; } kprintf("\n");*/ //copy page from bs to phy for(i = 0; i < NBPG/sizeof(unsigned long); i++) { *dst_addr = *bs_addr; dst_addr++; bs_addr++; } ptr->pt_base = free_frm; restore(ps); //kprintf("\nmap bs%d/page: %d to frame %d",bs_id, (backing_store_page-proctab[currpid].map[bs_id].base_page), free_frm); return OK; }
/*------------------------------------------------------------------------- * pfint - paging fault ISR *------------------------------------------------------------------------- */ SYSCALL pfint() { STATWORD ps; disable(ps); int store, pageth; unsigned long vaddr = read_cr2(); unsigned int p_offset = (vaddr & 0xFFC00000) >> 22; unsigned int q_offset = (vaddr & 0x3FF000) >> 12; bsm_lookup(currpid, vaddr, &store, &pageth); frame_t *frame_backing_store = obtain_frame(); bs_tab[store].pg_to_frm_map[pageth] = frame_backing_store->frm_num; frame_backing_store->bs = store; frame_backing_store->bs_page = pageth; frame_backing_store->status = FRM_BS; frame_backing_store->fr_type = FR_PAGE; read_bs((char *)(frame_backing_store->frm_num * 4096), store, pageth ); frame_t * obtained_free_frame = frame_backing_store; // unsigned long pdbr = add_pg_dir_entry_for_pg_fault(currpid, p_offset, q_offset, obtained_free_frame); unsigned long page_to_frame; int avail = 0; struct pentry *pptr = &proctab[currpid]; frame_t *directory = pptr->pd; pd_t *table_descriptor = (pd_t *) ((4096 * directory->frm_num) + p_offset * sizeof(pd_t)); if (table_descriptor->pd_pres == 1) { frame_t *page_frame; int i = 0; for (i = 0; i < NFRAMES; i++) { if (frm_tab[i].frm_num == table_descriptor->pd_base) { page_frame= &frm_tab[i]; } } pt_t *offset_value = (pt_t *) (4096 * page_frame->frm_num ); offset_value =offset_value+q_offset; pt_t ptr; ptr.pt_pres = 1; ptr.pt_write = 1; ptr.pt_user = 0; ptr.pt_pwt = 0; ptr.pt_pcd = 0; ptr.pt_acc = 0; ptr.pt_dirty = 0; ptr.pt_mbz = 0; ptr.pt_global = 0; ptr.pt_avail = 0; ptr.pt_base = obtained_free_frame->frm_num; *offset_value = ptr; } else { frame_t *page_frame = obtain_frame(); page_frame->status = FRM_PGT; page_frame->fr_type = FRM_PGT; page_frame->fr_pid = currpid; pd_t *table_descriptor = (pd_t *) (4096 * directory->frm_num); table_descriptor =table_descriptor+p_offset; pd_t ptr1; ptr1.pd_pres = 1; ptr1.pd_write = 1; ptr1.pd_user = 0; ptr1.pd_pwt = 0; ptr1.pd_pcd = 0; ptr1.pd_acc = 0; ptr1.pd_mbz = 0; ptr1.pd_fmb = 0; ptr1.pd_global = 0; ptr1.pd_avail = 0; ptr1.pd_base = page_frame->frm_num; *table_descriptor = ptr1; pt_t *offset_value = (pt_t *) (4096 * page_frame->frm_num ); offset_value =offset_value+q_offset; pt_t ptr; ptr.pt_pres = 1; ptr.pt_write = 1; ptr.pt_user = 0; ptr.pt_pwt = 0; ptr.pt_pcd = 0; ptr.pt_acc = 0; ptr.pt_dirty = 0; ptr.pt_mbz = 0; ptr.pt_global = 0; ptr.pt_avail = 0; ptr.pt_base = obtained_free_frame->frm_num; *offset_value = ptr; page_to_frame = page_frame->frm_num ; } unsigned long pdbr= pptr->pdbr; struct pentry *pptr1 = &proctab[currpid]; bs_map_t *map = &(pptr1->map[store]); if(map->frm == NULL) map->frm = obtained_free_frame; else{ frame_t *tmp = map->frm; while(tmp->bs_next != NULL) tmp = tmp->bs_next; tmp->bs_next = obtained_free_frame; } obtained_free_frame->fr_vpno = map->vpno + obtained_free_frame->bs_page; obtained_free_frame->fr_pid = currpid; write_cr3(pdbr * NBPG); restore(ps); return OK; }