L4Re - L4 Runtime Environment
region_mapping_svr_2
1 // vi:set ft=cpp: -*- Mode: C++ -*-
2 /**
3  * \internal
4  * \file
5  * \brief Region mapper server template.
6  */
7 /*
8  * (c) 2014 Alexander Warg <alexander.warg@kernkonzept.com>
9  *
10  * This file is part of TUD:OS and distributed under the terms of the
11  * GNU General Public License 2.
12  * Please see the COPYING-GPL-2 file for details.
13  *
14  * As a special exception, you may use this file as part of a free software
15  * library without restriction. Specifically, if other files instantiate
16  * templates or use macros or inline functions from this file, or you compile
17  * this file and link it with other files to produce an executable, this
18  * file does not by itself cause the resulting executable to be covered by
19  * the GNU General Public License. This exception does not however
20  * invalidate any other reasons why the executable file might be covered by
21  * the GNU General Public License.
22  */
23 #pragma once
24 
25 #include <l4/sys/types.h>
26 #include <l4/re/rm>
27 #include <l4/re/util/region_mapping>
28 
29 namespace L4Re { namespace Util {
30 
31 template<typename DERIVED, typename Dbg>
32 struct Rm_server
33 {
34 private:
35  DERIVED *rm() { return static_cast<DERIVED*>(this); }
36  DERIVED const *rm() const { return static_cast<DERIVED const *>(this); }
37 
38 public:
39 
40  /**
41  * Implementation of L4Re::Rm::_attach
42  */
43  long op_attach(L4Re::Rm::Rights, l4_addr_t &_start,
44  unsigned long size, unsigned long flags,
45  L4::Ipc::Snd_fpage ds_cap, l4_addr_t offs,
46  unsigned char align, l4_cap_idx_t client_cap_idx)
47  {
48  typename DERIVED::Dataspace ds;
49 
50  if (!(flags & Rm::Reserved))
51  {
52  if (long r = rm()->validate_ds(static_cast<DERIVED*>(this)->server_iface(), ds_cap, flags, &ds))
53  return r;
54  }
55 
56  size = l4_round_page(size);
57  l4_addr_t start = l4_trunc_page(_start);
58 
59  if (size < L4_PAGESIZE)
60  return -L4_EINVAL;
61 
62  unsigned r_flags = flags & Rm::Region_flags;
63  unsigned a_flags = flags & Rm::Attach_flags;
64 
65  start = l4_addr_t(rm()->attach((void*)start, size,
66  typename DERIVED::Region_handler(ds, client_cap_idx, offs, r_flags),
67  a_flags, align));
68 
69  if (start == L4_INVALID_ADDR)
70  return -L4_EADDRNOTAVAIL;
71 
72  _start = start;
73  return L4_EOK;
74  }
75 
76  /**
77  * Implementation of L4Re::Rm::free_area
78  */
79  long op_free_area(L4Re::Rm::Rights, l4_addr_t start)
80  {
81  if (!rm()->detach_area(start))
82  return -L4_ENOENT;
83 
84  return L4_EOK;
85  }
86 
87  /**
88  * Implementation of L4Re::Rm::_find
89  */
90  long op_find(L4Re::Rm::Rights, l4_addr_t &addr, unsigned long &size,
91  unsigned &flags, l4_addr_t &offset,
92  L4::Cap<L4Re::Dataspace> &m)
93  {
94  if (!DERIVED::Have_find)
95  return -L4_EPERM;
96 
97  unsigned flag_area = 0;
98 
99  typename DERIVED::Node r = rm()->find(Region(addr, addr + size -1));
100  if (!r)
101  {
102  r = rm()->area_find(Region(addr, addr + size - 1));
103  if (!r)
104  return -L4_ENOENT;
105  flag_area = Rm::In_area;
106  }
107 
108  addr = r->first.start();
109  size = r->first.end() + 1 - addr;
110 
111  flags = r->second.flags() | flag_area;
112  offset = r->second.offset();
113  m = L4::Cap<L4Re::Dataspace>(DERIVED::find_res(r->second.memory()));
114  return L4_EOK;
115  }
116 
117  /**
118  * Implementation of L4Re::Rm::_detach
119  */
120  long op_detach(L4Re::Rm::Rights, l4_addr_t addr,
121  unsigned long size, unsigned flags,
122  l4_addr_t &start, l4_addr_t &rsize,
123  l4_cap_idx_t &mem_cap)
124  {
125  Region r;
126  typename DERIVED::Region_handler h;
127  int err = rm()->detach((void*)addr, size, flags, &r, &h);
128  if (err < 0)
129  return err;
130 
131  if (r.invalid())
132  return -L4_ENOENT;
133 
134  start = r.start();
135  rsize = r.size();
136  mem_cap = h.client_cap_idx();
137  return err;
138  }
139 
140  /**
141  * Implementation of L4Re::Rm::_reserve_area
142  */
143  long op_reserve_area(L4Re::Rm::Rights, l4_addr_t &start, unsigned long size,
144  unsigned flags, unsigned char align)
145  {
146  start = rm()->attach_area(start, size, flags, align);
147  if (start == L4_INVALID_ADDR)
148  return -L4_EADDRNOTAVAIL;
149  return L4_EOK;
150  }
151 
152  /**
153  * Implementation of L4Re::Rm::get_regions
154  */
155  long op_get_regions(L4Re::Rm::Rights, l4_addr_t addr,
156  L4::Ipc::Ret_array<L4Re::Rm::Region> regions)
157  {
158  typename DERIVED::Node r;
159  unsigned num = 0;
160  while ((r = rm()->lower_bound(Region(addr, addr +1))))
161  {
162  Rm::Region &x = regions.value[num];
163  x.start = r->first.start();
164  x.end = r->first.end();
165  x.offset = r->second.offset();
166 
167  if (++num >= regions.max)
168  break;
169 
170  if (x.end >= rm()->max_addr())
171  break;
172  addr = x.end + 1;
173  }
174  return num;
175  }
176 
177  /**
178  * Implementation of L4Re::Rm::get_areas
179  */
180  long op_get_areas(L4Re::Rm::Rights, l4_addr_t addr,
181  L4::Ipc::Ret_array<L4Re::Rm::Area> areas)
182  {
183  typename DERIVED::Node r;
184  unsigned num = 0;
185  while ((r = rm()->lower_bound_area(Region(addr, addr +1))))
186  {
187  Rm::Area &x = areas.value[num];
188  x.start = r->first.start();
189  x.end = r->first.end();
190 
191  if (++num >= areas.max)
192  break;
193 
194  if (x.end >= rm()->max_addr())
195  break;
196 
197  addr = x.end + 1;
198  }
199  return num;
200  }
201 
202 private:
203  static void pager_set_result(L4::Ipc::Opt<l4_mword_t> *,
204  L4::Ipc::Opt<L4::Ipc::Snd_fpage> *fp,
205  L4::Ipc::Snd_fpage const &f)
206  { *fp = f; }
207 
208  static void pager_set_result(L4::Ipc::Opt<l4_mword_t> *result,
209  L4::Ipc::Opt<L4::Ipc::Snd_fpage> *, ...)
210  { *result = 0; }
211 public:
212 
213  /**
214  * Pager API
215  */
216  long op_io_page_fault(L4::Io_pager::Rights, l4_fpage_t, l4_umword_t,
217  L4::Ipc::Opt<l4_mword_t> &result,
218  L4::Ipc::Opt<L4::Ipc::Snd_fpage> &)
219  {
220  // generate exception
221  result = ~0;
222  return L4_EOK;
223  }
224 
225  long op_page_fault(L4::Pager::Rights, l4_umword_t addr, l4_umword_t pc,
226  L4::Ipc::Opt<l4_mword_t> &result,
227  L4::Ipc::Opt<L4::Ipc::Snd_fpage> &fp)
228  {
229  Dbg(Dbg::Server).printf("page fault: %lx pc=%lx\n", addr, pc);
230 
231  unsigned writable = addr & 2;
232  addr = addr & ~7UL;
233 
234  typename DERIVED::Node n = rm()->find(addr);
235 
236  if (!n || !n->second.memory())
237  {
238  Dbg(Dbg::Warn, "rm").printf("unhandled %s page fault at 0x%lx pc=0x%lx\n",
239  writable ? "write" : "read", addr, pc);
240  // generate exception
241  result = ~0;
242  return L4_EOK;
243  }
244 
245  if (n->second.is_ro() && writable)
246  {
247  Dbg(Dbg::Warn, "rm").printf("write page fault in readonly region at 0x%lx pc=0x%lx\n",
248  addr, pc);
249  // generate exception
250  result = ~0;
251  return L4_EOK;
252  }
253 
254  typename DERIVED::Region_handler::Ops::Map_result map_res;
255  if (int err = n->second.map(addr, n->first, writable, &map_res))
256  {
257  Dbg(Dbg::Warn, "rm").printf("mapping for page fault failed with error %d at 0x%lx pc=0x%lx\n",
258  err, addr, pc);
259  // generate exception
260  result = ~0;
261  return L4_EOK;
262  }
263 
264  pager_set_result(&result, &fp, map_res);
265  return L4_EOK;
266  }
267 };
268 
269 }}