1 /*
2 * (c) 2008-2010 Adam Lackorzynski <adam@os.inf.tu-dresden.de>,
3 * Alexander Warg <warg@os.inf.tu-dresden.de>,
4 * Björn Döbel <doebel@os.inf.tu-dresden.de>
5 * economic rights: Technische Universität Dresden (Germany)
6 *
7 * This file is part of TUD:OS and distributed under the terms of the
8 * GNU General Public License 2.
9 * Please see the COPYING-GPL-2 file for details.
10 *
11 * As a special exception, you may use this file as part of a free software
12 * library without restriction. Specifically, if other files instantiate
13 * templates or use macros or inline functions from this file, or you compile
14 * this file and link it with other files to produce an executable, this
15 * file does not by itself cause the resulting executable to be covered by
16 * the GNU General Public License. This exception does not however
17 * invalidate any other reasons why the executable file might be covered by
18 * the GNU General Public License.
19 */
20
21 #include "fd_store.h"
22 #include "vcon_stream.h"
23 #include "ns_fs.h"
24
25 #include <l4/re/env>
26 #include <l4/re/rm>
27 #include <l4/re/dataspace>
28 #include <l4/cxx/hlist>
29 #include <l4/cxx/pair>
30 #include <l4/cxx/std_alloc>
31
32 #include <l4/l4re_vfs/backend>
33 #include <l4/re/shared_cap>
34
35 #include <unistd.h>
36 #include <cstdarg>
37 #include <errno.h>
38 #include <sys/uio.h>
39
40 #if 0
41 #include <l4/sys/kdebug.h>
42 static int debug_mmap = 1;
43 #define DEBUG_LOG(level, dbg...) do { if (level) dbg } while (0)
44 #else
45 #define DEBUG_LOG(level, dbg...) do { } while (0)
46 #endif
47
48 /**
49 * If USE_BIG_ANON_DS is defined the implementation will use a really big
50 * data space for backing anonymous memory. Otherwise each mmap call
51 * with anonymous memory will allocate a separate data space.
52 */
53 #define USE_BIG_ANON_DS
54
55 using L4Re::Rm;
56
57 namespace {
58
59 using cxx::Ref_ptr;
60
61 class Fd_store : public L4Re::Core::Fd_store
62 {
63 public:
64 Fd_store() throw();
65 };
66
67 // for internal Vcon_streams we want to have a placement new operator, so
68 // inherit and add one
69 class Std_stream : public L4Re::Core::Vcon_stream
70 {
71 public:
Std_stream(L4::Cap<L4::Vcon> c)72 Std_stream(L4::Cap<L4::Vcon> c) : L4Re::Core::Vcon_stream(c) {}
73 };
74
Fd_store()75 Fd_store::Fd_store() throw()
76 {
77 // use this strange way to prevent deletion of the stdio object
78 // this depends on Fd_store to being a singleton !!!
79 static char m[sizeof(Std_stream)] __attribute__((aligned(sizeof(long))));
80 Std_stream *s = new (m) Std_stream(L4Re::Env::env()->log());
81 // make sure that we never delete the static io stream thing
82 s->add_ref();
83 set(0, cxx::ref_ptr(s)); // stdin
84 set(1, cxx::ref_ptr(s)); // stdout
85 set(2, cxx::ref_ptr(s)); // stderr
86 }
87
88 class Root_mount_tree : public L4Re::Vfs::Mount_tree
89 {
90 public:
Root_mount_tree()91 Root_mount_tree() : L4Re::Vfs::Mount_tree(0) {}
delete(void *)92 void operator delete (void *) {}
93 };
94
95 class Vfs : public L4Re::Vfs::Ops
96 {
97 private:
98 bool _early_oom;
99
100 public:
Vfs()101 Vfs()
102 : _early_oom(true), _root_mount(), _root(L4Re::Env::env())
103 {
104 _root_mount.add_ref();
105 _root.add_ref();
106 _root_mount.mount(cxx::ref_ptr(&_root));
107 _cwd = cxx::ref_ptr(&_root);
108
109 #if 0
110 Ref_ptr<L4Re::Vfs::File> rom;
111 _root.openat("rom", 0, 0, &rom);
112
113 _root_mount.create_tree("lib/foo", rom);
114
115 _root.openat("lib", 0, 0, &_cwd);
116
117 #endif
118 }
119
120 int alloc_fd(Ref_ptr<L4Re::Vfs::File> const &f) throw();
121 Ref_ptr<L4Re::Vfs::File> free_fd(int fd) throw();
122 Ref_ptr<L4Re::Vfs::File> get_root() throw();
123 Ref_ptr<L4Re::Vfs::File> get_cwd() throw();
124 void set_cwd(Ref_ptr<L4Re::Vfs::File> const &dir) throw();
125 Ref_ptr<L4Re::Vfs::File> get_file(int fd) throw();
126 cxx::Pair<Ref_ptr<L4Re::Vfs::File>, int>
127 set_fd(int fd, Ref_ptr<L4Re::Vfs::File> const &f = Ref_ptr<>::Nil) throw();
128
129 int mmap2(void *start, size_t len, int prot, int flags, int fd,
130 off_t offset, void **ptr) throw();
131
132 int munmap(void *start, size_t len) throw();
133 int mremap(void *old, size_t old_sz, size_t new_sz, int flags,
134 void **new_addr) throw();
135 int mprotect(const void *a, size_t sz, int prot) throw();
136 int msync(void *addr, size_t len, int flags) throw();
137 int madvise(void *addr, size_t len, int advice) throw();
138
139 int register_file_system(L4Re::Vfs::File_system *f) throw();
140 int unregister_file_system(L4Re::Vfs::File_system *f) throw();
141 L4Re::Vfs::File_system *get_file_system(char const *fstype) throw();
142
143 int register_file_factory(cxx::Ref_ptr<L4Re::Vfs::File_factory> f) throw();
144 int unregister_file_factory(cxx::Ref_ptr<L4Re::Vfs::File_factory> f) throw();
145 Ref_ptr<L4Re::Vfs::File_factory> get_file_factory(int proto) throw();
146 Ref_ptr<L4Re::Vfs::File_factory> get_file_factory(char const *proto_name) throw();
147 int mount(char const *path, cxx::Ref_ptr<L4Re::Vfs::File> const &dir) throw();
148
delete(void *)149 void operator delete (void *) {}
150
malloc(size_t size)151 void *malloc(size_t size) noexcept { return Vfs_config::malloc(size); }
free(void * m)152 void free(void *m) noexcept { Vfs_config::free(m); }
153
154 private:
155 Root_mount_tree _root_mount;
156 L4Re::Core::Env_dir _root;
157 Ref_ptr<L4Re::Vfs::File> _cwd;
158 Fd_store fds;
159
160 L4Re::Vfs::File_system *_fs_registry;
161
162 struct File_factory_item : cxx::H_list_item_t<File_factory_item>
163 {
164 cxx::Ref_ptr<L4Re::Vfs::File_factory> f;
File_factory_itemFile_factory_item165 explicit File_factory_item(cxx::Ref_ptr<L4Re::Vfs::File_factory> const &f)
166 : f(f) {};
167
168 File_factory_item() = default;
169 File_factory_item(File_factory_item const &) = delete;
170 File_factory_item &operator = (File_factory_item const &) = delete;
171 };
172
173 cxx::H_list_t<File_factory_item> _file_factories;
174
175 l4_addr_t _anon_offset;
176 L4Re::Shared_cap<L4Re::Dataspace> _anon_ds;
177
178 int alloc_ds(unsigned long size, L4Re::Shared_cap<L4Re::Dataspace> *ds);
179 int alloc_anon_mem(l4_umword_t size, L4Re::Shared_cap<L4Re::Dataspace> *ds,
180 l4_addr_t *offset);
181 };
182
strequal(char const * a,char const * b)183 static inline bool strequal(char const *a, char const *b)
184 {
185 for (;*a && *a == *b; ++a, ++b)
186 ;
187 return *a == *b;
188 }
189
190 int
register_file_system(L4Re::Vfs::File_system * f)191 Vfs::register_file_system(L4Re::Vfs::File_system *f) throw()
192 {
193 using L4Re::Vfs::File_system;
194
195 if (!f)
196 return -EINVAL;
197
198 for (File_system *c = _fs_registry; c; c = c->next())
199 if (strequal(c->type(), f->type()))
200 return -EEXIST;
201
202 f->next(_fs_registry);
203 _fs_registry = f;
204
205 return 0;
206 }
207
208 int
unregister_file_system(L4Re::Vfs::File_system * f)209 Vfs::unregister_file_system(L4Re::Vfs::File_system *f) throw()
210 {
211 using L4Re::Vfs::File_system;
212
213 if (!f)
214 return -EINVAL;
215
216 File_system **p = &_fs_registry;
217
218 for (; *p; p = &(*p)->next())
219 if (*p == f)
220 {
221 *p = f->next();
222 f->next() = 0;
223 return 0;
224 }
225
226 return -ENOENT;
227 }
228
229 L4Re::Vfs::File_system *
get_file_system(char const * fstype)230 Vfs::get_file_system(char const *fstype) throw()
231 {
232 bool try_dynamic = true;
233 for (;;)
234 {
235 using L4Re::Vfs::File_system;
236 for (File_system *c = _fs_registry; c; c = c->next())
237 if (strequal(c->type(), fstype))
238 return c;
239
240 if (!try_dynamic)
241 return 0;
242
243 // try to load a file system module dynamically
244 int res = Vfs_config::load_module(fstype);
245
246 if (res < 0)
247 return 0;
248
249 try_dynamic = false;
250 }
251 }
252
253 int
register_file_factory(cxx::Ref_ptr<L4Re::Vfs::File_factory> f)254 Vfs::register_file_factory(cxx::Ref_ptr<L4Re::Vfs::File_factory> f) throw()
255 {
256 if (!f)
257 return -EINVAL;
258
259 void *x = this->malloc(sizeof(File_factory_item));
260 if (!x)
261 return -ENOMEM;
262
263 auto ff = new (x, cxx::Nothrow()) File_factory_item(f);
264 _file_factories.push_front(ff);
265 return 0;
266 }
267
268 int
unregister_file_factory(cxx::Ref_ptr<L4Re::Vfs::File_factory> f)269 Vfs::unregister_file_factory(cxx::Ref_ptr<L4Re::Vfs::File_factory> f) throw()
270 {
271 for (auto p: _file_factories)
272 {
273 if (p->f == f)
274 {
275 _file_factories.remove(p);
276 p->~File_factory_item();
277 this->free(p);
278 return 0;
279 }
280 }
281 return -ENOENT;
282 }
283
284 Ref_ptr<L4Re::Vfs::File_factory>
get_file_factory(int proto)285 Vfs::get_file_factory(int proto) throw()
286 {
287 for (auto p: _file_factories)
288 if (p->f->proto() == proto)
289 return p->f;
290
291 return Ref_ptr<L4Re::Vfs::File_factory>();
292 }
293
294 Ref_ptr<L4Re::Vfs::File_factory>
get_file_factory(char const * proto_name)295 Vfs::get_file_factory(char const *proto_name) throw()
296 {
297 for (auto p: _file_factories)
298 {
299 auto n = p->f->proto_name();
300 if (n)
301 {
302 char const *a = n;
303 char const *b = proto_name;
304 for (; *a && *b && *a == *b; ++a, ++b)
305 ;
306
307 if ((*a == 0) && (*b == 0))
308 return p->f;
309 }
310 }
311
312 return Ref_ptr<L4Re::Vfs::File_factory>();
313 }
314
315 int
alloc_fd(Ref_ptr<L4Re::Vfs::File> const & f)316 Vfs::alloc_fd(Ref_ptr<L4Re::Vfs::File> const &f) throw()
317 {
318 int fd = fds.alloc();
319 if (fd < 0)
320 return -EMFILE;
321
322 if (f)
323 fds.set(fd, f);
324
325 return fd;
326 }
327
328 Ref_ptr<L4Re::Vfs::File>
free_fd(int fd)329 Vfs::free_fd(int fd) throw()
330 {
331 Ref_ptr<L4Re::Vfs::File> f = fds.get(fd);
332
333 if (!f)
334 return Ref_ptr<>::Nil;
335
336 fds.free(fd);
337 return f;
338 }
339
340
341 Ref_ptr<L4Re::Vfs::File>
get_root()342 Vfs::get_root() throw()
343 {
344 return cxx::ref_ptr(&_root);
345 }
346
347 Ref_ptr<L4Re::Vfs::File>
get_cwd()348 Vfs::get_cwd() throw()
349 {
350 return _cwd;
351 }
352
353 void
set_cwd(Ref_ptr<L4Re::Vfs::File> const & dir)354 Vfs::set_cwd(Ref_ptr<L4Re::Vfs::File> const &dir) throw()
355 {
356 // FIXME: check for is dir
357 if (dir)
358 _cwd = dir;
359 }
360
361 Ref_ptr<L4Re::Vfs::File>
get_file(int fd)362 Vfs::get_file(int fd) throw()
363 {
364 return fds.get(fd);
365 }
366
367 cxx::Pair<Ref_ptr<L4Re::Vfs::File>, int>
set_fd(int fd,Ref_ptr<L4Re::Vfs::File> const & f)368 Vfs::set_fd(int fd, Ref_ptr<L4Re::Vfs::File> const &f) throw()
369 {
370 if (!fds.check_fd(fd))
371 return cxx::pair(Ref_ptr<L4Re::Vfs::File>(Ref_ptr<>::Nil), EBADF);
372
373 Ref_ptr<L4Re::Vfs::File> old = fds.get(fd);
374 fds.set(fd, f);
375 return cxx::pair(old, 0);
376 }
377
378
379 #define GET_FILE_DBG(fd, err) \
380 Ref_ptr<L4Re::Vfs::File> fi = fds.get(fd); \
381 if (!fi) \
382 { \
383 return -err; \
384 }
385
386 #define GET_FILE(fd, err) \
387 Ref_ptr<L4Re::Vfs::File> fi = fds.get(fd); \
388 if (!fi) \
389 return -err;
390
391
392 int
munmap(void * start,size_t len)393 Vfs::munmap(void *start, size_t len) L4_NOTHROW
394 {
395 using namespace L4;
396 using namespace L4Re;
397
398 int err;
399 Cap<Dataspace> ds;
400 Cap<Rm> r = Env::env()->rm();
401
402 while (1)
403 {
404 DEBUG_LOG(debug_mmap, {
405 outstring("DETACH: ");
406 outhex32(l4_addr_t(start));
407 outstring(" ");
408 outhex32(len);
409 outstring("\n");
410 });
411 err = r->detach(l4_addr_t(start), len, &ds, This_task);
412 if (err < 0)
413 return err;
414
415 switch (err & Rm::Detach_result_mask)
416 {
417 case Rm::Split_ds:
418 if (ds.is_valid())
419 L4Re::virt_cap_alloc->take(ds);
420 return 0;
421 case Rm::Detached_ds:
422 if (ds.is_valid())
423 L4Re::virt_cap_alloc->release(ds);
424 break;
425 default:
426 break;
427 }
428
429 if (!(err & Rm::Detach_again))
430 return 0;
431 }
432 }
433
434 int
alloc_ds(unsigned long size,L4Re::Shared_cap<L4Re::Dataspace> * ds)435 Vfs::alloc_ds(unsigned long size, L4Re::Shared_cap<L4Re::Dataspace> *ds)
436 {
437 *ds = L4Re::make_shared_cap<L4Re::Dataspace>(L4Re::virt_cap_alloc);
438
439 if (!ds->is_valid())
440 return -ENOMEM;
441
442 int err;
443 if ((err = Vfs_config::allocator()->alloc(size, ds->get())) < 0)
444 return err;
445
446 DEBUG_LOG(debug_mmap, {
447 outstring("ANON DS ALLOCATED: size=");
448 outhex32(size);
449 outstring(" cap=");
450 outhex32(ds->cap());
451 outstring("\n");
452 });
453
454 return 0;
455 }
456
457 int
alloc_anon_mem(l4_umword_t size,L4Re::Shared_cap<L4Re::Dataspace> * ds,l4_addr_t * offset)458 Vfs::alloc_anon_mem(l4_umword_t size, L4Re::Shared_cap<L4Re::Dataspace> *ds,
459 l4_addr_t *offset)
460 {
461 #ifdef USE_BIG_ANON_DS
462 enum
463 {
464 ANON_MEM_DS_POOL_SIZE = 256UL << 20, // size of a pool dataspace used for anon memory
465 ANON_MEM_MAX_SIZE = 32UL << 20, // chunk size that will be allocate a dataspace
466 };
467 #else
468 enum
469 {
470 ANON_MEM_DS_POOL_SIZE = 256UL << 20, // size of a pool dataspace used for anon memory
471 ANON_MEM_MAX_SIZE = 0UL << 20, // chunk size that will be allocate a dataspace
472 };
473 #endif
474
475 if (size >= ANON_MEM_MAX_SIZE)
476 {
477 int err;
478 if ((err = alloc_ds(size, ds)) < 0)
479 return err;
480
481 *offset = 0;
482
483 if (!_early_oom)
484 return err;
485
486 return (*ds)->allocate(0, size);
487 }
488
489 if (!_anon_ds.is_valid() || _anon_offset + size >= ANON_MEM_DS_POOL_SIZE)
490 {
491 int err;
492 if ((err = alloc_ds(ANON_MEM_DS_POOL_SIZE, ds)) < 0)
493 return err;
494
495 _anon_offset = 0;
496 _anon_ds = *ds;
497 }
498 else
499 *ds = _anon_ds;
500
501 if (_early_oom)
502 {
503 if (int err = (*ds)->allocate(_anon_offset, size))
504 return err;
505 }
506
507 *offset = _anon_offset;
508 _anon_offset += size;
509 return 0;
510 }
511
512 int
mmap2(void * start,size_t len,int prot,int flags,int fd,off_t _offset,void ** resptr)513 Vfs::mmap2(void *start, size_t len, int prot, int flags, int fd, off_t _offset,
514 void **resptr) L4_NOTHROW
515 {
516 using namespace L4Re;
517 off64_t offset = l4_trunc_page(_offset << 12);
518
519 start = (void*)l4_trunc_page(l4_addr_t(start));
520 len = l4_round_page(len);
521 l4_umword_t size = (len + L4_PAGESIZE-1) & ~(L4_PAGESIZE-1);
522
523 // special code to just reserve an area of the virtual address space
524 if (flags & 0x1000000)
525 {
526 int err;
527 L4::Cap<Rm> r = Env::env()->rm();
528 l4_addr_t area = (l4_addr_t)start;
529 err = r->reserve_area(&area, size, L4Re::Rm::F::Search_addr);
530 if (err < 0)
531 return err;
532 *resptr = (void*)area;
533 DEBUG_LOG(debug_mmap, {
534 outstring("MMAP reserved area: ");
535 outhex32(area);
536 outstring(" size=");
537 outhex32(size);
538 outstring("\n");
539 });
540 return 0;
541 }
542
543 L4Re::Shared_cap<L4Re::Dataspace> ds;
544 l4_addr_t anon_offset = 0;
545 L4Re::Rm::Flags rm_flags(0);
546
547 if (flags & (MAP_ANONYMOUS | MAP_PRIVATE))
548 {
549 rm_flags |= L4Re::Rm::F::Detach_free;
550
551 int err = alloc_anon_mem(size, &ds, &anon_offset);
552 if (err)
553 return err;
554
555 DEBUG_LOG(debug_mmap, {
556 outstring("USE ANON MEM: ");
557 outhex32(ds.cap());
558 outstring(" offs=");
559 outhex32(anon_offset);
560 outstring("\n");
561 });
562 }
563
564 if (!(flags & MAP_ANONYMOUS))
565 {
566 Ref_ptr<L4Re::Vfs::File> fi = fds.get(fd);
567 if (!fi)
568 {
569 return -EBADF;
570 }
571
572 L4::Cap<L4Re::Dataspace> fds = fi->data_space();
573
574 if (!fds.is_valid())
575 {
576 return -EINVAL;
577 }
578
579 if (size + offset > l4_round_page(fds->size()))
580 {
581 return -EINVAL;
582 }
583
584 if (flags & MAP_PRIVATE)
585 {
586 DEBUG_LOG(debug_mmap, outstring("COW\n"););
587 int err = ds->copy_in(anon_offset, fds, l4_trunc_page(offset),
588 l4_round_page(size));
589 if (err < 0)
590 return err;
591
592 offset = anon_offset;
593 }
594 else
595 {
596 L4Re::virt_cap_alloc->take(fds);
597 ds = L4Re::Shared_cap<L4Re::Dataspace>(fds, L4Re::virt_cap_alloc);
598 }
599 }
600 else
601 offset = anon_offset;
602
603
604 if (!(flags & MAP_FIXED) && start == 0)
605 start = (void*)L4_PAGESIZE;
606
607 char *data = (char *)start;
608 L4::Cap<Rm> r = Env::env()->rm();
609 l4_addr_t overmap_area = L4_INVALID_ADDR;
610
611 int err;
612 if (flags & MAP_FIXED)
613 {
614 overmap_area = l4_addr_t(start);
615
616 err = r->reserve_area(&overmap_area, size);
617 if (err < 0)
618 overmap_area = L4_INVALID_ADDR;
619
620 rm_flags |= Rm::F::In_area;
621
622 err = munmap(start, len);
623 if (err && err != -ENOENT)
624 return err;
625 }
626
627 if (!(flags & MAP_FIXED)) rm_flags |= Rm::F::Search_addr;
628 if (prot & PROT_READ) rm_flags |= Rm::F::R;
629 if (prot & PROT_WRITE) rm_flags |= Rm::F::W;
630 if (prot & PROT_EXEC) rm_flags |= Rm::F::X;
631
632 err = r->attach(&data, size, rm_flags,
633 L4::Ipc::make_cap(ds.get(), (prot & PROT_WRITE)
634 ? L4_CAP_FPAGE_RW
635 : L4_CAP_FPAGE_RO),
636 offset);
637
638 DEBUG_LOG(debug_mmap, {
639 outstring(" MAPPED: ");
640 outhex32(ds.cap());
641 outstring(" addr: ");
642 outhex32(l4_addr_t(data));
643 outstring(" bytes: ");
644 outhex32(size);
645 outstring(" offset: ");
646 outhex32(offset);
647 outstring(" err=");
648 outdec(err);
649 outstring("\n");
650 });
651
652
653 if (overmap_area != L4_INVALID_ADDR)
654 r->free_area(overmap_area);
655
656 if (err < 0)
657 return err;
658
659 l4_assert (!(start && !data));
660
661 // release ownership of the attached DS
662 ds.release();
663 *resptr = data;
664
665 return 0;
666 }
667
668 namespace {
669 class Auto_area
670 {
671 public:
672 L4::Cap<L4Re::Rm> r;
673 l4_addr_t a;
674
675 explicit Auto_area(L4::Cap<L4Re::Rm> r, l4_addr_t a = L4_INVALID_ADDR)
r(r)676 : r(r), a(a) {}
677
reserve(l4_addr_t _a,l4_size_t sz,L4Re::Rm::Flags flags)678 int reserve(l4_addr_t _a, l4_size_t sz, L4Re::Rm::Flags flags)
679 {
680 free();
681 a = _a;
682 int e = r->reserve_area(&a, sz, flags);
683 if (e)
684 a = L4_INVALID_ADDR;
685 return e;
686 }
687
free()688 void free()
689 {
690 if (is_valid())
691 {
692 r->free_area(a);
693 a = L4_INVALID_ADDR;
694 }
695 }
696
is_valid()697 bool is_valid() const { return a != L4_INVALID_ADDR; }
698
~Auto_area()699 ~Auto_area() { free(); }
700 };
701 }
702
703 int
mremap(void * old_addr,size_t old_size,size_t new_size,int flags,void ** new_addr)704 Vfs::mremap(void *old_addr, size_t old_size, size_t new_size, int flags,
705 void **new_addr) L4_NOTHROW
706 {
707 using namespace L4Re;
708
709 DEBUG_LOG(debug_mmap, {
710 outstring("Mremap: addr=");
711 outhex32((l4_umword_t)old_addr);
712 outstring(" old_size=");
713 outhex32(old_size);
714 outstring(" new_size=");
715 outhex32(new_size);
716 outstring("\n");
717 });
718
719 if (flags & MREMAP_FIXED && !(flags & MREMAP_MAYMOVE))
720 return -EINVAL;
721
722 l4_addr_t oa = l4_trunc_page((l4_addr_t)old_addr);
723 if (oa != (l4_addr_t)old_addr)
724 return -EINVAL;
725
726 bool const fixed = flags & MREMAP_FIXED;
727 bool const maymove = flags & MREMAP_MAYMOVE;
728
729 L4::Cap<Rm> r = Env::env()->rm();
730
731 // sanitize input parameters to multiples of pages
732 old_size = l4_round_page(old_size);
733 new_size = l4_round_page(new_size);
734
735 if (!fixed)
736 {
737 if (new_size < old_size)
738 {
739 *new_addr = old_addr;
740 return munmap((void*)(oa + new_size), old_size - new_size);
741 }
742
743 if (new_size == old_size)
744 {
745 *new_addr = old_addr;
746 return 0;
747 }
748 }
749
750 Auto_area old_area(r);
751 int err = old_area.reserve(oa, old_size, L4Re::Rm::Flags(0));
752 if (err < 0)
753 return -EINVAL;
754
755 l4_addr_t pad_addr;
756 Auto_area new_area(r);
757 if (fixed)
758 {
759 l4_addr_t na = l4_trunc_page((l4_addr_t)*new_addr);
760 if (na != (l4_addr_t)*new_addr)
761 return -EINVAL;
762
763 // check if the current virtual memory area can be expanded
764 int err = new_area.reserve(na, new_size, L4Re::Rm::Flags(0));
765 if (err < 0)
766 return err;
767
768 pad_addr = na;
769 // unmap all stuff and remap ours ....
770 }
771 else
772 {
773 l4_addr_t ta = oa + old_size;
774 unsigned long ts = new_size - old_size;
775 // check if the current virtual memory area can be expanded
776 int err = new_area.reserve(ta, ts, L4Re::Rm::Flags(0));
777 if (!maymove && err)
778 return -ENOMEM;
779
780 L4Re::Rm::Offset toffs;
781 L4Re::Rm::Flags tflags;
782 L4::Cap<L4Re::Dataspace> tds;
783
784 err = r->find(&ta, &ts, &toffs, &tflags, &tds);
785
786 // there is enough space to expand the mapping in place
787 if (err == -ENOENT || (err == 0 && (tflags & Rm::F::In_area)))
788 {
789 old_area.free(); // pad at the original address
790 pad_addr = oa + old_size;
791 *new_addr = old_addr;
792 }
793 else if (!maymove)
794 return -ENOMEM;
795 else
796 {
797 // search for a new area to remap
798 err = new_area.reserve(0, new_size, Rm::F::Search_addr);
799 if (err < 0)
800 return -ENOMEM;
801
802 pad_addr = new_area.a + old_size;
803 *new_addr = (void *)new_area.a;
804 }
805 }
806
807 if (old_area.is_valid())
808 {
809 l4_addr_t a = old_area.a;
810 unsigned long s = old_size;
811 L4Re::Rm::Offset o;
812 L4Re::Rm::Flags f;
813 L4::Cap<L4Re::Dataspace> ds;
814
815 for (; r->find(&a, &s, &o, &f, &ds) >= 0 && (!(f & Rm::F::In_area));)
816 {
817 if (a < old_area.a)
818 {
819 auto d = old_area.a - a;
820 a = old_area.a;
821 s -= d;
822 o += d;
823 }
824
825 if (a + s > old_area.a + old_size)
826 s = old_area.a + old_size - a;
827
828 l4_addr_t x = a - old_area.a + new_area.a;
829
830 int err = r->attach(&x, s, Rm::F::In_area | f,
831 L4::Ipc::make_cap(ds, f.cap_rights()),
832 o);
833 if (err < 0)
834 return err;
835
836 // cout the new attached ds reference
837 L4Re::virt_cap_alloc->take(ds);
838
839 err = r->detach(a, s, &ds, This_task,
840 Rm::Detach_exact | Rm::Detach_keep);
841 if (err < 0)
842 return err;
843
844 switch (err & Rm::Detach_result_mask)
845 {
846 case Rm::Split_ds:
847 // add a reference as we split up a mapping
848 if (ds.is_valid())
849 L4Re::virt_cap_alloc->take(ds);
850 break;
851 case Rm::Detached_ds:
852 if (ds.is_valid())
853 L4Re::virt_cap_alloc->release(ds);
854 break;
855 default:
856 break;
857 }
858 }
859 old_area.free();
860 }
861
862 if (old_size < new_size)
863 {
864 l4_addr_t const pad_sz = new_size - old_size;
865 l4_addr_t toffs;
866 L4Re::Shared_cap<L4Re::Dataspace> tds;
867 int err = alloc_anon_mem(pad_sz, &tds, &toffs);
868 if (err)
869 return err;
870
871 // FIXME: must get the protection rights from the old
872 // mapping and use the same here, for now just use RWX
873 err = r->attach(&pad_addr, pad_sz,
874 Rm::F::In_area | Rm::F::Detach_free | Rm::F::RWX,
875 L4::Ipc::make_cap_rw(tds.get()), toffs);
876 if (err < 0)
877 return err;
878
879 // release ownership of tds, the region map is now the new owner
880 tds.release();
881 }
882
883 return 0;
884 }
885
886 int
mprotect(const void * a,size_t sz,int prot)887 Vfs::mprotect(const void *a, size_t sz, int prot) L4_NOTHROW
888 {
889 (void)a;
890 (void)sz;
891 return (prot & PROT_WRITE) ? -1 : 0;
892 }
893
894 int
msync(void *,size_t,int)895 Vfs::msync(void *, size_t, int) L4_NOTHROW
896 { return 0; }
897
898 int
madvise(void *,size_t,int)899 Vfs::madvise(void *, size_t, int) L4_NOTHROW
900 { return 0; }
901
902 }
903
904 L4Re::Vfs::Ops *__rtld_l4re_env_posix_vfs_ops;
905 extern void *l4re_env_posix_vfs_ops __attribute__((alias("__rtld_l4re_env_posix_vfs_ops"), visibility("default")));
906
907 namespace {
908 class Real_mount_tree : public L4Re::Vfs::Mount_tree
909 {
910 public:
Real_mount_tree(char * n)911 explicit Real_mount_tree(char *n) : Mount_tree(n) {}
912
new(size_t size)913 void *operator new (size_t size)
914 { return __rtld_l4re_env_posix_vfs_ops->malloc(size); }
915
delete(void * mem)916 void operator delete (void *mem)
917 { __rtld_l4re_env_posix_vfs_ops->free(mem); }
918 };
919 }
920
921 int
mount(char const * path,cxx::Ref_ptr<L4Re::Vfs::File> const & dir)922 Vfs::mount(char const *path, cxx::Ref_ptr<L4Re::Vfs::File> const &dir) throw()
923 {
924 using L4Re::Vfs::File;
925 using L4Re::Vfs::Mount_tree;
926 using L4Re::Vfs::Path;
927
928 cxx::Ref_ptr<Mount_tree> root = get_root()->mount_tree();
929 if (!root)
930 return -EINVAL;
931
932 cxx::Ref_ptr<Mount_tree> base;
933 Path p = root->lookup(Path(path), &base);
934
935 while (!p.empty())
936 {
937 Path f = p.strip_first();
938
939 if (f.empty())
940 return -EEXIST;
941
942 char *name = __rtld_l4re_env_posix_vfs_ops->strndup(f.path(), f.length());
943 if (!name)
944 return -ENOMEM;
945
946 cxx::Ref_ptr<Mount_tree> nt(new Real_mount_tree(name));
947 if (!nt)
948 {
949 __rtld_l4re_env_posix_vfs_ops->free(name);
950 return -ENOMEM;
951 }
952
953 base->add_child_node(nt);
954 base = nt;
955
956 if (p.empty())
957 {
958 nt->mount(dir);
959 return 0;
960 }
961 }
962
963 return -EINVAL;
964 }
965
966
967 #undef DEBUG_LOG
968 #undef GET_FILE_DBG
969 #undef GET_FILE
970
971