L4Re Operating System Framework
Interface and Usage Documentation
Loading...
Searching...
No Matches
region_mapping
Go to the documentation of this file.
1// -*- Mode: C++ -*-
2// vim:ft=cpp
7/*
8 * (c) 2008-2009 Adam Lackorzynski <adam@os.inf.tu-dresden.de>,
9 * Alexander Warg <warg@os.inf.tu-dresden.de>,
10 * Björn Döbel <doebel@os.inf.tu-dresden.de>
11 * economic rights: Technische Universität Dresden (Germany)
12 *
13 * License: see LICENSE.spdx (in this directory or the directories above)
14 */
15
16#pragma once
17
18#include <l4/cxx/avl_map>
19#include <l4/sys/types.h>
20#include <l4/re/rm>
21
22namespace L4Re { namespace Util {
23
24class Region
25{
26private:
27 l4_addr_t _start, _end;
28#ifdef CONFIG_L4RE_REGION_INFO
29 char _dbg_name[40]; // Not a 0-terminating string
30 unsigned char _dbg_name_len = 0;
31 static_assert(sizeof(_dbg_name) < 256);
32 Rm::Offset _dbg_backing_offset = 0;
33#endif
34
35public:
36 Region() noexcept : _start(~0UL), _end(~0UL) {}
37 Region(l4_addr_t addr) noexcept : _start(addr), _end(addr) {}
38 Region(l4_addr_t start, l4_addr_t end) noexcept
39 : _start(start), _end(end) {}
40 Region(l4_addr_t start, l4_addr_t end,
41 char const *name, unsigned name_len,
42 Rm::Offset backing_offset) noexcept
43 : _start(start), _end(end)
44 {
45#ifdef CONFIG_L4RE_REGION_INFO
46 _dbg_name_len = name_len > sizeof(_dbg_name)
47 ? sizeof(_dbg_name) : name_len;
48 for (unsigned i = 0; i < _dbg_name_len; ++i)
49 _dbg_name[i] = name[i];
50
51 _dbg_backing_offset = backing_offset;
52#else
53 (void)name;
54 (void)name_len;
55 (void)backing_offset;
56#endif
57 }
58 l4_addr_t start() const noexcept { return _start; }
59 l4_addr_t end() const noexcept { return _end; }
60 unsigned long size() const noexcept { return end() - start() + 1; }
61 bool invalid() const noexcept { return _start == ~0UL && _end == ~0UL; }
62 bool operator < (Region const &o) const noexcept
63 { return end() < o.start(); }
64 bool contains(Region const &o) const noexcept
65 { return o.start() >= start() && o.end() <= end(); }
66 bool operator == (Region const &o) const noexcept
67 { return o.start() == start() && o.end() == end(); }
68 ~Region() noexcept {}
69
70#ifdef CONFIG_L4RE_REGION_INFO
71 char const *name() const { return _dbg_name; }
72 unsigned char name_len() const { return _dbg_name_len; }
73 Rm::Offset backing_offset() const { return _dbg_backing_offset; }
74#else
75 char const *name() const { return "N/A"; }
76 unsigned char name_len() const { return 3; }
77 Rm::Offset backing_offset() const { return 0; }
78#endif
79};
80
81
82template< typename Hdlr, template<typename T> class Alloc >
83class Region_map
84{
85protected:
86 typedef cxx::Avl_map<Region, Hdlr, cxx::Lt_functor, Alloc> Tree;
87
88 Tree _rm;
89 Tree _am;
90
91private:
92 l4_addr_t _start;
93 l4_addr_t _end;
94
95protected:
96 void set_limits(l4_addr_t start, l4_addr_t end) noexcept
97 {
98 _start = start;
99 _end = end;
100 }
101
102public:
103 typedef typename Tree::Item_type Item;
104 typedef typename Tree::Node Node;
105 typedef typename Tree::Key_type Key_type;
106 typedef Hdlr Region_handler;
107
108 typedef typename Tree::Iterator Iterator;
109 typedef typename Tree::Const_iterator Const_iterator;
110 typedef typename Tree::Rev_iterator Rev_iterator;
111 typedef typename Tree::Const_rev_iterator Const_rev_iterator;
112
113 Iterator begin() noexcept { return _rm.begin(); }
114 Const_iterator begin() const noexcept { return _rm.begin(); }
115 Iterator end() noexcept { return _rm.end(); }
116 Const_iterator end() const noexcept { return _rm.end(); }
117
118 Iterator area_begin() noexcept { return _am.begin(); }
119 Const_iterator area_begin() const noexcept { return _am.begin(); }
120 Iterator area_end() noexcept { return _am.end(); }
121 Const_iterator area_end() const noexcept { return _am.end(); }
122 Node area_find(Key_type const &c) const noexcept { return _am.find_node(c); }
123
124 l4_addr_t min_addr() const noexcept { return _start; }
125 l4_addr_t max_addr() const noexcept { return _end; }
126
127 Region_map(l4_addr_t start, l4_addr_t end) noexcept : _start(start), _end(end) {}
128
129 Node find(Key_type const &key) const noexcept
130 {
131 Node n = _rm.find_node(key);
132 if (!n)
133 return Node();
134
135 // 'find' should find any region overlapping with the searched one, the
136 // caller should check for further requirements
137 if (0)
138 if (!n->first.contains(key))
139 return Node();
140
141 return n;
142 }
143
144 Node lower_bound(Key_type const &key) const noexcept
145 {
146 Node n = _rm.lower_bound_node(key);
147 return n;
148 }
149
150 Node lower_bound_area(Key_type const &key) const noexcept
151 {
152 Node n = _am.lower_bound_node(key);
153 return n;
154 }
155
156 l4_addr_t attach_area(l4_addr_t addr, unsigned long size,
157 L4Re::Rm::Flags flags = L4Re::Rm::Flags(0),
158 unsigned char align = L4_PAGESHIFT) noexcept
159 {
160 if (size < 2)
161 return L4_INVALID_ADDR;
162
163 Region c;
164
165 if (!(flags & L4Re::Rm::F::Search_addr))
166 {
167 c = Region(addr, addr + size - 1);
168 Node r = _am.find_node(c);
169 if (r)
170 return L4_INVALID_ADDR;
171 }
172
173 while (flags & L4Re::Rm::F::Search_addr)
174 {
175 if (addr < min_addr() || (addr + size - 1) > max_addr())
176 addr = min_addr();
177
178 addr = find_free(addr, max_addr(), size, align, flags);
179 if (addr == L4_INVALID_ADDR)
180 return L4_INVALID_ADDR;
181
182 c = Region(addr, addr + size - 1);
183 Node r = _am.find_node(c);
184 if (!r)
185 break;
186
187 if (r->first.end() >= max_addr())
188 return L4_INVALID_ADDR;
189
190 addr = r->first.end() + 1;
191 }
192
193 if (_am.insert(c, Hdlr(typename Hdlr::Dataspace(), 0, 0, flags.region_flags())).second == 0)
194 return addr;
195
196 return L4_INVALID_ADDR;
197 }
198
199 bool detach_area(l4_addr_t addr) noexcept
200 {
201 if (_am.remove(addr))
202 return false;
203
204 return true;
205 }
206
207 void *attach(void *addr, unsigned long size, Hdlr const &hdlr,
208 L4Re::Rm::Flags attach_flags = L4Re::Rm::Flags(0),
209 unsigned char align = L4_PAGESHIFT,
210 char const *name = nullptr, unsigned name_len = 0,
211 L4Re::Rm::Offset backing_offset = 0) noexcept
212 {
213 if (size < 2)
214 return L4_INVALID_PTR;
215
216 l4_addr_t beg, end;
217 int err = hdlr.map_info(&beg, &end);
218 if (err > 0)
219 {
220 // Mapping address determined by underlying dataspace. Make sure we
221 // prevent any additional alignment. We already know the place!
222 beg += hdlr.offset();
223 end = beg + size - 1U;
224 align = L4_PAGESHIFT;
225
226 // In case of exact mappings, the supplied address must match because
227 // we cannot remap.
228 if (!(attach_flags & L4Re::Rm::F::Search_addr)
229 && reinterpret_cast<l4_addr_t>(addr) != beg)
230 return L4_INVALID_PTR;
231
232 // When searching for a suitable address, the start must cover the
233 // dataspace beginning to "find" the right spot.
234 if ((attach_flags & L4Re::Rm::F::Search_addr)
235 && reinterpret_cast<l4_addr_t>(addr) > beg)
236 return L4_INVALID_PTR;
237 }
238 else if (err == 0)
239 {
240 beg = reinterpret_cast<l4_addr_t>(addr);
241 end = max_addr();
242 }
243 else if (err < 0)
244 return L4_INVALID_PTR;
245
246 if (attach_flags & L4Re::Rm::F::In_area)
247 {
248 Node r = _am.find_node(Region(beg, beg + size - 1));
249 if (!r || (r->second.flags() & L4Re::Rm::F::Reserved))
250 return L4_INVALID_PTR;
251
252 end = r->first.end();
253 }
254
255 if (attach_flags & L4Re::Rm::F::Search_addr)
256 {
257 beg = find_free(beg, end, size, align, attach_flags);
258 if (beg == L4_INVALID_ADDR)
259 return L4_INVALID_PTR;
260 }
261
262 if (!(attach_flags & (L4Re::Rm::F::Search_addr | L4Re::Rm::F::In_area))
263 && _am.find_node(Region(beg, beg + size - 1)))
264 return L4_INVALID_PTR;
265
266 if (beg < min_addr() || beg + size - 1 > end)
267 return L4_INVALID_PTR;
268
269 if (_rm.insert(Region(beg, beg + size - 1,
270 name, name_len, backing_offset), hdlr).second
271 == 0)
272 {
273 hdlr.attached(beg, beg + size - 1);
274 return reinterpret_cast<void*>(beg);
275 }
276
277 return L4_INVALID_PTR;
278 }
279
280 int detach(void *addr, unsigned long sz, unsigned flags,
281 Region *reg, Hdlr *hdlr) noexcept
282 {
283 l4_addr_t a = reinterpret_cast<l4_addr_t>(addr);
284 Region dr(a, a + sz - 1);
285 Region res(~0UL, 0);
286
287 Node r = find(dr);
288 if (!r)
289 return -L4_ENOENT;
290
291 Region g = r->first;
292 Hdlr const &h = r->second;
293
294 if (flags & L4Re::Rm::Detach_overlap || dr.contains(g))
295 {
296 // Successful removal of the AVL tree item also frees the node.
297 Hdlr h_copy = h;
298
299 if (_rm.remove(g))
300 return -L4_ENOENT;
301
302 if (!(flags & L4Re::Rm::Detach_keep) && (h_copy.flags() & L4Re::Rm::F::Detach_free))
303 h_copy.free(0, g.size());
304
305 h_copy.detached(g.start(), g.end());
306
307 if (hdlr)
308 *hdlr = h_copy;
309 if (reg)
310 *reg = g;
311
312 if (find(dr))
314 else
315 return Rm::Detached_ds;
316 }
317 else if (dr.start() <= g.start())
318 {
319 // Move the start of a region.
320
321 if (!(flags & L4Re::Rm::Detach_keep) && (h.flags() & L4Re::Rm::F::Detach_free))
322 h.free(0, dr.end() + 1 - g.start());
323
324 h.detached(g.start(), dr.end());
325
326 unsigned long sz = dr.end() + 1 - g.start();
327 Item &cn = const_cast<Item &>(*r);
328 cn.first = Region(dr.end() + 1, g.end(), g.name(), g.name_len(),
329 g.backing_offset() + sz);
330 cn.second = cn.second + sz;
331 if (hdlr)
332 *hdlr = Hdlr();
333 if (reg)
334 *reg = Region(g.start(), dr.end());
335 if (find(dr))
337 else
338 return Rm::Kept_ds;
339 }
340 else if (dr.end() >= g.end())
341 {
342 // Move the end of a region.
343
344 if (!(flags & L4Re::Rm::Detach_keep)
345 && (h.flags() & L4Re::Rm::F::Detach_free))
346 h.free(dr.start() - g.start(), g.end() + 1 - dr.start());
347
348 h.detached(dr.start(), g.end());
349
350 Item &cn = const_cast<Item &>(*r);
351 cn.first = Region(g.start(), dr.start() - 1, g.name(), g.name_len(),
352 g.backing_offset());
353 if (hdlr)
354 *hdlr = Hdlr();
355 if (reg)
356 *reg = Region(dr.start(), g.end());
357
358 if (find(dr))
360 else
361 return Rm::Kept_ds;
362 }
363 else if (g.contains(dr))
364 {
365 // Split a single region that contains the new region.
366
367 if (!(flags & L4Re::Rm::Detach_keep) && (h.flags() & L4Re::Rm::F::Detach_free))
368 h.free(dr.start() - g.start(), dr.size());
369
370 h.detached(dr.start(), dr.end());
371
372 // First move the end off the existing region before the new one.
373 Item &cn = const_cast<Item &>(*r);
374 cn.first = Region(g.start(), dr.start()-1, g.name(), g.name_len(),
375 g.backing_offset());
376
377 int err;
378
379 // Insert a second region for the remaining tail of
380 // the old existing region.
381 auto tail_sz = dr.end() + 1 - g.start();
382 err = _rm.insert(Region(dr.end() + 1, g.end(), g.name(), g.name_len(),
383 g.backing_offset() + tail_sz),
384 h + tail_sz).second;
385
386 if (err)
387 return err;
388
389 if (hdlr)
390 *hdlr = h;
391 if (reg)
392 *reg = dr;
393 return Rm::Split_ds;
394 }
395
396 return -L4_ENOENT;
397 }
398
399 l4_addr_t find_free(l4_addr_t start, l4_addr_t end, l4_addr_t size,
400 unsigned char align, L4Re::Rm::Flags attach_flags) const noexcept;
401};
402
403template<typename Hdlr, template<typename T> class Alloc>
405Region_map<Hdlr, Alloc>::find_free(l4_addr_t start, l4_addr_t end,
406 unsigned long size, unsigned char align, L4Re::Rm::Flags attach_flags) const noexcept
407{
408 l4_addr_t addr = start;
409
410 if (addr == ~0UL || addr < min_addr() || addr >= end)
411 addr = min_addr();
412
413 addr = l4_round_size(addr, align);
414 Node r;
415
416 for (;;)
417 {
418 if (addr > 0 && addr - 1 > end - size)
419 return L4_INVALID_ADDR;
420
421 Region c(addr, addr + size - 1);
422 r = _rm.find_node(c);
423
424 if (!r)
425 {
426 if (!(attach_flags & L4Re::Rm::F::In_area) && (r = _am.find_node(c)))
427 {
428 if (r->first.end() > end - size)
429 return L4_INVALID_ADDR;
430
431 addr = l4_round_size(r->first.end() + 1, align);
432 continue;
433 }
434
435 break;
436 }
437 else if (r->first.end() > end - size)
438 return L4_INVALID_ADDR;
439
440 addr = l4_round_size(r->first.end() + 1, align);
441 }
442
443 if (!r)
444 return addr;
445
446 return L4_INVALID_ADDR;
447}
448
449}}
AVL map.
@ Detached_ds
Detached data space.
Definition rm:91
@ Detach_again
Detached data space, more to do.
Definition rm:96
@ Split_ds
Split data space, and done.
Definition rm:93
@ Kept_ds
Kept data space.
Definition rm:92
@ Detach_overlap
Do an unmap of all overlapping regions.
Definition rm:238
@ Detach_keep
Do not free the detached data space, ignore the F::Detach_free.
Definition rm:247
ITEM_TYPE Item_type
Type for the items store in the set.
Definition avl_set:147
unsigned long l4_addr_t
Address type.
Definition l4int.h:34
@ L4_ENOENT
No such entity.
Definition err.h:35
#define L4_INVALID_PTR
Invalid address as pointer type.
Definition consts.h:531
#define L4_PAGESHIFT
Size of a page, log2-based.
Definition consts.h:26
l4_addr_t l4_round_size(l4_addr_t value, unsigned char bits) L4_NOTHROW
Round value up to the next alignment with bits size.
Definition consts.h:503
@ L4_INVALID_ADDR
Invalid address.
Definition consts.h:524
Common L4 ABI Data Types.
Documentation of the L4 Runtime Environment utility functionality in C++.
Definition l4re.dox:21
L4Re C++ Interfaces.
Definition cmd_control:14
Region mapper interface.
@ Reserved
Region is reserved (blocked).
Definition rm:153
@ Detach_free
Free the portion of the data space after detach.
Definition rm:148
@ Search_addr
Search for a suitable address range.
Definition rm:113
@ In_area
Search only in area, or map into area.
Definition rm:115