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() << "???";
99 void *Romain::Region_map::attach_locally(void* addr, unsigned long size,
100 Romain::Region_handler *hdlr,
101 unsigned flags, unsigned char align)
103 long r; (void)align; (void)addr;
104 Romain::Region_handler::Dataspace const *ds = &hdlr->memory(0);
105 L4Re::Dataspace::Stats dsstat;
106 (*ds)->info(&dsstat);
109 MSG() << "attaching DS " << std::hex << ds->cap()
110 << ", addr = " << addr
111 << ", flags = " << flags << " (" << dsstat.flags << ")"
112 << ", size = " << size;
115 if (!ds->is_valid()) {
116 enter_kdebug("attaching invalid cap");
120 * Here's what the variables below mean in the original DS. If the DS is
121 * read-only, we still want a writable version, because some users, such as
122 * GDB, want to modify ro data (e.g., GDB breakpoints). Therefore, we then
123 * create a copy of the original DS and adapt the variables afterwards.
126 * +------+----+----+----------------------+
127 * | |'..'|..'.| | Original DS
129 * +------+----+----+----------------------+
140 * 1 .. original DS start
141 * 2 .. page base of region (page_base)
142 * 3 .. offset within DS (hdlr()->offset)
143 * 4 .. region end (hdlr()->offset + size)
144 * 5 .. original DS end
148 * offset_in_page = $3 - $2
149 * eff_size = size + offset_in_page rounded to page size
157 l4_addr_t page_base = l4_trunc_page(hdlr->offset());
158 l4_addr_t offset_in_page = hdlr->offset() - page_base;
159 unsigned eff_size = l4_round_page(size + offset_in_page);
162 MSG() << " page_base " << (void*)page_base << ", offset " << std::hex << offset_in_page
163 << ", eff_size " << eff_size << ", hdlr->offset " << hdlr->offset();
166 hdlr->offset(page_base /*hdlr->offset() - offset_in_page*/);
169 * If the dataspace we attach was originally not mapped writable,
170 * make a writable copy here, so that fault handlers such as GDB
171 * can instrument this memory even if the client should not get
174 if (!(dsstat.flags & L4Re::Dataspace::Map_rw)) {
175 //MSG() << "Copying to rw dataspace.";
176 L4::Cap<L4Re::Dataspace> mem;
178 Romain::Region_map::allocate_ds(&mem, eff_size);
180 mem->copy_in(0, *ds, page_base, hdlr->offset() + size);
181 ds = &mem; // taking pointer to stack?? XXX
182 flags &= ~L4Re::Rm::Read_only;
185 * XXX: If we copied the dataspace above, what happens to the
186 * original DS that was passed in? Shoudln't it be released?
188 * No. It might still be attached elsewhere. Perhaps decrement
189 * some refcnt? XXX check
194 * flags contains the replica's flags setting. If the replica asks to attach into
195 * a previously reserved region, then this is only valid for the replica's
196 * rm::attach() call, but not for attaching our local version/copy of the DS.
198 flags &= ~L4Re::Rm::In_area;
201 r = L4Re::Env::env()->rm()->attach(&a, eff_size,
202 L4Re::Rm::Search_addr | flags,
204 _check(r != 0, "attach error");
206 Romain::Region reg(a, a+eff_size - 1);
209 hdlr->set_local_region(_active_instance, reg);
210 return (void*)(a + offset_in_page);
213 void *Romain::Region_map::attach(void* addr, unsigned long size,
214 Romain::Region_handler const &hdlr,
215 unsigned flags, unsigned char align, bool shared)
218 Romain::Region_handler _handler(hdlr);
220 _handler.shared(shared);
222 /* Only attach locally, if this hasn't been done beforehand yet. */
223 if (!_handler.local_region(_active_instance).start()) {
224 void* a = attach_locally(addr, size, &_handler, flags, align);
225 _check(a == 0, "Error in local attach");
227 ret = Base::attach(addr, size, _handler, flags, align);
229 MSG() << "new mapping (" << _active_instance << ") "
230 << "[" << std::hex << _handler.local_region(_active_instance).start()
231 << " - " << _handler.local_region(_active_instance).end()
233 //enter_kdebug("after attach");
241 int Romain::Region_map::detach(void* addr, unsigned long size, unsigned flags,
242 L4Re::Util::Region* reg, Romain::Region_handler* h)
244 MSG() << "addr " << std::hex << l4_addr_t(addr) << " " << size
246 MSG() << "active instance: " << _active_instance;
247 enter_kdebug("detach");
252 bool Romain::Region_map::lazy_map_region(Romain::Region_map::Base::Node &n, unsigned inst)
254 /* already mapped? */
255 if (n->second.local_region(inst).start())
258 DEBUGf(Romain::Log::Memory) << "start " << n->second.local_region(inst).start();
259 DEBUGf(Romain::Log::Memory) << "replica without yet established mapping.";
260 DEBUGf(Romain::Log::Memory) << "ro: " << n->second.is_ro();
261 DEBUGf(Romain::Log::Memory) << "shared: " << (n->second.shared() ? "true" : "false");
264 * As we found a node, we know there exists at least one replica
265 * that already has this mapping. Therefore, we go and look for
266 * one of those mappings to start from.
268 int existing = find_existing_region(n);
269 _check(existing < 0, "no mapping???");
270 _check(existing > Romain::MAX_REPLICAS, "no mapping???");
272 Romain::Rm_guard(this, inst);
273 Romain::Region_handler *rh = const_cast<Romain::Region_handler*>(&n->second);
276 * Case 1: region is read-only -> we share the mapping from
277 * the first node, because it was already established.
280 if (n->second.is_ro() or rh->shared()) {
282 * XXX: Why is setting local_region and memory split up?
284 rh->set_local_region(inst, n->second.local_region(existing));
285 rh->memory(inst, n->second.memory(existing));
287 DEBUGf(Romain::Log::Memory) << "Copying existing mapping.";
288 bool b = copy_existing_mapping(*rh, existing, inst);
289 _check(!b, "error creating rw copy");