Browse Source

movs: allow overlapping strings, as long as they don't overlay within a page

Fabian 1 year ago
parent
commit
752869dbff
1 changed files with 23 additions and 17 deletions
  1. 23 17
      src/rust/cpu/string.rs

+ 23 - 17
src/rust/cpu/string.rs

@@ -151,7 +151,7 @@ unsafe fn string_instruction(
     let mut movs_into_svga_lfb = false;
     let mut movs_reenter_fast_path = false;
 
-    if rep_fast {
+    let count_until_end_of_page = if rep_fast {
         match instruction {
             Instruction::Movs => {
                 let (addr, skip) =
@@ -186,9 +186,25 @@ unsafe fn string_instruction(
             _ => {},
         };
 
+        let count_until_end_of_page = u32::min(
+            count,
+            match instruction {
+                Instruction::Movs | Instruction::Cmps => u32::min(
+                    count_until_end_of_page(direction, size_bytes, phys_src),
+                    count_until_end_of_page(direction, size_bytes, phys_dst),
+                ),
+                Instruction::Stos | Instruction::Ins | Instruction::Scas => {
+                    count_until_end_of_page(direction, size_bytes, phys_dst)
+                },
+                Instruction::Lods | Instruction::Outs => {
+                    count_until_end_of_page(direction, size_bytes, phys_src)
+                },
+            },
+        );
+
         match instruction {
             Instruction::Movs => {
-                let c = count * size_bytes as u32;
+                let c = count_until_end_of_page * size_bytes as u32;
 
                 let overlap_interferes = if phys_src < phys_dst {
                     // backward moves may overlap at the front of the destination string
@@ -212,24 +228,14 @@ unsafe fn string_instruction(
             },
             _ => {},
         }
+
+        count_until_end_of_page
     }
+    else {
+        0 // not used
+    };
 
     if rep_fast {
-        let count_until_end_of_page = u32::min(
-            count,
-            match instruction {
-                Instruction::Movs | Instruction::Cmps => u32::min(
-                    count_until_end_of_page(direction, size_bytes, phys_src),
-                    count_until_end_of_page(direction, size_bytes, phys_dst),
-                ),
-                Instruction::Stos | Instruction::Ins | Instruction::Scas => {
-                    count_until_end_of_page(direction, size_bytes, phys_dst)
-                },
-                Instruction::Lods | Instruction::Outs => {
-                    count_until_end_of_page(direction, size_bytes, phys_src)
-                },
-            },
-        );
         dbg_assert!(count_until_end_of_page > 0);
 
         if !skip_dirty_page {