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 if (!(flags & (Rm::F::Reserved | Rm::F::Kernel)))
41 {
42 if (l4_ret_t r = rm()->validate_ds(ds_cap, flags.region_flags(), &ds))
43 return r;
44 }
45
46 size = l4_round_page(size);
47 l4_addr_t start = l4_trunc_page(_start);
48
49 if (size < L4_PAGESIZE)
50 return -L4_EINVAL;
51
52 Rm::Region_flags r_flags = flags.region_flags();
53 Rm::Attach_flags a_flags = flags.attach_flags();
54
55 typename DERIVED::Region_handler handler(ds, client_cap_idx, offs, r_flags);
56 start = l4_addr_t(rm()->attach(reinterpret_cast<void*>(start), size,
57 handler, a_flags, align,
58 name.data,
59 // L4::Ipc::String includes terminating '\0'
60 name.length ? name.length - 1 : 0,
61 backing_offset));
62
63 if (start == L4_INVALID_ADDR)
64 return -L4_EADDRNOTAVAIL;
65
66 _start = start;
67 return L4_EOK;
68 }
69
73 l4_ret_t op_free_area(L4Re::Rm::Rights, l4_addr_t start)
74 {
75 if (!rm()->detach_area(start))
76 return -L4_ENOENT;
77
78 return L4_EOK;
79 }
80
84 l4_ret_t op_find(L4Re::Rm::Rights, l4_addr_t &addr, unsigned long &size,
85 L4Re::Rm::Flags &flags, L4Re::Rm::Offset &offset,
86 L4::Cap<L4Re::Dataspace> &m)
87 {
88 if (!DERIVED::Have_find)
89 return -L4_EPERM;
90
91 Rm::Flags flag_area { 0 };
92
93 typename DERIVED::Node r = rm()->find(Region(addr, addr + size -1));
94 if (!r)
95 {
96 r = rm()->area_find(Region(addr, addr + size - 1));
97 if (!r)
98 return -L4_ENOENT;
99 flag_area = Rm::F::In_area;
100 }
101
102 addr = r->first.start();
103 size = r->first.end() + 1 - addr;
104
105 flags = r->second.flags() | flag_area;
106 offset = r->second.offset();
107 m = L4::Cap<L4Re::Dataspace>(DERIVED::find_res(r->second.memory()));
108 return L4_EOK;
109 }
110
114 l4_ret_t op_detach(L4Re::Rm::Rights, l4_addr_t addr,
115 unsigned long size, unsigned flags,
116 l4_addr_t &start, l4_addr_t &rsize,
117 l4_cap_idx_t &mem_cap)
118 {
119 Region r;
120 typename DERIVED::Region_handler h;
121 int err = rm()->detach(reinterpret_cast<void*>(addr), size, flags, &r, &h);
122 if (err < 0)
123 {
124 start = rsize = 0;
125 mem_cap = L4_INVALID_CAP;
126 return err;
127 }
128
129 if (r.invalid())
130 {
131 start = rsize = 0;
132 mem_cap = L4_INVALID_CAP;
133 return -L4_ENOENT;
134 }
135
136 start = r.start();
137 rsize = r.size();
138 mem_cap = h.client_cap_idx();
139 return err;
140 }
141
145 l4_ret_t op_reserve_area(L4Re::Rm::Rights, l4_addr_t &start, unsigned long size,
146 L4Re::Rm::Flags flags, unsigned char align)
147 {
148 start = rm()->attach_area(start, size, flags, align);
149 if (start == L4_INVALID_ADDR)
150 return -L4_EADDRNOTAVAIL;
151 return L4_EOK;
152 }
153
157 l4_ret_t op_get_regions(L4Re::Rm::Rights, l4_addr_t addr,
158 L4::Ipc::Ret_array<L4Re::Rm::Region> regions)
159 {
160 typename DERIVED::Node r;
161 unsigned num = 0;
162 while ((r = rm()->lower_bound(Region(addr))))
163 {
164 Rm::Region &x = regions.value[num];
165 x.start = r->first.start();
166 x.end = r->first.end();
167 x.flags = r->second.flags();
168
169 if (++num >= regions.max)
170 break;
171
172 if (x.end >= rm()->max_addr())
173 break;
174 addr = x.end + 1;
175 }
176 return num;
177 }
178
182 l4_ret_t op_get_areas(L4Re::Rm::Rights, l4_addr_t addr,
183 L4::Ipc::Ret_array<L4Re::Rm::Area> areas)
184 {
185 typename DERIVED::Node r;
186 unsigned num = 0;
187 while ((r = rm()->lower_bound_area(Region(addr))))
188 {
189 Rm::Area &x = areas.value[num];
190 x.start = r->first.start();
191 x.end = r->first.end();
192
193 if (++num >= areas.max)
194 break;
195
196 if (x.end >= rm()->max_addr())
197 break;
198
199 addr = x.end + 1;
200 }
201
202 return num;
203 }
204
205private:
206 static void pager_set_result(L4::Ipc::Opt<L4::Ipc::Snd_fpage> *fp,
207 L4::Ipc::Snd_fpage const &f)
208 { *fp = f; }
209
210 static void pager_set_result(L4::Ipc::Opt<L4::Ipc::Snd_fpage> *, ...)
211 {}
212
213public:
214
218 l4_ret_t op_io_page_fault(L4::Io_pager::Rights, l4_fpage_t, l4_umword_t,
219 L4::Ipc::Opt<L4::Ipc::Snd_fpage> &)
220 {
221 // generate exception
222 return -L4_ENOMEM;
223 }
224
225 l4_ret_t op_page_fault(L4::Pager::Rights, l4_umword_t addr, l4_umword_t pc,
226 L4::Ipc::Opt<L4::Ipc::Snd_fpage> &fp)
227 {
228 Dbg(Dbg::Server).printf("page fault: %lx pc=%lx\n", addr, pc);
229
230 bool need_w = addr & 2;
231 bool need_x = addr & 4;
232
233 typename DERIVED::Node n = rm()->find(addr);
234
235 if (!n || !n->second.memory())
236 {
237 Dbg(Dbg::Warn, "rm").printf("unhandled %s page fault at 0x%lx pc=0x%lx\n",
238 need_w ? "write" :
239 need_x ? "instruction" : "read", addr, pc);
240 // generate exception
241 return -L4_ENOMEM;
242 }
243
244 if (!(n->second.flags() & L4Re::Rm::F::W) && need_w)
245 {
246 Dbg(Dbg::Warn, "rm").printf("write page fault in readonly region at 0x%lx pc=0x%lx\n",
247 addr, pc);
248 // generate exception
249 return -L4_EACCESS;
250 }
251
252 if (!(n->second.flags() & L4Re::Rm::F::X) && need_x)
253 {
254 Dbg(Dbg::Warn, "rm").printf("instruction page fault in non-exec region at 0x%lx pc=0x%lx\n",
255 addr, pc);
256 // generate exception
257 return -L4_EACCESS;
258 }
259
260 // This check is optional but avoids doing a map operation that will not
261 // work. We shall never get here from a page-fault but only from
262 // artificial page handling.
263 if (n->second.flags() & (L4Re::Rm::F::Kernel | L4Re::Rm::F::Reserved))
264 {
265 Dbg(Dbg::Warn, "rm").printf("page fault handling in kernel-memory provided region or reserved region at 0x%lx pc=0x%lx\n",
266 addr, pc);
267 // generate exception
268 return -L4_ENODEV;
269 }
270
271 typename DERIVED::Region_handler::Map_result map_res;
272 if (int err = n->second.map(addr, n->first, need_w, &map_res))
273 {
274 Dbg(Dbg::Warn, "rm").printf("mapping for page fault failed with error %d at 0x%lx pc=0x%lx\n",
275 err, addr, pc);
276 // generate exception
277 return -L4_ENOMEM;
278 }
279
280 pager_set_result(&fp, map_res);
281 return L4_EOK;
282 }
283
284 long op_get_info(L4Re::Rm::Rights, l4_addr_t addr,
285 L4::Ipc::String<char> &name, L4Re::Rm::Offset &backing_offset)
286 {
287#ifdef CONFIG_L4RE_REGION_INFO
288 typename DERIVED::Node r = rm()->find(Region(addr));
289 if (!r)
290 return -L4_ENOENT;
291 backing_offset = r->first.backing_offset();
292 unsigned long i;
293 char const *src = r->first.name();
294 unsigned src_len = r->first.name_len();
295 for (i = 0; i < src_len && i < name.length - 1; ++i)
296 name.data[i] = src[i];
297 name.length = i + 1;
298 name.data[i] = '\0';
299 return L4_EOK;
300#else
301 (void)addr;
302 (void)name;
303 (void)backing_offset;
304 return -L4_ENOSYS;
305#endif
306 }
307};
308
309}}
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:357
@ L4_ENOENT
No such entity.
Definition err.h:35
@ L4_ENOSYS
No sys.
Definition err.h:51
@ 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:53
@ 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:467
l4_addr_t l4_round_page(l4_addr_t address) L4_NOTHROW
Round address up to the next page.
Definition consts.h:492
#define L4_PAGESIZE
Minimal page size (in bytes).
Definition consts.h:410
@ L4_INVALID_ADDR
Invalid address.
Definition consts.h:524
#define L4_INVALID_CAP
Invalid capability selector.
Definition consts.h:152
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:28
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.
@ Reserved
Region is reserved (blocked).
Definition rm:153
@ X
Executable region.
Definition rm:137
@ W
Writable region.
Definition rm:135
@ Kernel
Kernel-provided memory (KUMEM).
Definition rm:146
@ In_area
Search only in area, or map into area.
Definition rm:115