diff --git a/src/rust/cpu/memory.rs b/src/rust/cpu/memory.rs index 21458641..d900e21a 100644 --- a/src/rust/cpu/memory.rs +++ b/src/rust/cpu/memory.rs @@ -236,6 +236,16 @@ pub unsafe fn memcpy_no_mmap_or_dirty_check(src_addr: u32, dst_addr: u32, count: ) } +pub unsafe fn memcpy_into_svga_lfb(src_addr: u32, dst_addr: u32, count: u32) { + dbg_assert!(src_addr < *memory_size); + dbg_assert!(in_svga_lfb(dst_addr)); + ptr::copy_nonoverlapping( + mem8.offset(src_addr as isize), + vga_mem8.offset((dst_addr - VGA_LFB_ADDRESS) as isize), + count as usize, + ) +} + pub unsafe fn mmap_write8(addr: u32, value: i32) { if in_svga_lfb(addr) { vga::mark_dirty(addr); diff --git a/src/rust/cpu/string.rs b/src/rust/cpu/string.rs index 50a15193..3bf14cfe 100644 --- a/src/rust/cpu/string.rs +++ b/src/rust/cpu/string.rs @@ -19,9 +19,9 @@ use cpu::cpu::{ }; use cpu::global_pointers::{flags, instruction_pointer, previous_ip}; use cpu::memory::{ - in_mapped_range, memcpy_no_mmap_or_dirty_check, memset_no_mmap_or_dirty_check, - read8_no_mmap_check, read16_no_mmap_check, read32_no_mmap_check, write8_no_mmap_or_dirty_check, - write16_no_mmap_or_dirty_check, write32_no_mmap_or_dirty_check, + in_mapped_range, in_svga_lfb, memcpy_into_svga_lfb, memcpy_no_mmap_or_dirty_check, + memset_no_mmap_or_dirty_check, read8_no_mmap_check, read16_no_mmap_check, read32_no_mmap_check, + write8_no_mmap_or_dirty_check, write16_no_mmap_or_dirty_check, write32_no_mmap_or_dirty_check, }; use page::Page; @@ -145,10 +145,19 @@ unsafe fn string_instruction( let mut phys_dst = 0; let mut phys_src = 0; let mut skip_dirty_page = false; + let mut movs_into_svga_lfb = false; if rep_fast { match instruction { - Instruction::Movs | Instruction::Stos | Instruction::Ins => { + Instruction::Movs => { + let (addr, skip) = + return_on_pagefault!(translate_address_write_and_can_skip_dirty(es + dst)); + movs_into_svga_lfb = in_svga_lfb(addr); + rep_fast = rep_fast && (!in_mapped_range(addr) || movs_into_svga_lfb); + phys_dst = addr; + skip_dirty_page = skip; + }, + Instruction::Stos | Instruction::Ins => { let (addr, skip) = return_on_pagefault!(translate_address_write_and_can_skip_dirty(es + dst)); rep_fast = rep_fast && !in_mapped_range(addr); @@ -256,11 +265,21 @@ unsafe fn string_instruction( phys_src -= (count_until_end_of_page - 1) * size_bytes as u32; phys_dst -= (count_until_end_of_page - 1) * size_bytes as u32; } - memcpy_no_mmap_or_dirty_check( - phys_src, - phys_dst, - count_until_end_of_page * size_bytes as u32, - ); + if movs_into_svga_lfb { + ::cpu::vga::mark_dirty(phys_dst); + memcpy_into_svga_lfb( + phys_src, + phys_dst, + count_until_end_of_page * size_bytes as u32, + ); + } + else { + memcpy_no_mmap_or_dirty_check( + phys_src, + phys_dst, + count_until_end_of_page * size_bytes as u32, + ); + } i = count_until_end_of_page; break; },