|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * The contents of this file constitute Original Code as defined in and ! 7: * are subject to the Apple Public Source License Version 1.1 (the ! 8: * "License"). You may not use this file except in compliance with the ! 9: * License. Please obtain a copy of the License at ! 10: * http://www.apple.com/publicsource and read it before using this file. ! 11: * ! 12: * This Original Code and all software distributed under the License are ! 13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 17: * License for the specific language governing rights and limitations ! 18: * under the License. ! 19: * ! 20: * @APPLE_LICENSE_HEADER_END@ ! 21: */ ! 22: /* ! 23: * ! 24: * File: vm/vm_shared_memory_server.c ! 25: * Author: Chris Youngworth ! 26: * ! 27: * Support routines for an in-kernel shared memory allocator ! 28: */ ! 29: ! 30: #include <ipc/ipc_port.h> ! 31: #include <kern/thread.h> ! 32: #include <mach/shared_memory_server.h> ! 33: #include <kern/zalloc.h> ! 34: #include <mach/kern_return.h> ! 35: #include <mach/vm_inherit.h> ! 36: #include <vm/vm_kern.h> ! 37: #include <vm/vm_map.h> ! 38: #include <vm/vm_page.h> ! 39: ! 40: ! 41: zone_t lsf_zone; ! 42: vm_offset_t alternate_load_base; ! 43: vm_offset_t alternate_load_next; ! 44: ! 45: /* called at boot time, allocates two regions, each 256 megs in size */ ! 46: /* these regions are later mapped into task spaces, allowing them to */ ! 47: /* share the contents of the regions. shared_file_init is part of */ ! 48: /* a shared_memory_server which not only allocates the backing maps */ ! 49: /* but also coordinates requests for space. */ ! 50: ! 51: ! 52: kern_return_t ! 53: shared_file_init( ! 54: ipc_port_t *shared_text_region_handle, ! 55: vm_size_t text_region_size, ! 56: ipc_port_t *shared_data_region_handle, ! 57: vm_size_t data_region_size, ! 58: vm_offset_t *shared_file_mapping_array) ! 59: { ! 60: vm_offset_t aligned_address; ! 61: shared_file_info_t *sf_head; ! 62: vm_offset_t table_mapping_address; ! 63: ipc_port_t sfma_handle; ! 64: int data_table_size; ! 65: int hash_size; ! 66: int i; ! 67: kern_return_t kret; ! 68: ! 69: vm_object_t buf_object; ! 70: vm_map_entry_t entry; ! 71: vm_size_t alloced; ! 72: vm_offset_t b; ! 73: vm_page_t p; ! 74: ! 75: *shared_file_mapping_array = 0; ! 76: ! 77: /* create text and data maps/regions */ ! 78: if(kret = vm_region_object_create(kernel_map, ! 79: text_region_size, ! 80: shared_text_region_handle)) { ! 81: ! 82: return kret; ! 83: } ! 84: if(kret = vm_region_object_create(kernel_map, ! 85: data_region_size, ! 86: shared_data_region_handle)) { ! 87: ipc_port_release_send(*shared_text_region_handle); ! 88: return kret; ! 89: } ! 90: ! 91: data_table_size = data_region_size >> 9; ! 92: hash_size = data_region_size >> 14; ! 93: ! 94: buf_object = vm_object_allocate(data_table_size); ! 95: ! 96: if(vm_map_find_space(kernel_map, shared_file_mapping_array, ! 97: data_table_size, 0, &entry) != KERN_SUCCESS) { ! 98: ! 99: panic("shared_file_init: no space"); ! 100: } ! 101: vm_map_unlock(kernel_map); ! 102: entry->object.vm_object = buf_object; ! 103: entry->offset = 0; ! 104: ! 105: for (b = *shared_file_mapping_array, alloced = 0; ! 106: alloced < round_page(sizeof(struct sf_mapping)); ! 107: alloced += PAGE_SIZE, b += PAGE_SIZE) { ! 108: vm_object_lock(buf_object); ! 109: p = vm_page_alloc(buf_object, alloced); ! 110: if (p == VM_PAGE_NULL) { ! 111: panic("shared_file_init: no space"); ! 112: } ! 113: p->busy = FALSE; ! 114: vm_object_unlock(buf_object); ! 115: pmap_enter(kernel_pmap, b, p->phys_addr, ! 116: VM_PROT_READ | VM_PROT_WRITE, TRUE); ! 117: } ! 118: ! 119: ! 120: /* initialize loaded file array */ ! 121: sf_head = (shared_file_info_t *)*shared_file_mapping_array; ! 122: sf_head->hash = (queue_head_t *) ! 123: (((int)*shared_file_mapping_array) + ! 124: sizeof(struct shared_file_info)); ! 125: sf_head->hash_size = hash_size/sizeof(queue_head_t); ! 126: mutex_init(&(sf_head->lock), (ETAP_VM_MAP)); ! 127: sf_head->hash_init = FALSE; ! 128: ! 129: table_mapping_address = data_region_size - data_table_size; ! 130: ! 131: mach_make_memory_entry(kernel_map, &data_table_size, ! 132: *shared_file_mapping_array, VM_PROT_READ, &sfma_handle, ! 133: NULL); ! 134: ! 135: vm_map(((vm_named_entry_t) ! 136: (*shared_data_region_handle)->ip_kobject)->backing.map, ! 137: &table_mapping_address, ! 138: data_table_size, 0, SHARED_LIB_ALIAS, ! 139: sfma_handle, 0, FALSE, ! 140: VM_PROT_READ, VM_PROT_READ, VM_INHERIT_NONE); ! 141: ! 142: ipc_port_release_send(sfma_handle); ! 143: ! 144: lsf_zone = zinit(sizeof(struct load_file_ele), ! 145: data_table_size - hash_size, ! 146: 0, "load_file_server"); ! 147: ! 148: zone_change(lsf_zone, Z_EXHAUST, TRUE); ! 149: zone_change(lsf_zone, Z_COLLECT, FALSE); ! 150: zone_change(lsf_zone, Z_EXPAND, FALSE); ! 151: zone_change(lsf_zone, Z_FOREIGN, TRUE); ! 152: ! 153: alternate_load_base = text_region_size>>2; ! 154: alternate_load_next = text_region_size>>2; ! 155: } ! 156: ! 157: /* A call made from user space, copyin_shared_file requires the user to */ ! 158: /* provide the address and size of a mapped file, the full path name of */ ! 159: /* that file and a list of offsets to be mapped into shared memory. */ ! 160: /* By requiring that the file be pre-mapped, copyin_shared_file can */ ! 161: /* guarantee that the file is neither deleted nor changed after the user */ ! 162: /* begins the call. */ ! 163: ! 164: kern_return_t ! 165: copyin_shared_file( ! 166: vm_offset_t mapped_file, ! 167: vm_size_t mapped_file_size, ! 168: vm_offset_t *base_address, ! 169: int map_cnt, ! 170: sf_mapping_t *mappings, ! 171: vm_object_t file_object, ! 172: int *flags) ! 173: { ! 174: vm_map_entry_t entry; ! 175: shared_file_info_t *shared_file_header; ! 176: load_struct_t *file_entry; ! 177: sf_mapping_t *file_mapping; ! 178: boolean_t alternate; ! 179: int i; ! 180: kern_return_t ret; ! 181: ! 182: ! 183: shared_file_header = (shared_file_info_t *)shared_file_mapping_array; ! 184: ! 185: mutex_lock(&shared_file_header->lock); ! 186: ! 187: if(shared_file_header->hash_init == FALSE) { ! 188: vm_size_t hash_table_size; ! 189: vm_size_t hash_table_offset; ! 190: ! 191: hash_table_size = (shared_file_header->hash_size) ! 192: * sizeof(struct queue_entry); ! 193: hash_table_offset = hash_table_size + ! 194: round_page(sizeof(struct sf_mapping)); ! 195: for (i = 0; i < shared_file_header->hash_size; i++) ! 196: queue_init(&shared_file_header->hash[i]); ! 197: ! 198: zcram(lsf_zone, shared_file_mapping_array + ! 199: hash_table_offset, ! 200: (hash_table_size<<5) - hash_table_offset); ! 201: shared_file_header->hash_init = TRUE; ! 202: } ! 203: ! 204: ! 205: if(vm_map_lookup_entry(current_map(), mapped_file, &entry)) { ! 206: vm_object_t mapped_object; ! 207: if(entry->is_sub_map) { ! 208: mutex_unlock(&shared_file_header->lock); ! 209: return KERN_FAILURE; ! 210: } ! 211: mapped_object = entry->object.vm_object; ! 212: while(mapped_object->shadow != NULL) { ! 213: mapped_object = mapped_object->shadow; ! 214: } ! 215: if(file_object != mapped_object) { ! 216: mutex_unlock(&shared_file_header->lock); ! 217: return KERN_FAILURE; ! 218: } ! 219: } else { ! 220: mutex_unlock(&shared_file_header->lock); ! 221: return KERN_FAILURE; ! 222: } ! 223: ! 224: alternate = (*flags & ALTERNATE_LOAD_SITE) ? TRUE : FALSE; ! 225: ! 226: if (file_entry = lsf_hash_lookup(shared_file_header->hash, ! 227: (void *) file_object, ! 228: shared_file_header->hash_size, alternate)) { ! 229: /* File is loaded, check the load manifest for exact match */ ! 230: /* we simplify by requiring that the elements be the same */ ! 231: /* size and in the same order rather than checking for */ ! 232: /* semantic equivalence. */ ! 233: ! 234: /* If the file is being loaded in the alternate */ ! 235: /* area, one load to alternate is allowed per mapped */ ! 236: /* object the base address is passed back to the */ ! 237: /* caller and the mappings field is filled in. If the */ ! 238: /* caller does not pass the precise mappings_cnt */ ! 239: /* and the Alternate is already loaded, an error */ ! 240: /* is returned. */ ! 241: i = 0; ! 242: file_mapping = file_entry->mappings; ! 243: while(file_mapping != NULL) { ! 244: if(i>=map_cnt) { ! 245: mutex_unlock(&shared_file_header->lock); ! 246: return KERN_FAILURE; ! 247: } ! 248: if (mappings[i].mapping_offset != ! 249: file_mapping->mapping_offset || ! 250: mappings[i].size != ! 251: file_mapping->size || ! 252: mappings[i].file_offset != ! 253: file_mapping->file_offset || ! 254: mappings[i].protection != ! 255: file_mapping->protection) { ! 256: break; ! 257: } ! 258: file_mapping = file_mapping->next; ! 259: i++; ! 260: } ! 261: if(i!=map_cnt) { ! 262: mutex_unlock(&shared_file_header->lock); ! 263: return KERN_FAILURE; ! 264: } ! 265: *base_address = file_entry->base_address; ! 266: *flags = SF_PREV_LOADED; ! 267: mutex_unlock(&shared_file_header->lock); ! 268: return KERN_SUCCESS; ! 269: } else { ! 270: /* File is not loaded, lets attempt to load it */ ! 271: ret = lsf_load(mapped_file, mapped_file_size, base_address, ! 272: mappings, map_cnt, ! 273: (void *)file_object, *flags); ! 274: *flags = 0; ! 275: mutex_unlock(&shared_file_header->lock); ! 276: return ret; ! 277: } ! 278: } ! 279: ! 280: /* A hash lookup function for the list of loaded files in */ ! 281: /* shared_memory_server space. */ ! 282: ! 283: load_struct_t * ! 284: lsf_hash_lookup( ! 285: queue_head_t *hash_table, ! 286: void *file_object, ! 287: int size, ! 288: boolean_t alternate) ! 289: { ! 290: register queue_t bucket; ! 291: load_struct_t *entry; ! 292: ! 293: bucket = &(hash_table[load_file_hash((int)file_object, size)]); ! 294: for (entry = (load_struct_t *)queue_first(bucket); ! 295: !queue_end(bucket, &entry->links); ! 296: entry = (load_struct_t *)queue_next(&entry->links)) { ! 297: if (entry->file_object == (int)file_object) { ! 298: if(alternate) { ! 299: if (entry->base_address >= alternate_load_base) ! 300: return entry; ! 301: } else { ! 302: if (entry->base_address < alternate_load_base) ! 303: return entry; ! 304: } ! 305: } ! 306: } ! 307: ! 308: return (load_struct_t *)0; ! 309: } ! 310: ! 311: /* Removes a map_list, (list of loaded extents) for a file from */ ! 312: /* the loaded file hash table. */ ! 313: ! 314: load_struct_t * ! 315: lsf_hash_delete( ! 316: void *file_object) ! 317: { ! 318: register queue_t bucket; ! 319: shared_file_info_t *shared_file_header; ! 320: load_struct_t *entry; ! 321: load_struct_t *prev_entry; ! 322: ! 323: shared_file_header = (shared_file_info_t *)shared_file_mapping_array; ! 324: ! 325: bucket = &shared_file_header->hash ! 326: [load_file_hash((int)file_object, shared_file_header->hash_size)]; ! 327: ! 328: for (entry = (load_struct_t *)queue_first(bucket); ! 329: !queue_end(bucket, &entry->links); ! 330: entry = (load_struct_t *)queue_next(&entry->links)) { ! 331: if (entry->file_object == (int) file_object) { ! 332: queue_remove(bucket, entry, load_struct_ptr_t, links); ! 333: return entry; ! 334: } ! 335: ! 336: } ! 337: ! 338: return (load_struct_t *)0; ! 339: } ! 340: ! 341: /* Inserts a new map_list, (list of loaded file extents), into the */ ! 342: /* server loaded file hash table. */ ! 343: ! 344: void ! 345: lsf_hash_insert( ! 346: load_struct_t *entry) ! 347: { ! 348: shared_file_info_t *shared_file_header; ! 349: ! 350: shared_file_header = (shared_file_info_t *)shared_file_mapping_array; ! 351: queue_enter(&shared_file_header->hash ! 352: [load_file_hash(entry->file_object, ! 353: shared_file_header->hash_size)], ! 354: entry, load_struct_ptr_t, links); ! 355: } ! 356: ! 357: /* Looks up the file type requested. If already loaded and the */ ! 358: /* file extents are an exact match, returns Success. If not */ ! 359: /* loaded attempts to load the file extents at the given offsets */ ! 360: /* if any extent fails to load or if the file was already loaded */ ! 361: /* in a different configuration, lsf_load fails. */ ! 362: ! 363: kern_return_t ! 364: lsf_load( ! 365: vm_offset_t mapped_file, ! 366: vm_size_t mapped_file_size, ! 367: vm_offset_t *base_address, ! 368: sf_mapping_t *mappings, ! 369: int map_cnt, ! 370: void *file_object, ! 371: int flags) ! 372: { ! 373: ! 374: load_struct_t *entry; ! 375: vm_map_copy_t copy_object; ! 376: sf_mapping_t *file_mapping; ! 377: sf_mapping_t **tptr; ! 378: int i; ! 379: ipc_port_t local_map; ! 380: ! 381: entry = (load_struct_t *)zalloc(lsf_zone); ! 382: entry->file_object = (int)file_object; ! 383: entry->base_address = *base_address; ! 384: entry->mapping_cnt = map_cnt; ! 385: entry->mappings = NULL; ! 386: entry->links.prev = (queue_entry_t) 0; ! 387: entry->links.next = (queue_entry_t) 0; ! 388: ! 389: lsf_hash_insert(entry); ! 390: tptr = &(entry->mappings); ! 391: ! 392: ! 393: if (flags & ALTERNATE_LOAD_SITE) { ! 394: int max_loadfile_offset; ! 395: ! 396: *base_address = alternate_load_next; ! 397: max_loadfile_offset = 0; ! 398: for(i = 0; i<map_cnt; i++) { ! 399: if((mappings[i].mapping_offset + mappings[i].size) > ! 400: max_loadfile_offset) { ! 401: max_loadfile_offset = ! 402: mappings[i].mapping_offset ! 403: + mappings[i].size; ! 404: } ! 405: } ! 406: alternate_load_next += round_page(max_loadfile_offset); ! 407: } ! 408: /* copyin mapped file data */ ! 409: for(i = 0; i<map_cnt; i++) { ! 410: vm_offset_t target_address; ! 411: ! 412: if(mappings[i].protection & VM_PROT_COW) { ! 413: local_map = shared_data_region_handle; ! 414: } else { ! 415: local_map = shared_text_region_handle; ! 416: } ! 417: if((mapped_file + mappings[i].file_offset + ! 418: mappings[i].size) > ! 419: (mapped_file + mapped_file_size)) { ! 420: lsf_unload(file_object); ! 421: return KERN_FAILURE; ! 422: } ! 423: target_address = *base_address + mappings[i].mapping_offset; ! 424: if(vm_allocate(((vm_named_entry_t)local_map->ip_kobject) ! 425: ->backing.map, &target_address, ! 426: mappings[i].size, FALSE)) { ! 427: lsf_unload(file_object); ! 428: return KERN_FAILURE; ! 429: } ! 430: if(vm_map_copyin(current_map(), ! 431: mapped_file + mappings[i].file_offset, ! 432: mappings[i].size, TRUE, ©_object)) { ! 433: lsf_unload(file_object); ! 434: return KERN_FAILURE; ! 435: } ! 436: target_address = *base_address + mappings[i].mapping_offset; ! 437: vm_map_copy_overwrite(((vm_named_entry_t)local_map->ip_kobject) ! 438: ->backing.map, target_address, ! 439: copy_object, FALSE); ! 440: vm_map_protect(((vm_named_entry_t)local_map->ip_kobject) ! 441: ->backing.map, target_address, ! 442: target_address + mappings[i].size, ! 443: mappings[i].protection & ~VM_PROT_COW, FALSE); ! 444: file_mapping = (sf_mapping_t *)zalloc(lsf_zone); ! 445: file_mapping->mapping_offset = mappings[i].mapping_offset; ! 446: file_mapping->size = mappings[i].size; ! 447: file_mapping->file_offset = mappings[i].file_offset; ! 448: file_mapping->protection = mappings[i].protection; ! 449: file_mapping->next == NULL; ! 450: *tptr = file_mapping; ! 451: tptr = &(file_mapping->next); ! 452: } ! 453: return KERN_SUCCESS; ! 454: ! 455: } ! 456: ! 457: ! 458: /* finds the file_object extent list in the shared memory hash table */ ! 459: /* If one is found the associated extents in shared memory are deallocated */ ! 460: /* and the extent list is freed */ ! 461: ! 462: void ! 463: lsf_unload( ! 464: void *file_object) ! 465: { ! 466: load_struct_t *entry; ! 467: ipc_port_t local_map; ! 468: sf_mapping_t *map_ele; ! 469: sf_mapping_t *back_ptr; ! 470: ! 471: entry = lsf_hash_delete(file_object); ! 472: if(entry) { ! 473: map_ele = entry->mappings; ! 474: while(map_ele != NULL) { ! 475: if(map_ele->protection & VM_PROT_COW) { ! 476: local_map = shared_data_region_handle; ! 477: } else { ! 478: local_map = shared_text_region_handle; ! 479: } ! 480: vm_deallocate(((vm_named_entry_t)local_map->ip_kobject) ! 481: ->backing.map, entry->base_address + ! 482: map_ele->mapping_offset, ! 483: map_ele->size); ! 484: back_ptr = map_ele; ! 485: map_ele = map_ele->next; ! 486: zfree(lsf_zone, (vm_offset_t)back_ptr); ! 487: } ! 488: zfree(lsf_zone, (vm_offset_t)entry); ! 489: } ! 490: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.