Пример #1
0
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
}