1 /*
2  * (c) 2008-2009 Adam Lackorzynski <adam@os.inf.tu-dresden.de>,
3  *               Alexander Warg <warg@os.inf.tu-dresden.de>
4  *     economic rights: Technische Universität Dresden (Germany)
5  *
6  * This file is part of TUD:OS and distributed under the terms of the
7  * GNU General Public License 2.
8  * Please see the COPYING-GPL-2 file for details.
9  */
10 #pragma once
11 
12 #include "dataspace.h"
13 
14 namespace Moe {
15 
16 /**
17  * Dataspace with dynamic backing of physical memory.
18  *
19  * The dataspace is created in an empty state. Memory pages are allocated
20  * and freed dynamically as they are requested by the client.
21  */
22 class Dataspace_noncont : public Dataspace
23 {
24 public:
25   enum
26   {
27     Page_addr_mask = ~((1UL << 12)-1),
28     Page_cow = 0x04UL,
29   };
30 
31   class Page
32   {
33   private:
34     unsigned long p;
35 
36   public:
Page()37     Page() throw() : p(0) {}
throw()38     void *operator * () const throw() { return (void*)(p & Page_addr_mask); }
valid()39     bool valid() const throw() { return p & Page_addr_mask;}
flags()40     unsigned long flags() const throw() { return p & ~Page_addr_mask; }
41 
set(void * addr,unsigned long flags)42     void set(void *addr, unsigned long flags) throw()
43     { p = ((unsigned long)addr & Page_addr_mask) | (flags & ~Page_addr_mask); }
44 
throw()45     void flags(unsigned long add, unsigned long del = 0) throw()
46     {
47       p = (p & Page_addr_mask & ~(del & ~Page_addr_mask))
48         | ((unsigned long)add & ~Page_addr_mask);
49     }
50 
addr(void * a)51     void addr(void *a) throw()
52     { p = (p & ~Page_addr_mask) | ((unsigned long)a & Page_addr_mask); }
53   };
54 
is_static()55   bool is_static() const throw() override { return false; }
56 
57   Dataspace_noncont(unsigned long size,
throw()58                     Flags flags = L4Re::Dataspace::F::RWX) throw()
59   : Dataspace(size, flags | Flags(Cow_enabled), L4_LOG2_PAGESIZE), _pages(0)
60   {}
61 
~Dataspace_noncont()62   virtual ~Dataspace_noncont() {}
63 
64   Address address(l4_addr_t offset,
65                   Flags flags = L4Re::Dataspace::F::RWX, l4_addr_t hot_spot = 0,
66                   l4_addr_t min = 0, l4_addr_t max = ~0) const override;
67   int copy_address(l4_addr_t offset, Flags flags, l4_addr_t *copy_addr,
68                    unsigned long *copy_size) const override;
69 
70   int pre_allocate(l4_addr_t offset, l4_size_t size, unsigned rights) override;
71 
72   virtual Page &page(unsigned long offs) const throw() = 0;
73   virtual Page &alloc_page(unsigned long offs) const = 0;
74 
num_pages()75   unsigned long num_pages() const throw()
76   { return (size()+page_size()-1) / page_size(); }
77 
78 #if 0
79 private:
80   unsigned idx_of(unsigned long offset) const { return offset >> 12; }
81 
82   void *page(unsigned idx) const
83   { return (void*)(pages[idx] & Page_addr_mask); }
84   unsigned flags(unsigned idx) const { return pages[idx] & ~Page_addr_mask; }
85   void page(unsigned idx, void *page, unsigned flags = 0) const
86   {
87     pages[idx] = (unsigned long)page & Page_addr_mask | flags
88       & ~Page_addr_mask;
89   }
90 #endif
91 
92   void free_page(Page &p) const throw();
93   void unmap_page(Page const &p, bool ro = false) const throw();
94 
95 public:
96   long clear(unsigned long offs, unsigned long size) const throw() override;
97 
98   static Dataspace_noncont *create(Q_alloc *q, unsigned long size,
99                                    Flags flags = L4Re::Dataspace::F::RWX);
100 
101 protected:
102   union
103   {
104     Page *_pages;
105     Page _page;
106   };
107 
108 private:
109   Address map_address(l4_addr_t offset, Flags flags) const;
110 };
111 };
112