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