VM protection, code writes, and target cache traversal
VM map implementations behind protection changes and data overwrites. The MATTR_CACHE path walks target mappings, follows submaps and VM objects, and invokes pmap_attribute_cache_sync for resident physical pages.
vm_map_protect source
vm_map_protect:
Sets the protection of the specified address
region in the target map. If "set_max" is
specified, the maximum protection is to be set;
otherwise, only the current protection is affected.
kern_return_t vm_map_protect( vm_map_t map, vm_map_offset_ut start_u, vm_map_offset_ut end_u, boolean_t set_max, vm_prot_ut new_prot_u) { vm_map_entry_t current; vm_map_offset_t prev; vm_map_entry_t entry; vm_prot_t new_prot; vm_prot_t new_max; int pmap_options = 0; kern_return_t kr; vm_map_offset_t start, original_start; vm_map_offset_t end; vmlp_api_start(VM_MAP_PROTECT); kr = vm_map_protect_sanitize(map, start_u, end_u, new_prot_u, &start, &end, &new_prot); if (__improbable(kr != KERN_SUCCESS)) { kr = vm_sanitize_get_kr(kr); vmlp_api_end(VM_MAP_PROTECT, kr); … more in source
vm_map_copy_overwrite source
kern_return_t vm_map_copy_overwrite( vm_map_t dst_map, vm_map_offset_ut dst_addr_u, vm_map_copy_t copy, vm_map_size_ut copy_size_u, boolean_t interruptible) { vm_map_offset_t dst_addr, dst_end; vm_map_size_t copy_size; vm_map_size_t head_size, tail_size; vm_map_copy_t head_copy, tail_copy; vm_map_offset_t head_addr, tail_addr; vm_map_entry_t entry; kern_return_t kr; vm_map_offset_t effective_page_mask, effective_page_size; uint16_t copy_page_shift; vmlp_api_start(VM_MAP_COPY_OVERWRITE); head_size = 0; tail_size = 0; head_copy = NULL; tail_copy = NULL; head_addr = 0; tail_addr = 0; /* * Check for null copy object. */ … more in source
vm_map_machine_attribute source
Routine: vm_map_machine_attribute
Purpose:
Provide machine-specific attributes to mappings,
such as cachability etc. for machines that provide
them. NUMA architectures and machines with big/strange
caches will use this.
Note:
Responsibilities for locking and checking are handled here,
everything else in the pmap module. If any non-volatile
information must be kept, the pmap module should handle
it itself. [This assumes that attributes do not
need to be inherited, which seems ok to me]
kern_return_t vm_map_machine_attribute( vm_map_t map, vm_map_offset_ut start_u, vm_map_offset_ut end_u, vm_machine_attribute_t attribute, vm_machine_attribute_val_t *value) /* IN/OUT */ { mach_vm_offset_t start, end; vm_map_size_t sync_size; kern_return_t ret; vm_map_entry_t entry; vmlp_api_start(VM_MAP_MACHINE_ATTRIBUTE); ret = vm_map_machine_attribute_sanitize(map, start_u, end_u, &start, &end, &sync_size); if (__improbable(ret != KERN_SUCCESS)) { ret = vm_sanitize_get_kr(ret); vmlp_api_end(VM_MAP_MACHINE_ATTRIBUTE, ret); return ret; } if (start < vm_map_min(map) || end > vm_map_max(map)) { vmlp_api_end(VM_MAP_MACHINE_ATTRIBUTE, KERN_INVALID_ADDRESS); return KERN_INVALID_ADDRESS; … more in source