2 * (c) 2008-2009 Alexander Warg <warg@os.inf.tu-dresden.de>
3 * economic rights: Technische Universität Dresden (Germany)
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.
9 #include "dataspace_util.h"
10 #include "dataspace_noncont.h"
14 #include <l4/cxx/iostream>
15 #include <l4/cxx/minmax>
19 using Moe::Dataspace_noncont;
23 unsigned long aligned(unsigned page_size, unsigned long addr)
24 { return !(addr & (page_size-1)); }
26 unsigned long trunc_page(unsigned page_size, unsigned long addr)
27 { return addr & ~(page_size-1); }
30 __do_real_copy(Dataspace *dst, unsigned long &dst_offs,
31 Dataspace const *src, unsigned long &src_offs, unsigned long sz)
35 Dataspace::Address src_a = src->address(src_offs, Dataspace::Read_only);
36 Dataspace::Address dst_a = dst->address(dst_offs, Dataspace::Writable);
38 unsigned long b_sz = min(min(src_a.sz() - src_a.of(),
39 dst_a.sz() - dst_a.of()), sz);
41 memcpy(dst_a.adr(), src_a.adr(), b_sz);
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)
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);
62 src_offs += dst_pg_sz;
63 dst_offs += dst_pg_sz;
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)
72 //L4::cout << "real COW\n";
75 Dataspace_noncont::Page &src_p = src->page(src_offs);
76 Dataspace_noncont::Page *dst_p;
78 dst_p = &dst->alloc_page(dst_offs);
80 dst_p = &dst->page(dst_offs);
82 dst->free_page(*dst_p);
85 Moe::Pages::share(*src_p);
86 if (!(src_p.flags() & Dataspace_noncont::Page_cow))
88 src->unmap_page(src_p, true);
89 src_p.set(*src_p, src_p.flags() | Dataspace_noncont::Page_cow);
92 dst_p->set(*src_p, src_p.flags() | Dataspace_noncont::Page_cow);
95 src_offs += dst_pg_sz;
96 dst_offs += dst_pg_sz;
102 __do_eager_copy(Dataspace *dst, unsigned long dst_offs,
103 Dataspace const *src, unsigned long src_offs, unsigned long size)
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)
110 size = min(min(size, dst_sz - dst_offs), src_sz - src_offs);
112 __do_real_copy(dst, dst_offs, src, src_offs, size);
118 __do_lazy_copy(Dataspace_noncont *dst, unsigned long dst_offs,
119 Dataspace const *src, unsigned long src_offs, unsigned long &size)
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)
129 unsigned dst_pg_sz = dst->page_size();
131 if (src->page_size() < dst_pg_sz)
133 //L4::cout << "page sizes do not map\n";
137 unsigned long dst_align = dst_offs & (dst_pg_sz-1);
139 if (dst_align != (src_offs & (dst_pg_sz-1)))
142 L4::cout << "alignment error " << L4::hex << src_offs
143 << " " << dst_offs << L4::dec << '\n';
148 L4::cout << "do copy on write\n";
150 unsigned long copy_sz = size
151 = min(min(size, dst_sz - dst_offs), src_sz - src_offs);
155 unsigned long cp_sz = min(copy_sz, dst_pg_sz - dst_align);
158 L4::cout << "ensure cow starts on page: cp=" << cp_sz << '\n';
161 __do_real_copy(dst, dst_offs, src, src_offs, cp_sz);
164 unsigned long cow_sz = trunc_page(dst_pg_sz, copy_sz);
165 unsigned long cp_sz = copy_sz - cow_sz;
168 << "cow_sz=" << cow_sz << "; cp_sz=" << cp_sz << '\n';
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);
178 __do_lazy_copy2(Dataspace_noncont *dst, unsigned long dst_offs,
179 Dataspace_noncont const *src, unsigned long src_offs, unsigned long &size)
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)
189 unsigned dst_pg_sz = dst->page_size();
191 if (src->page_size() != dst_pg_sz)
193 //L4::cout << "page sizes do not map\n";
197 unsigned long dst_align = dst_offs & (dst_pg_sz-1);
199 if (dst_align != (src_offs & (dst_pg_sz-1)))
202 L4::cout << "alignment error " << L4::hex << src_offs
203 << " " << dst_offs << L4::dec << '\n';
208 L4::cout << "do copy on write\n";
210 unsigned long copy_sz = size
211 = min(min(size, dst_sz - dst_offs), src_sz - src_offs);
215 unsigned long cp_sz = min(copy_sz, dst_pg_sz - dst_align);
218 L4::cout << "ensure cow starts on page: cp=" << cp_sz << '\n';
221 __do_real_copy(dst, dst_offs, src, src_offs, cp_sz);
224 unsigned long cow_sz = trunc_page(dst_pg_sz, copy_sz);
225 unsigned long cp_sz = copy_sz - cow_sz;
228 << "cow_sz=" << cow_sz << "; cp_sz=" << cp_sz << '\n';
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);
237 }; // and local annon namespace
240 Dataspace_util::copy(Dataspace *dst, unsigned long dst_offs,
241 Dataspace const *src, unsigned long src_offs, unsigned long size)
243 if (src->can_cow() && dst->can_cow())
245 if (!src->is_writable() && src->is_static())
247 Dataspace_noncont *nc = dynamic_cast<Dataspace_noncont*>(dst);
248 if (nc && __do_lazy_copy(nc, dst_offs, src, src_offs, size))
253 Dataspace_noncont *dst_n = dynamic_cast<Dataspace_noncont*>(dst);
254 Dataspace_noncont const *src_n = dynamic_cast<Dataspace_noncont const *>(src);
256 && __do_lazy_copy2(dst_n, dst_offs, src_n, src_offs, size))
261 return __do_eager_copy(dst, dst_offs, src, src_offs, size);