]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/valgrind/src/valgrind-3.6.0-svn/coregrind/l4re/rm_init.cpp
update
[l4.git] / l4 / pkg / valgrind / src / valgrind-3.6.0-svn / coregrind / l4re / rm_init.cpp
1 /*
2  * This file is part of the Valgrind port to L4Re.
3  *
4  * (c) 2009-2010 Aaron Pohle <apohle@os.inf.tu-dresden.de>,
5  *               Bjoern Doebel <doebel@os.inf.tu-dresden.de>
6  *     economic rights: Technische Universitaet Dresden (Germany)
7  */
8 #include <l4/re/util/cap_alloc>
9 #include <l4/re/env>
10 #include <l4/re/util/region_mapping>
11 #include <l4/cxx/slab_alloc>
12 #include <l4/cxx/ipc_server>
13
14 __BEGIN_DECLS
15 #include "l4re/myelf.h"
16 #include "pub_core_basics.h"
17 #include "pub_l4re.h"
18 #include "pub_l4re_consts.h"
19 #include "pub_tool_libcbase.h"
20 #include "pub_tool_libcfile.h"
21 #include "pub_core_libcprint.h"
22 __END_DECLS
23 #include "pub_core_vki.h"
24 __BEGIN_DECLS
25 #include "pub_core_tooliface.h"
26 #include "pub_core_libcassert.h" // VG_(exit)
27 #include "l4re_helper.h"
28 __END_DECLS
29
30 /***********************************************************************************
31  *
32  *                          L4Re kernel compatibility cruft
33  *                          -------------------------------
34  *
35  * L4Re executes the L4Re kernel within every application. The kernel's is respon-
36  * sible for loading the application (until startup of the main thread) and there-
37  * after acts as the application's region manager and page fault handler. Both of
38  * these tasks are in our case taken over by VCap. However, in order to do this,
39  * Valgrind needs info about the initial memory layout upon startup of its address
40  * space manager.
41  *
42  * Since there is no easy way to gain this information from the L4Re kernel (as it
43  * is deliberately kept private, because we don't want anyone messing aroung with
44  * the region map), we need to take the slightly fragile way of mirroring parts of
45  * the L4Re kernel's class declarations here in order to be able to use them later
46  * on.
47  *
48  * This means
49  *   (1) Be careful, when to use this stuff. By now, only VG_(am_startup)() should
50  *       need to call this.
51  *       ==> There is a check in vrm_get_lists() to make sure this won't work
52  *           after VCap took over.
53  *   (2) Be careful with copied class declarations.
54  *       ==> Clearly mark where these decls come from.
55  *
56  ***********************************************************************************/
57
58 // l4re_kernel/server/src/page_alloc.h, revision 37866
59 class Region_map;
60
61 class Single_page_alloc_base
62 {
63 public:
64   static void init(L4::Cap<L4Re::Mem_alloc> alloc);
65   static void init_local_rm(Region_map *lrm);
66 protected:
67   Single_page_alloc_base();
68   static void *_alloc();
69   static void _free(void *p);
70 };
71
72 template<typename A>
73 class Single_page_alloc : public Single_page_alloc_base
74 {
75 public:
76   enum { can_free = true };
77   A *alloc() { return reinterpret_cast<A*>(_alloc()); }
78   void free(A *o) { _free(o); }
79 };
80
81
82 // l4re_kernel/server/src/slab_alloc.h, revision 37866
83 template< typename Type >
84 class Slab_alloc 
85 : public cxx::Slab_static<Type, L4_PAGESIZE, 2, Single_page_alloc>
86 {};
87
88
89 // l4re_kernel/server/src/region.h, revision 37866
90 class Region_ops;
91
92 typedef L4Re::Util::Region_handler<L4::Cap<L4Re::Dataspace>, Region_ops> Region_handler;
93
94 class Region_ops
95 {
96 public:
97   typedef l4_umword_t Map_result;
98   static int map(Region_handler const *h, l4_addr_t addr,
99                  L4Re::Util::Region const &r, bool writable,
100                  l4_umword_t *result);
101
102   static void unmap(Region_handler const *h, l4_addr_t vaddr,
103                     l4_addr_t offs, unsigned long size);
104
105   static void free(Region_handler const *h, l4_addr_t start, unsigned long size);
106
107   static void take(Region_handler const *h);
108   static void release(Region_handler const *h);
109 };
110
111
112 class Region_map
113 : public L4Re::Util::Region_map<Region_handler, Slab_alloc>
114 {
115 private:
116   typedef L4Re::Util::Region_map<Region_handler, Slab_alloc> Base;
117
118 public:
119   Region_map();
120   //void setup_wait(L4::Ipc_istream &istr);
121   int handle_pagefault(L4::Ipc_iostream &ios);
122   int handle_rm_request(L4::Ipc_iostream &ios);
123   virtual ~Region_map() {}
124
125   void init();
126
127   void debug_dump(unsigned long function) const;
128 private:
129   int reply_err(L4::Ipc_iostream &ios);
130 };
131
132
133 EXTERN_C void* mmap(void *, size_t, int, int, int, off_t) throw();
134 EXTERN_C int munmap(void *, size_t) throw();
135
136
137 static Region_map *vrm_determine_local_rm_address()
138 {
139     /*
140      * Determine the address of the RE kernel's local RM.
141      */
142
143     /*
144      * 1. Try to find symbol in ELF image file
145      */
146     if (dbg_elf) VG_(printf)("opening rom/l4re\n");
147     SysRes res = VG_(open)((const Char*)"rom/l4re", VKI_O_RDONLY, 0);
148     if (dbg_elf) VG_(printf)("opened: %ld\n", sr_Res(res));
149     if (sr_isError(res)) {
150         VG_(printf)("Error opening file: %ld\n", sr_Err(res));
151         enter_kdebug();
152     }
153
154     int fd = sr_Res(res);
155
156     struct vg_stat statbuf;
157     int err = VG_(fstat)(fd, &statbuf);
158     if (dbg_elf) VG_(printf)("stat: %d, size %d\n", err, (int)statbuf.size);
159
160     if (err) {
161         VG_(printf)("error on fstat(): %d\n", err);
162         enter_kdebug();
163     }
164
165     void *a = 0;
166     a = mmap(a, statbuf.size, VKI_PROT_READ, VKI_MAP_PRIVATE, fd, 0);
167     if (dbg_elf) VG_(printf)("mmap to %p\n", a);
168
169     melf_global_elf_info i;
170     err = melf_parse_elf(a, &i);
171     if (dbg_elf) VG_(printf)("parsed: %d\n", err);
172
173     char *rm_addr = melf_find_symbol_by_name(&i, (char*)"__local_rm");
174     if (dbg_elf) VG_(printf)("Found symbol %s @ %p\n", (char*)"__local_rm", rm_addr);
175
176     munmap(a, VG_PGROUNDUP(statbuf.size));
177     VG_(close)(fd);
178
179     if (rm_addr)
180         return reinterpret_cast<Region_map*>(rm_addr);
181
182     /*
183      * 2. If not successful parsing binary, try hard-coded value
184      */
185     VG_(printf)("Did not find local-rm, aborting\n");
186     VG_(exit)(1);
187
188     /* Not found? */
189 }
190
191
192 EXTERN_C void vrm_get_lists(struct vrm_region_lists *rlist, unsigned num_regions,
193                             unsigned num_areas)
194 {
195     /*
196      * If we happen to need this function while vcap is running (which should not be
197      * the case), then implement it as a call to vcap in order to serialize segment
198      * list access...
199      */
200     if (vcap_running) {
201         VG_(debugLog)(0, "vcap", "Attention: VCAP thread is already running.");
202         VG_(exit)(1);
203     }
204
205     /*
206      * ... otherwise we'll now assume that we are running single-threaded and
207      * vcap has not been started yet. (This is the case where am_startup() uses
208      * this function to populate the segment list initially.)
209      */
210
211     Region_map *lrm = vrm_determine_local_rm_address();
212     if (dbg_elf) VG_(printf)("LRM found @ %p\n", lrm);
213     if (lrm) {
214
215         /* LRM generic stats */
216         rlist->min_addr     = lrm->min_addr();
217         rlist->max_addr     = lrm->max_addr();
218         rlist->region_count = 0;
219         rlist->area_count   = 0;
220         if (dbg_rm) VG_(debugLog)(2, "vcap", "rlist min: %08lx\n", rlist->min_addr);
221         if (dbg_rm) VG_(debugLog)(2, "vcap", "rlist max: %08lx\n", rlist->max_addr);
222
223         /* Read LRM areas */
224         struct vrm_area *area = rlist->areas;
225         for (Region_map::Const_iterator i = lrm->area_begin();
226              i != lrm->area_end();
227              ++i) {
228             if (dbg_rm) VG_(debugLog)(2, "vcap", "AREA %08lx - %08lx\n", i->first.start(), i->first.end());
229             area->start = i->first.start();
230             area->end   = i->first.end();
231             area->flags = i->second.flags();
232
233             ++area;
234             ++rlist->area_count;
235         }
236
237         /* Read LRM regions */
238         struct vrm_region *reg = rlist->regions;
239         for (Region_map::Const_iterator i = lrm->begin();
240              i != lrm->end();
241              ++i) {
242             if (dbg_rm) VG_(debugLog)(2, "vcap", "REGION %08lx - %08lx\n", i->first.start(), i->first.end());
243             reg->start        = i->first.start();
244             reg->end          = i->first.end();
245             reg->flags        = i->second.flags();
246             reg->offset_in_ds = i->second.offset();
247             reg->ds           = i->second.memory().cap();
248
249             ++reg;
250             ++rlist->region_count;
251         }
252     }
253     else {
254         VG_(printf)("implement probing fallback...\n");
255         VG_(exit)(1);
256     }
257 }