11#include "vcon_stream.h"
14#include <l4/bid_config.h>
19#include <l4/cxx/hlist>
21#include <l4/cxx/std_alloc>
23#include <l4/l4re_vfs/backend>
34static int debug_mmap = 1;
35#define DEBUG_LOG(level, dbg...) do { if (level) dbg } while (0)
37#define DEBUG_LOG(level, dbg...) do { } while (0)
45#define USE_BIG_ANON_DS
53class Fd_store :
public L4Re::Core::Fd_store
61class Std_stream : public L4Re::Core::Vcon_stream
64 Std_stream(L4::Cap<L4::Vcon> c) : L4Re::Core::Vcon_stream(c) {}
67Fd_store::Fd_store() noexcept
71 static char m[
sizeof(Std_stream)] __attribute__((aligned(
sizeof(
long))));
75 set(0, cxx::ref_ptr(s));
76 set(1, cxx::ref_ptr(s));
77 set(2, cxx::ref_ptr(s));
80class Root_mount_tree :
public L4Re::Vfs::Mount_tree
83 Root_mount_tree() : L4Re::Vfs::Mount_tree(0) {}
84 void operator delete (
void *) {}
87class Vfs :
public L4Re::Vfs::Ops
94 : _early_oom(true), _root_mount(), _root(L4Re::Env::env())
96 _root_mount.add_ref();
98 _root_mount.mount(cxx::ref_ptr(&_root));
99 _cwd = cxx::ref_ptr(&_root);
102 Ref_ptr<L4Re::Vfs::File> rom;
103 _root.openat(
"rom", 0, 0, &rom);
105 _root_mount.create_tree(
"lib/foo", rom);
107 _root.openat(
"lib", 0, 0, &_cwd);
112 int alloc_fd(Ref_ptr<L4Re::Vfs::File>
const &f)
noexcept override;
113 Ref_ptr<L4Re::Vfs::File> free_fd(
int fd)
noexcept override;
114 Ref_ptr<L4Re::Vfs::File> get_root() noexcept override;
115 Ref_ptr<L4Re::Vfs::File> get_cwd() noexcept override;
116 void set_cwd(Ref_ptr<L4Re::Vfs::File> const &dir) noexcept override;
117 Ref_ptr<L4Re::Vfs::File> get_file(
int fd) noexcept override;
118 cxx::Pair<Ref_ptr<L4Re::Vfs::File>,
int>
119 set_fd(
int fd, Ref_ptr<L4Re::Vfs::File> const &f = Ref_ptr<>::Nil) noexcept
122 int mmap2(
void *start,
size_t len,
int prot,
int flags,
int fd,
123 off_t offset,
void **ptr) noexcept override;
125 int munmap(
void *start,
size_t len) noexcept override;
126 int mremap(
void *old,
size_t old_sz,
size_t new_sz,
int flags,
127 void **new_addr) noexcept override;
128 int mprotect(const
void *a,
size_t sz,
int prot) noexcept override;
129 int msync(
void *addr,
size_t len,
int flags) noexcept override;
130 int madvise(
void *addr,
size_t len,
int advice) noexcept override;
132 int register_file_system(L4Re::Vfs::File_system *f) noexcept override;
133 int unregister_file_system(L4Re::Vfs::File_system *f) noexcept override;
134 L4Re::Vfs::File_system *get_file_system(
char const *fstype) noexcept override;
135 L4Re::Vfs::File_system_list file_system_list() noexcept override;
137 int register_file_factory(cxx::Ref_ptr<L4Re::Vfs::File_factory> f) noexcept override;
138 int unregister_file_factory(cxx::Ref_ptr<L4Re::Vfs::File_factory> f) noexcept override;
139 Ref_ptr<L4Re::Vfs::File_factory> get_file_factory(
int proto) noexcept override;
140 Ref_ptr<L4Re::Vfs::File_factory> get_file_factory(
char const *proto_name) noexcept override;
141 int mount(
char const *path, cxx::Ref_ptr<L4Re::Vfs::File> const &dir) noexcept override;
143 void operator delete (
void *) {}
145 void *malloc(
size_t size)
noexcept override {
return Vfs_config::malloc(size); }
146 void free(
void *m)
noexcept override { Vfs_config::free(m); }
149 Root_mount_tree _root_mount;
150 L4Re::Core::Env_dir _root;
151 Ref_ptr<L4Re::Vfs::File> _cwd;
154 L4Re::Vfs::File_system *_fs_registry;
156 struct File_factory_item : cxx::H_list_item_t<File_factory_item>
158 cxx::Ref_ptr<L4Re::Vfs::File_factory> f;
159 explicit File_factory_item(cxx::Ref_ptr<L4Re::Vfs::File_factory>
const &f)
162 File_factory_item() =
default;
163 File_factory_item(File_factory_item
const &) =
delete;
164 File_factory_item &operator = (File_factory_item
const &) =
delete;
167 cxx::H_list_t<File_factory_item> _file_factories;
176 void align_mmap_start_and_length(
void **start,
size_t *length);
177 int munmap_regions(
void *start,
size_t len);
179 L4Re::Vfs::File_system *find_fs_from_type(
char const *fstype)
noexcept;
182static inline bool strequal(
char const *a,
char const *b)
184 for (;*a && *a == *b; ++a, ++b)
190Vfs::register_file_system(L4Re::Vfs::File_system *f)
noexcept
192 using L4Re::Vfs::File_system;
197 for (File_system *c = _fs_registry; c; c = c->next())
198 if (strequal(c->type(), f->type()))
201 f->next(_fs_registry);
208Vfs::unregister_file_system(L4Re::Vfs::File_system *f)
noexcept
210 using L4Re::Vfs::File_system;
215 File_system **p = &_fs_registry;
217 for (; *p; p = &(*p)->next())
228L4Re::Vfs::File_system *
229Vfs::find_fs_from_type(
char const *fstype)
noexcept
231 L4Re::Vfs::File_system_list fsl(_fs_registry);
232 for (L4Re::Vfs::File_system_list::Iterator c = fsl.begin();
234 if (strequal(c->type(), fstype))
239L4Re::Vfs::File_system_list
240Vfs::file_system_list() noexcept
242 return L4Re::Vfs::File_system_list(_fs_registry);
245L4Re::Vfs::File_system *
246Vfs::get_file_system(
char const *fstype)
noexcept
248 L4Re::Vfs::File_system *fs;
249 if ((fs = find_fs_from_type(fstype)))
253 int res = Vfs_config::load_module(fstype);
258 return find_fs_from_type(fstype);
262Vfs::register_file_factory(cxx::Ref_ptr<L4Re::Vfs::File_factory> f)
noexcept
267 void *x = this->malloc(
sizeof(File_factory_item));
271 auto ff =
new (x, cxx::Nothrow()) File_factory_item(f);
272 _file_factories.push_front(ff);
277Vfs::unregister_file_factory(cxx::Ref_ptr<L4Re::Vfs::File_factory> f)
noexcept
279 for (
auto p: _file_factories)
283 _file_factories.remove(p);
284 p->~File_factory_item();
292Ref_ptr<L4Re::Vfs::File_factory>
293Vfs::get_file_factory(
int proto)
noexcept
295 for (
auto p: _file_factories)
296 if (p->f->proto() == proto)
299 return Ref_ptr<L4Re::Vfs::File_factory>();
302Ref_ptr<L4Re::Vfs::File_factory>
303Vfs::get_file_factory(
char const *proto_name)
noexcept
305 for (
auto p: _file_factories)
307 auto n = p->f->proto_name();
311 char const *b = proto_name;
312 for (; *a && *b && *a == *b; ++a, ++b)
315 if ((*a == 0) && (*b == 0))
320 return Ref_ptr<L4Re::Vfs::File_factory>();
324Vfs::alloc_fd(Ref_ptr<L4Re::Vfs::File>
const &f)
noexcept
326 int fd = fds.alloc();
336Ref_ptr<L4Re::Vfs::File>
337Vfs::free_fd(
int fd)
noexcept
339 Ref_ptr<L4Re::Vfs::File> f = fds.get(fd);
342 return Ref_ptr<>::Nil;
349Ref_ptr<L4Re::Vfs::File>
350Vfs::get_root() noexcept
352 return cxx::ref_ptr(&_root);
355Ref_ptr<L4Re::Vfs::File>
356Vfs::get_cwd() noexcept
362Vfs::set_cwd(Ref_ptr<L4Re::Vfs::File>
const &dir)
noexcept
369Ref_ptr<L4Re::Vfs::File>
370Vfs::get_file(
int fd)
noexcept
375cxx::Pair<Ref_ptr<L4Re::Vfs::File>,
int>
376Vfs::set_fd(
int fd, Ref_ptr<L4Re::Vfs::File>
const &f)
noexcept
378 if (!fds.check_fd(fd))
379 return cxx::pair(Ref_ptr<L4Re::Vfs::File>(Ref_ptr<>::Nil), EBADF);
381 Ref_ptr<L4Re::Vfs::File> old = fds.get(fd);
383 return cxx::pair(old, 0);
387#define GET_FILE_DBG(fd, err) \
388 Ref_ptr<L4Re::Vfs::File> fi = fds.get(fd); \
394#define GET_FILE(fd, err) \
395 Ref_ptr<L4Re::Vfs::File> fi = fds.get(fd); \
400Vfs::align_mmap_start_and_length(
void **start,
size_t *length)
410Vfs::munmap_regions(
void *start,
size_t len)
413 using namespace L4Re;
417 Cap<Rm> r = Env::env()->rm();
422 align_mmap_start_and_length(&start, &len);
426 DEBUG_LOG(debug_mmap, {
433 err = r->detach(
l4_addr_t(start), len, &ds, This_task);
437 switch (err & Rm::Detach_result_mask)
441 L4Re::virt_cap_alloc->take(ds);
445 L4Re::virt_cap_alloc->release(ds);
457Vfs::munmap(
void *start,
size_t len)
L4_NOTHROW
460 using namespace L4Re;
463 Cap<Rm> r = Env::env()->rm();
468 bool matches_area =
false;
474 area_cnt = r->get_areas((
l4_addr_t) start, &area_array);
482 size_t area_size = area_array[0].end - area_array[0].start + 1;
485 if (area_array[0].start == (
l4_addr_t) start && area_size == len)
495 err = munmap_regions(start, len);
496 if (err == -ENOENT && matches_area)
511 if ((err = Vfs_config::allocator()->alloc(size, ds->get())) < 0)
514 DEBUG_LOG(debug_mmap, {
529#if !defined(CONFIG_MMU)
534 ANON_MEM_DS_POOL_SIZE = 256UL << 10,
535 ANON_MEM_MAX_SIZE = 32UL << 10,
537#elif defined(USE_BIG_ANON_DS)
540 ANON_MEM_DS_POOL_SIZE = 256UL << 20,
541 ANON_MEM_MAX_SIZE = 32UL << 20,
546 ANON_MEM_DS_POOL_SIZE = 256UL << 20,
547 ANON_MEM_MAX_SIZE = 0UL << 20,
551 if (size >= ANON_MEM_MAX_SIZE)
554 if ((err = alloc_ds(size, ds)) < 0)
562 return (*ds)->allocate(0, size);
565 if (!_anon_ds.is_valid() || _anon_offset + size >= ANON_MEM_DS_POOL_SIZE)
568 if ((err = alloc_ds(ANON_MEM_DS_POOL_SIZE, ds)) < 0)
579 if (
int err = (*ds)->allocate(_anon_offset, size))
583 *offset = _anon_offset;
584 _anon_offset += size;
589Vfs::mmap2(
void *start,
size_t len,
int prot,
int flags,
int fd, off_t page4k_offset,
592 DEBUG_LOG(debug_mmap, {
607 using namespace L4Re;
610 if (flags & MAP_FIXED)
614 align_mmap_start_and_length(&start, &len);
619 if ((flags & 0x1000000) || (prot == PROT_NONE))
622 L4::Cap<Rm> r = Env::env()->rm();
628 *resptr =
reinterpret_cast<void*
>(area);
630 DEBUG_LOG(debug_mmap, {
643 L4Re::Rm::Flags rm_flags(0);
645 if (flags & (MAP_ANONYMOUS | MAP_PRIVATE))
649 int err = alloc_anon_mem(len, &ds, &anon_offset);
653 DEBUG_LOG(debug_mmap, {
662 char const *region_name =
"[unknown]";
664 if (!(flags & MAP_ANONYMOUS))
666 Ref_ptr<L4Re::Vfs::File> fi = fds.get(fd);
670 region_name = fi->path();
672 L4::Cap<L4Re::Dataspace> fds = fi->data_space();
680 if (flags & MAP_PRIVATE)
683 int err = ds->copy_in(anon_offset, fds, offset, len);
684 file_offset = offset;
687 L4::Cap<Rm> r = Env::env()->rm();
690 err = r->attach(&src, len,
696 err = r->attach(&dst, len,
698 ds.get(), anon_offset);
702 memcpy(dst.
get(), src.
get(), len);
704 region_name =
"[mmap-private]";
705 file_offset = (
unsigned long)dst.
get();
710 offset = anon_offset;
714 L4Re::virt_cap_alloc->take(fds);
720 offset = anon_offset;
721 region_name =
"[anon]";
722 file_offset = offset;
726 if (!(flags & MAP_FIXED) && start == 0)
729 char *data =
static_cast<char *
>(start);
730 L4::Cap<Rm> r = Env::env()->rm();
734 if (flags & MAP_FIXED)
738 err = r->reserve_area(&overmap_area, len);
747 err = munmap_regions(start, len);
748 if (err && err != -ENOENT)
752 if (!(flags & MAP_FIXED))
754 if (prot & PROT_READ)
756 if (prot & PROT_WRITE)
758 if (prot & PROT_EXEC)
761 err = r->attach(&data, len, rm_flags,
766 region_name, file_offset);
768 DEBUG_LOG(debug_mmap, {
784 r->free_area(overmap_area);
812 int e = r->reserve_area(&a, sz, flags);
829 ~Auto_area() { free(); }
834Vfs::mremap(
void *old_addr,
size_t old_size,
size_t new_size,
int flags,
837 using namespace L4Re;
839 DEBUG_LOG(debug_mmap, {
849 if (flags & MREMAP_FIXED && !(flags & MREMAP_MAYMOVE))
853 if (oa !=
reinterpret_cast<l4_addr_t>(old_addr))
856 bool const fixed = flags & MREMAP_FIXED;
857 bool const maymove = flags & MREMAP_MAYMOVE;
859 L4::Cap<Rm> r = Env::env()->rm();
867 if (new_size < old_size)
869 *new_addr = old_addr;
870 return munmap(
reinterpret_cast<void*
>(oa + new_size),
871 old_size - new_size);
874 if (new_size == old_size)
876 *new_addr = old_addr;
881 Auto_area old_area(r);
882 int err = old_area.reserve(oa, old_size, L4Re::Rm::Flags(0));
887 Auto_area new_area(r);
891 if (na !=
reinterpret_cast<l4_addr_t>(*new_addr))
895 int err = new_area.reserve(na, new_size, L4Re::Rm::Flags(0));
905 unsigned long ts = new_size - old_size;
907 long err = new_area.reserve(ta, ts, L4Re::Rm::Flags(0));
911 L4Re::Rm::Offset toffs;
912 L4Re::Rm::Flags tflags;
913 L4::Cap<L4Re::Dataspace> tds;
915 err = r->find(&ta, &ts, &toffs, &tflags, &tds);
921 pad_addr = oa + old_size;
922 *new_addr = old_addr;
933 pad_addr = new_area.a + old_size;
934 *new_addr =
reinterpret_cast<void *
>(new_area.a);
938 if (old_area.is_valid())
940 unsigned long size = old_size;
946 L4::Cap<L4Re::Dataspace> ds;
948 while (r->find(&a, &s, &o, &f, &ds) >= 0 && !(f &
Rm::F::In_area))
952 auto d = old_area.a - a;
958 if (a + s > old_area.a + old_size)
959 s = old_area.a + old_size - a;
961 l4_addr_t x = a - old_area.a + new_area.a;
969 L4Re::virt_cap_alloc->take(ds);
971 err = r->detach(a, s, &ds, This_task,
976 switch (err & Rm::Detach_result_mask)
981 L4Re::virt_cap_alloc->take(ds);
985 L4Re::virt_cap_alloc->release(ds);
1001 if (old_size < new_size)
1003 l4_addr_t const pad_sz = new_size - old_size;
1006 int err = alloc_anon_mem(pad_sz, &tds, &toffs);
1012 err = r->attach(&pad_addr, pad_sz,
1026Vfs::mprotect(
const void * ,
size_t ,
int prot)
L4_NOTHROW
1028 return (prot & PROT_WRITE) ? -ENOSYS : 0;
1042extern void *l4re_env_posix_vfs_ops __attribute__((alias(
"__rtld_l4re_env_posix_vfs_ops"), visibility(
"default")));
1045 class Real_mount_tree :
public L4Re::Vfs::Mount_tree
1048 explicit Real_mount_tree(
char *n) : Mount_tree(n) {}
1050 void *
operator new (
size_t size)
1051 {
return __rtld_l4re_env_posix_vfs_ops->malloc(size); }
1053 void operator delete (
void *mem)
1054 { __rtld_l4re_env_posix_vfs_ops->free(mem); }
1063 using L4Re::Vfs::Mount_tree;
1064 using L4Re::Vfs::Path;
1071 Path p = root->lookup(Path(path), &base);
1075 Path f = p.strip_first();
1080 char *name = __rtld_l4re_env_posix_vfs_ops->strndup(f.path(), f.length());
1084 auto nt = cxx::make_ref_obj<Real_mount_tree>(name);
1087 __rtld_l4re_env_posix_vfs_ops->free(name);
1091 base->add_child_node(nt);
static Env const * env() noexcept
Returns the initial environment for the current task.
@ Detached_ds
Detached data sapce.
@ Detach_again
Detached data space, more to do.
@ Split_ds
Splitted data space, and done.
@ Detach_exact
Do an unmap of the exact region given.
@ Detach_keep
Do not free the detached data space, ignore the F::Detach_free.
The basic interface for an open POSIX file.
Interface for the POSIX backends of an application.
l4_cap_idx_t cap() const noexcept
Return capability selector.
bool is_valid() const noexcept
Test whether the capability is a valid capability index (i.e., not L4_INVALID_CAP).
@ Invalid
Invalid capability selector.
T get() const noexcept
Return the address.
A reference-counting pointer with automatic cleanup.
unsigned int l4_size_t
Unsigned size type.
unsigned long l4_umword_t
Unsigned machine word.
unsigned long l4_addr_t
Address type.
@ L4_EINVAL
Invalid argument.
@ L4_CAP_FPAGE_RO
Read right for capability flexpages.
@ L4_CAP_FPAGE_RW
Read and interface specific 'W' right for capability flexpages.
l4_addr_t l4_trunc_page(l4_addr_t address) L4_NOTHROW
Round an address down to the next lower page boundary.
l4_addr_t l4_round_page(l4_addr_t address) L4_NOTHROW
Round address up to the next page.
#define L4_PAGESIZE
Minimal page size (in bytes).
#define L4_PAGESHIFT
Size of a page, log2-based.
@ L4_INVALID_ADDR
Invalid address.
#define L4_NOTHROW
Mark a function declaration and definition as never throwing an exception.
Functionality for invoking the kernel debugger.
void l4_kd_outdec(l4_mword_t number)
Output a decimal unsigned machine word via the kernel debugger.
void l4_kd_outhex32(l4_uint32_t number)
Output a 32-bit unsigned hexadecimal number via the kernel debugger.
void l4_kd_outstring(char const *text)
Output a string via the kernel debugger.
Shared_cap< T > make_shared_cap(L4Re::Cap_alloc *ca)
Allocate a capability slot and wrap it in a Shared_cap.
L4::Detail::Shared_cap_impl< T, Smart_count_cap< L4_FP_ALL_SPACES > > Shared_cap
Shared capability that implements automatic free and unmap of the capability selector.
Cap< T > make_cap(L4::Cap< T > cap, unsigned rights) noexcept
Make an L4::Ipc::Cap<T> for the given capability and rights.
Cap< T > make_cap_rw(L4::Cap< T > cap) noexcept
Make an L4::Ipc::Cap<T> for the given capability with L4_CAP_FPAGE_RW rights.
Shared_cap / Shared_del_cap.
An area is a range of virtual addresses which is reserved, see L4Re::Rm::reserve_area().
@ RWX
Readable, writable and executable region.
@ RW
Readable and writable region.
@ Detach_free
Free the portion of the data space after detach.
@ Search_addr
Search for a suitable address range.
@ In_area
Search only in area, or map into area.
Low-level assert implementation.
#define l4_assert(expr)
Low-level assert.