user_memory.h revision 95e97463
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
17namespace {
18
19
20struct 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
43template<typename Function>
44bool 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	dprintf("Hi! This is fault handler speaking.\n");
57	return false;
58}
59
60
61inline status_t
62arch_cpu_user_memcpy(void* src, const void* dst, size_t n)
63{
64	return user_access([=] { memcpy(src, dst, n); }) ? B_OK : B_ERROR;
65}
66
67
68inline status_t
69arch_cpu_user_memset(void* src, char v, size_t n)
70{
71	return user_access([=] { memset(src, v, n); }) ? B_OK : B_ERROR;
72}
73
74
75inline ssize_t
76arch_cpu_user_strlcpy(char* src, const char* dst, size_t n)
77{
78	ssize_t result;
79	return user_access([=, &result] { result = strlcpy(src, dst, n); })
80		? result : B_ERROR;
81}
82
83}
84
85#endif	// _KERNEL_ARCH_GENERIC_USER_MEMORY_H
86
87