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)
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.
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.
23 #include "vcon_stream.h"
29 #include <l4/re/dataspace>
31 #include <l4/l4re_vfs/backend>
38 //#include <l4/sys/kdebug.h>
39 //static int debug_mmap = 1;
40 //#define DEBUG_LOG(level, dbg...) do { if (level) dbg } while (0)
42 #define DEBUG_LOG(level, dbg...) do { } while (0)
45 * If USE_BIG_ANON_DS is defined the implementation will use a really big
46 * data space for backing anonymous memory. Otherwise each mmap call
47 * with anonymous memory will allocate a separate data space.
49 #define USE_BIG_ANON_DS
57 void *(*malloc)(size_t);
60 unsigned long (*cap_alloc)();
61 void (*cap_free)(unsigned long);
66 class Fd_store : public L4Re::Core::Fd_store
72 // for internal Vcon_streams we want to have a placement new operator, so
73 // inherit and add one
74 class Std_stream : public L4Re::Core::Vcon_stream
77 inline void *operator new (size_t, void *p) throw() { return p; }
78 Std_stream(L4::Cap<L4::Vcon> c) : L4Re::Core::Vcon_stream(c) {}
81 Fd_store::Fd_store() throw()
83 // use this strange way to prevent deletion of the stdio object
84 // this depends on Fd_store to being a singleton !!!
85 static char m[sizeof(Std_stream)] __attribute__((aligned(sizeof(long))));
86 Std_stream *s = new (m) Std_stream(L4Re::Env::env()->log());
87 // make sure that we never delete the static io stream thing
89 set(0, cxx::ref_ptr(s)); // stdin
90 set(1, cxx::ref_ptr(s)); // stdout
91 set(2, cxx::ref_ptr(s)); // stderr
94 class Root_mount_tree : public L4Re::Vfs::Mount_tree
97 Root_mount_tree() : L4Re::Vfs::Mount_tree(0) {}
98 void operator delete (void *) {}
101 class Vfs : public L4Re::Vfs::Ops
107 void *operator new (size_t, void *p) throw() { return p; }
109 : _early_oom(true), _root_mount(), _root(L4Re::Env::env()),
110 _annon_size(0x10000000)
112 _root_mount.add_ref();
114 _root_mount.mount(cxx::ref_ptr(&_root));
118 Ref_ptr<L4Re::Vfs::File> rom;
119 _root.openat("rom", 0, 0, &rom);
121 _root_mount.create_tree("lib/foo", rom);
123 _root.openat("lib", 0, 0, &_cwd);
128 int alloc_fd(Ref_ptr<L4Re::Vfs::File> const &f) throw();
129 Ref_ptr<L4Re::Vfs::File> free_fd(int fd) throw();
130 Ref_ptr<L4Re::Vfs::File> get_root() throw();
131 Ref_ptr<L4Re::Vfs::File> get_cwd() throw();
132 void set_cwd(Ref_ptr<L4Re::Vfs::File> const &dir) throw();
133 Ref_ptr<L4Re::Vfs::File> get_file(int fd) throw();
134 Ref_ptr<L4Re::Vfs::File> set_fd(int fd, Ref_ptr<L4Re::Vfs::File> const &f = Ref_ptr<>::Nil) throw();
135 L4Re::Cap_alloc *cap_alloc() throw();
137 int mmap2(void *start, size_t len, int prot, int flags, int fd,
138 off_t offset, void **ptr) throw();
140 int munmap(void *start, size_t len) throw();
141 int mremap(void *old, size_t old_sz, size_t new_sz, int flags,
142 void **new_adr) throw();
143 int mprotect(const void *a, size_t sz, int prot) throw();
144 int msync(void *addr, size_t len, int flags) throw();
145 int madvise(void *addr, size_t len, int advice) throw();
147 int register_file_system(L4Re::Vfs::File_system *f) throw();
148 int unregister_file_system(L4Re::Vfs::File_system *f) throw();
149 L4Re::Vfs::File_system *get_file_system(char const *fstype) throw();
151 void operator delete (void *) {}
154 Root_mount_tree _root_mount;
155 L4Re::Core::Env_dir _root;
156 Ref_ptr<L4Re::Vfs::File> _cwd;
159 L4Re::Vfs::File_system *_fs_registry;
161 l4_addr_t _annon_size;
162 l4_addr_t _annon_offset;
163 L4::Cap<L4Re::Dataspace> _annon_ds;
165 int alloc_ds(unsigned long size, L4::Cap<L4Re::Dataspace> *ds);
166 int alloc_anon_mem(l4_umword_t size, L4::Cap<L4Re::Dataspace> *ds,
170 static inline bool strequal(char const *a, char const *b)
172 for (;*a && *a == *b; ++a, ++b)
178 Vfs::register_file_system(L4Re::Vfs::File_system *f) throw()
180 using L4Re::Vfs::File_system;
185 for (File_system *c = _fs_registry; c; c = c->next())
186 if (strequal(c->type(), f->type()))
189 f->next(_fs_registry);
196 Vfs::unregister_file_system(L4Re::Vfs::File_system *f) throw()
198 using L4Re::Vfs::File_system;
203 File_system **p = &_fs_registry;
205 for (; *p; p = &(*p)->next())
216 L4Re::Vfs::File_system *
217 Vfs::get_file_system(char const *fstype) throw()
219 bool try_dynamic = true;
222 using L4Re::Vfs::File_system;
223 for (File_system *c = _fs_registry; c; c = c->next())
224 if (strequal(c->type(), fstype))
230 // try to load a file system module dynamically
231 int res = Vfs_config::load_module(fstype);
241 Vfs::alloc_fd(Ref_ptr<L4Re::Vfs::File> const &f) throw()
243 int fd = fds.alloc();
253 Ref_ptr<L4Re::Vfs::File>
254 Vfs::free_fd(int fd) throw()
256 Ref_ptr<L4Re::Vfs::File> f = fds.get(fd);
259 return Ref_ptr<>::Nil;
266 Ref_ptr<L4Re::Vfs::File>
267 Vfs::get_root() throw()
269 return cxx::ref_ptr(&_root);
272 Ref_ptr<L4Re::Vfs::File>
273 Vfs::get_cwd() throw()
279 Vfs::set_cwd(Ref_ptr<L4Re::Vfs::File> const &dir) throw()
281 // FIXME: check for is dir
286 Ref_ptr<L4Re::Vfs::File>
287 Vfs::get_file(int fd) throw()
292 Ref_ptr<L4Re::Vfs::File>
293 Vfs::set_fd(int fd, Ref_ptr<L4Re::Vfs::File> const &f) throw()
295 Ref_ptr<L4Re::Vfs::File> old = fds.get(fd);
301 Vfs::cap_alloc() throw()
303 return L4Re::Core::cap_alloc();
308 #define GET_FILE_DBG(fd, err) \
309 Ref_ptr<L4Re::Vfs::File> fi = fds.get(fd); \
315 #define GET_FILE(fd, err) \
316 Ref_ptr<L4Re::Vfs::File> fi = fds.get(fd); \
322 Vfs::munmap(void *start, size_t len) L4_NOTHROW
325 using namespace L4Re;
329 Cap<Rm> r = Env::env()->rm();
333 DEBUG_LOG(debug_mmap, {
334 outstring("DETACH: ");
335 outhex32(l4_addr_t(start));
340 err = r->detach(l4_addr_t(start), len, &ds, This_task);
344 switch (err & Rm::Detach_result_mask)
350 case Rm::Detached_ds:
352 L4Re::Core::release_ds(ds);
358 if (!(err & Rm::Detach_again))
364 Vfs::alloc_ds(unsigned long size, L4::Cap<L4Re::Dataspace> *ds)
366 *ds = Vfs_config::cap_alloc.alloc<L4Re::Dataspace>();
372 if ((err = Vfs_config::allocator()->alloc(size, *ds)) < 0)
375 DEBUG_LOG(debug_mmap, {
376 outstring("ANNON DS ALLOCATED: size=");
387 Vfs::alloc_anon_mem(l4_umword_t size, L4::Cap<L4Re::Dataspace> *ds,
390 #ifdef USE_BIG_ANON_DS
391 if (!_annon_ds.is_valid() || _annon_offset + size >= _annon_size)
393 if (_annon_ds.is_valid())
394 L4Re::Core::release_ds(_annon_ds);
397 if ((err = alloc_ds(_annon_size, ds)) < 0)
410 if (int err = (*ds)->allocate(_annon_offset, size))
414 *offset = _annon_offset;
415 _annon_offset += size;
418 if ((err = alloc_ds(size, ds)) < 0)
423 if ((err = (*ds)->allocate(0, size)))
432 Vfs::mmap2(void *start, size_t len, int prot, int flags, int fd, off_t _offset,
433 void **resptr) L4_NOTHROW
435 using namespace L4Re;
436 off64_t offset = _offset << 12;
438 start = (void*)l4_trunc_page(l4_addr_t(start));
439 len = l4_round_page(len);
440 l4_umword_t size = (len + L4_PAGESIZE-1) & ~(L4_PAGESIZE-1);
442 // special code to just reserve an area of the virtual address space
443 if (flags & 0x1000000)
446 L4::Cap<Rm> r = Env::env()->rm();
447 l4_addr_t area = (l4_addr_t)start;
448 err = r->reserve_area(&area, size, L4Re::Rm::Search_addr);
451 *resptr = (void*)area;
452 DEBUG_LOG(debug_mmap, {
453 outstring("MMAP reserved area: ");
462 L4::Cap<L4Re::Dataspace> ds;
463 l4_addr_t annon_offset = 0;
464 unsigned rm_flags = 0;
466 if (flags & (MAP_ANONYMOUS | MAP_PRIVATE))
468 rm_flags |= L4Re::Rm::Detach_free;
470 int err = alloc_anon_mem(size, &ds, &annon_offset);
474 DEBUG_LOG(debug_mmap, {
475 outstring("USE ANNON MEM: ");
478 outhex32(annon_offset);
483 if (!(flags & MAP_ANONYMOUS))
485 Ref_ptr<L4Re::Vfs::File> fi = fds.get(fd);
491 L4::Cap<L4Re::Dataspace> fds = fi->data_space();
498 if (size + offset > l4_round_page(fds->size()))
503 if (flags & MAP_PRIVATE)
505 DEBUG_LOG(debug_mmap, outstring("COW\n"););
506 ds->copy_in(annon_offset, fds, l4_trunc_page(offset), l4_round_page(size));
507 offset = annon_offset;
516 offset = annon_offset;
519 if (!(flags & MAP_FIXED) && start == 0)
520 start = (void*)L4_PAGESIZE;
523 char *data = (char *)start;
524 L4::Cap<Rm> r = Env::env()->rm();
525 l4_addr_t overmap_area = L4_INVALID_ADDR;
527 if (flags & MAP_FIXED)
529 overmap_area = l4_addr_t(start);
531 err = r->reserve_area(&overmap_area, size);
533 overmap_area = L4_INVALID_ADDR;
535 rm_flags |= Rm::In_area;
537 err = munmap(start, len);
538 if (err && err != -ENOENT)
542 if (!(flags & MAP_FIXED)) rm_flags |= Rm::Search_addr;
543 if (!(prot & PROT_WRITE)) rm_flags |= Rm::Read_only;
545 err = r->attach(&data, size, rm_flags, ds, offset);
547 DEBUG_LOG(debug_mmap, {
548 outstring(" MAPPED: ");
550 outstring(" addr: ");
551 outhex32(l4_addr_t(data));
552 outstring(" bytes: ");
554 outstring(" offset: ");
562 if (overmap_area != L4_INVALID_ADDR)
563 r->free_area(overmap_area);
584 explicit Auto_area(L4::Cap<L4Re::Rm> r, l4_addr_t a = L4_INVALID_ADDR)
587 int reserve(l4_addr_t _a, l4_size_t sz, unsigned flags)
590 int e = r->reserve_area(&a, sz, flags);
598 if (a != L4_INVALID_ADDR)
605 ~Auto_area() { free(); }
610 Vfs::mremap(void *old_addr, size_t old_size, size_t new_size, int flags,
611 void **new_addr) L4_NOTHROW
613 using namespace L4Re;
615 if (flags & MREMAP_FIXED && !(flags & MREMAP_MAYMOVE))
618 L4::Cap<Rm> r = Env::env()->rm();
620 // sanitize input parameters to multiples of pages
621 l4_addr_t oa = l4_trunc_page((l4_addr_t)old_addr);
622 old_size = l4_round_page(old_size);
623 new_size = l4_round_page(new_size);
627 if (new_size < old_size)
629 *new_addr = old_addr;
630 return munmap((void*)(oa + new_size), old_size - new_size);
633 if (new_size == old_size)
635 *new_addr = old_addr;
641 if (!(flags & MREMAP_FIXED))
644 na = l4_trunc_page((l4_addr_t)new_addr);
648 // check if the current virtual memory area can be expanded
649 err = area.reserve(oa, new_size, 0);
653 l4_addr_t ta = oa + old_size;
654 unsigned long ts = new_size - old_size;
657 L4::Cap<L4Re::Dataspace> tds;
659 err = r->find(&ta, &ts, &toffs, &tflags, &tds);
661 // there is enough space to expand the mapping in place
662 if (!(err == -ENOENT || (err == 0 && (tflags & Rm::In_area))))
664 if ((flags & (MREMAP_FIXED | MREMAP_MAYMOVE)) != MREMAP_MAYMOVE)
667 // free our old reserved area, used for blocking the old memory region
671 err = area.reserve(0, new_size, Rm::Search_addr);
677 // move all the old regions to the new place ...
678 Auto_area block_area(r);
679 err = block_area.reserve(oa, old_size, 0);
688 err = r->find(&ta, &ts, &toffs, &tflags, &tds);
689 if (err == -ENOENT || (err == 0 && (tflags & Rm::In_area)))
702 l4_addr_t n = na + (ta - oa);
703 unsigned long max_s = old_size - (ta - oa);
708 err = r->attach(&n, ts, tflags | Rm::In_area, tds, toffs);
714 err = r->detach(ta, ts, &tds, This_task);
718 switch (err & Rm::Detach_result_mask)
724 case Rm::Detached_ds:
726 L4Re::Core::release_ds(tds);
734 err = alloc_anon_mem(new_size - old_size, &tds, &toffs);
738 *new_addr = (void *)na;
740 err = r->attach(&na, new_size - old_size, Rm::In_area, tds, toffs);
746 Vfs::mprotect(const void *a, size_t sz, int prot) L4_NOTHROW
750 return (prot & PROT_WRITE) ? -1 : 0;
754 Vfs::msync(void *, size_t, int) L4_NOTHROW
758 Vfs::madvise(void *, size_t, int) L4_NOTHROW
762 // use this container construct here to prevent a destructor for
763 // our VFS main object is ever called!
764 static char vfs_cnt[sizeof(Vfs)] __attribute__((aligned(sizeof(long))));
765 static void init_vfs() { new (vfs_cnt) Vfs(); }
766 L4_DECLARE_CONSTRUCTOR(init_vfs, INIT_PRIO_VFS_INIT);
771 //L4Re::Vfs::Ops *__ldso_posix_vfs_ops = &vfs;
772 void *__rtld_l4re_env_posix_vfs_ops = &vfs_cnt;
773 extern void *l4re_env_posix_vfs_ops __attribute__((alias("__rtld_l4re_env_posix_vfs_ops"), visibility("default")));