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