-
Notifications
You must be signed in to change notification settings - Fork 246
/
attached_ram_dataspace.h
155 lines (129 loc) · 3.87 KB
/
attached_ram_dataspace.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
/*
* \brief RAM dataspace utility
* \author Norman Feske
* \date 2008-03-22
*/
/*
* Copyright (C) 2008-2013 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _INCLUDE__OS__ATTACHED_RAM_DATASPACE_H_
#define _INCLUDE__OS__ATTACHED_RAM_DATASPACE_H_
#include <ram_session/ram_session.h>
#include <util/touch.h>
#include <base/env.h>
namespace Genode { class Attached_ram_dataspace; }
/*
* Utility for allocating and attaching a RAM dataspace
*
* The combination of RAM allocation and a local RM attachment is a frequent
* use case. Each function may fail, which makes error handling inevitable.
* This utility class encapsulates this functionality to handle both operations
* as a transaction. When embedded as a member, this class also takes care
* about freeing and detaching the dataspace at destruction time.
*/
class Genode::Attached_ram_dataspace
{
private:
size_t _size;
Ram_session *_ram_session;
Ram_dataspace_capability _ds;
void *_local_addr;
Cache_attribute const _cached;
template <typename T>
static void _swap(T &v1, T &v2) { T tmp = v1; v1 = v2; v2 = tmp; }
void _detach_and_free_dataspace()
{
if (_local_addr)
env()->rm_session()->detach(_local_addr);
if (_ram_session && _ds.valid())
_ram_session->free(_ds);
}
void _alloc_and_attach()
{
if (!_size || !_ram_session) return;
try {
_ds = _ram_session->alloc(_size, _cached);
_local_addr = env()->rm_session()->attach(_ds);
/* revert allocation if attaching the dataspace failed */
} catch (Rm_session::Attach_failed) {
_ram_session->free(_ds);
throw;
}
/*
* Eagerly map dataspace if used for DMA
*
* On some platforms, namely Fiasco.OC on ARMv7, the handling
* of page faults interferes with the caching attributes used
* for uncached DMA memory. See issue #452 for more details
* (https://github.com/genodelabs/genode/issues/452). As a
* work-around for this issues, we eagerly map the whole
* dataspace before writing actual content to it.
*/
if (_cached != CACHED) {
enum { PAGE_SIZE = 4096 };
unsigned char volatile *base = (unsigned char volatile *)_local_addr;
for (size_t i = 0; i < _size; i += PAGE_SIZE)
touch_read_write(base + i);
}
}
public:
/**
* Constructor
*
* \throw Ram_session::Alloc_failed
* \throw Rm_session::Attach_failed
*/
Attached_ram_dataspace(Ram_session *ram_session, size_t size,
Cache_attribute cached = CACHED)
:
_size(size), _ram_session(ram_session), _local_addr(0),
_cached(cached)
{
_alloc_and_attach();
}
/**
* Destructor
*/
~Attached_ram_dataspace() { _detach_and_free_dataspace(); }
/**
* Return capability of the used RAM dataspace
*/
Ram_dataspace_capability cap() const { return _ds; }
/**
* Request local address
*
* This is a template to avoid inconvenient casts at
* the caller. A newly allocated RAM dataspace is
* untyped memory anyway.
*/
template <typename T>
T *local_addr() const { return static_cast<T *>(_local_addr); }
/**
* Return size
*/
size_t size() const { return _size; }
void swap(Attached_ram_dataspace &other)
{
_swap(_size, other._size);
_swap(_ram_session, other._ram_session);
_swap(_ds, other._ds);
_swap(_local_addr, other._local_addr);
}
/**
* Re-allocate dataspace with a new size
*
* The content of the original dataspace is not retained.
*/
void realloc(Ram_session *ram_session, size_t new_size)
{
if (new_size < _size) return;
_detach_and_free_dataspace();
_size = new_size;
_ram_session = ram_session;
_alloc_and_attach();
}
};
#endif /* _INCLUDE__OS__ATTACHED_RAM_DATASPACE_H_ */