L4Re Operating System Framework
Interface and Usage Documentation
Loading...
Searching...
No Matches
region_mapping_svr
1// vi:set ft=cpp: -*- Mode: C++ -*-
7/*
8 * (c) 2014 Alexander Warg <alexander.warg@kernkonzept.com>
9 *
10 * License: see LICENSE.spdx (in this directory or the directories above)
11 */
12#pragma once
13
14#include <l4/sys/types.h>
15#include <l4/re/rm>
17
18namespace L4Re { namespace Util {
19
20template<typename DERIVED, typename Dbg>
21struct Rm_server
22{
23private:
24 DERIVED *rm() { return static_cast<DERIVED*>(this); }
25 DERIVED const *rm() const { return static_cast<DERIVED const *>(this); }
26
27public:
28
32 l4_ret_t op_attach(L4Re::Rm::Rights, l4_addr_t &_start,
33 unsigned long size, Rm::Flags flags,
34 L4::Ipc::Snd_fpage ds_cap, L4Re::Rm::Offset offs,
35 unsigned char align, l4_cap_idx_t client_cap_idx,
36 L4::Ipc::String<> name, L4Re::Rm::Offset backing_offset)
37 {
38 typename DERIVED::Dataspace ds;
39
40 constexpr auto Known_flags =
41 // Attach_flags
44 // Region_flags
48
49 if (flags & ~Known_flags)
50 return -L4_EINVAL;
51
53 {
54 if (l4_ret_t r = rm()->validate_ds(ds_cap, flags.region_flags(), &ds))
55 return r;
56 }
57
58 if (size == 0)
59 return -L4_EINVAL;
60
61 constexpr unsigned Max_align = sizeof(l4_addr_t) * 8 - 1;
62 if (flags & Rm::F::Search_addr && ( align < L4_PAGESHIFT
63 || align > Max_align))
64 return -L4_EINVAL;
65
66 size = l4_round_page(size);
67 l4_addr_t start = l4_trunc_page(_start);
68 if (size == 0 || start + size - 1 < start)
69 return -L4_EINVAL;
70
71 Rm::Region_flags r_flags = flags.region_flags();
72 Rm::Attach_flags a_flags = flags.attach_flags();
73
74 typename DERIVED::Region_handler handler(ds, client_cap_idx, offs, r_flags);
75 if (int err = handler.init(rm(), size); err < 0)
76 return err;
77
78 start = l4_addr_t(rm()->attach(reinterpret_cast<void*>(start), size,
79 handler, a_flags, align,
80 name.data,
81 // L4::Ipc::String includes terminating '\0'
82 name.length ? name.length - 1 : 0,
83 backing_offset));
84
85 if (start == L4_INVALID_ADDR)
86 return -L4_EADDRNOTAVAIL;
87
88 _start = start;
89 return L4_EOK;
90 }
91
95 l4_ret_t op_free_area(L4Re::Rm::Rights, l4_addr_t start)
96 {
97 if (!rm()->detach_area(start))
98 return -L4_ENOENT;
99
100 return L4_EOK;
101 }
102
106 l4_ret_t op_find(L4Re::Rm::Rights, l4_addr_t &addr, unsigned long &size,
107 L4Re::Rm::Flags &flags, L4Re::Rm::Offset &offset,
108 l4_cap_idx_t &m)
109 {
110 if (!DERIVED::Have_find)
111 return -L4_EPERM;
112
113 if (size == 0)
114 return -L4_EINVAL;
115
116 Rm::Flags flag_area { 0 };
117
118 typename DERIVED::Node r = rm()->find(Region(addr, addr + size -1));
119 if (!r)
120 {
121 r = rm()->area_find(Region(addr, addr + size - 1));
122 if (!r)
123 return -L4_ENOENT;
124 flag_area = Rm::F::In_area;
125 }
126
127 addr = r->first.start();
128 size = r->first.end() + 1 - addr;
129
130 flags = r->second.flags() | flag_area;
131 offset = r->second.offset();
132 m = r->second.client_cap_idx();
133 return L4_EOK;
134 }
135
139 l4_ret_t op_detach(L4Re::Rm::Rights, l4_addr_t addr,
140 unsigned long size, unsigned flags,
141 l4_addr_t &start, l4_addr_t &rsize,
142 l4_cap_idx_t &mem_cap)
143 {
144 start = rsize = 0;
145 mem_cap = L4_INVALID_CAP;
146
147 constexpr unsigned Known_flags = Rm::Detach_exact | Rm::Detach_overlap;
148 if (flags & ~Known_flags)
149 return -L4_EINVAL;
150
151 if (size == 0)
152 return -L4_EINVAL;
153
154 l4_addr_t aligned_addr = l4_trunc_page(addr);
155 size = l4_round_page(addr - aligned_addr + size);
156 if (size == 0 || aligned_addr + size - 1 < aligned_addr)
157 return -L4_EINVAL;
158
159 Region r;
160 typename DERIVED::Region_handler h;
161 int err = rm()->detach(reinterpret_cast<void*>(aligned_addr), size, flags,
162 &r, &h);
163 if (err < 0)
164 return err;
165
166 if (r.invalid())
167 return -L4_ENOENT;
168
169 start = r.start();
170 rsize = r.size();
171 mem_cap = h.client_cap_idx();
172 return err;
173 }
174
178 l4_ret_t op_reserve_area(L4Re::Rm::Rights, l4_addr_t &start, unsigned long size,
179 L4Re::Rm::Flags flags, unsigned char align)
180 {
181 constexpr auto Known_flags = Rm::F::Search_addr | Rm::F::Kernel
183 if (flags & ~Known_flags)
184 return -L4_EINVAL;
185
186 if (size == 0 || start + size - 1 < start)
187 return -L4_EINVAL;
188
189 constexpr unsigned Max_align = sizeof(l4_addr_t) * 8 - 1;
190 if (flags & Rm::F::Search_addr && align > Max_align)
191 return -L4_EINVAL;
192
193 start = rm()->attach_area(start, size, flags, align);
194 if (start == L4_INVALID_ADDR)
195 return -L4_EADDRNOTAVAIL;
196
197 return L4_EOK;
198 }
199
203 l4_ret_t op_get_regions(L4Re::Rm::Rights, l4_addr_t addr,
204 L4::Ipc::Array_ref<L4Re::Rm::Region> &regions)
205 {
206 typename DERIVED::Node r;
207 unsigned limit = regions.length;
208
209 regions.length = 0;
210 while ((r = rm()->lower_bound(Region(addr))))
211 {
212 Rm::Region &x = regions.data[regions.length];
213 x.start = r->first.start();
214 x.end = r->first.end();
215 x.flags = r->second.flags();
216
217 if (++regions.length >= limit)
218 break;
219
220 if (x.end >= rm()->max_addr())
221 break;
222 addr = x.end + 1;
223 }
224
225 return regions.length;
226 }
227
231 l4_ret_t op_get_areas(L4Re::Rm::Rights, l4_addr_t addr,
232 L4::Ipc::Array_ref<L4Re::Rm::Area> &areas)
233 {
234 typename DERIVED::Node r;
235 unsigned limit = areas.length;
236
237 areas.length = 0;
238 while ((r = rm()->lower_bound_area(Region(addr))))
239 {
240 Rm::Area &x = areas.data[areas.length];
241 x.start = r->first.start();
242 x.end = r->first.end();
243 x.flags = r->second.flags();
244
245 if (++areas.length >= limit)
246 break;
247
248 if (x.end >= rm()->max_addr())
249 break;
250
251 addr = x.end + 1;
252 }
253
254 return areas.length;
255 }
256
260 l4_ret_t op_add_rescue_jump(L4Re::Rm::Rights, l4_addr_t pc_begin,
261 l4_addr_t pc_end, l4_addr_t rescue_pc)
262 {
263 return rm()->add_rescue_jump(pc_begin, pc_end, rescue_pc);
264 }
265
269 l4_ret_t op_remove_rescue_jump(L4Re::Rm::Rights, l4_addr_t pc)
270 {
271 return rm()->remove_rescue_jump(pc);
272 }
273
277 l4_ret_t op_page_in(L4Re::Rm::Rights, l4_addr_t min_addr, l4_addr_t max_addr,
278 L4Re::Rm::Region_flags rights, L4::Ipc::Snd_fpage &fp,
279 L4Re::Rm::page_in_fn &helper)
280 {
281 // Start and end address are inclusive. They must be page aligned.
282 if ( l4_trunc_page(min_addr) != min_addr
283 || l4_trunc_page(max_addr + 1) != max_addr + 1)
284 return -L4_EINVAL;
285
286 // The default implementation assumes it is executed in a dedicated thread.
287 helper = nullptr;
288
289 typename DERIVED::Region_handler::Map_result map_res;
290 l4_ret_t res = rm()->page_in(min_addr, max_addr, rights, &map_res);
291 if (res >= 0)
292 pager_set_result(&fp, map_res);
293
294 return res;
295 }
296
297private:
298 static void pager_set_result(L4::Ipc::Opt<L4::Ipc::Snd_fpage> *fp,
299 L4::Ipc::Snd_fpage const &f)
300 { *fp = f; }
301
302 static void pager_set_result(L4::Ipc::Snd_fpage *fp,
303 L4::Ipc::Snd_fpage const &f)
304 { *fp = f; }
305
306 static void pager_set_result(L4::Ipc::Opt<L4::Ipc::Snd_fpage> *, ...)
307 {}
308
309public:
310
314 l4_ret_t op_io_page_fault(L4::Io_pager::Rights, l4_fpage_t, l4_umword_t,
315 L4::Ipc::Opt<L4::Ipc::Snd_fpage> &)
316 {
317 // generate exception
318 return -L4_ENOMEM;
319 }
320
321 l4_ret_t op_page_fault(L4::Pager::Rights, l4_umword_t addr, l4_umword_t pc,
322 L4::Ipc::Opt<L4::Ipc::Snd_fpage> &fp)
323 {
324 Dbg(Dbg::Server).printf("page fault: %lx pc=%lx\n", addr, pc);
325
326 bool need_w = addr & 2;
327 bool need_x = addr & 4;
328
329 typename DERIVED::Node n = rm()->find(addr);
330
331 if (!n)
332 {
333 Dbg(Dbg::Warn, "rm").printf("unhandled %s page fault at 0x%lx pc=0x%lx\n",
334 need_w ? "write" :
335 need_x ? "instruction" : "read", addr, pc);
336 // generate exception
337 return -L4_ENOMEM;
338 }
339
340 if (!(n->second.flags() & L4Re::Rm::F::W) && need_w)
341 {
342 Dbg(Dbg::Warn, "rm").printf("write page fault in readonly region at 0x%lx pc=0x%lx\n",
343 addr, pc);
344 // generate exception
345 return -L4_EACCESS;
346 }
347
348 if (!(n->second.flags() & L4Re::Rm::F::X) && need_x)
349 {
350 Dbg(Dbg::Warn, "rm").printf("instruction page fault in non-exec region at 0x%lx pc=0x%lx\n",
351 addr, pc);
352 // generate exception
353 return -L4_EACCESS;
354 }
355
356 // This check is optional but avoids doing a map operation that will not
357 // work. We shall never get here from a page-fault but only from
358 // artificial page handling.
359 if (n->second.flags() & (L4Re::Rm::F::Kernel | L4Re::Rm::F::Reserved))
360 {
361 Dbg(Dbg::Warn, "rm").printf("page fault handling in kernel-memory provided region or reserved region at 0x%lx pc=0x%lx\n",
362 addr, pc);
363 // generate exception
364 return -L4_ENODEV;
365 }
366
367 typename DERIVED::Region_handler::Map_result map_res;
368 if (int err = n->second.map(addr, n->first, need_w, &map_res))
369 {
370 Dbg(Dbg::Warn, "rm").printf("mapping for page fault failed with error %d at 0x%lx pc=0x%lx\n",
371 err, addr, pc);
372 // generate exception
373 return -L4_ENOMEM;
374 }
375
376 pager_set_result(&fp, map_res);
377 return L4_EOK;
378 }
379
380 long op_get_info(L4Re::Rm::Rights, l4_addr_t addr,
381 L4::Ipc::String<char> &name, L4Re::Rm::Offset &backing_offset)
382 {
383#ifdef CONFIG_L4RE_REGION_INFO
384 typename DERIVED::Node r = rm()->find(Region(addr));
385 if (!r)
386 return -L4_ENOENT;
387 backing_offset = r->first.backing_offset();
388 unsigned long i;
389 char const *src = r->first.name();
390 unsigned src_len = r->first.name_len();
391 for (i = 0; i < src_len && i < name.length - 1; ++i)
392 name.data[i] = src[i];
393 name.length = i + 1;
394 name.data[i] = '\0';
395 return L4_EOK;
396#else
397 (void)addr;
398 (void)name;
399 (void)backing_offset;
400 return -L4_ENOSYS;
401#endif
402 }
403};
404
405}}
l4_ret_t(* page_in_fn)(l4_addr_t min_addr, l4_addr_t max_addr, Region_flags rights)
In-thread eager paging function.
Definition rm:847
@ Detach_overlap
Do an unmap of all overlapping regions.
Definition rm:245
@ Detach_exact
Do an unmap of the exact region given.
Definition rm:234
unsigned long l4_umword_t
Unsigned machine word.
Definition l4int.h:40
unsigned long l4_addr_t
Address type.
Definition l4int.h:34
unsigned long l4_cap_idx_t
Capability selector type.
Definition types.h:372
#define L4_INVALID_CAP
Invalid capability selector; see l4_cap_idx_t.
Definition consts.h:165
@ L4_ENOENT
No such entity.
Definition err.h:35
@ L4_ENOSYS
No sys.
Definition err.h:52
@ L4_EACCESS
Permission denied.
Definition err.h:41
@ L4_EINVAL
Invalid argument.
Definition err.h:47
@ L4_ENODEV
No such thing.
Definition err.h:45
@ L4_EOK
Ok.
Definition err.h:33
@ L4_EADDRNOTAVAIL
Address not available.
Definition err.h:54
@ L4_EPERM
No permission.
Definition err.h:34
@ L4_ENOMEM
No memory.
Definition err.h:40
l4_addr_t l4_trunc_page(l4_addr_t address) L4_NOTHROW
Round an address down to the next lower page boundary.
Definition consts.h:459
l4_addr_t l4_round_page(l4_addr_t address) L4_NOTHROW
Round address up to the next page.
Definition consts.h:484
#define L4_PAGESHIFT
Size of a page, log2-based.
Definition consts.h:26
@ L4_INVALID_ADDR
Invalid address.
Definition consts.h:516
Common L4 ABI Data Types.
l4_int16_t l4_ret_t
Return value of an IPC call as well as an RPC call.
Definition types.h:29
Documentation of the L4 Runtime Environment utility functionality in C++.
Definition l4re.dox:21
L4Re C++ Interfaces.
Definition cmd_control:14
Region handling.
Region mapper interface.
@ Private
Attach the dataspace privately with copy-on-write semantics.
Definition rm:156
@ Reserved
Region is reserved (blocked).
Definition rm:153
@ Pager
Region has a pager.
Definition rm:151
@ RWX
Readable, writable and executable region.
Definition rm:145
@ X
Executable region.
Definition rm:139
@ W
Writable region.
Definition rm:137
@ Anonymous
Attach anonymous memory in the region.
Definition rm:160
@ Caching_mask
Mask of all Rm cache bits.
Definition rm:164
@ Kernel
Kernel-provided memory (KUMEM).
Definition rm:148
@ Search_addr
Search for a suitable address range.
Definition rm:115
@ No_eager_map
Prevent eager mapping of the attached data space.
Definition rm:121
@ Eager_map
Eagerly map the attached data space in.
Definition rm:119
@ In_area
Search only in area, or map into area.
Definition rm:117