|
|
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.