Files
haiku-beta6/headers/private/kernel/arch/generic/user_memory.h
T
Augustin Cavalier 6f88de113d kernel: Rename set/clear_ac to arch_cpu_enable/disable_user_access.
These are architecture-specific routines, so they deserve proper
architecture-specific naming. The user memory access routines are
already under arch_cpu (arch_cpu_user_memcpy, etc.), and the methods
usually change a CPU flag, so it makes sense to put these there too.

RISC-V had get_ac but nothing else defined or used it, so it's removed.

No functional change intended.

Change-Id: Id4715214e32f73d4a93bc7ba8249411a0878d174
Reviewed-on: https://review.haiku-os.org/c/haiku/+/8106
Reviewed-by: waddlesplash <[email protected]>
Reviewed-by: X512 X512 <[email protected]>
Reviewed-by: Jérôme Duval <[email protected]>
Tested-by: Commit checker robot <[email protected]>
2024-08-26 19:39:28 +00:00

104 lines
2.2 KiB
C++

/*
* Copyright 2018, Jérôme Duval, [email protected].
* Copyright 2014, Paweł Dziepak, [email protected].
* Distributed under the terms of the MIT License.
*/
#ifndef _KERNEL_ARCH_GENERIC_USER_MEMORY_H
#define _KERNEL_ARCH_GENERIC_USER_MEMORY_H
#include <atomic>
#include <setjmp.h>
#include <string.h>
#include <thread.h>
namespace {
struct FaultHandlerGuard {
FaultHandlerGuard()
{
old_handler = thread_get_current_thread()->fault_handler;
if (old_handler != nullptr) {
memcpy(old_handler_state,
thread_get_current_thread()->fault_handler_state,
sizeof(jmp_buf));
}
thread_get_current_thread()->fault_handler = HandleFault;
std::atomic_signal_fence(std::memory_order_acq_rel);
}
~FaultHandlerGuard()
{
std::atomic_signal_fence(std::memory_order_acq_rel);
thread_get_current_thread()->fault_handler = old_handler;
if (old_handler != nullptr) {
memcpy(thread_get_current_thread()->fault_handler_state,
old_handler_state,
sizeof(jmp_buf));
}
}
[[noreturn]] static void HandleFault()
{
longjmp(thread_get_current_thread()->fault_handler_state, 1);
}
void (*old_handler)(void);
jmp_buf old_handler_state;
};
template<typename Function>
bool user_access(Function function)
{
FaultHandlerGuard guard;
// TODO: try { } catch (...) { } would be much nicer, wouldn't it?
// And faster... And world wouldn't end in a terrible disaster if function()
// or anything it calls created on stack an object with non-trivial
// destructor.
auto fail = setjmp(thread_get_current_thread()->fault_handler_state);
if (fail == 0) {
arch_cpu_enable_user_access();
function();
arch_cpu_disable_user_access();
return true;
}
arch_cpu_disable_user_access();
return false;
}
inline status_t
arch_cpu_user_memcpy(void* src, const void* dst, size_t n)
{
return user_access([=] { memcpy(src, dst, n); }) ? B_OK : B_ERROR;
}
inline status_t
arch_cpu_user_memset(void* src, char v, size_t n)
{
return user_access([=] { memset(src, v, n); }) ? B_OK : B_ERROR;
}
inline ssize_t
arch_cpu_user_strlcpy(char* src, const char* dst, size_t n)
{
ssize_t result;
return user_access([=, &result] { result = strlcpy(src, dst, n); })
? result : B_ERROR;
}
}
#endif // _KERNEL_ARCH_GENERIC_USER_MEMORY_H