@@ -184,8 +184,82 @@ enum execerr_t {
184184 TYPE, m_vm_cache((t)->m, VM_PERM_RW), &(t)->m->s->vm_map, vaddr__, value__); \
185185}
186186
187+ #define HADDR_OFFS_MASK ((uintptr)( (uintptr)PAGE_SIZE - (uintptr)1 ))
188+ #define HADDR_PAGE_MASK ((uintptr)( ~(uintptr)0 ^ ((uintptr)PAGE_SIZE - (uintptr)1) ))
189+
187190static void mcopy (EXEC_PARAMS , u64 dstaddr , u64 srcaddr , u64 size ) {
188- panic ("NOT IMPLEMENTED" ); // TODO virtual memory
191+ // mcopy copies at page boundaries to reduce vm_translate operations.
192+ //
193+ // Example: addresses at different page offsets: (worst case scenario)
194+ // mcopy(0x5d00, 0x1200, 9000)
195+ //
196+ // 0x1200 ─────src───── 0x3528 0x5d00 ─────dst───── 0x8028
197+ // ┌─┴──────┬────────┬────┴───┬────────┬──────┴─┬────────┬────────┬─┴──────┐
198+ // │ 0x1000 │ 0x2000 │ 0x3000 │ 0x4000 │ 0x5000 │ 0x6000 │ 0x7000 │ 0x8000 │
199+ // └────────┴────────┴────────┴────────┴────────┴────────┴────────┴────────┘
200+ //
201+ // copy 768 B 0x1200-0x1500 ⟶ 0x5d00-0x6000 (nearest page boundary: 0x6000)
202+ // copy 2816 B 0x1500-0x2000 ⟶ 0x6000-0x6b00 (nearest page boundary: 0x2000)
203+ // copy 1280 B 0x2000-0x2500 ⟶ 0x6b00-0x7000 (nearest page boundary: 0x7000)
204+ // copy 2816 B 0x2500-0x3000 ⟶ 0x7000-0x7b00 (nearest page boundary: 0x3000)
205+ // copy 1280 B 0x3000-0x3500 ⟶ 0x7b00-0x8000 (nearest page boundary: 0x8000)
206+ // copy 40 B 0x3500-0x3528 ⟶ 0x8000-0x8028 (tail)
207+ //
208+ // Example: addresses at matching page offsets:
209+ // mcopy(0x5200, 0x1200, 9000)
210+ //
211+ // 0x1200 ─────src───── 0x3528 0x5200 ─────dst───── 0x7528
212+ // ┌─┴──────┬────────┬────┴───┬────────┬─┴──────┬────────┬────┴───┐
213+ // │ 0x1000 │ 0x2000 │ 0x3000 │ 0x4000 │ 0x5000 │ 0x6000 │ 0x7000 │
214+ // └────────┴────────┴────────┴────────┴────────┴────────┴────────┘
215+ //
216+ // copy 3584 B 0x1200-0x2000 ⟶ 0x5200-0x6000
217+ // copy 4096 B 0x2000-0x3000 ⟶ 0x6000-0x7000
218+ // copy 1320 B 0x3000-0x3528 ⟶ 0x7000-0x7528
219+ //
220+ vm_map_t * map = & (t )-> m -> s -> vm_map ;
221+ vm_cache_t * cache = m_vm_cache ((t )-> m , VM_PERM_RW );
222+
223+ tracemem ("%012llx <- %012llx (%llu B)" , dstaddr , srcaddr , size );
224+
225+ // check for overlapping address ranges
226+ #if RSM_SAFE
227+ if (vm_ranges_overlap (dstaddr , size , srcaddr , size )) {
228+ panic (
229+ "overlapping address ranges:\n dst %012llx…%012llx\n src %012llx…%012llx" ,
230+ dstaddr , dstaddr + size , srcaddr , srcaddr + size );
231+ }
232+ #endif
233+
234+ void * src = (void * )vm_translate (cache , map , srcaddr , 1 , VM_OP_LOAD_1 );
235+ void * dst = (void * )vm_translate (cache , map , dstaddr , 1 , VM_OP_STORE_1 );
236+ //tracemem("[haddr] dst %p, src %p, size %llu", dst, src, size);
237+
238+ for (;;) {
239+ uintptr src_nextpage = ((uintptr )src + PAGE_SIZE ) & HADDR_PAGE_MASK ;
240+ uintptr dst_nextpage = ((uintptr )dst + PAGE_SIZE ) & HADDR_PAGE_MASK ;
241+
242+ usize src_nbyte = (usize )(src_nextpage - (uintptr )src );
243+ usize dst_nbyte = (usize )(dst_nextpage - (uintptr )dst );
244+ usize nbyte = MIN (src_nbyte , dst_nbyte );
245+ if ((u64 )nbyte > size )
246+ nbyte = (usize )size ;
247+
248+ dlog ("copy %4zu B %p-%p -> %p-%p" , nbyte , src , src + nbyte , dst , dst + nbyte );
249+ memcpy (dst , src , nbyte );
250+
251+ if (size == (u64 )nbyte )
252+ break ;
253+
254+ assert_no_sub_overflow (size , (u64 )nbyte );
255+ size -= (u64 )nbyte ;
256+
257+ srcaddr += (u64 )nbyte ;
258+ dstaddr += (u64 )nbyte ;
259+
260+ src = (void * )vm_translate (cache , map , srcaddr , 1 , VM_OP_LOAD_1 );
261+ dst = (void * )vm_translate (cache , map , dstaddr , 1 , VM_OP_STORE_1 );
262+ }
189263}
190264
191265static i64 mcmp (EXEC_PARAMS , u64 xaddr , u64 yaddr , u64 size ) {
0 commit comments