6 * Memory management classes, mirroring the L4 RM's ones.
8 * (c) 2011-2012 Björn Döbel <doebel@os.inf.tu-dresden.de>,
9 * economic rights: Technische Universität Dresden (Germany)
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.
16 * Memory management (e.g., region manager)
26 #include <l4/util/util.h>
27 #include <l4/re/util/cap_alloc>
28 #include <l4/re/util/region_mapping>
29 #include <l4/re/util/dataspace_svr>
31 #include <l4/sys/kdebug.h>
33 #include "constants.h"
48 l4_addr_t sp() { return _sp; }
52 * Push a value to the stack
55 l4_addr_t push(T value)
64 * Push a buffer to stack.
66 * Returns difference to previous stack ptr. This diff may be
67 * different from the len parameter for alignment reasons.
70 unsigned push_data(T* buf, unsigned len)
72 l4_addr_t orig_sp = _sp;
73 unsigned space = len * sizeof(T);
75 _sp &= ~0x03; // word alignment XXX
76 memcpy((char*)_sp, buf, space);
85 template <typename TYPE>
88 enum { can_free = true };
90 Allocator() throw() {}
91 Allocator(Romain::Allocator<TYPE> const &) throw() {}
92 ~Allocator() throw() {}
94 TYPE *alloc() throw() { return static_cast<TYPE*>(::malloc(sizeof(TYPE))); }
95 void free(void* ptr) throw() { ::free(ptr); }
100 class Region : public L4Re::Util::Region
103 typedef L4Re::Util::Region Base;
105 Region(l4_addr_t addr = 0) throw()
109 Region(l4_addr_t start, l4_addr_t end) throw()
116 DEBUG() << "touching 0x" << std::hex << this->start()
117 << " + " << this->size() << " rw'able";
119 l4_touch_rw((void*)this->start(), this->size());
125 * Romain Memory region handler. This handler is different from L4Re's region
126 * handler in that it can manage multiple source mappings.
128 * Multiple sources are used for handling multiple replicas which have
129 * write access to a memory region. In this case we need to establish a
130 * mapping per replica.
132 template <typename DS, typename OPS>
133 class Region_handler_template
136 typedef L4::Cap<L4Re::Dataspace> DSCAP;
137 typedef DS Dataspace;
139 typedef typename OPS::Map_result Map_result;
141 enum RegionWritableType {
143 Read_only_emulate_write,
149 Romain::Region _local_regions[Romain::MAX_REPLICAS];
151 DS _mem[Romain::MAX_REPLICAS];
152 unsigned char _flags;
153 RegionWritableType _row;
158 Region_handler_template()
159 : _cap(L4_INVALID_CAP), _offs(0), _flags(),
160 _row(Romain::Region_handler_template<DS, OPS>::Read_only),
165 Region_handler_template(const Region_handler_template& o)
166 : _cap(o.client_cap_idx()),
172 for (unsigned i = 0; i < o.local_region_count(); ++i) {
173 _local_regions[i] = o.local_region(i);
174 _mem[i] = o.memory(i);
178 Region_handler_template(DSCAP cap, l4_cap_idx_t client_cap = L4_INVALID_CAP, l4_addr_t offset = 0,
179 unsigned flags = 0, Romain::Region local_reg = Romain::Region(0,0))
180 : _cap(client_cap), _offs(offset), _flags(flags), _shared(false)
182 _local_regions[0] = local_reg;
184 for (unsigned i = 1; i < Romain::MAX_REPLICAS; ++i)
188 * Yes, this looks like a copy of the RO flag. But in our case, this is actually
189 * a tri-state. A page may be writable but mapped read-only if the mapping is
190 * shared memory. This fact is however established by someone else (e.g., the syscall
191 * observer) and here we just set one of the two default states.
193 if (flags & L4Re::Rm::Read_only) {
194 writable(Romain::Region_handler_template<DS, OPS>::Read_only);
196 writable(Romain::Region_handler_template<DS, OPS>::Writable);
200 unsigned local_region_count() const { return MAX_REPLICAS; }
201 Romain::Region const & local_region(unsigned idx) const { return _local_regions[idx]; }
203 void writable(RegionWritableType rw) { _row = rw; }
204 RegionWritableType writable() const { return _row; }
207 * Set a value for the mapping established for a given combination
208 * of Region and Instance.
210 void set_local_region(unsigned idx, Romain::Region const & r)
212 _check(idx >= Romain::MAX_REPLICAS, "invalid instance");
213 _local_regions[idx] = r;
216 //DS const &memory() const throw() { return _mem; }
217 DS const & memory(unsigned idx = 0) const throw() { return _mem[idx]; }
218 void memory(unsigned idx, DS const & m) { _mem[idx] = m; }
219 l4_cap_idx_t client_cap_idx() const throw() { return _cap; }
220 l4_addr_t offset() const throw() { return _offs; }
221 void offset(l4_addr_t o) { _offs = o; }
222 l4_addr_t is_ro() const throw() { return _flags & L4Re::Rm::Read_only; }
223 unsigned flags() const throw() { return _flags; }
225 bool shared() const throw() { return _shared; }
226 void shared(bool yn) { _shared = yn; }
228 void take() const { Ops::take(this); }
229 void release() const { Ops::release(this); }
232 Region_handler_template operator + (long offset) throw()
233 { Region_handler_template n = *this; n._offs += offset; return n; }
235 void unmap(l4_addr_t va, l4_addr_t ds_offs, unsigned long size) const throw()
236 { Ops::unmap(this, va, ds_offs, size); }
238 void free(l4_addr_t start, unsigned long size) const throw()
239 { Ops::free(this, start, size); }
241 int map(l4_addr_t adr, Region const &r, bool writable, Map_result *result) const
242 { return Ops::map(this, adr, r, writable, result); }
247 typedef Romain::Region_handler_template<L4::Cap<L4Re::Dataspace>, Romain::Region_ops> Region_handler;
253 typedef l4_umword_t Map_result;
254 static int map(Region_handler const *h, l4_addr_t addr,
255 L4Re::Util::Region const &r, bool writable,
256 l4_umword_t *result);
258 static void unmap(Region_handler const *h, l4_addr_t vaddr,
259 l4_addr_t offs, unsigned long size);
261 static void free(Region_handler const *h, l4_addr_t start, unsigned long size);
263 static void take(Region_handler const *h);
264 static void release(Region_handler const *h);
269 : public L4Re::Util::Region_map<Romain::Region_handler,
273 typedef L4Re::Util::Region_map<Romain::Region_handler, Romain::Allocator> Base;
274 enum { Invalid_inst = ~0U };
276 void activate(unsigned inst)
278 _check(_active_instance != Invalid_inst, "rm already used, lock!!!");
279 _active_instance = inst;
284 _active_instance = Invalid_inst;
288 * Initialization, see loader/server/src/region.cc
292 l4_addr_t remote_to_local(l4_addr_t remote, unsigned inst)
294 Base::Node n = find(remote);
297 if (n->second.local_region(inst).start() == 0)
298 lazy_map_region(n, inst);
299 l4_addr_t offs = remote - n->first.start();
300 return n->second.local_region(inst).start() + offs;
307 bool copy_existing_mapping(Romain::Region_handler& r,
309 unsigned inst_id) const
311 if (orig_id == inst_id) return true;
313 L4::Cap<L4Re::Dataspace> mem = L4Re::Util::cap_alloc.alloc<L4Re::Dataspace>();
314 _check(!mem.is_valid(), "could not allocate ds cap?");
316 unsigned long size = r.local_region(orig_id).size();
317 int ret = L4Re::Env::env()->mem_alloc()->alloc(size, mem);
318 _check(ret != 0, "memory allocation failed");
321 ret = L4Re::Env::env()->rm()->attach(&a, size,
322 L4Re::Rm::Search_addr,
324 _check(ret != 0, "attach failed");
325 memcpy((void*)a, (void*)r.local_region(orig_id).start(), size);
327 //DEBUG() << "COPY: DS " << std::hex << mem.cap() << " SIZE " << size
328 // << " attached @ " << a;
329 r.set_local_region(inst_id, Romain::Region(a, a+size-1));
330 r.memory(inst_id, mem);
337 * Check if a node already has a mapping to one of the replicas. If so,
338 * take a shortcut mapping to the next one (determined by inst parameter).
340 bool lazy_map_region(Romain::Region_map::Base::Node &n, unsigned inst);
343 unsigned _active_instance;
346 * Determine the index of the first instance that already holds a
347 * valid mapping for an existing region.
349 int find_existing_region(Romain::Region_map::Base::Node n) const
352 for (ret = 0; ret < Romain::MAX_REPLICAS; ++ret) {
353 if (n->second.local_region(ret).start())
361 * Every DS we attach to the client is also attached locally within
362 * the master process.
364 void *attach_locally(void* addr, unsigned long size, Romain::Region_handler *hdlr,
365 unsigned flags = None, unsigned char align=L4_PAGESHIFT);
368 void *attach(void* addr, unsigned long size, Romain::Region_handler const &hdlr,
369 unsigned flags = None, unsigned char align=L4_PAGESHIFT, bool shared = false);
372 * Copy the content of all writable regions of instance 'from' to
373 * the respective regions of instance 'to'.
375 void replicate(unsigned from, unsigned to)
377 for (Base::Const_iterator i = begin(); i != end(); ++i) {
378 if (!i->second.is_ro()) {
379 unsigned size = i->first.end() - i->first.start() - 1;
380 memcpy((void*)i->second.local_region(to).start(),
381 (void*)i->second.local_region(from).start(), size);
388 class Region_map_server
391 typedef L4::Cap<L4Re::Dataspace> Dataspace;
392 enum { Have_find = true };
394 static int validate_ds(L4::Ipc::Snd_fpage const &ds_cap,
395 unsigned, L4::Cap<L4Re::Dataspace> *ds)
398 * XXX We need to check if actually a cap was received.
399 * However, the default check for ds_cap.local_id_received()
400 * fails here, because we are only proxying this call.
402 *ds = L4::Cap<L4Re::Dataspace>(ds_cap.base());
407 static l4_umword_t find_res(L4::Cap<void> const &ds) { return ds.cap(); }