xref: /haiku/headers/private/kernel/arch/generic/user_memory.h (revision 778611c7e6a61b8ba072212756ce53eda826360a)
1 /*
2  * Copyright 2014, Paweł Dziepak, pdziepak@quarnos.org.
3  * Distributed under the terms of the MIT License.
4  */
5 #ifndef _KERNEL_ARCH_GENERIC_USER_MEMORY_H
6 #define _KERNEL_ARCH_GENERIC_USER_MEMORY_H
7 
8 
9 #include <atomic>
10 
11 #include <setjmp.h>
12 #include <string.h>
13 
14 #include <thread.h>
15 
16 
17 namespace {
18 
19 
20 struct FaultHandlerGuard {
21 	FaultHandlerGuard()
22 	{
23 		ASSERT(thread_get_current_thread()->fault_handler == nullptr);
24 		thread_get_current_thread()->fault_handler = HandleFault;
25 		std::atomic_signal_fence(std::memory_order_acq_rel);
26 	}
27 
28 
29 	~FaultHandlerGuard()
30 	{
31 		std::atomic_signal_fence(std::memory_order_acq_rel);
32 		thread_get_current_thread()->fault_handler = nullptr;
33 	}
34 
35 
36 	[[noreturn]] static void HandleFault()
37 	{
38 		longjmp(thread_get_current_thread()->fault_handler_state, 1);
39 	}
40 };
41 
42 
43 template<typename Function>
44 bool user_access(Function function)
45 {
46 	FaultHandlerGuard guard;
47 	// TODO: try { } catch (...) { } would be much nicer, wouldn't it?
48 	// And faster... And world wouldn't end in a terrible disaster if function()
49 	// or anything it calls created on stack an object with non-trivial
50 	// destructor.
51 	auto fail = setjmp(thread_get_current_thread()->fault_handler_state);
52 	if (fail == 0) {
53 		function();
54 		return true;
55 	}
56 	return false;
57 }
58 
59 
60 inline status_t
61 arch_cpu_user_memcpy(void* src, const void* dst, size_t n)
62 {
63 	return user_access([=] { memcpy(src, dst, n); }) ? B_OK : B_ERROR;
64 }
65 
66 
67 inline status_t
68 arch_cpu_user_memset(void* src, char v, size_t n)
69 {
70 	return user_access([=] { memset(src, v, n); }) ? B_OK : B_ERROR;
71 }
72 
73 
74 inline ssize_t
75 arch_cpu_user_strlcpy(char* src, const char* dst, size_t n)
76 {
77 	ssize_t result;
78 	return user_access([=, &result] { result = strlcpy(src, dst, n); })
79 		? result : B_ERROR;
80 }
81 
82 }
83 
84 #endif	// _KERNEL_ARCH_GENERIC_USER_MEMORY_H
85 
86