void thread_impl_t::start_exception_handler(exception_stack_frame& info) { if (0) { dprintf("ExceptionCode %08lx\n", info.rec.ExceptionCode); dprintf("ExceptionFlags %08lx\n", info.rec.ExceptionFlags); dprintf("ExceptionRecord %p\n", info.rec.ExceptionRecord); dprintf("ExceptionAddress %p\n", info.rec.ExceptionAddress); dprintf("NumberParameters %ld\n", info.rec.NumberParameters); } if (send_exception( this, info.rec )) return; info.ctx.ContextFlags = context_all; info.ctx.SegCs &= 0xffff; info.ctx.SegEs &= 0xffff; info.ctx.SegSs &= 0xffff; info.ctx.SegDs &= 0xffff; info.ctx.SegFs &= 0xffff; info.ctx.SegGs &= 0xffff; // hack to stop looping if (info.ctx.Eip & 0x80000000) { dprintf("Eip invalid %08lx\n", info.ctx.Eip); terminate(STATUS_ACCESS_VIOLATION); return; } // push the context, exception record and KiUserExceptionDispatcher args exception_stack_frame *stack = (exception_stack_frame*)((BYTE*) ctx.Esp - sizeof info); info.pctx = &stack->ctx; info.prec = &stack->rec; ctx.Esp = (LONG) stack; NTSTATUS r = copy_to_user( stack, &info, sizeof info ); if (r < STATUS_SUCCESS) { dprintf("%04lx: invalid stack handling exception at %08lx\n", id, ctx.Eip); terminate(r); return; } // get the address of the user side handler // FIXME: this should be stored in the process_t structure BYTE *pKiExceptionDispatcher = (BYTE*)process->pntdll + get_proc_address( ntdll_section, "KiUserExceptionDispatcher" ); if (!pKiExceptionDispatcher) die("failed to find KiExceptionDispatcher in ntdll\n"); context_changed = 1; ctx.Eip = (ULONG) pKiExceptionDispatcher; }
PRIVATE inline int Thread::handle_io_page_fault(Trap_state *ts) { Address eip = ts->ip(); if (!check_io_bitmap_delimiter_fault(ts)) return 0; // Check for IO page faults. If we got exception #14, the IO bitmap page is // not available. If we got exception #13, the IO bitmap is available but // the according bit is set. In both cases we have to dispatch the code at // the faulting eip to deterine the IO port and send an IO flexpage to our // pager. If it was a page fault, check the faulting address to prevent // touching userland. if (eip < Kmem::mem_user_max && (ts->_trapno == 13 && (ts->_err & 7) == 0 || ts->_trapno == 14 && Kmem::is_io_bitmap_page_fault(ts->_cr2))) { unsigned port, size; if (get_ioport(eip, ts, &port, &size)) { Mword io_page = L4_fpage::io(port, size).raw(); // set User mode flag to get correct IP in handle_page_fault_pager // pretend a write page fault static const unsigned io_error_code = PF_ERR_WRITE | PF_ERR_USERMODE; CNT_IO_FAULT; if (EXPECT_FALSE (log_page_fault())) page_fault_log(io_page, io_error_code, eip); // treat it as a page fault in the region above 0xf0000000, // We could also reset the Thread_cancel at slowtraps entry but it // could be harmful for debugging (see also comment at slowtraps:). // // This must be done while interrupts are off to prevent that an // other thread sets the flag again. state_del(Thread_cancel); // set cr2 in ts so that we also get the io_page value in an // consecutive exception ts->_cr2 = io_page; if (EXPECT_FALSE(state() & Thread_alien)) { // special case for alien tasks: Don't generate pagefault but // send (pagefault) exception to pager. ts->_trapno = 14; if (send_exception(ts)) return 1; else return 2; // fail, don't send exception again } bool ipc_code = handle_page_fault_pager(_pager, io_page, io_error_code, L4_msg_tag::Label_io_page_fault); if (ipc_code) return 1; } } return 0; // fail }