[RFC 6/6] Catch unhandled page faults in vm86 mode.

Jan Klötzke <[email protected]> Tue, 29 Apr 2008 00:45:59 +0200
Newsgroups gmane.os.openbeos.kernel.devel
Message-ID <[email protected]>
* Add a "fault_callback" to the thread structure which is called when a
  unhandled page fault happens in user space. A SIGSEGV will only be sent if
  the callback return "true".
* Use fault_callback mechanism to return from vm86 mode when a unhandled page
  fault happens in vm86 mode.
---
 headers/private/kernel/thread_types.h |    4 ++++
 src/system/kernel/arch/x86/vm86.c     |   24 ++++++++++++++++++++----
 src/system/kernel/thread.cpp          |    1 +
 src/system/kernel/vm/vm.cpp           |    8 ++++++--
 4 files changed, 31 insertions(+), 6 deletions(-)

diff --git a/headers/private/kernel/thread_types.h b/headers/private/kernel/thread_types.h
index ac3240e..c8b8424 100644
--- a/headers/private/kernel/thread_types.h
+++ b/headers/private/kernel/thread_types.h
@@ -214,6 +214,9 @@ struct team {
 
 typedef int32 (*thread_entry_func)(thread_func, void *);
 
+typedef bool (*page_fault_callback)(addr_t address, addr_t faultAddress,
+	bool isWrite);
+
 struct thread {
 	int32			flags;			// summary of events relevant in interrupt
 									// handlers (signals pending, user debugging
@@ -264,6 +267,7 @@ struct thread {
 	} msg;
 
 	addr_t			fault_handler;
+	page_fault_callback fault_callback;
 	int32			page_faults_allowed;
 		/* this field may only stay in debug builds in the future */
 
diff --git a/src/system/kernel/arch/x86/vm86.c b/src/system/kernel/arch/x86/vm86.c
index d8737e9..6cde8f4 100644
--- a/src/system/kernel/arch/x86/vm86.c
+++ b/src/system/kernel/arch/x86/vm86.c
@@ -511,6 +511,19 @@ emulate(struct vm86_state *state)
 }
 
 
+static bool
+vm86_fault_callback(addr_t address, addr_t faultAddress, bool isWrite)
+{
+	struct iframe *frame = i386_get_user_iframe();
+
+	// we shouldn't have unhandled page faults in vm86 mode
+	x86_vm86_return((struct vm86_iframe *)frame, B_BAD_ADDRESS);
+
+	// not reached
+	return false;
+}
+
+
 status_t
 vm86_prepare(struct vm86_state *state, unsigned int ram_size)
 {
@@ -586,6 +599,8 @@ vm86_do_int(struct vm86_state *state, uint8 vec)
 {
 	int8 *ip;
 	int emu_state;
+	struct thread *thread = thread_get_current_thread();
+	status_t ret;
 
 	// prepare environment
 	state->regs.ss  = 0x600 >> 4;
@@ -603,14 +618,15 @@ vm86_do_int(struct vm86_state *state, uint8 vec)
     *ip++ = RETURN_TO_32_INT;
 
 	// execute interrupt
+	thread->fault_callback = &vm86_fault_callback;
 	do {
-		if (x86_vm86_enter(&state->regs) != B_OK) {
-			emu_state = -1;
+		ret = x86_vm86_enter(&state->regs);
+		if (ret != B_OK)
 			break;
-		}
 		emu_state = emulate(state);
 	} while (emu_state == 0);
+	thread->fault_callback = NULL;
 
-	return (emu_state > 0) ? B_OK : B_BAD_DATA;
+	return (emu_state > 0) ? ret : B_BAD_DATA;
 }
 
diff --git a/src/system/kernel/thread.cpp b/src/system/kernel/thread.cpp
index ad397db..466dedf 100644
--- a/src/system/kernel/thread.cpp
+++ b/src/system/kernel/thread.cpp
@@ -226,6 +226,7 @@ create_thread_struct(struct thread *inthread, const char *name,
 	thread->team = NULL;
 	thread->cpu = cpu;
 	thread->fault_handler = 0;
+	thread->fault_callback = NULL;
 	thread->page_faults_allowed = 1;
 	thread->kernel_stack_area = -1;
 	thread->kernel_stack_base = 0;
diff --git a/src/system/kernel/vm/vm.cpp b/src/system/kernel/vm/vm.cpp
index e14f898..3ab7ad0 100644
--- a/src/system/kernel/vm/vm.cpp
+++ b/src/system/kernel/vm/vm.cpp
@@ -3840,8 +3840,12 @@ vm_page_fault(addr_t address, addr_t faultAddress, bool isWrite, bool isUser,
 			release_sem_etc(addressSpace->sem, READ_COUNT, 0);
 			vm_put_address_space(addressSpace);
 #endif
-			if (user_debug_exception_occurred(B_SEGMENT_VIOLATION, SIGSEGV))
-				send_signal(team_get_current_team_id(), SIGSEGV);
+			struct thread *thread = thread_get_current_thread();
+			if (thread->fault_callback == NULL || thread->fault_callback(
+				address, faultAddress, isWrite)) {
+				if (user_debug_exception_occurred(B_SEGMENT_VIOLATION, SIGSEGV))
+					send_signal(team_get_current_team_id(), SIGSEGV);
+			}
 		}
 	}
 
-- 
1.5.4.2


-------------------------------------------------------------------------
This SF.net email is sponsored by the 2008 JavaOne(SM) Conference 
Don't miss this year's exciting event. There's still time to save $100. 
Use priority code J8TL2D2. 
http://ad.doubleclick.net/clk;198757673;13503038;p?http://java.sun.com/javaone