23 #include "vcon_stream.h" 30 #include <l4/cxx/hlist> 31 #include <l4/cxx/std_alloc> 33 #include <l4/l4re_vfs/backend> 41 #include <l4/sys/kdebug.h> 42 static int debug_mmap = 1;
43 #define DEBUG_LOG(level, dbg...) do { if (level) dbg } while (0) 45 #define DEBUG_LOG(level, dbg...) do { } while (0) 53 #define USE_BIG_ANON_DS 61 class Fd_store :
public L4Re::Core::Fd_store
69 class Std_stream : public
L4Re::Core::Vcon_stream
75 Fd_store::Fd_store() throw()
79 static char m[
sizeof(Std_stream)] __attribute__((aligned(
sizeof(
long))));
83 set(0, cxx::ref_ptr(s));
84 set(1, cxx::ref_ptr(s));
85 set(2, cxx::ref_ptr(s));
88 class Root_mount_tree :
public L4Re::Vfs::Mount_tree
91 Root_mount_tree() :
L4Re::Vfs::Mount_tree(0) {}
92 void operator delete (
void *) {}
102 : _early_oom(true), _root_mount(), _root(
L4Re::Env::env())
104 _root_mount.add_ref();
106 _root_mount.mount(cxx::ref_ptr(&_root));
107 _cwd = cxx::ref_ptr(&_root);
110 Ref_ptr<L4Re::Vfs::File> rom;
111 _root.openat(
"rom", 0, 0, &rom);
113 _root_mount.create_tree(
"lib/foo", rom);
115 _root.openat(
"lib", 0, 0, &_cwd);
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 Ref_ptr<
L4Re::Vfs::File> set_fd(
int fd, Ref_ptr<
L4Re::Vfs::File> const &f = Ref_ptr<>::Nil) throw();
129 int mmap2(
void *start,
size_t len,
int prot,
int flags,
int fd,
130 off_t offset,
void **ptr) throw();
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();
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();
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();
148 void operator delete (
void *) {}
150 void *malloc(
size_t size) noexcept {
return Vfs_config::malloc(size); }
151 void free(
void *m) noexcept { Vfs_config::free(m); }
154 Root_mount_tree _root_mount;
155 L4Re::Core::Env_dir _root;
156 Ref_ptr<L4Re::Vfs::File> _cwd;
167 File_factory_item() =
default;
168 File_factory_item(File_factory_item
const &) =
delete;
169 File_factory_item &operator = (File_factory_item
const &) =
delete;
182 static inline bool strequal(
char const *a,
char const *b)
184 for (;*a && *a == *b; ++a, ++b)
197 for (File_system *c = _fs_registry; c; c = c->next())
198 if (strequal(c->type(), f->type()))
201 f->next(_fs_registry);
215 File_system **p = &_fs_registry;
217 for (; *p; p = &(*p)->next())
229 Vfs::get_file_system(
char const *fstype)
throw()
231 bool try_dynamic =
true;
235 for (File_system *c = _fs_registry; c; c = c->next())
236 if (strequal(c->type(), fstype))
243 int res = Vfs_config::load_module(fstype);
258 void *x = this->malloc(
sizeof(File_factory_item));
263 _file_factories.push_front(ff);
270 for (
auto p: _file_factories)
274 _file_factories.remove(p);
275 p->~File_factory_item();
283 Ref_ptr<L4Re::Vfs::File_factory>
284 Vfs::get_file_factory(
int proto)
throw()
286 for (
auto p: _file_factories)
287 if (p->f->proto() == proto)
290 return Ref_ptr<L4Re::Vfs::File_factory>();
293 Ref_ptr<L4Re::Vfs::File_factory>
294 Vfs::get_file_factory(
char const * )
throw()
296 #if 0 // strcmp not available in ldso so disable this for now 297 for (
auto p: _file_factories)
299 auto n = p->f->proto_name();
300 if (n && __builtin_strcmp(n, proto_name) == 0)
304 return Ref_ptr<L4Re::Vfs::File_factory>();
308 Vfs::alloc_fd(Ref_ptr<L4Re::Vfs::File>
const &f)
throw()
310 int fd = fds.alloc();
320 Ref_ptr<L4Re::Vfs::File>
321 Vfs::free_fd(
int fd)
throw()
323 Ref_ptr<L4Re::Vfs::File> f = fds.get(fd);
326 return Ref_ptr<>::Nil;
333 Ref_ptr<L4Re::Vfs::File>
334 Vfs::get_root() throw()
336 return cxx::ref_ptr(&_root);
339 Ref_ptr<L4Re::Vfs::File>
340 Vfs::get_cwd() throw()
346 Vfs::set_cwd(Ref_ptr<L4Re::Vfs::File>
const &dir)
throw()
353 Ref_ptr<L4Re::Vfs::File>
354 Vfs::get_file(
int fd)
throw()
359 Ref_ptr<L4Re::Vfs::File>
360 Vfs::set_fd(
int fd, Ref_ptr<L4Re::Vfs::File>
const &f)
throw()
362 Ref_ptr<L4Re::Vfs::File> old = fds.get(fd);
375 #define GET_FILE_DBG(fd, err) \ 376 Ref_ptr<L4Re::Vfs::File> fi = fds.get(fd); \ 382 #define GET_FILE(fd, err) \ 383 Ref_ptr<L4Re::Vfs::File> fi = fds.get(fd); \ 389 Vfs::munmap(
void *start,
size_t len)
L4_NOTHROW 392 using namespace L4Re;
400 DEBUG_LOG(debug_mmap, {
401 outstring(
"DETACH: ");
411 switch (err & Rm::Detach_result_mask)
415 case Rm::Detached_ds:
417 L4Re::Core::release_ds(ds);
423 if (!(err & Rm::Detach_again))
437 if ((err = Vfs_config::allocator()->alloc(size, *ds)) < 0)
440 DEBUG_LOG(debug_mmap, {
441 outstring(
"ANON DS ALLOCATED: size=");
455 #ifdef USE_BIG_ANON_DS 458 ANON_MEM_DS_POOL_SIZE = 256UL << 20,
459 ANON_MEM_MAX_SIZE = 32UL << 20,
464 ANON_MEM_DS_POOL_SIZE = 256UL << 20,
465 ANON_MEM_MAX_SIZE = 0UL << 20,
469 if (size >= ANON_MEM_MAX_SIZE)
472 if ((err = alloc_ds(size, ds)) < 0)
480 return (*ds)->allocate(0, size);
483 if (!_anon_ds.is_valid() || _anon_offset + size >= ANON_MEM_DS_POOL_SIZE)
485 if (_anon_ds.is_valid())
486 L4Re::Core::release_ds(_anon_ds);
489 if ((err = alloc_ds(ANON_MEM_DS_POOL_SIZE, ds)) < 0)
500 if (
int err = (*ds)->allocate(_anon_offset, size))
504 *offset = _anon_offset;
505 _anon_offset += size;
510 Vfs::mmap2(
void *start,
size_t len,
int prot,
int flags,
int fd, off_t _offset,
513 using namespace L4Re;
521 if (flags & 0x1000000)
529 *resptr = (
void*)area;
530 DEBUG_LOG(debug_mmap, {
531 outstring(
"MMAP reserved area: ");
542 unsigned rm_flags = 0;
544 if (flags & (MAP_ANONYMOUS | MAP_PRIVATE))
548 int err = alloc_anon_mem(size, &ds, &anon_offset);
552 DEBUG_LOG(debug_mmap, {
553 outstring(
"USE ANON MEM: ");
556 outhex32(anon_offset);
561 if (!(flags & MAP_ANONYMOUS))
563 Ref_ptr<L4Re::Vfs::File> fi = fds.get(fd);
581 if (flags & MAP_PRIVATE)
583 DEBUG_LOG(debug_mmap, outstring(
"COW\n"););
585 offset = anon_offset;
593 offset = anon_offset;
596 if (!(flags & MAP_FIXED) && start == 0)
600 char *data = (
char *)start;
604 if (flags & MAP_FIXED)
612 rm_flags |= Rm::In_area;
614 err = munmap(start, len);
615 if (err && err != -ENOENT)
619 if (!(flags & MAP_FIXED)) rm_flags |= Rm::Search_addr;
620 if (!(prot & PROT_WRITE)) rm_flags |= Rm::Read_only;
622 err = r->
attach(&data, size, rm_flags,
628 DEBUG_LOG(debug_mmap, {
629 outstring(
" MAPPED: ");
631 outstring(
" addr: ");
633 outstring(
" bytes: ");
635 outstring(
" offset: ");
686 ~Auto_area() { free(); }
691 Vfs::mremap(
void *old_addr,
size_t old_size,
size_t new_size,
int flags,
694 using namespace L4Re;
696 DEBUG_LOG(debug_mmap, {
697 outstring(
"Mremap: addr=");
699 outstring(
" old_size=");
701 outstring(
" new_size=");
706 if (flags & MREMAP_FIXED && !(flags & MREMAP_MAYMOVE))
718 if (new_size < old_size)
720 *new_addr = old_addr;
721 return munmap((
void*)(oa + new_size), old_size - new_size);
724 if (new_size == old_size)
726 *new_addr = old_addr;
732 if (!(flags & MREMAP_FIXED))
740 err = area.reserve(oa, new_size, 0);
745 unsigned long ts = new_size - old_size;
750 err = r->
find(&ta, &ts, &toffs, &tflags, &tds);
753 if (!(err == -ENOENT || (err == 0 && (tflags & Rm::In_area))))
755 if ((flags & (MREMAP_FIXED | MREMAP_MAYMOVE)) != MREMAP_MAYMOVE)
762 err = area.reserve(0, new_size, Rm::Search_addr);
769 Auto_area block_area(r);
770 err = block_area.reserve(oa, old_size, 0);
779 err = r->
find(&ta, &ts, &toffs, &tflags, &tds);
780 if (err == -ENOENT || (err == 0 && (tflags & Rm::In_area)))
794 unsigned long max_s = old_size - (ta - oa);
799 err = r->
attach(&n, ts, tflags | Rm::In_area,
807 err = r->
detach(ta, ts, &tds, This_task, Rm::Detach_exact | Rm::Detach_keep);
811 switch (err & Rm::Detach_result_mask)
815 case Rm::Detached_ds:
817 L4Re::Core::release_ds(tds);
825 err = alloc_anon_mem(new_size - old_size, &tds, &toffs);
829 *new_addr = (
void *)na;
831 err = r->
attach(&na, new_size - old_size, Rm::In_area | Rm::Detach_free,
841 Vfs::mprotect(
const void *a,
size_t sz,
int prot)
L4_NOTHROW 845 return (prot & PROT_WRITE) ? -1 : 0;
858 void *__rtld_l4re_env_posix_vfs_ops;
859 extern void *l4re_env_posix_vfs_ops __attribute__((alias(
"__rtld_l4re_env_posix_vfs_ops"), visibility(
"default")));
L4::Cap< Log > log() const
Object-capability to the logging service.
unsigned int l4_size_t
Unsigned size type.
Read and interface specific 'W' right for capability flex-pages.
long reserve_area(l4_addr_t *start, unsigned long size, unsigned flags=0, unsigned char align=L4_PAGESHIFT) const
Reserve the given area in the region map.
unsigned long size() const
Get size of a dataspace.
A reference-counting pointer with automatic cleanup.
Interface for the POSIX backends for an application.
long free_area(l4_addr_t addr)
Free an area from the region map.
Double-linked list of typed H_list_item_t elements.
Helper type to distinguish the oeprator new version that does not throw exceptions.
l4_addr_t l4_round_page(l4_addr_t address) L4_NOTHROW
Round address up to the next page.
Capability allocator interface.
L4 low-level kernel interface.
Cap< T > make_cap(L4::Cap< T > cap, unsigned rights)
Make an L4::Ipc::Cap<T> for the given capability and rights.
l4_addr_t l4_trunc_page(l4_addr_t address) L4_NOTHROW
Round an address down to the next lower page boundary.
Search for a suitable address range.
long copy_in(l4_addr_t dst_offs, L4::Ipc::Cap< Dataspace > src, l4_addr_t src_offs, unsigned long size)
Copy contents from another dataspace.
Read right for capability flex-pages.
Interface for memory-like objects.
#define L4_PAGESIZE
Minimal page size (in bytes).
static Env const * env()
Returns the initial environment for the current task.
int detach(l4_addr_t addr, L4::Cap< Dataspace > *mem, L4::Cap< L4::Task > const &task=This_task) const
Detach a region from the address space.
l4_cap_idx_t cap() const
Return capability selector.
_Cap_alloc & cap_alloc
Capability allocator.
Basic element type for a double-linked H_list.
unsigned long l4_umword_t
Unsigned machine word.
Free the portion of the data space after detach.
L4::Cap< void > alloc()
Allocated a new capability.
l4_cap_idx_t cap() const
Return capability selector.
bool is_valid() const
Test whether the capability is a valid capability index (i.e., not L4_INVALID_CAP).
int find(l4_addr_t *addr, unsigned long *size, l4_addr_t *offset, unsigned *flags, L4::Cap< Dataspace > *m)
Find a region given an address and size.
unsigned long l4_addr_t
Address type.
long attach(l4_addr_t *start, unsigned long size, unsigned long flags, L4::Ipc::Cap< Dataspace > mem, l4_addr_t offs=0, unsigned char align=L4_PAGESHIFT) const
Attach a data space to a region.
Basic interface for an L4Re::Vfs file system.
#define L4_NOTHROW
Mark a function declaration and definition as never throwing an exception.