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> 
   33static int debug_mmap = 1;
 
   34#define DEBUG_LOG(level, dbg...) do { if (level) dbg } while (0) 
   36#define DEBUG_LOG(level, dbg...) do { } while (0) 
   44#define USE_BIG_ANON_DS 
   52class Fd_store : 
public L4Re::Core::Fd_store
 
   60class Std_stream : public L4Re::Core::Vcon_stream
 
   63  Std_stream(L4::Cap<L4::Vcon> c) : L4Re::Core::Vcon_stream(c) {}
 
   66Fd_store::Fd_store() noexcept
 
   70  static char m[
sizeof(Std_stream)] __attribute__((aligned(
sizeof(
long))));
 
   74  set(0, cxx::ref_ptr(s)); 
 
   75  set(1, cxx::ref_ptr(s)); 
 
   76  set(2, cxx::ref_ptr(s)); 
 
   79class Root_mount_tree : 
public L4Re::Vfs::Mount_tree
 
   82  Root_mount_tree() : L4Re::Vfs::Mount_tree(0) {}
 
   83  void operator delete (
void *) {}
 
   86class Vfs : 
public L4Re::Vfs::Ops
 
   93  : _early_oom(true), _root_mount(), _root(L4Re::Env::env())
 
   95    _root_mount.add_ref();
 
   97    _root_mount.mount(cxx::ref_ptr(&_root));
 
   98    _cwd = cxx::ref_ptr(&_root);
 
  101    Ref_ptr<L4Re::Vfs::File> rom;
 
  102    _root.openat(
"rom", 0, 0, &rom);
 
  104    _root_mount.create_tree(
"lib/foo", rom);
 
  106    _root.openat(
"lib", 0, 0, &_cwd);
 
  111  int alloc_fd(Ref_ptr<L4Re::Vfs::File> 
const &f) 
noexcept override;
 
  112  Ref_ptr<L4Re::Vfs::File> free_fd(
int fd) 
noexcept override;
 
  113  Ref_ptr<L4Re::Vfs::File> get_root() noexcept override;
 
  114  Ref_ptr<L4Re::Vfs::File> get_cwd() noexcept override;
 
  115  void set_cwd(Ref_ptr<L4Re::Vfs::File> const &dir) noexcept override;
 
  116  Ref_ptr<L4Re::Vfs::File> get_file(
int fd) noexcept override;
 
  117  cxx::Pair<Ref_ptr<L4Re::Vfs::File>, 
int>
 
  118    set_fd(
int fd, Ref_ptr<L4Re::Vfs::File> const &f = Ref_ptr<>::Nil) noexcept
 
  121  int mmap2(
void *start, 
size_t len, 
int prot, 
int flags, 
int fd,
 
  122            off_t offset, 
void **ptr) noexcept override;
 
  124  int munmap(
void *start, 
size_t len) noexcept override;
 
  125  int mremap(
void *old, 
size_t old_sz, 
size_t new_sz, 
int flags,
 
  126             void **new_addr) noexcept override;
 
  127  int mprotect(const 
void *a, 
size_t sz, 
int prot) noexcept override;
 
  128  int msync(
void *addr, 
size_t len, 
int flags) noexcept override;
 
  129  int madvise(
void *addr, 
size_t len, 
int advice) noexcept override;
 
  131  int register_file_system(L4Re::Vfs::File_system *f) noexcept override;
 
  132  int unregister_file_system(L4Re::Vfs::File_system *f) noexcept override;
 
  133  L4Re::Vfs::File_system *get_file_system(
char const *fstype) noexcept override;
 
  134  L4Re::Vfs::File_system_list file_system_list() noexcept override;
 
  136  int register_file_factory(cxx::Ref_ptr<L4Re::Vfs::File_factory> f) noexcept override;
 
  137  int unregister_file_factory(cxx::Ref_ptr<L4Re::Vfs::File_factory> f) noexcept override;
 
  138  Ref_ptr<L4Re::Vfs::File_factory> get_file_factory(
int proto) noexcept override;
 
  139  Ref_ptr<L4Re::Vfs::File_factory> get_file_factory(
char const *proto_name) noexcept override;
 
  140  int mount(
char const *path, cxx::Ref_ptr<L4Re::Vfs::File> const &dir) noexcept override;
 
  142  void operator delete (
void *) {}
 
  144  void *malloc(
size_t size) 
noexcept override { 
return Vfs_config::malloc(size); }
 
  145  void free(
void *m) 
noexcept override { Vfs_config::free(m); }
 
  148  Root_mount_tree _root_mount;
 
  149  L4Re::Core::Env_dir _root;
 
  150  Ref_ptr<L4Re::Vfs::File> _cwd;
 
  153  L4Re::Vfs::File_system *_fs_registry;
 
  155  struct File_factory_item : cxx::H_list_item_t<File_factory_item>
 
  157    cxx::Ref_ptr<L4Re::Vfs::File_factory> f;
 
  158    explicit File_factory_item(cxx::Ref_ptr<L4Re::Vfs::File_factory> 
const &f)
 
  161    File_factory_item() = 
default;
 
  162    File_factory_item(File_factory_item 
const &) = 
delete;
 
  163    File_factory_item &operator = (File_factory_item 
const &) = 
delete;
 
  166  cxx::H_list_t<File_factory_item> _file_factories;
 
  175  void align_mmap_start_and_length(
void **start, 
size_t *length);
 
  176  int munmap_regions(
void *start, 
size_t len);
 
  178  L4Re::Vfs::File_system *find_fs_from_type(
char const *fstype) 
noexcept;
 
  181static inline bool strequal(
char const *a, 
char const *b)
 
  183  for (;*a && *a == *b; ++a, ++b)
 
  189Vfs::register_file_system(L4Re::Vfs::File_system *f) 
noexcept 
  191  using L4Re::Vfs::File_system;
 
  196  for (File_system *c = _fs_registry; c; c = c->next())
 
  197    if (strequal(c->type(), f->type()))
 
  200  f->next(_fs_registry);
 
  207Vfs::unregister_file_system(L4Re::Vfs::File_system *f) 
noexcept 
  209  using L4Re::Vfs::File_system;
 
  214  File_system **p = &_fs_registry;
 
  216  for (; *p; p = &(*p)->next())
 
  227L4Re::Vfs::File_system *
 
  228Vfs::find_fs_from_type(
char const *fstype) 
noexcept 
  230  L4Re::Vfs::File_system_list fsl(_fs_registry);
 
  231  for (L4Re::Vfs::File_system_list::Iterator c = fsl.begin();
 
  233    if (strequal(c->type(), fstype))
 
  238L4Re::Vfs::File_system_list
 
  239Vfs::file_system_list() noexcept
 
  241  return L4Re::Vfs::File_system_list(_fs_registry);
 
  244L4Re::Vfs::File_system *
 
  245Vfs::get_file_system(
char const *fstype) 
noexcept 
  247  L4Re::Vfs::File_system *fs;
 
  248  if ((fs = find_fs_from_type(fstype)))
 
  252  int res = Vfs_config::load_module(fstype);
 
  257  return find_fs_from_type(fstype);
 
  261Vfs::register_file_factory(cxx::Ref_ptr<L4Re::Vfs::File_factory> f) 
noexcept 
  266  void *x = this->malloc(
sizeof(File_factory_item));
 
  270  auto ff = 
new (x, cxx::Nothrow()) File_factory_item(f);
 
  271  _file_factories.push_front(ff);
 
  276Vfs::unregister_file_factory(cxx::Ref_ptr<L4Re::Vfs::File_factory> f) 
noexcept 
  278  for (
auto p: _file_factories)
 
  282          _file_factories.remove(p);
 
  283          p->~File_factory_item();
 
  291Ref_ptr<L4Re::Vfs::File_factory>
 
  292Vfs::get_file_factory(
int proto) 
noexcept 
  294  for (
auto p: _file_factories)
 
  295    if (p->f->proto() == proto)
 
  298  return Ref_ptr<L4Re::Vfs::File_factory>();
 
  301Ref_ptr<L4Re::Vfs::File_factory>
 
  302Vfs::get_file_factory(
char const *proto_name) 
noexcept 
  304  for (
auto p: _file_factories)
 
  306      auto n = p->f->proto_name();
 
  310          char const *b = proto_name;
 
  311          for (; *a && *b && *a == *b; ++a, ++b)
 
  314          if ((*a == 0) && (*b == 0))
 
  319  return Ref_ptr<L4Re::Vfs::File_factory>();
 
  323Vfs::alloc_fd(Ref_ptr<L4Re::Vfs::File> 
const &f) 
noexcept 
  325  int fd = fds.alloc();
 
  335Ref_ptr<L4Re::Vfs::File>
 
  336Vfs::free_fd(
int fd) 
noexcept 
  338  Ref_ptr<L4Re::Vfs::File> f = fds.get(fd);
 
  341    return Ref_ptr<>::Nil;
 
  348Ref_ptr<L4Re::Vfs::File>
 
  349Vfs::get_root() noexcept
 
  351  return cxx::ref_ptr(&_root);
 
  354Ref_ptr<L4Re::Vfs::File>
 
  355Vfs::get_cwd() noexcept
 
  361Vfs::set_cwd(Ref_ptr<L4Re::Vfs::File> 
const &dir) 
noexcept 
  368Ref_ptr<L4Re::Vfs::File>
 
  369Vfs::get_file(
int fd) 
noexcept 
  374cxx::Pair<Ref_ptr<L4Re::Vfs::File>, 
int>
 
  375Vfs::set_fd(
int fd, Ref_ptr<L4Re::Vfs::File> 
const &f) 
noexcept 
  377  if (!fds.check_fd(fd))
 
  378    return cxx::pair(Ref_ptr<L4Re::Vfs::File>(Ref_ptr<>::Nil), EBADF);
 
  380  Ref_ptr<L4Re::Vfs::File> old = fds.get(fd);
 
  382  return cxx::pair(old, 0);
 
  386#define GET_FILE_DBG(fd, err) \ 
  387  Ref_ptr<L4Re::Vfs::File> fi = fds.get(fd); \ 
  393#define GET_FILE(fd, err) \ 
  394  Ref_ptr<L4Re::Vfs::File> fi = fds.get(fd); \ 
  399Vfs::align_mmap_start_and_length(
void **start, 
size_t *length)
 
  409Vfs::munmap_regions(
void *start, 
size_t len)
 
  412  using namespace L4Re;
 
  416  Cap<Rm> r = Env::env()->rm();
 
  421  align_mmap_start_and_length(&start, &len);
 
  425      DEBUG_LOG(debug_mmap, {
 
  432      err = r->detach(
l4_addr_t(start), len, &ds, This_task);
 
  436      switch (err & Rm::Detach_result_mask)
 
  440            L4Re::virt_cap_alloc->take(ds);
 
  444            L4Re::virt_cap_alloc->release(ds);
 
  456Vfs::munmap(
void *start, 
size_t len) 
L4_NOTHROW 
  459  using namespace L4Re;
 
  462  Cap<Rm> r = Env::env()->rm();
 
  467  bool matches_area = 
false;        
 
  473  area_cnt = r->get_areas((
l4_addr_t) start, &area_array);
 
  481      size_t area_size = area_array[0].end - area_array[0].start + 1;
 
  484      if (area_array[0].start == (
l4_addr_t) start && area_size == len)
 
  494  err = munmap_regions(start, len);
 
  495  if (err == -ENOENT && matches_area)
 
  510  if ((err = Vfs_config::allocator()->alloc(size, ds->get())) < 0)
 
  513  DEBUG_LOG(debug_mmap, {
 
  528#if !defined(CONFIG_MMU) 
  533    ANON_MEM_DS_POOL_SIZE = 256UL << 10, 
 
  534    ANON_MEM_MAX_SIZE     =  32UL << 10, 
 
  536#elif defined(USE_BIG_ANON_DS) 
  539    ANON_MEM_DS_POOL_SIZE = 256UL << 20, 
 
  540    ANON_MEM_MAX_SIZE     = 32UL << 20,  
 
  545    ANON_MEM_DS_POOL_SIZE = 256UL << 20, 
 
  546    ANON_MEM_MAX_SIZE     = 0UL << 20,   
 
  550  if (size >= ANON_MEM_MAX_SIZE)
 
  553      if ((err = alloc_ds(size, ds)) < 0)
 
  561      return (*ds)->allocate(0, size);
 
  564  if (!_anon_ds.is_valid() || _anon_offset + size >= ANON_MEM_DS_POOL_SIZE)
 
  567      if ((err = alloc_ds(ANON_MEM_DS_POOL_SIZE, ds)) < 0)
 
  578      if (
int err = (*ds)->allocate(_anon_offset, size))
 
  582  *offset = _anon_offset;
 
  583  _anon_offset += size;
 
  588Vfs::mmap2(
void *start, 
size_t len, 
int prot, 
int flags, 
int fd, off_t page4k_offset,
 
  591  DEBUG_LOG(debug_mmap, {
 
  606  using namespace L4Re;
 
  609  if (flags & MAP_FIXED)
 
  613  align_mmap_start_and_length(&start, &len);
 
  618  if ((flags & 0x1000000) || (prot == PROT_NONE))
 
  621      L4::Cap<Rm> r = Env::env()->rm();
 
  627      *resptr = 
reinterpret_cast<void*
>(area);
 
  629      DEBUG_LOG(debug_mmap, {
 
  642  L4Re::Rm::Flags rm_flags(0);
 
  644  if (flags & (MAP_ANONYMOUS | MAP_PRIVATE))
 
  648      int err = alloc_anon_mem(len, &ds, &anon_offset);
 
  652      DEBUG_LOG(debug_mmap, {
 
  661  char const *region_name = 
"[unknown]";
 
  663  if (!(flags & MAP_ANONYMOUS))
 
  665      Ref_ptr<L4Re::Vfs::File> fi = fds.get(fd);
 
  669      region_name = fi->path();
 
  671      L4::Cap<L4Re::Dataspace> fds = fi->data_space();
 
  679      if (flags & MAP_PRIVATE)
 
  681          DEBUG_LOG(debug_mmap, 
outstring(
"COW\n"););
 
  682          int err = ds->copy_in(anon_offset, fds, offset, len);
 
  683          file_offset = offset;
 
  686              L4::Cap<Rm> r = Env::env()->rm();
 
  689              err = r->attach(&src, len,
 
  695              err = r->attach(&dst, len,
 
  697                              ds.get(), anon_offset);
 
  701              memcpy(dst.
get(), src.
get(), len);
 
  703              region_name = 
"[mmap-private]";
 
  704              file_offset = (
unsigned long)dst.
get();
 
  709          offset = anon_offset;
 
  713          L4Re::virt_cap_alloc->take(fds);
 
  719      offset = anon_offset;
 
  720      region_name = 
"[anon]";
 
  721      file_offset = offset;
 
  725  if (!(flags & MAP_FIXED) && start == 0)
 
  728  char *data = 
static_cast<char *
>(start);
 
  729  L4::Cap<Rm> r = Env::env()->rm();
 
  733  if (flags & MAP_FIXED)
 
  737      err = r->reserve_area(&overmap_area, len);
 
  746      err = munmap_regions(start, len);
 
  747      if (err && err != -ENOENT)
 
  751  if (!(flags & MAP_FIXED))
 
  753  if (prot & PROT_READ)
 
  755  if (prot & PROT_WRITE)
 
  757  if (prot & PROT_EXEC)
 
  760  err = r->attach(&data, len, rm_flags,
 
  765                  region_name, file_offset);
 
  767  DEBUG_LOG(debug_mmap, {
 
  783    r->free_area(overmap_area);
 
  811      int e = r->reserve_area(&a, sz, flags);
 
  828    ~Auto_area() { free(); }
 
  833Vfs::mremap(
void *old_addr, 
size_t old_size, 
size_t new_size, 
int flags,
 
  836  using namespace L4Re;
 
  838  DEBUG_LOG(debug_mmap, {
 
  848  if (flags & MREMAP_FIXED && !(flags & MREMAP_MAYMOVE))
 
  852  if (oa != 
reinterpret_cast<l4_addr_t>(old_addr))
 
  855  bool const fixed = flags & MREMAP_FIXED;
 
  856  bool const maymove = flags & MREMAP_MAYMOVE;
 
  858  L4::Cap<Rm> r = Env::env()->rm();
 
  866      if (new_size < old_size)
 
  868          *new_addr = old_addr;
 
  869          return munmap(
reinterpret_cast<void*
>(oa + new_size),
 
  870                        old_size - new_size);
 
  873      if (new_size == old_size)
 
  875          *new_addr = old_addr;
 
  880  Auto_area old_area(r);
 
  881  int err = old_area.reserve(oa, old_size, L4Re::Rm::Flags(0));
 
  886  Auto_area new_area(r);
 
  890      if (na != 
reinterpret_cast<l4_addr_t>(*new_addr))
 
  894      int err = new_area.reserve(na, new_size, L4Re::Rm::Flags(0));
 
  904      unsigned long ts = new_size - old_size;
 
  906      long err = new_area.reserve(ta, ts, L4Re::Rm::Flags(0));
 
  910      L4Re::Rm::Offset toffs;
 
  911      L4Re::Rm::Flags tflags;
 
  912      L4::Cap<L4Re::Dataspace> tds;
 
  914      err = r->find(&ta, &ts, &toffs, &tflags, &tds);
 
  920          pad_addr = oa + old_size;
 
  921          *new_addr = old_addr;
 
  932          pad_addr = new_area.a + old_size;
 
  933          *new_addr = 
reinterpret_cast<void *
>(new_area.a);
 
  937  if (old_area.is_valid())
 
  939      unsigned long size = old_size;
 
  945      L4::Cap<L4Re::Dataspace> ds;
 
  947      while (r->find(&a, &s, &o, &f, &ds) >= 0 && !(f & 
Rm::F::In_area))
 
  951              auto d = old_area.a - a;
 
  957          if (a + s > old_area.a + old_size)
 
  958            s = old_area.a + old_size - a;
 
  960          l4_addr_t x = a - old_area.a + new_area.a;
 
  968          L4Re::virt_cap_alloc->take(ds);
 
  970          err = r->detach(a, s, &ds, This_task,
 
  975          switch (err & Rm::Detach_result_mask)
 
  980                L4Re::virt_cap_alloc->take(ds);
 
  984                L4Re::virt_cap_alloc->release(ds);
 
 1000  if (old_size < new_size)
 
 1002      l4_addr_t const pad_sz = new_size - old_size;
 
 1005      int err = alloc_anon_mem(pad_sz, &tds, &toffs);
 
 1011      err = r->attach(&pad_addr, pad_sz,
 
 1025Vfs::mprotect(
const void * , 
size_t , 
int prot) 
L4_NOTHROW 
 1027  return (prot & PROT_WRITE) ? -ENOSYS : 0;
 
 1041extern void *l4re_env_posix_vfs_ops __attribute__((alias(
"__rtld_l4re_env_posix_vfs_ops"), visibility(
"default")));
 
 1044  class Real_mount_tree : 
public L4Re::Vfs::Mount_tree
 
 1047    explicit Real_mount_tree(
char *n) : Mount_tree(n) {}
 
 1049    void *
operator new (
size_t size)
 
 1050    { 
return __rtld_l4re_env_posix_vfs_ops->malloc(size); }
 
 1052    void operator delete (
void *mem)
 
 1053    { __rtld_l4re_env_posix_vfs_ops->free(mem); }
 
 1062  using L4Re::Vfs::Mount_tree;
 
 1063  using L4Re::Vfs::Path;
 
 1070  Path p = root->lookup(Path(path), &base);
 
 1074      Path f = p.strip_first();
 
 1079      char *name = __rtld_l4re_env_posix_vfs_ops->strndup(f.path(), f.length());
 
 1083      auto nt = cxx::make_ref_obj<Real_mount_tree>(name);
 
 1086          __rtld_l4re_env_posix_vfs_ops->free(name);
 
 1090      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 outhex32(l4_uint32_t number)
Output a 32-bit unsigned hexadecimal number via the kernel debugger.
 
void outstring(char const *text)
Output a string via the kernel debugger.
 
void outdec(l4_mword_t number)
Output a decimal unsigned machine word 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.