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)
48 enter_kdebug("ops::free");
52 void Romain::Region_ops::take(Region_handler const* h)
55 enter_kdebug("ops::take");
59 void Romain::Region_ops::release(Region_handler const* h)
62 enter_kdebug("ops::release");
66 Romain::Region_map::Region_map()
67 : Base(0,0), _active_instance(Invalid_inst)
69 l4_kernel_info_t *kip = l4re_kip();
70 MSG() << "kip found at 0x" << std::hex << kip
71 << " having " << L4::Kip::Mem_desc::count(kip)
74 L4::Kip::Mem_desc *d = L4::Kip::Mem_desc::first(kip);
75 unsigned long count = L4::Kip::Mem_desc::count(kip);
77 for (L4::Kip::Mem_desc *desc = d; desc < d + count; ++desc) {
79 if (!desc->is_virtual())
82 l4_addr_t s = desc->start() == 0 ? 0x1000 : desc->start();
83 l4_addr_t e = desc->end();
84 MSG() << "virtual range: [" << std::hex << s << "-" << e << "] ";
86 switch(desc->type()) {
87 case L4::Kip::Mem_desc::Conventional:
91 WARN() << "type " << desc->type() << "???";
100 * Attach a replica region locally in the master AS.
102 * The Romain::Master manages replicas' region map. As a part of this, the master
103 * attaches a copy of every region attached to one of the replicas to its own
104 * address space. This local region is then used to service page faults caused by
107 * For read-only replica dataspaces, the master creates a writable copy of the
108 * original region in a separate dataspace. This allows us to modify their content
109 * if necessary (e.g., setting debug breakpoints on read-only code).
111 * For writable dataspaces, the master simply attaches the same region that has
112 * already been attached to the replica AS into its own address space.
114 void *Romain::Region_map::attach_locally(void* addr, unsigned long size,
115 Romain::Region_handler *hdlr,
116 unsigned flags, unsigned char align)
119 Romain::Region_handler::Dataspace const *ds = &hdlr->memory(0);
120 L4Re::Dataspace::Stats dsstat;
121 (*ds)->info(&dsstat);
125 << "attaching DS " << std::hex << ds->cap()
126 << ", addr = " << addr
127 << ", flags = " << flags << " (" << dsstat.flags << ")"
128 << ", size = " << size
129 << ", align = " << (unsigned int)align
133 if (!ds->is_valid()) {
134 enter_kdebug("attaching invalid cap");
138 * Here's what the variables below mean in the original DS. If the DS is
139 * read-only, we still want a writable version, because some users, such as
140 * GDB, want to modify ro data (e.g., GDB breakpoints). Therefore, we then
141 * create a copy of the original DS and adapt the variables afterwards.
144 * +------+----+----+----------------------+
145 * | |'..'|..'.| | Original DS
147 * +------+----+----+----------------------+
158 * 1 .. original DS start
159 * 2 .. page base of region (page_base)
160 * 3 .. offset within DS (hdlr()->offset)
161 * 4 .. region end (hdlr()->offset + size)
162 * 5 .. original DS end
166 * offset_in_page = $3 - $2
167 * eff_size = size + offset_in_page rounded to page size
175 l4_addr_t page_base = l4_trunc_page(hdlr->offset());
176 l4_addr_t offset_in_page = hdlr->offset() - page_base;
177 unsigned eff_size = l4_round_page(size + offset_in_page);
180 MSG() << " page_base " << (void*)page_base << ", offset " << std::hex << offset_in_page
181 << ", eff_size " << eff_size << ", hdlr->offset " << hdlr->offset();
184 hdlr->offset(page_base /*hdlr->offset() - offset_in_page*/);
187 * If the dataspace we attach was originally not mapped writable,
188 * make a writable copy here, so that fault handlers such as GDB
189 * can instrument this memory even if the client should not get
192 if (!(dsstat.flags & L4Re::Dataspace::Map_rw)) {
193 //MSG() << "Copying to rw dataspace.";
194 L4::Cap<L4Re::Dataspace> mem;
196 Romain::Region_map::allocate_ds(&mem, eff_size);
198 mem->copy_in(0, *ds, page_base, hdlr->offset() + size);
199 ds = &mem; // taking pointer to stack?? XXX
200 flags &= ~L4Re::Rm::Read_only;
203 * XXX: If we copied the dataspace above, what happens to the
204 * original DS that was passed in? Shoudln't it be released?
206 * No. It might still be attached elsewhere. Perhaps decrement
207 * some refcnt? XXX check
212 * flags contains the replica's flags setting. If the replica asks to attach into
213 * a previously reserved region, then this is only valid for the replica's
214 * rm::attach() call, but not for attaching our local version/copy of the DS.
216 flags &= ~L4Re::Rm::In_area;
219 r = L4Re::Env::env()->rm()->attach(&a, eff_size,
220 L4Re::Rm::Search_addr | flags,
221 *ds, page_base, align);
222 _check(r != 0, "attach error");
224 Romain::Region reg(a, a+eff_size - 1);
227 MSG() << "set_local_region(" << _active_instance << ", "
228 << std::hex << reg.start() << ")";
229 hdlr->set_local_region(_active_instance, reg);
230 return (void*)(a + offset_in_page);
233 void *Romain::Region_map::attach(void* addr, unsigned long size,
234 Romain::Region_handler const &hdlr,
235 unsigned flags, unsigned char align, bool shared)
240 * XXX: the only reason for this Region_handler to exist is to copy
241 * the shared parameter into the handler. Shouldn't the caller
244 Romain::Region_handler _handler(hdlr);
245 _handler.shared(shared);
248 * First, do the attach() in the remote address space. Thereby we get
249 * the remote address and can then during local attaching make sure
250 * that the memory alignment of the local mapping matches the remote
251 * alignment. This allows us to play mapping tricks later.
253 ret = Base::attach(addr, size, _handler, flags, align);
256 * The node is now present in the region map. This means we now need
257 * to continue working with the node's handler member instead of our
258 * local copy (because the attach() call has made a copy of it).
260 Romain::Region_map::Base::Node n = find((l4_addr_t)ret);
261 // and the region handler is const by default ... *grrrml*
262 Romain::Region_handler* theHandler = const_cast<Romain::Region_handler*>(&(n->second));
265 * Figure out the best possible alignment we can have between the local
266 * and the remote region. If the alignments match, we can later map more
267 * than one page at a time.
269 theHandler->alignToAddressAndSize(reinterpret_cast<l4_addr_t>(ret), size);
271 /* Only attach locally, if this hasn't been done beforehand yet. */
272 if (!n->second.local_region(_active_instance).start()) {
273 void* a = attach_locally(addr, size, theHandler,
274 flags, theHandler->alignment());
275 _check(a == 0, "Error in local attach");
278 MSG() << "new mapping (" << _active_instance << ") "
279 << "[" << std::hex << n->second.local_region(_active_instance).start()
280 << " - " << n->second.local_region(_active_instance).end()
282 //enter_kdebug("after attach");
290 int Romain::Region_map::detach(void* addr, unsigned long size, unsigned flags,
291 L4Re::Util::Region* reg, Romain::Region_handler* h)
293 MSG() << "addr " << std::hex << l4_addr_t(addr) << " " << size
295 MSG() << "active instance: " << _active_instance;
296 enter_kdebug("detach");
301 bool Romain::Region_map::lazy_map_region(Romain::Region_map::Base::Node &n, unsigned inst)
303 /* already mapped? */
304 if (n->second.local_region(inst).start())
307 DEBUGf(Romain::Log::Memory) << "start " << n->second.local_region(inst).start();
308 DEBUGf(Romain::Log::Memory) << "replica without yet established mapping.";
309 DEBUGf(Romain::Log::Memory) << "ro: " << n->second.is_ro();
310 DEBUGf(Romain::Log::Memory) << "shared: " << (n->second.shared() ? "true" : "false");
313 * As we found a node, we know there exists at least one replica
314 * that already has this mapping. Therefore, we go and look for
315 * one of those mappings to start from.
317 int existing = find_existing_region(n);
318 _check(existing < 0, "no mapping???");
319 _check(existing > Romain::MAX_REPLICAS, "no mapping???");
321 Romain::Rm_guard(this, inst);
322 Romain::Region_handler *rh = const_cast<Romain::Region_handler*>(&n->second);
325 * Case 1: region is read-only -> we share the mapping from
326 * the first node, because it was already established.
329 if (n->second.is_ro() or rh->shared()) {
331 * XXX: Why is setting local_region and memory split up?
333 rh->set_local_region(inst, n->second.local_region(existing));
334 rh->memory(inst, n->second.memory(existing));
336 DEBUGf(Romain::Log::Memory) << "Copying existing mapping.";
337 bool b = copy_existing_mapping(*rh, existing, inst);
338 _check(!b, "error creating rw copy");