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))));
74 Std_stream *s =
new (m) Std_stream(log);
75 set(0, cxx::ref_ptr(s));
76 set(1, cxx::ref_ptr(s));
77 set(2, cxx::ref_ptr(s));
84class Root_mount_tree :
public L4Re::Vfs::Mount_tree
87 Root_mount_tree() : L4Re::Vfs::Mount_tree(0) {}
88 void operator delete (
void *) {}
91class Vfs :
public L4Re::Vfs::Ops
98 : _early_oom(true), _root_mount(), _root(L4Re::Env::env())
100 _root_mount.add_ref();
102 _root_mount.mount(cxx::ref_ptr(&_root));
103 _cwd = cxx::ref_ptr(&_root);
106 Ref_ptr<L4Re::Vfs::File> rom;
107 _root.openat(
"rom", 0, 0, &rom);
109 _root_mount.create_tree(
"lib/foo", rom);
111 _root.openat(
"lib", 0, 0, &_cwd);
116 int alloc_fd(Ref_ptr<L4Re::Vfs::File>
const &f)
noexcept override;
117 Ref_ptr<L4Re::Vfs::File> free_fd(
int fd)
noexcept override;
118 Ref_ptr<L4Re::Vfs::File> get_root() noexcept override;
119 Ref_ptr<L4Re::Vfs::File> get_cwd() noexcept override;
120 void set_cwd(Ref_ptr<L4Re::Vfs::File> const &dir) noexcept override;
121 Ref_ptr<L4Re::Vfs::File> get_file(
int fd) noexcept override;
122 cxx::Pair<Ref_ptr<L4Re::Vfs::File>,
int>
123 set_fd(
int fd, Ref_ptr<L4Re::Vfs::File> const &f = Ref_ptr<>::Nil) noexcept
126 int mmap2(
void *start,
size_t len,
int prot,
int flags,
int fd,
127 off_t offset,
void **ptr) noexcept override;
129 int munmap(
void *start,
size_t len) noexcept override;
130 int mprotect(const
void *a,
size_t sz,
int prot) noexcept override;
131 int msync(
void *addr,
size_t len,
int flags) noexcept override;
132 int madvise(
void *addr,
size_t len,
int advice) noexcept override;
134 int register_file_system(L4Re::Vfs::File_system *f) noexcept override;
135 int unregister_file_system(L4Re::Vfs::File_system *f) noexcept override;
136 L4Re::Vfs::File_system *get_file_system(
char const *fstype) noexcept override;
137 L4Re::Vfs::File_system_list file_system_list() noexcept override;
139 int register_file_factory(cxx::Ref_ptr<L4Re::Vfs::File_factory> f) noexcept override;
140 int unregister_file_factory(cxx::Ref_ptr<L4Re::Vfs::File_factory> f) noexcept override;
141 Ref_ptr<L4Re::Vfs::File_factory> get_file_factory(
int proto) noexcept override;
142 Ref_ptr<L4Re::Vfs::File_factory> get_file_factory(
char const *proto_name) noexcept override;
143 int mount(
char const *path, cxx::Ref_ptr<L4Re::Vfs::File> const &dir) noexcept override;
145 void operator delete (
void *) {}
147 void *malloc(
size_t size)
noexcept override {
return Vfs_config::malloc(size); }
148 void free(
void *m)
noexcept override { Vfs_config::free(m); }
151 Root_mount_tree _root_mount;
152 L4Re::Core::Env_dir _root;
153 Ref_ptr<L4Re::Vfs::File> _cwd;
156 L4Re::Vfs::File_system *_fs_registry;
158 struct File_factory_item : cxx::H_list_item_t<File_factory_item>
160 cxx::Ref_ptr<L4Re::Vfs::File_factory> f;
161 explicit File_factory_item(cxx::Ref_ptr<L4Re::Vfs::File_factory>
const &f)
164 File_factory_item() =
default;
165 File_factory_item(File_factory_item
const &) =
delete;
166 File_factory_item &operator = (File_factory_item
const &) =
delete;
169 cxx::H_list_t<File_factory_item> _file_factories;
171 void align_mmap_start_and_length(
void **start,
size_t *length);
172 int munmap_regions(
void *start,
size_t len);
174 L4Re::Vfs::File_system *find_fs_from_type(
char const *fstype)
noexcept;
177static inline bool strequal(
char const *a,
char const *b)
179 for (;*a && *a == *b; ++a, ++b)
185Vfs::register_file_system(L4Re::Vfs::File_system *f)
noexcept
187 using L4Re::Vfs::File_system;
192 for (File_system *c = _fs_registry; c; c = c->next())
193 if (strequal(c->type(), f->type()))
196 f->next(_fs_registry);
203Vfs::unregister_file_system(L4Re::Vfs::File_system *f)
noexcept
205 using L4Re::Vfs::File_system;
210 File_system **p = &_fs_registry;
212 for (; *p; p = &(*p)->next())
223L4Re::Vfs::File_system *
224Vfs::find_fs_from_type(
char const *fstype)
noexcept
226 L4Re::Vfs::File_system_list fsl(_fs_registry);
227 for (L4Re::Vfs::File_system_list::Iterator c = fsl.begin();
229 if (strequal(c->type(), fstype))
234L4Re::Vfs::File_system_list
235Vfs::file_system_list() noexcept
237 return L4Re::Vfs::File_system_list(_fs_registry);
240L4Re::Vfs::File_system *
241Vfs::get_file_system(
char const *fstype)
noexcept
243 L4Re::Vfs::File_system *fs;
244 if ((fs = find_fs_from_type(fstype)))
248 int res = Vfs_config::load_module(fstype);
253 return find_fs_from_type(fstype);
257Vfs::register_file_factory(cxx::Ref_ptr<L4Re::Vfs::File_factory> f)
noexcept
262 void *x = this->malloc(
sizeof(File_factory_item));
266 auto ff =
new (x, cxx::Nothrow()) File_factory_item(f);
267 _file_factories.push_front(ff);
272Vfs::unregister_file_factory(cxx::Ref_ptr<L4Re::Vfs::File_factory> f)
noexcept
274 for (
auto p: _file_factories)
278 _file_factories.remove(p);
279 p->~File_factory_item();
287Ref_ptr<L4Re::Vfs::File_factory>
288Vfs::get_file_factory(
int proto)
noexcept
290 for (
auto p: _file_factories)
291 if (p->f->proto() == proto)
294 return Ref_ptr<L4Re::Vfs::File_factory>();
297Ref_ptr<L4Re::Vfs::File_factory>
298Vfs::get_file_factory(
char const *proto_name)
noexcept
300 for (
auto p: _file_factories)
302 auto n = p->f->proto_name();
306 char const *b = proto_name;
307 for (; *a && *b && *a == *b; ++a, ++b)
310 if ((*a == 0) && (*b == 0))
315 return Ref_ptr<L4Re::Vfs::File_factory>();
319Vfs::alloc_fd(Ref_ptr<L4Re::Vfs::File>
const &f)
noexcept
321 int fd = fds.alloc();
331Ref_ptr<L4Re::Vfs::File>
332Vfs::free_fd(
int fd)
noexcept
334 Ref_ptr<L4Re::Vfs::File> f = fds.get(fd);
337 return Ref_ptr<>::Nil;
344Ref_ptr<L4Re::Vfs::File>
345Vfs::get_root() noexcept
347 return cxx::ref_ptr(&_root);
350Ref_ptr<L4Re::Vfs::File>
351Vfs::get_cwd() noexcept
357Vfs::set_cwd(Ref_ptr<L4Re::Vfs::File>
const &dir)
noexcept
364Ref_ptr<L4Re::Vfs::File>
365Vfs::get_file(
int fd)
noexcept
370cxx::Pair<Ref_ptr<L4Re::Vfs::File>,
int>
371Vfs::set_fd(
int fd, Ref_ptr<L4Re::Vfs::File>
const &f)
noexcept
373 if (!fds.check_fd(fd))
374 return cxx::pair(Ref_ptr<L4Re::Vfs::File>(Ref_ptr<>::Nil), EBADF);
376 Ref_ptr<L4Re::Vfs::File> old = fds.get(fd);
378 return cxx::pair(old, 0);
382#define GET_FILE_DBG(fd, err) \
383 Ref_ptr<L4Re::Vfs::File> fi = fds.get(fd); \
389#define GET_FILE(fd, err) \
390 Ref_ptr<L4Re::Vfs::File> fi = fds.get(fd); \
395Vfs::align_mmap_start_and_length(
void **start,
size_t *length)
405Vfs::munmap_regions(
void *start,
size_t len)
408 using namespace L4Re;
411 Cap<Rm> r = Env::env()->rm();
416 align_mmap_start_and_length(&start, &len);
420 DEBUG_LOG(debug_mmap, {
427 err = r->detach(
l4_addr_t(start), len,
nullptr, This_task);
437Vfs::munmap(
void *start,
size_t len)
L4_NOTHROW
440 using namespace L4Re;
443 Cap<Rm> r = Env::env()->rm();
447 L4::Ipc::Array_ref<Rm::Area> areas_in_utcb;
448 bool matches_area =
false;
454 area_cnt = r->get_areas((
l4_addr_t) start, areas_in_utcb);
462 Rm::Area const &first_area = areas_in_utcb.data[0];
463 size_t area_size = first_area.end - first_area.start + 1;
466 if (first_area.start == (
l4_addr_t) start && area_size == len)
476 err = munmap_regions(start, len);
477 if (err == -ENOENT && matches_area)
484Vfs::mmap2(
void *start,
size_t len,
int prot,
int flags,
int fd, off_t page4k_offset,
487 DEBUG_LOG(debug_mmap, {
502 using namespace L4Re;
505 if (flags & MAP_FIXED)
509 align_mmap_start_and_length(&start, &len);
514 if ((flags & 0x1000000) || (prot == PROT_NONE))
517 L4::Cap<Rm> r = Env::env()->rm();
523 *resptr =
reinterpret_cast<void*
>(area);
525 DEBUG_LOG(debug_mmap, {
536 L4::Cap<L4Re::Dataspace> ds;
537 L4Re::Rm::Flags rm_flags(0);
538 char const *region_name =
"[unknown]";
541 if (flags & MAP_PRIVATE)
544 if (flags & MAP_ANONYMOUS)
548 region_name =
"[anon]";
552 Ref_ptr<L4Re::Vfs::File> fi = fds.get(fd);
556 region_name = fi->path();
558 ds = fi->data_space();
567 if (!(flags & MAP_FIXED) && start == 0)
570 char *data =
static_cast<char *
>(start);
571 L4::Cap<Rm> r = Env::env()->rm();
575 if (flags & MAP_FIXED)
579 err = r->reserve_area(&overmap_area, len);
588 err = munmap_regions(start, len);
589 if (err && err != -ENOENT)
593 if (!(flags & MAP_FIXED))
595 if (prot & PROT_READ)
597 if (prot & PROT_WRITE)
599 if (prot & PROT_EXEC)
603 err = r->attach(&data, len, rm_flags,
608 region_name, file_offset);
610 DEBUG_LOG(debug_mmap, {
626 r->free_area(overmap_area);
639Vfs::mprotect(
const void * ,
size_t ,
int prot)
L4_NOTHROW
641 return (prot & PROT_WRITE) ? -ENOSYS : 0;
655extern void *l4re_env_posix_vfs_ops __attribute__((alias(
"__rtld_l4re_env_posix_vfs_ops"), visibility(
"default")));
658 class Real_mount_tree :
public L4Re::Vfs::Mount_tree
661 explicit Real_mount_tree(
char *n) : Mount_tree(n) {}
663 void *
operator new (
size_t size)
664 {
return __rtld_l4re_env_posix_vfs_ops->malloc(size); }
666 void operator delete (
void *mem)
667 { __rtld_l4re_env_posix_vfs_ops->free(mem); }
676 using L4Re::Vfs::Mount_tree;
677 using L4Re::Vfs::Path;
684 Path p = root->lookup(Path(path), &base);
688 Path f = p.strip_first();
693 char *name = __rtld_l4re_env_posix_vfs_ops->strndup(f.path(), f.length());
697 auto nt = cxx::make_ref_obj<Real_mount_tree>(name);
700 __rtld_l4re_env_posix_vfs_ops->free(name);
704 base->add_child_node(nt);
static Env const * env() noexcept
Returns the initial environment for the current task.
@ Detach_again
Detached data space, more to do.
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.
A reference-counting pointer with automatic cleanup.
unsigned long l4_addr_t
Address type.
@ 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.
Cap< T > make_cap(L4::Cap< T > cap, unsigned rights) noexcept
Make an L4::Ipc::Cap<T> for the given capability and rights.
Shared_cap / Shared_del_cap.
An area is a range of virtual addresses which is reserved, see L4Re::Rm::reserve_area().
@ Private
Attach the dataspace privately with copy-on-write semantics.
@ Anonymous
Attach anonymous memory in the region.
@ 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.