+/* com region support */
+ipc_port_t com_region_handle32 = NULL;
+ipc_port_t com_region_handle64 = NULL;
+vm_map_t com_region_map32 = NULL;
+vm_map_t com_region_map64 = NULL;
+vm_size_t com_region_size = _COMM_PAGE_AREA_LENGTH;
+shared_region_mapping_t com_mapping_resource = NULL;
+
+
+#if DEBUG
+int shared_region_debug = 0;
+#endif /* DEBUG */
+
+
+kern_return_t
+vm_get_shared_region(
+ task_t task,
+ shared_region_mapping_t *shared_region)
+{
+ *shared_region = (shared_region_mapping_t) task->system_shared_region;
+ if (*shared_region) {
+ assert((*shared_region)->ref_count > 0);
+ }
+ SHARED_REGION_DEBUG(("vm_get_shared_region(task=%p) -> %p\n",
+ task, *shared_region));
+ return KERN_SUCCESS;
+}
+
+kern_return_t
+vm_set_shared_region(
+ task_t task,
+ shared_region_mapping_t shared_region)
+{
+ SHARED_REGION_DEBUG(("vm_set_shared_region(task=%p, "
+ "shared_region=%p)\n",
+ task, shared_region));
+ if (shared_region) {
+ assert(shared_region->ref_count > 0);
+ }
+ task->system_shared_region = shared_region;
+ return KERN_SUCCESS;
+}
+
+/*
+ * shared_region_object_chain_detach:
+ *
+ * Mark the shared region as being detached or standalone. This means
+ * that we won't keep track of which file is mapped and how, for this shared
+ * region. And we don't have a "shadow" shared region.
+ * This is used when we clone a private shared region and we intend to remove
+ * some mappings from it. It won't need to maintain mappings info because it's
+ * now private. It can't have a "shadow" shared region because we don't want
+ * to see the shadow of the mappings we're about to remove.
+ */
+void
+shared_region_object_chain_detached(
+ shared_region_mapping_t target_region)
+{
+ shared_region_mapping_lock(target_region);
+ target_region->flags |= SHARED_REGION_STANDALONE;
+ shared_region_mapping_unlock(target_region);
+}
+
+/*
+ * shared_region_object_chain_attach:
+ *
+ * Link "target_region" to "object_chain_region". "object_chain_region"
+ * is treated as a shadow of "target_region" for the purpose of looking up
+ * mappings. Since the "target_region" preserves all the mappings of the
+ * older "object_chain_region", we won't duplicate all the mappings info and
+ * we'll just lookup the next region in the "object_chain" if we can't find
+ * what we're looking for in the "target_region". See lsf_hash_lookup().
+ */
+kern_return_t
+shared_region_object_chain_attach(
+ shared_region_mapping_t target_region,
+ shared_region_mapping_t object_chain_region)
+{
+ shared_region_object_chain_t object_ele;
+
+ SHARED_REGION_DEBUG(("shared_region_object_chain_attach("
+ "target_region=%p, object_chain_region=%p\n",
+ target_region, object_chain_region));
+ assert(target_region->ref_count > 0);
+ assert(object_chain_region->ref_count > 0);
+ if(target_region->object_chain)
+ return KERN_FAILURE;
+ object_ele = (shared_region_object_chain_t)
+ kalloc(sizeof (struct shared_region_object_chain));
+ shared_region_mapping_lock(object_chain_region);
+ target_region->object_chain = object_ele;
+ object_ele->object_chain_region = object_chain_region;
+ object_ele->next = object_chain_region->object_chain;
+ object_ele->depth = object_chain_region->depth;
+ object_chain_region->depth++;
+ target_region->alternate_next = object_chain_region->alternate_next;
+ shared_region_mapping_unlock(object_chain_region);
+ return KERN_SUCCESS;
+}
+
+/* LP64todo - need 64-bit safe version */
+kern_return_t
+shared_region_mapping_create(
+ ipc_port_t text_region,
+ vm_size_t text_size,
+ ipc_port_t data_region,
+ vm_size_t data_size,
+ vm_offset_t region_mappings,
+ vm_offset_t client_base,
+ shared_region_mapping_t *shared_region,
+ vm_offset_t alt_base,
+ vm_offset_t alt_next)
+{
+ SHARED_REGION_DEBUG(("shared_region_mapping_create()\n"));
+ *shared_region = (shared_region_mapping_t)
+ kalloc(sizeof (struct shared_region_mapping));
+ if(*shared_region == NULL) {
+ SHARED_REGION_DEBUG(("shared_region_mapping_create: "
+ "failure\n"));
+ return KERN_FAILURE;
+ }
+ shared_region_mapping_lock_init((*shared_region));
+ (*shared_region)->text_region = text_region;
+ (*shared_region)->text_size = text_size;
+ (*shared_region)->fs_base = ENV_DEFAULT_ROOT;
+ (*shared_region)->system = cpu_type();
+ (*shared_region)->data_region = data_region;
+ (*shared_region)->data_size = data_size;
+ (*shared_region)->region_mappings = region_mappings;
+ (*shared_region)->client_base = client_base;
+ (*shared_region)->ref_count = 1;
+ (*shared_region)->next = NULL;
+ (*shared_region)->object_chain = NULL;
+ (*shared_region)->self = *shared_region;
+ (*shared_region)->flags = 0;
+ (*shared_region)->depth = 0;
+ (*shared_region)->default_env_list = NULL;
+ (*shared_region)->alternate_base = alt_base;
+ (*shared_region)->alternate_next = alt_next;
+ SHARED_REGION_DEBUG(("shared_region_mapping_create -> %p\n",
+ *shared_region));
+ return KERN_SUCCESS;
+}
+
+/* LP64todo - need 64-bit safe version */
+kern_return_t
+shared_region_mapping_info(
+ shared_region_mapping_t shared_region,
+ ipc_port_t *text_region,
+ vm_size_t *text_size,
+ ipc_port_t *data_region,
+ vm_size_t *data_size,
+ vm_offset_t *region_mappings,
+ vm_offset_t *client_base,
+ vm_offset_t *alt_base,
+ vm_offset_t *alt_next,
+ unsigned int *fs_base,
+ unsigned int *system,
+ int *flags,
+ shared_region_mapping_t *next)
+{
+ shared_region_mapping_lock(shared_region);
+
+ SHARED_REGION_DEBUG(("shared_region_mapping_info(shared_region=%p)\n",
+ shared_region));
+ assert(shared_region->ref_count > 0);
+ *text_region = shared_region->text_region;
+ *text_size = shared_region->text_size;
+ *data_region = shared_region->data_region;
+ *data_size = shared_region->data_size;
+ *region_mappings = shared_region->region_mappings;
+ *client_base = shared_region->client_base;
+ *alt_base = shared_region->alternate_base;
+ *alt_next = shared_region->alternate_next;
+ *flags = shared_region->flags;
+ *fs_base = shared_region->fs_base;
+ *system = shared_region->system;
+ *next = shared_region->next;
+
+ shared_region_mapping_unlock(shared_region);
+}
+
+kern_return_t
+shared_region_mapping_ref(
+ shared_region_mapping_t shared_region)
+{
+ SHARED_REGION_DEBUG(("shared_region_mapping_ref(shared_region=%p): "
+ "ref_count=%d + 1\n",
+ shared_region,
+ shared_region ? shared_region->ref_count : 0));
+ if(shared_region == NULL)
+ return KERN_SUCCESS;
+ assert(shared_region->ref_count > 0);
+ hw_atomic_add(&shared_region->ref_count, 1);
+ return KERN_SUCCESS;
+}
+
+static kern_return_t
+shared_region_mapping_dealloc_lock(
+ shared_region_mapping_t shared_region,
+ int need_sfh_lock,
+ int need_drl_lock)
+{
+ struct shared_region_task_mappings sm_info;
+ shared_region_mapping_t next = NULL;
+ int ref_count;
+
+ SHARED_REGION_DEBUG(("shared_region_mapping_dealloc_lock"
+ "(shared_region=%p,%d,%d) ref_count=%d\n",
+ shared_region, need_sfh_lock, need_drl_lock,
+ shared_region ? shared_region->ref_count : 0));
+ while (shared_region) {
+ SHARED_REGION_DEBUG(("shared_region_mapping_dealloc_lock(%p): "
+ "ref_count=%d\n",
+ shared_region, shared_region->ref_count));
+ assert(shared_region->ref_count > 0);
+ if ((ref_count =
+ hw_atomic_sub(&shared_region->ref_count, 1)) == 0) {
+ shared_region_mapping_lock(shared_region);
+
+ sm_info.text_region = shared_region->text_region;
+ sm_info.text_size = shared_region->text_size;
+ sm_info.data_region = shared_region->data_region;
+ sm_info.data_size = shared_region->data_size;
+ sm_info.region_mappings = shared_region->region_mappings;
+ sm_info.client_base = shared_region->client_base;
+ sm_info.alternate_base = shared_region->alternate_base;
+ sm_info.alternate_next = shared_region->alternate_next;
+ sm_info.flags = shared_region->flags;
+ sm_info.self = (vm_offset_t)shared_region;
+
+ if(shared_region->region_mappings) {
+ lsf_remove_regions_mappings_lock(shared_region, &sm_info, need_sfh_lock);
+ }
+ if(((vm_named_entry_t)
+ (shared_region->text_region->ip_kobject))
+ ->backing.map->pmap) {
+ pmap_remove(((vm_named_entry_t)
+ (shared_region->text_region->ip_kobject))
+ ->backing.map->pmap,
+ sm_info.client_base,
+ sm_info.client_base + sm_info.text_size);
+ }
+ ipc_port_release_send(shared_region->text_region);
+ if(shared_region->data_region)
+ ipc_port_release_send(shared_region->data_region);
+ if (shared_region->object_chain) {
+ next = shared_region->object_chain->object_chain_region;
+ kfree(shared_region->object_chain,
+ sizeof (struct shared_region_object_chain));
+ } else {
+ next = NULL;
+ }
+ shared_region_mapping_unlock(shared_region);
+ SHARED_REGION_DEBUG(
+ ("shared_region_mapping_dealloc_lock(%p): "
+ "freeing\n",
+ shared_region));
+ bzero((void *)shared_region,
+ sizeof (*shared_region)); /* FBDP debug */
+ kfree(shared_region,
+ sizeof (struct shared_region_mapping));
+ shared_region = next;
+ } else {
+ /* Stale indicates that a system region is no */
+ /* longer in the default environment list. */
+ if((ref_count == 1) &&
+ (shared_region->flags & SHARED_REGION_SYSTEM)
+ && !(shared_region->flags & SHARED_REGION_STALE)) {
+ SHARED_REGION_DEBUG(
+ ("shared_region_mapping_dealloc_lock"
+ "(%p): removing stale\n",
+ shared_region));
+ remove_default_shared_region_lock(shared_region,need_sfh_lock, need_drl_lock);
+ }
+ break;
+ }
+ }
+ SHARED_REGION_DEBUG(("shared_region_mapping_dealloc_lock(%p): done\n",
+ shared_region));
+ return KERN_SUCCESS;
+}
+
+/*
+ * Stub function; always indicates that the lock needs to be taken in the
+ * call to lsf_remove_regions_mappings_lock().
+ */
+kern_return_t
+shared_region_mapping_dealloc(
+ shared_region_mapping_t shared_region)
+{
+ SHARED_REGION_DEBUG(("shared_region_mapping_dealloc"
+ "(shared_region=%p)\n",
+ shared_region));
+ if (shared_region) {
+ assert(shared_region->ref_count > 0);
+ }
+ return shared_region_mapping_dealloc_lock(shared_region, 1, 1);
+}
+
+static
+kern_return_t
+shared_region_object_create(
+ vm_size_t size,
+ ipc_port_t *object_handle)
+{
+ vm_named_entry_t user_entry;
+ ipc_port_t user_handle;
+
+ ipc_port_t previous;
+ vm_map_t new_map;
+
+ user_entry = (vm_named_entry_t)
+ kalloc(sizeof (struct vm_named_entry));
+ if(user_entry == NULL) {
+ return KERN_FAILURE;
+ }
+ named_entry_lock_init(user_entry);
+ user_handle = ipc_port_alloc_kernel();
+
+
+ ip_lock(user_handle);
+
+ /* make a sonce right */
+ user_handle->ip_sorights++;
+ ip_reference(user_handle);
+
+ user_handle->ip_destination = IP_NULL;
+ user_handle->ip_receiver_name = MACH_PORT_NULL;
+ user_handle->ip_receiver = ipc_space_kernel;
+
+ /* make a send right */
+ user_handle->ip_mscount++;
+ user_handle->ip_srights++;
+ ip_reference(user_handle);
+
+ ipc_port_nsrequest(user_handle, 1, user_handle, &previous);
+ /* nsrequest unlocks user_handle */
+
+ /* Create a named object based on a submap of specified size */
+
+ new_map = vm_map_create(pmap_create(0), 0, size, TRUE);
+ user_entry->backing.map = new_map;
+ user_entry->internal = TRUE;
+ user_entry->is_sub_map = TRUE;
+ user_entry->is_pager = FALSE;
+ user_entry->offset = 0;
+ user_entry->protection = VM_PROT_ALL;
+ user_entry->size = size;
+ user_entry->ref_count = 1;
+
+ ipc_kobject_set(user_handle, (ipc_kobject_t) user_entry,
+ IKOT_NAMED_ENTRY);
+ *object_handle = user_handle;
+ return KERN_SUCCESS;
+}
+
+/* called for the non-default, private branch shared region support */
+/* system default fields for fs_base and system supported are not */
+/* relevant as the system default flag is not set */