]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/plr/server/src/memory.cc
8677d1807f2efbd7890a8a940610f6dfb924ba9a
[l4.git] / l4 / pkg / plr / server / src / memory.cc
1 /*
2  * memory.cc --
3  *
4  * Memory management implementation
5  *
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.
11  */
12 #include "memory"
13 #include "app_loading"
14 #include "locking.h"
15 #include <l4/sys/kdebug.h>
16
17 #define MSG() DEBUGf(Romain::Log::Memory)
18
19 int Romain::Region_ops::map(Region_handler const *h, l4_addr_t addr,
20                             L4Re::Util::Region const &r, bool writable,
21                             l4_umword_t *result)
22 {
23         (void)h;
24         (void)addr;
25         (void)r;
26         (void)writable;
27         (void)result;
28         enter_kdebug("ops::map");
29         return -1;
30 }
31
32 void Romain::Region_ops::unmap(Region_handler const *h, l4_addr_t vaddr,
33                                l4_addr_t offs, unsigned long size)
34 {
35         (void)h;
36         (void)vaddr;
37         (void)offs;
38         (void)size;
39         enter_kdebug("ops::unmap");
40 }
41
42
43 void Romain::Region_ops::free(Region_handler const *h, l4_addr_t start, unsigned long size)
44 {
45         (void)h;
46         (void)start;
47         (void)size;
48         enter_kdebug("ops::free");
49 }
50
51
52 void Romain::Region_ops::take(Region_handler const* h)
53 {
54         (void)h;
55         enter_kdebug("ops::take");
56 }
57
58
59 void Romain::Region_ops::release(Region_handler const* h)
60 {
61         (void)h;
62         enter_kdebug("ops::release");
63 }
64
65
66 Romain::Region_map::Region_map()
67         : Base(0,0), _active_instance(Invalid_inst)
68 {
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)
72               << " entries.";
73
74         L4::Kip::Mem_desc *d = L4::Kip::Mem_desc::first(kip);
75         unsigned long count  = L4::Kip::Mem_desc::count(kip);
76
77         for (L4::Kip::Mem_desc *desc = d; desc < d + count; ++desc) {
78
79                 if (!desc->is_virtual())
80                         continue;
81
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 << "] ";
85
86                 switch(desc->type()) {
87                         case L4::Kip::Mem_desc::Conventional:
88                                 set_limits(s,e);
89                                 break;
90                         default:
91                                 WARN() << "type " << desc->type() << "???";
92                                 break;
93                 }
94
95         }
96 }
97
98
99 /*
100  * Attach a replica region locally in the master AS.
101  *
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
105  * the replicas.
106  *
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).
110  *
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.
113  */
114 void *Romain::Region_map::attach_locally(void* addr, unsigned long size,
115                                          Romain::Region_handler *hdlr,
116                                          unsigned flags, unsigned char align)
117 {
118         long r; (void)addr;
119         Romain::Region_handler::Dataspace const *ds = &hdlr->memory(0);
120         L4Re::Dataspace::Stats dsstat;
121         (*ds)->info(&dsstat);
122
123 #if 1
124         MSG() << PURPLE
125                   << "attaching DS " << std::hex << ds->cap()
126               << ", addr = "     << addr
127               << ", flags = "    << flags << " (" << dsstat.flags << ")"
128               << ", size = "     << size
129               << ", align = "    << (unsigned int)align
130               << NOCOLOR;
131 #endif
132
133         if (!ds->is_valid()) {
134                 enter_kdebug("attaching invalid cap");
135         }
136
137         /*
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.
142          *
143          * 1      2    3    4                      5
144          * +------+----+----+----------------------+
145          * |      |'..'|..'.|                      |       Original DS
146          * |      |.''.|''.'|                      |
147          * +------+----+----+----------------------+
148          *        \         \
149          *         \         \
150          *          \         \
151          *           \         \
152          *           +---------+
153          *           |''.''.''.|                           New DS
154          *           |..'..'..'|
155          *           +---------+
156          *           6         7
157          *
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
163          * 6 .. new DS start
164          * 7 .. new DS end
165          *
166          * offset_in_page = $3 - $2
167          * eff_size       = size + offset_in_page rounded to page size
168          *
169          * After copy:
170          *    page_base      = 0
171          *    hdlr()->offset = 0
172          *
173          */
174
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);
178
179 #if 1
180         MSG() << "  page_base " << (void*)page_base << ", offset " << std::hex << offset_in_page
181               << ", eff_size " << eff_size << ", hdlr->offset " << hdlr->offset();
182 #endif
183
184         hdlr->offset(page_base /*hdlr->offset() - offset_in_page*/);
185
186         /*
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
190          * it writable.
191          */
192         if (!(dsstat.flags & L4Re::Dataspace::Map_rw)) {
193                 //MSG() << "Copying to rw dataspace.";
194                 L4::Cap<L4Re::Dataspace> mem;
195
196                 Romain::Region_map::allocate_ds(&mem, eff_size);
197
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;
201                 page_base = 0;
202                 /*
203                  * XXX: If we copied the dataspace above, what happens to the
204                  *      original DS that was passed in? Shoudln't it be released?
205                  *
206                  *      No. It might still be attached elsewhere. Perhaps decrement
207                  *      some refcnt? XXX check
208                  */
209         }
210
211         /*
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.
215          */
216         flags &= ~L4Re::Rm::In_area;
217
218         l4_addr_t a = 0;
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");
223
224         Romain::Region reg(a, a+eff_size - 1);
225         reg.touch_rw();
226
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);
231 }
232
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)
236 {
237         void *ret = 0;
238
239         /*
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
242          *      do this???
243          */
244         Romain::Region_handler _handler(hdlr);
245         _handler.shared(shared);
246
247         /*
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.
252          */
253         ret = Base::attach(addr, size, _handler, flags, align);
254
255         /*
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).
259          */
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));
263         
264         /*
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.
268          */
269         theHandler->alignToAddressAndSize(reinterpret_cast<l4_addr_t>(ret), size);
270
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");
276         }
277
278         MSG() << "new mapping (" << _active_instance << ") "
279               << "[" << std::hex << n->second.local_region(_active_instance).start()
280               << " - " << n->second.local_region(_active_instance).end()
281               << "] -> " << ret;
282         //enter_kdebug("after attach");
283
284         return ret;
285 }
286
287
288
289 #if 0
290 int Romain::Region_map::detach(void* addr, unsigned long size, unsigned flags,
291                             L4Re::Util::Region* reg, Romain::Region_handler* h)
292 {
293         MSG() << "addr " << std::hex << l4_addr_t(addr) << " " << size
294               << " " << flags;
295         MSG() << "active instance: " << _active_instance;
296         enter_kdebug("detach");
297         return -1;
298 }
299 #endif
300
301 bool Romain::Region_map::lazy_map_region(Romain::Region_map::Base::Node &n, unsigned inst)
302 {
303         /* already mapped? */
304         if (n->second.local_region(inst).start())
305                 return false;
306
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");
311
312         /*
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.
316          */
317         int existing = find_existing_region(n);
318         _check(existing < 0, "no mapping???");
319         _check(existing > Romain::MAX_REPLICAS, "no mapping???");
320
321         Romain::Rm_guard(this, inst);
322         Romain::Region_handler *rh = const_cast<Romain::Region_handler*>(&n->second);
323
324         /*
325          * Case 1: region is read-only -> we share the mapping from
326          *         the first node, because it was already established.
327          */
328         
329         if (n->second.is_ro() or rh->shared()) {
330                 /*
331                  * XXX: Why is setting local_region and memory split up?
332                  */
333                 rh->set_local_region(inst, n->second.local_region(existing));
334                 rh->memory(inst, n->second.memory(existing));
335         } else {
336                 DEBUGf(Romain::Log::Memory) << "Copying existing mapping.";
337                 bool b = copy_existing_mapping(*rh, existing, inst);
338                 _check(!b, "error creating rw copy");
339         }
340         return true;
341 }