]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/moe/server/src/dataspace_util.cc
update
[l4.git] / l4 / pkg / moe / server / src / dataspace_util.cc
1 /*
2  * (c) 2008-2009 Alexander Warg <warg@os.inf.tu-dresden.de>
3  *     economic rights: Technische Universität Dresden (Germany)
4  *
5  * This file is part of TUD:OS and distributed under the terms of the
6  * GNU General Public License 2.
7  * Please see the COPYING-GPL-2 file for details.
8  */
9 #include "dataspace_util.h"
10 #include "dataspace_noncont.h"
11 #include "pages.h"
12
13 #include <cstring>
14 #include <l4/cxx/iostream>
15 #include <l4/cxx/minmax>
16
17 using cxx::min;
18 using Moe::Dataspace;
19 using Moe::Dataspace_noncont;
20
21 namespace {
22
23 unsigned long aligned(unsigned page_size, unsigned long addr)
24 { return !(addr & (page_size-1)); }
25
26 unsigned long trunc_page(unsigned page_size, unsigned long addr)
27 { return addr & ~(page_size-1); }
28
29 inline void 
30 __do_real_copy(Dataspace *dst, unsigned long &dst_offs,
31     Dataspace const *src, unsigned long &src_offs, unsigned long sz)
32 {
33   while (sz)
34     {
35       Dataspace::Address src_a = src->address(src_offs, Dataspace::Read_only);
36       Dataspace::Address dst_a = dst->address(dst_offs, Dataspace::Writable);
37
38       unsigned long b_sz = min(min(src_a.sz() - src_a.of(),
39             dst_a.sz() - dst_a.of()), sz);
40
41       memcpy(dst_a.adr(), src_a.adr(), b_sz);
42
43       src_offs += b_sz;
44       dst_offs += b_sz;
45       sz -= b_sz;
46     }
47 }
48
49 inline void 
50 __do_cow_copy(Dataspace_noncont *dst, unsigned long &dst_offs, unsigned dst_pg_sz,
51     Dataspace const *src, unsigned long &src_offs, unsigned long sz)
52 {
53   while (sz)
54     {
55       Dataspace::Address src_a = src->address(src_offs, Dataspace::Read_only);
56       Dataspace_noncont::Page &dst_p = dst->alloc_page(dst_offs);
57       dst->free_page(dst_p);
58       void *src_p = (void*)trunc_page(dst_pg_sz,src_a.adr<unsigned long>());
59       Moe::Pages::share(src_p);
60       dst_p.set(src_p, Dataspace_noncont::Page_cow);
61
62       src_offs += dst_pg_sz;
63       dst_offs += dst_pg_sz;
64       sz  -= dst_pg_sz;
65     }
66 }
67
68 inline void 
69 __do_cow_copy2(Dataspace_noncont *dst, unsigned long &dst_offs, unsigned dst_pg_sz,
70     Dataspace_noncont const *src, unsigned long &src_offs, unsigned long sz)
71 {
72   //L4::cout << "real COW\n";
73   while (sz)
74     {
75       Dataspace_noncont::Page &src_p = src->page(src_offs);
76       Dataspace_noncont::Page *dst_p;
77       if (src_p.valid())
78         dst_p = &dst->alloc_page(dst_offs);
79       else
80         dst_p = &dst->page(dst_offs);
81       
82       dst->free_page(*dst_p);
83       if (*src_p)
84         {
85           Moe::Pages::share(*src_p);
86           if (!(src_p.flags() & Dataspace_noncont::Page_cow))
87             {
88               src->unmap_page(src_p, true);
89               src_p.set(*src_p, src_p.flags() | Dataspace_noncont::Page_cow);
90             }
91
92           dst_p->set(*src_p, src_p.flags() | Dataspace_noncont::Page_cow);
93         }
94
95       src_offs += dst_pg_sz;
96       dst_offs += dst_pg_sz;
97       sz  -= dst_pg_sz;
98     }
99 }
100
101 unsigned long 
102 __do_eager_copy(Dataspace *dst, unsigned long dst_offs,
103     Dataspace const *src, unsigned long src_offs, unsigned long size)
104 {
105   unsigned long dst_sz = dst->size();
106   unsigned long src_sz = src->round_size();
107   if (dst_offs >= dst_sz || src_offs >= src_sz)
108     return 0;
109
110   size = min(min(size, dst_sz - dst_offs), src_sz - src_offs);
111
112   __do_real_copy(dst, dst_offs, src, src_offs, size);
113   return size;
114 }
115
116
117 bool  
118 __do_lazy_copy(Dataspace_noncont *dst, unsigned long dst_offs,
119     Dataspace const *src, unsigned long src_offs, unsigned long &size)
120 {
121   unsigned long dst_sz = dst->size();
122   unsigned long src_sz = src->round_size();
123   if (dst_offs >= dst_sz || src_offs >= src_sz)
124     {
125       size = 0;
126       return true;
127     }
128   
129   unsigned dst_pg_sz = dst->page_size();
130
131   if (src->page_size() < dst_pg_sz)
132     {
133       //L4::cout << "page sizes do not map\n";
134       return false;
135     }
136
137   unsigned long dst_align = dst_offs & (dst_pg_sz-1);
138   
139   if (dst_align != (src_offs & (dst_pg_sz-1)))
140     {
141 #if 0
142       L4::cout << "alignment error " << L4::hex << src_offs 
143         << " " << dst_offs << L4::dec << '\n';
144 #endif
145       return false;
146     }
147 #if 0
148   L4::cout << "do copy on write\n";
149 #endif
150   unsigned long copy_sz = size 
151     = min(min(size, dst_sz - dst_offs), src_sz - src_offs);
152   
153   if (dst_align)
154     {
155       unsigned long cp_sz = min(copy_sz, dst_pg_sz - dst_align);
156       copy_sz -= cp_sz;
157 #if 0
158       L4::cout << "ensure cow starts on page: cp=" << cp_sz << '\n';
159 #endif
160
161       __do_real_copy(dst, dst_offs, src, src_offs, cp_sz);
162     }
163   
164   unsigned long cow_sz = trunc_page(dst_pg_sz, copy_sz);
165   unsigned long cp_sz = copy_sz - cow_sz;
166 #if 0
167   L4::cout  
168     << "cow_sz=" << cow_sz << "; cp_sz=" << cp_sz << '\n';
169 #endif
170     
171   __do_cow_copy(dst, dst_offs, dst_pg_sz, src, src_offs, cow_sz);
172   __do_real_copy(dst, dst_offs, src, src_offs, cp_sz);
173
174   return true;
175 }
176
177 bool  
178 __do_lazy_copy2(Dataspace_noncont *dst, unsigned long dst_offs,
179     Dataspace_noncont const *src, unsigned long src_offs, unsigned long &size)
180 {
181   unsigned long dst_sz = dst->size();
182   unsigned long src_sz = src->round_size();
183   if (dst_offs >= dst_sz || src_offs >= src_sz)
184     {
185       size = 0;
186       return true;
187     }
188   
189   unsigned dst_pg_sz = dst->page_size();
190
191   if (src->page_size() != dst_pg_sz)
192     {
193       //L4::cout << "page sizes do not map\n";
194       return false;
195     }
196
197   unsigned long dst_align = dst_offs & (dst_pg_sz-1);
198   
199   if (dst_align != (src_offs & (dst_pg_sz-1)))
200     {
201 #if 0
202       L4::cout << "alignment error " << L4::hex << src_offs 
203         << " " << dst_offs << L4::dec << '\n';
204 #endif
205       return false;
206     }
207 #if 0
208   L4::cout << "do copy on write\n";
209 #endif
210   unsigned long copy_sz = size 
211     = min(min(size, dst_sz - dst_offs), src_sz - src_offs);
212   
213   if (dst_align)
214     {
215       unsigned long cp_sz = min(copy_sz, dst_pg_sz - dst_align);
216       copy_sz -= cp_sz;
217 #if 0
218       L4::cout << "ensure cow starts on page: cp=" << cp_sz << '\n';
219 #endif
220
221       __do_real_copy(dst, dst_offs, src, src_offs, cp_sz);
222     }
223   
224   unsigned long cow_sz = trunc_page(dst_pg_sz, copy_sz);
225   unsigned long cp_sz = copy_sz - cow_sz;
226 #if 0
227   L4::cout  
228     << "cow_sz=" << cow_sz << "; cp_sz=" << cp_sz << '\n';
229 #endif
230     
231   __do_cow_copy2(dst, dst_offs, dst_pg_sz, src, src_offs, cow_sz);
232   __do_real_copy(dst, dst_offs, src, src_offs, cp_sz);
233
234   return true;
235 }
236
237 }; // and local annon namespace
238
239 unsigned long 
240 Dataspace_util::copy(Dataspace *dst, unsigned long dst_offs,
241     Dataspace const *src, unsigned long src_offs, unsigned long size)
242 {
243   if (src->can_cow() && dst->can_cow())
244     {
245       if (!src->is_writable() && src->is_static())
246         {
247           Dataspace_noncont *nc = dynamic_cast<Dataspace_noncont*>(dst);
248           if (nc && __do_lazy_copy(nc, dst_offs, src, src_offs, size))
249             return size;
250         }
251       else
252         {
253           Dataspace_noncont *dst_n = dynamic_cast<Dataspace_noncont*>(dst);
254           Dataspace_noncont const *src_n = dynamic_cast<Dataspace_noncont const *>(src);
255           if (dst_n && src_n 
256               && __do_lazy_copy2(dst_n, dst_offs, src_n, src_offs, size))
257             return size;
258         }
259     }
260
261   return __do_eager_copy(dst, dst_offs, src, src_offs, size);
262 }
263
264