@@ -193,8 +193,38 @@ guest_main(uint64 size, uint64 cpu)
193193 guest_uexit ((uint64 )- 1 );
194194}
195195
196+ // Some ARM chips use 128-byte cache lines. Pick 256 to be on the safe side.
197+ #define MAX_CACHE_LINE_SIZE 256
198+
199+ GUEST_CODE static noinline void
200+ flush_cache_range (void * addr , uint64 size )
201+ {
202+ uint64 start = (uint64 )addr ;
203+ uint64 end = start + size ;
204+
205+ // For self-modifying code, we must clean the D-cache and invalidate the
206+ // I-cache for the memory range that was modified. This is the sequence
207+ // mandated by the ARMv8-A architecture.
208+
209+ // 1. Clean D-cache over the whole range to the Point of Unification.
210+ for (uint64 i = start ; i < end ; i += MAX_CACHE_LINE_SIZE )
211+ asm volatile ("dc cvau, %[addr]" : : [addr ] "r" (i ) : "memory" );
212+ // 2. Wait for the D-cache clean to complete.
213+ asm volatile ("dsb sy" : : : "memory" );
214+
215+ // 3. Invalidate I-cache over the whole range.
216+ for (uint64 i = start ; i < end ; i += MAX_CACHE_LINE_SIZE )
217+ asm volatile ("ic ivau, %[addr]" : : [addr ] "r" (i ) : "memory" );
218+ // 4. Wait for the I-cache invalidate to complete.
219+ asm volatile ("dsb sy" : : : "memory" );
220+
221+ // 5. Flush pipeline to force re-fetch of new instruction.
222+ asm volatile ("isb" : : : "memory" );
223+ }
224+
196225GUEST_CODE static noinline void guest_execute_code (uint32 * insns , uint64 size )
197226{
227+ flush_cache_range (insns , size );
198228 volatile void (* fn )() = (volatile void (* )())insns ;
199229 fn ();
200230}
@@ -236,9 +266,6 @@ GUEST_CODE static uint32 get_cpu_id()
236266 return (uint32 )val ;
237267}
238268
239- // Some ARM chips use 128-byte cache lines. Pick 256 to be on the safe side.
240- #define MAX_CACHE_LINE_SIZE 256
241-
242269// Read the value from a system register using an MRS instruction.
243270GUEST_CODE static noinline void
244271guest_handle_mrs (uint64 reg )
@@ -249,6 +276,7 @@ guest_handle_mrs(uint64 reg)
249276 uint32 * insn = (uint32 * )((uint64 )ARM64_ADDR_SCRATCH_CODE + cpu_id * MAX_CACHE_LINE_SIZE );
250277 insn [0 ] = mrs ;
251278 insn [1 ] = 0xd65f03c0 ; // RET
279+ flush_cache_range (insn , 8 );
252280 // Make a call to the generated MSR instruction and clobber x0.
253281 asm("blr %[pc]\n"
254282 :
@@ -273,6 +301,7 @@ guest_handle_msr(uint64 reg, uint64 val)
273301 uint32 * insn = (uint32 * )((uint64 )ARM64_ADDR_SCRATCH_CODE + cpu_id * MAX_CACHE_LINE_SIZE );
274302 insn [0 ] = msr ;
275303 insn [1 ] = 0xd65f03c0 ; // RET
304+ flush_cache_range (insn , 8 );
276305 // Put `val` into x0 and make a call to the generated MSR instruction.
277306 asm("mov x0, %[val]\nblr %[pc]\n"
278307 :
0 commit comments