]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/plr/server/src/memory.cc
update
[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 void *Romain::Region_map::attach_locally(void* addr, unsigned long size,
100                                          Romain::Region_handler *hdlr,
101                                          unsigned flags, unsigned char align)
102 {
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);
107
108 #if 0
109         MSG() << "attaching DS " << std::hex << ds->cap()
110               << ", addr = "     << addr
111               << ", flags = "    << flags << " (" << dsstat.flags << ")"
112               << ", size = "     << size;
113 #endif
114
115         if (!ds->is_valid()) {
116                 enter_kdebug("attaching invalid cap");
117         }
118
119         /*
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.
124          *
125          * 1      2    3    4                      5
126          * +------+----+----+----------------------+
127          * |      |'..'|..'.|                      |       Original DS
128          * |      |.''.|''.'|                      |
129          * +------+----+----+----------------------+
130          *        \         \
131          *         \         \
132          *          \         \
133          *           \         \
134          *           +---------+
135          *           |''.''.''.|                           New DS
136          *           |..'..'..'|
137          *           +---------+
138          *           6         7
139          *
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
145          * 6 .. new DS start
146          * 7 .. new DS end
147          *
148          * offset_in_page = $3 - $2
149          * eff_size       = size + offset_in_page rounded to page size
150          *
151          * After copy:
152          *    page_base      = 0
153          *    hdlr()->offset = 0
154          *
155          */
156
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);
160
161 #if 1
162         MSG() << "  page_base " << (void*)page_base << ", offset " << std::hex << offset_in_page
163               << ", eff_size " << eff_size << ", hdlr->offset " << hdlr->offset();
164 #endif
165
166         hdlr->offset(page_base /*hdlr->offset() - offset_in_page*/);
167
168         /*
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
172          * it writable.
173          */
174         if (!(dsstat.flags & L4Re::Dataspace::Map_rw)) {
175                 //MSG() << "Copying to rw dataspace.";
176                 L4::Cap<L4Re::Dataspace> mem;
177
178                 Romain::Region_map::allocate_ds(&mem, eff_size);
179
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;
183                 page_base = 0;
184                 /*
185                  * XXX: If we copied the dataspace above, what happens to the
186                  *      original DS that was passed in? Shoudln't it be released?
187                  *
188                  *      No. It might still be attached elsewhere. Perhaps decrement
189                  *      some refcnt? XXX check
190                  */
191         }
192
193         /*
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.
197          */
198         flags &= ~L4Re::Rm::In_area;
199
200         l4_addr_t a = 0;
201         r = L4Re::Env::env()->rm()->attach(&a, eff_size,
202                                            L4Re::Rm::Search_addr | flags,
203                                            *ds, page_base);
204         _check(r != 0, "attach error");
205
206         Romain::Region reg(a, a+eff_size - 1);
207         reg.touch_rw();
208
209         hdlr->set_local_region(_active_instance, reg);
210         return (void*)(a + offset_in_page);
211 }
212
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)
216 {
217         void *ret = 0;
218         Romain::Region_handler _handler(hdlr);
219
220         _handler.shared(shared);
221
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");
226         }
227         ret = Base::attach(addr, size, _handler, flags, align);
228
229         MSG() << "new mapping (" << _active_instance << ") "
230               << "[" << std::hex << _handler.local_region(_active_instance).start()
231               << " - " << _handler.local_region(_active_instance).end()
232               << "] -> " << ret;
233         //enter_kdebug("after attach");
234
235         return ret;
236 }
237
238
239
240 #if 0
241 int Romain::Region_map::detach(void* addr, unsigned long size, unsigned flags,
242                             L4Re::Util::Region* reg, Romain::Region_handler* h)
243 {
244         MSG() << "addr " << std::hex << l4_addr_t(addr) << " " << size
245               << " " << flags;
246         MSG() << "active instance: " << _active_instance;
247         enter_kdebug("detach");
248         return -1;
249 }
250 #endif
251
252 bool Romain::Region_map::lazy_map_region(Romain::Region_map::Base::Node &n, unsigned inst)
253 {
254         /* already mapped? */
255         if (n->second.local_region(inst).start())
256                 return false;
257
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");
262
263         /*
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.
267          */
268         int existing = find_existing_region(n);
269         _check(existing < 0, "no mapping???");
270         _check(existing > Romain::MAX_REPLICAS, "no mapping???");
271
272         Romain::Rm_guard(this, inst);
273         Romain::Region_handler *rh = const_cast<Romain::Region_handler*>(&n->second);
274
275         /*
276          * Case 1: region is read-only -> we share the mapping from
277          *         the first node, because it was already established.
278          */
279         
280         if (n->second.is_ro() or rh->shared()) {
281                 /*
282                  * XXX: Why is setting local_region and memory split up?
283                  */
284                 rh->set_local_region(inst, n->second.local_region(existing));
285                 rh->memory(inst, n->second.memory(existing));
286         } else {
287                 DEBUGf(Romain::Log::Memory) << "Copying existing mapping.";
288                 bool b = copy_existing_mapping(*rh, existing, inst);
289                 _check(!b, "error creating rw copy");
290         }
291         return true;
292 }