@@ -175,6 +175,15 @@ pub extern "C" fn wasmtime_init_traps(handler: wasmtime_trap_handler_t) -> i32 {
175175// Copy a VA range to a new VA. Old and new VA, and len, must be
176176// page-aligned.
177177fn copy_va_mapping ( base : * const u8 , len : usize , to_va : * mut u8 , remap_original : bool ) {
178+ // TODO: all this barrier code is amd64 specific. It should be
179+ // refactored to use some better architecture-independent APIs.
180+ //
181+ // On amd64, "upgrades" including the first time that a a valid
182+ // translation exists for a VA, only need a light (serialising
183+ // instruction) barrier. Since invlpg is also a barrier, we don't
184+ // even need that, if we did do a downgrade remap just before.
185+ let mut needs_first_valid_exposure_barrier = false ;
186+
178187 // TODO: make this more efficient by directly exposing the ability
179188 // to traverse an entire VA range in
180189 // hyperlight_guest_bin::paging::virt_to_phys, and coalescing
@@ -188,18 +197,25 @@ fn copy_va_mapping(base: *const u8, len: usize, to_va: *mut u8, remap_original:
188197 // Skip unmapped pages, since they will be unmapped in
189198 // both the original and the new copy
190199 vmem:: MappingKind :: Unmapped => continue ,
191- vmem:: MappingKind :: Basic ( bm) if bm. writable => ( vmem:: MappingKind :: Cow ( vmem:: CowMapping {
192- readable : bm. readable ,
193- executable : bm. executable ,
194- } ) , true ) ,
195- vmem:: MappingKind :: Basic ( bm) => ( vmem:: MappingKind :: Basic ( vmem:: BasicMapping {
196- readable : bm. readable ,
197- writable : false ,
198- executable : bm. executable ,
199- } ) , false ) ,
200+ vmem:: MappingKind :: Basic ( bm) if bm. writable => (
201+ vmem:: MappingKind :: Cow ( vmem:: CowMapping {
202+ readable : bm. readable ,
203+ executable : bm. executable ,
204+ } ) ,
205+ true ,
206+ ) ,
207+ vmem:: MappingKind :: Basic ( bm) => (
208+ vmem:: MappingKind :: Basic ( vmem:: BasicMapping {
209+ readable : bm. readable ,
210+ writable : false ,
211+ executable : bm. executable ,
212+ } ) ,
213+ false ,
214+ ) ,
200215 vmem:: MappingKind :: Cow ( cm) => ( vmem:: MappingKind :: Cow ( cm) , false ) ,
201216 } ;
202- if remap_original && was_writable {
217+ let do_downgrade = remap_original && was_writable;
218+ if do_downgrade {
203219 // If necessary, remap the original page as Cow, instead
204220 // of whatever it is now, to ensure that any more writes to
205221 // that region do not change the image base.
@@ -225,6 +241,21 @@ fn copy_va_mapping(base: *const u8, len: usize, to_va: *mut u8, remap_original:
225241 new_kind,
226242 ) ;
227243 }
244+ if do_downgrade {
245+ // Since we have downgraded a page from writable to CoW we
246+ // need to do an invlpg on it. Because invlpg is a
247+ // serialising instruction, we don't need need the other
248+ // barrier for the new mapping.
249+ unsafe {
250+ core:: arch:: asm!( "invlpg [{}]" , in( reg) mapping. virt_base, options( readonly, nostack, preserves_flags) ) ;
251+ }
252+ needs_first_valid_exposure_barrier = false ;
253+ } else {
254+ needs_first_valid_exposure_barrier = true ;
255+ }
256+ }
257+ if needs_first_valid_exposure_barrier {
258+ paging:: barrier:: first_valid_same_ctx ( ) ;
228259 }
229260}
230261
@@ -259,7 +290,7 @@ pub extern "C" fn wasmtime_memory_image_map_at(
259290
260291#[ no_mangle]
261292pub extern "C" fn wasmtime_memory_image_free ( _image : * mut c_void ) {
262- /* This should never be called in practice, because we simple
293+ /* This should never be called in practice, because we simply
263294 * restore the snapshot rather than actually unload/destroy instances */
264295 panic ! ( "wasmtime_memory_image_free" ) ;
265296}
0 commit comments