4 * Memory management implementation
6 * (c) 2011-2013 Björn Döbel <doebel@os.inf.tu-dresden.de>,
7 * economic rights: Technische Universität Dresden (Germany)
8 * This file is part of TUD:OS and distributed under the terms of the
9 * GNU General Public License 2.
10 * Please see the COPYING-GPL-2 file for details.
13 #include "app_loading"
15 #include <l4/sys/kdebug.h>
17 #define MSG() DEBUGf(Romain::Log::Memory)
19 int Romain::Region_ops::map(Region_handler const *h, l4_addr_t addr,
20 L4Re::Util::Region const &r, bool writable,
28 enter_kdebug("ops::map");
32 void Romain::Region_ops::unmap(Region_handler const *h, l4_addr_t vaddr,
33 l4_addr_t offs, unsigned long size)
39 enter_kdebug("ops::unmap");
43 void Romain::Region_ops::free(Region_handler const *h, l4_addr_t start, unsigned long size)
45 if ((h->flags() & L4Re::Rm::Reserved))
48 if (h->flags() & L4Re::Rm::Pager)
51 L4::Cap<L4Re::Dataspace> ds(h->client_cap_idx());
52 ds->clear(h->offset() + start, size);
54 //enter_kdebug("ops::free");
58 void Romain::Region_ops::take(Region_handler const* h)
61 enter_kdebug("ops::take");
65 void Romain::Region_ops::release(Region_handler const* h)
68 enter_kdebug("ops::release");
72 Romain::Region_map::Region_map()
73 : Base(0,0), _active_instance(Invalid_inst)
75 pthread_mutex_init(&_mtx, 0);
77 l4_kernel_info_t *kip = l4re_kip();
78 MSG() << "kip found at 0x" << std::hex << kip
79 << " having " << L4::Kip::Mem_desc::count(kip)
82 L4::Kip::Mem_desc *d = L4::Kip::Mem_desc::first(kip);
83 unsigned long count = L4::Kip::Mem_desc::count(kip);
85 for (L4::Kip::Mem_desc *desc = d; desc < d + count; ++desc) {
87 if (!desc->is_virtual())
90 l4_addr_t s = desc->start() == 0 ? 0x1000 : desc->start();
91 l4_addr_t e = desc->end();
92 MSG() << "virtual range: [" << std::hex << s << "-" << e << "] ";
94 switch(desc->type()) {
95 case L4::Kip::Mem_desc::Conventional:
99 WARN() << "type " << desc->type() << "???";
108 * Attach a replica region locally in the master AS.
110 * The Romain::Master manages replicas' region map. As a part of this, the master
111 * attaches a copy of every region attached to one of the replicas to its own
112 * address space. This local region is then used to service page faults caused by
115 * For read-only replica dataspaces, the master creates a writable copy of the
116 * original region in a separate dataspace. This allows us to modify their content
117 * if necessary (e.g., setting debug breakpoints on read-only code).
119 * For writable dataspaces, the master simply attaches the same region that has
120 * already been attached to the replica AS into its own address space and maintains
121 * a copy for every replica.
123 * The replica copies lead to another problem: to reduce replication overhead, we
124 * would like to handle page faults using as few memory mappings as possible. To
125 * be able to do so, we however need to make sure that all replica copies are
126 * aligned to the same start address. The Romain::Master does this by ensuring
127 * that the replica address as well as the master-local addresses of the copies
128 * are aligned to the same offset within a minimally aligned region. The minimum
129 * alignment is defined by the Region_handler()'s MIN_ALIGNMENT member (XXX and
130 * should at some point become a configurable feature).
132 * The layout looks like this:
137 * +- - - - +---------------------------+
139 * +- - - - +---------------------------+
144 * +- - - - +---------------------------+
146 * +- - - - +---------------------------+
148 * (1) correct minimum alignment
152 * (A) address aligned similar to (1)
153 * (B) local_region[inst]->start()
154 * (C) local_region[inst]->end()
156 * MIN_ALIGNMENT_MASK := (1 << MIN_ALIGNMENT) - 1
157 * (1) := (2) - [(2) & MIN_ALIGNMENT_MASK]
158 * (A) := (B) - [(B) & MIN_ALIGNMENT_MASK]
160 * Attaching then works by first reserving an area with the RM
161 * that has the size (C) - (A). Then we attach the dataspace to
162 * (B) and free the reserved area so that the remaining memory
163 * can again be freely used.
165 void *Romain::Region_map::attach_locally(void* addr, unsigned long size,
166 Romain::Region_handler *hdlr,
167 unsigned flags, unsigned char align)
170 Romain::Region_handler::Dataspace const *ds = &hdlr->local_memory(0);
171 L4Re::Dataspace::Stats dsstat;
172 (*ds)->info(&dsstat);
176 << "attaching DS " << std::hex << ds->cap()
177 << ", addr = " << addr
178 << ", flags = " << flags << " (" << dsstat.flags << ")"
179 << ", size = " << size
180 << ", align = " << (unsigned int)align
184 if (!ds->is_valid()) {
185 enter_kdebug("attaching invalid cap");
189 * Here's what the variables below mean in the original DS. If the DS is
190 * read-only, we still want a writable version, because some users, such as
191 * GDB, want to modify ro data (e.g., GDB breakpoints). Therefore, we then
192 * create a copy of the original DS and adapt the variables afterwards.
195 * +------+----+----+----------------------+
196 * | |'..'|..'.| | Original DS
198 * +------+----+----+----------------------+
209 * 1 .. original DS start
210 * 2 .. page base of region (page_base)
211 * 3 .. offset within DS (hdlr()->offset)
212 * 4 .. region end (hdlr()->offset + size)
213 * 5 .. original DS end
217 * offset_in_page = $3 - $2
218 * eff_size = size + offset_in_page rounded to page size
226 l4_addr_t page_base = l4_trunc_page(hdlr->offset());
227 l4_addr_t offset_in_page = hdlr->offset() - page_base;
228 unsigned eff_size = l4_round_page(size + offset_in_page);
231 MSG() << " page_base " << (void*)page_base << ", offset " << std::hex << offset_in_page
232 << ", eff_size " << eff_size << ", hdlr->offset " << hdlr->offset();
235 hdlr->offset(page_base /*hdlr->offset() - offset_in_page*/);
238 * If the dataspace we attach was originally not mapped writable,
239 * make a writable copy here, so that fault handlers such as GDB
240 * can instrument this memory even if the client should not get
243 if (!(dsstat.flags & L4Re::Dataspace::Map_rw)) {
244 //MSG() << "Copying to rw dataspace.";
245 L4::Cap<L4Re::Dataspace> mem;
247 Romain::Region_map::allocate_ds(&mem, eff_size);
249 mem->copy_in(0, *ds, page_base, hdlr->offset() + size);
250 ds = &mem; // taking pointer to stack?? XXX
251 flags &= ~L4Re::Rm::Read_only;
254 * XXX: If we copied the dataspace above, what happens to the
255 * original DS that was passed in? Shouldn't it be released?
257 * No. It might still be attached elsewhere. Perhaps decrement
258 * some refcnt? XXX check
263 * flags contains the replica's flags setting. If the replica asks to attach into
264 * a previously reserved region, then this is only valid for the replica's
265 * rm::attach() call, but not for attaching our local version/copy of the DS.
267 flags &= ~L4Re::Rm::In_area;
269 l4_addr_t a = Romain::Region_map::attach_aligned(ds, eff_size,
274 Romain::Region reg(a, a+eff_size - 1);
277 MSG() << "set_local_region(" << _active_instance << ", "
278 << std::hex << reg.start() << ")";
279 hdlr->set_local_region(_active_instance, reg);
280 return (void*)(a + offset_in_page);
283 void *Romain::Region_map::attach(void* addr, unsigned long size,
284 Romain::Region_handler const &hdlr,
285 unsigned flags, unsigned char align, bool shared)
289 MSG() << std::hex << addr << " " << size << " " << (int)align << " " << flags;
290 MSG() << "cap " << std::hex << hdlr.client_cap_idx();
293 * XXX: the only reason for this Region_handler to exist is to copy
294 * the shared parameter into the handler. Shouldn't the caller
297 Romain::Region_handler _handler(hdlr);
298 _handler.shared(shared);
301 * First, do the attach() in the remote address space. Thereby we get
302 * the remote address and can then during local attaching make sure
303 * that the memory alignment of the local mapping matches the remote
304 * alignment. This allows us to play mapping tricks later.
306 * Note, we can only do this if the Search_addr flag is set, otherwise
307 * we might hurt the client's expectations about the mem region.
309 if ((flags & L4Re::Rm::Search_addr) and
310 !(flags & L4Re::Rm::In_area) and
311 (size > L4_SUPERPAGESIZE) and
312 (align < L4_LOG2_SUPERPAGESIZE)) {
313 align = L4_LOG2_SUPERPAGESIZE;
314 size = l4_round_size(size, L4_SUPERPAGESHIFT);
318 ret = Base::attach(addr, size, _handler, flags, align);
319 MSG() << "Base::attach = " << std::hex << ret << " hdlr.offs: " << _handler.offset();
320 if (ret == (void*)~0UL) {
321 INFO() << std::hex << addr << " " << size << " " << (int)align << " " << flags;
322 enter_kdebug("Attach error");
326 * The node is now present in the region map. This means we now need
327 * to continue working with the node's handler member instead of our
328 * local copy (because the attach() call has made a copy of it).
330 Romain::Region_map::Base::Node n = find((l4_addr_t)ret);
331 // and the region handler is const by default ... *grrrml*
332 Romain::Region_handler* theHandler = const_cast<Romain::Region_handler*>(&(n->second));
335 * Figure out the best possible alignment we can have between the local
336 * and the remote region. If the alignments match, we can later map more
337 * than one page at a time.
339 theHandler->alignToAddressAndSize(reinterpret_cast<l4_addr_t>(ret), size);
341 /* Only attach locally, if this hasn't been done beforehand yet. */
342 if (!n->second.local_region(_active_instance).start()) {
343 void* a = attach_locally(addr, size, theHandler,
344 flags, theHandler->alignment());
345 _check(a == 0, "Error in local attach");
348 MSG() << "new mapping (" << _active_instance << ") "
349 << "[" << std::hex << n->second.local_region(_active_instance).start()
350 << " - " << n->second.local_region(_active_instance).end()
352 //enter_kdebug("after attach");
359 int Romain::Region_map::detach(void* /* IN */ addr, unsigned long /* IN */ size,
360 unsigned /* IN */ flags,
361 L4Re::Util::Region* /* OUT */ reg,
362 Romain::Region_handler* /* OUT */ h)
364 /* First, do a lookup for the handler, because Base::Detach() will not always
365 * return the handler node, but we need it for detach later.
367 l4_addr_t srch = (l4_addr_t)addr;
368 Romain::Region_handler hd = Base::find(Region(srch, srch + size - 1))->second;
369 MSG() << "Client cap: " << std::hex << hd.client_cap_idx();
370 if (hd.client_cap_idx() == L4_INVALID_CAP) {
371 enter_kdebug("invalid cap!");
374 MSG() << std::hex << "Base::detach(" << (l4_addr_t)addr << " " << size << " " << flags << ")";
375 MSG() << std::hex << find((l4_addr_t)addr)->second.client_cap_idx();
376 int ret = Base::detach(addr, size, flags, reg, h);
377 MSG() << std::hex << "Base::detach(): " << ret << " r.start: " << reg->start() << " " << reg->size();
380 * Iterate over replicas and detach() the replicas' mappings within
383 for (unsigned idx = 0; idx < hd.local_region_count(); ++idx) {
384 if (hd.local_region(idx).start() == 0) {
388 MSG() << "[" << std::hex
389 << hd.local_region(idx).start() << " - "
390 << hd.local_region(idx).end() << "] ==> "
391 << "[" << reg->start() << " - "
392 << reg->end() << "]";
394 L4::Cap<L4Re::Dataspace> memcap;
395 int r = L4Re::Env::env()->rm()->detach(hd.local_region(idx).start(),
396 hd.local_region(idx).size(),
397 &memcap, L4Re::This_task);
398 MSG() << "detached locally: " << r << " cap: " << std::hex << memcap.cap();
400 if (!hd.writable()) {
401 /* For read-only regions, we only need to detach once */
410 bool Romain::Region_map::lazy_map_region(Romain::Region_map::Base::Node &n, unsigned inst, bool iswritepf)
412 /* already mapped? */
413 if (n->second.local_region(inst).start())
416 MSG() << "start " << n->second.local_region(inst).start();
417 MSG() << "replica without yet established mapping.";
418 MSG() << "ro: " << n->second.is_ro();
419 MSG() << "shared: " << (n->second.shared() ? "true" : "false");
422 * As we found a node, we know there exists at least one replica
423 * that already has this mapping. Therefore, we go and look for
424 * one of those mappings to start from.
426 int existing = find_existing_region(n);
427 _check(existing < 0, "no mapping???");
428 _check(existing > Romain::MAX_REPLICAS, "no mapping???");
430 Romain::Rm_guard(this, inst);
431 Romain::Region_handler *rh = const_cast<Romain::Region_handler*>(&n->second);
434 * Case 1: region is read-only -> we share the mapping from
435 * the first node, because it was already established.
437 if (n->second.is_ro() or rh->shared()) {
439 * XXX: Why is setting local_region and memory split up?
441 rh->set_local_region(inst, n->second.local_region(existing));
442 rh->local_memory(inst, n->second.local_memory(existing));
444 MSG() << "Copying existing mapping.";
445 bool b = copy_existing_mapping(*rh, existing, inst, iswritepf);
446 _check(!b, "error creating rw copy");