]>
Commit | Line | Data |
---|---|---|
1c79356b | 1 | /* |
91447636 | 2 | * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved. |
1c79356b A |
3 | * |
4 | * @APPLE_LICENSE_HEADER_START@ | |
5 | * | |
37839358 A |
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. | |
1c79356b | 11 | * |
37839358 A |
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 | |
1c79356b A |
14 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, |
15 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
37839358 A |
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. | |
1c79356b A |
19 | * |
20 | * @APPLE_LICENSE_HEADER_END@ | |
21 | */ | |
22 | /* | |
23 | * @OSF_COPYRIGHT@ | |
24 | */ | |
25 | /* | |
26 | * Mach Operating System | |
27 | * Copyright (c) 1991,1990 Carnegie Mellon University | |
28 | * All Rights Reserved. | |
29 | * | |
30 | * Permission to use, copy, modify and distribute this software and its | |
31 | * documentation is hereby granted, provided that both the copyright | |
32 | * notice and this permission notice appear in all copies of the | |
33 | * software, derivative works or modified versions, and any portions | |
34 | * thereof, and that both notices appear in supporting documentation. | |
35 | * | |
36 | * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" | |
37 | * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR | |
38 | * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. | |
39 | * | |
40 | * Carnegie Mellon requests users of this software to return to | |
41 | * | |
42 | * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU | |
43 | * School of Computer Science | |
44 | * Carnegie Mellon University | |
45 | * Pittsburgh PA 15213-3890 | |
46 | * | |
47 | * any improvements or extensions that they make and grant Carnegie Mellon | |
48 | * the rights to redistribute these changes. | |
49 | */ | |
50 | /* | |
51 | */ | |
52 | ||
53 | #include <kern/thread.h> | |
54 | #include <vm/vm_fault.h> | |
55 | #include <mach/kern_return.h> | |
56 | #include <mach/vm_behavior.h> | |
57 | #include <vm/vm_map.h> | |
58 | #include <vm/vm_object.h> | |
59 | #include <vm/vm_page.h> | |
60 | #include <vm/pmap.h> | |
61 | ||
62 | #include <i386/intel_read_fault.h> | |
63 | ||
64 | #include <kern/macro_help.h> | |
65 | ||
66 | /* | |
67 | * Expansion of vm_fault for read fault in kernel mode. | |
68 | * Must enter the mapping as writable, since the i386 | |
69 | * (and i860 in i386 compatability mode) ignores write | |
70 | * protection in kernel mode. | |
71 | * | |
72 | * Note that this routine can be called for pmap's other | |
73 | * than the kernel_pmap, in which case it just enters | |
74 | * a read-only mapping. (See e.g. kernel_trap().) | |
75 | */ | |
76 | kern_return_t | |
77 | intel_read_fault( | |
78 | vm_map_t map, | |
79 | vm_offset_t vaddr) | |
80 | { | |
81 | vm_map_version_t version; /* Map version for | |
82 | verification */ | |
83 | vm_object_t object; /* Top-level object */ | |
84 | vm_object_offset_t offset; /* Top-level offset */ | |
85 | vm_prot_t prot; /* Protection for mapping */ | |
86 | vm_behavior_t behavior; /* Expected paging behavior */ | |
91447636 | 87 | vm_map_offset_t lo_offset, hi_offset; |
1c79356b A |
88 | vm_page_t result_page; /* Result of vm_fault_page */ |
89 | vm_page_t top_page; /* Placeholder page */ | |
90 | boolean_t wired; /* Is map region wired? */ | |
91 | kern_return_t result; | |
92 | register vm_page_t m; | |
91447636 | 93 | vm_map_t map_pmap; |
1c79356b | 94 | vm_map_t original_map = map; |
9bccf70c A |
95 | thread_t cur_thread; |
96 | boolean_t funnel_set; | |
91447636 | 97 | funnel_t *curflock = NULL; |
9bccf70c A |
98 | |
99 | cur_thread = current_thread(); | |
9bccf70c A |
100 | if ((cur_thread->funnel_state & TH_FN_OWNED) == TH_FN_OWNED) { |
101 | funnel_set = TRUE; | |
102 | curflock = cur_thread->funnel_lock; | |
103 | thread_funnel_set( curflock , FALSE); | |
104 | } else { | |
105 | funnel_set = FALSE; | |
106 | } | |
1c79356b A |
107 | |
108 | RetryFault: | |
109 | ||
110 | map = original_map; | |
111 | ||
112 | /* | |
113 | * Find the backing store object and offset into it | |
114 | * to begin search. | |
115 | */ | |
116 | vm_map_lock_read(map); | |
117 | result = vm_map_lookup_locked(&map, vaddr, VM_PROT_READ, &version, | |
118 | &object, &offset, &prot, &wired, | |
119 | &behavior, &lo_offset, | |
91447636 | 120 | &hi_offset, &map_pmap); |
1c79356b A |
121 | |
122 | vm_map_unlock_read(map); | |
123 | ||
124 | if (result != KERN_SUCCESS) { | |
9bccf70c A |
125 | if (funnel_set) |
126 | thread_funnel_set( curflock, TRUE); | |
127 | return (result); | |
1c79356b A |
128 | } |
129 | ||
91447636 A |
130 | if(map_pmap != map) { |
131 | vm_map_reference(map_pmap); | |
132 | vm_map_unlock_read(map_pmap); | |
1c79356b A |
133 | } |
134 | ||
135 | /* | |
136 | * Make a reference to this object to prevent its | |
137 | * disposal while we are playing with it. | |
138 | */ | |
139 | assert(object->ref_count > 0); | |
140 | object->ref_count++; | |
141 | vm_object_res_reference(object); | |
142 | vm_object_paging_begin(object); | |
143 | ||
144 | result = vm_fault_page(object, offset, VM_PROT_READ, FALSE, | |
145 | THREAD_ABORTSAFE, | |
146 | lo_offset, hi_offset, behavior, | |
147 | &prot, &result_page, &top_page, (int *)0, | |
0b4e3aa0 | 148 | 0, map->no_zero_fill, FALSE, map, vaddr); |
1c79356b A |
149 | |
150 | if (result != VM_FAULT_SUCCESS) { | |
151 | vm_object_deallocate(object); | |
91447636 A |
152 | if(map_pmap != map) { |
153 | vm_map_deallocate(map_pmap); | |
1c79356b A |
154 | } |
155 | ||
156 | switch (result) { | |
157 | case VM_FAULT_RETRY: | |
158 | goto RetryFault; | |
159 | case VM_FAULT_INTERRUPTED: | |
9bccf70c A |
160 | if (funnel_set) |
161 | thread_funnel_set( curflock, TRUE); | |
1c79356b A |
162 | return (KERN_SUCCESS); |
163 | case VM_FAULT_MEMORY_SHORTAGE: | |
164 | VM_PAGE_WAIT(); | |
165 | goto RetryFault; | |
166 | case VM_FAULT_FICTITIOUS_SHORTAGE: | |
167 | vm_page_more_fictitious(); | |
168 | goto RetryFault; | |
169 | case VM_FAULT_MEMORY_ERROR: | |
170 | return (KERN_MEMORY_ERROR); | |
171 | } | |
172 | } | |
173 | ||
174 | m = result_page; | |
175 | ||
176 | /* | |
177 | * How to clean up the result of vm_fault_page. This | |
178 | * happens whether the mapping is entered or not. | |
179 | */ | |
180 | ||
181 | #define UNLOCK_AND_DEALLOCATE \ | |
182 | MACRO_BEGIN \ | |
183 | vm_fault_cleanup(m->object, top_page); \ | |
184 | vm_object_deallocate(object); \ | |
185 | MACRO_END | |
186 | ||
187 | /* | |
188 | * What to do with the resulting page from vm_fault_page | |
189 | * if it doesn't get entered into the physical map: | |
190 | */ | |
191 | ||
192 | #define RELEASE_PAGE(m) \ | |
193 | MACRO_BEGIN \ | |
194 | PAGE_WAKEUP_DONE(m); \ | |
195 | vm_page_lock_queues(); \ | |
196 | if (!m->active && !m->inactive) \ | |
197 | vm_page_activate(m); \ | |
198 | vm_page_unlock_queues(); \ | |
199 | MACRO_END | |
200 | ||
201 | /* | |
202 | * We must verify that the maps have not changed. | |
203 | */ | |
204 | vm_object_unlock(m->object); | |
205 | ||
206 | if ((map != original_map) || !vm_map_verify(map, &version)) { | |
207 | vm_object_t retry_object; | |
208 | vm_object_offset_t retry_offset; | |
209 | vm_prot_t retry_prot; | |
210 | ||
91447636 A |
211 | if (map != map_pmap) { |
212 | vm_map_deallocate(map_pmap); | |
1c79356b A |
213 | } |
214 | ||
215 | map = original_map; | |
216 | vm_map_lock_read(map); | |
217 | ||
218 | result = vm_map_lookup_locked(&map, vaddr, VM_PROT_READ, &version, | |
219 | &retry_object, &retry_offset, &retry_prot, | |
220 | &wired, &behavior, &lo_offset, | |
91447636 | 221 | &hi_offset, &map_pmap); |
1c79356b A |
222 | |
223 | if (result != KERN_SUCCESS) { | |
224 | vm_map_unlock_read(map); | |
225 | vm_object_lock(m->object); | |
226 | RELEASE_PAGE(m); | |
227 | UNLOCK_AND_DEALLOCATE; | |
9bccf70c A |
228 | if (funnel_set) |
229 | thread_funnel_set( curflock, TRUE); | |
1c79356b A |
230 | return (result); |
231 | } | |
232 | ||
91447636 A |
233 | if (map != map_pmap) { |
234 | vm_map_reference(map_pmap); | |
1c79356b A |
235 | } |
236 | ||
237 | vm_object_unlock(retry_object); | |
238 | ||
239 | if (retry_object != object || retry_offset != offset) { | |
240 | vm_object_lock(m->object); | |
241 | RELEASE_PAGE(m); | |
242 | vm_map_unlock_read(map); | |
91447636 A |
243 | if(map_pmap != map) { |
244 | vm_map_unlock_read(map_pmap); | |
245 | vm_map_deallocate(map_pmap); | |
1c79356b A |
246 | } |
247 | UNLOCK_AND_DEALLOCATE; | |
248 | goto RetryFault; | |
249 | } | |
250 | } | |
251 | ||
252 | /* | |
253 | * Put the page in the physical map. | |
254 | */ | |
255 | ||
91447636 | 256 | PMAP_ENTER(map_pmap->pmap, vaddr, m, VM_PROT_READ, PMAP_DEFAULT_CACHE, wired); |
1c79356b | 257 | |
91447636 A |
258 | if(map_pmap != map) { |
259 | vm_map_unlock_read(map_pmap); | |
260 | vm_map_deallocate(map_pmap); | |
1c79356b A |
261 | } |
262 | ||
263 | vm_object_lock(m->object); | |
264 | vm_page_lock_queues(); | |
265 | if (!m->active && !m->inactive) | |
266 | vm_page_activate(m); | |
267 | m->reference = TRUE; | |
268 | vm_page_unlock_queues(); | |
269 | ||
270 | vm_map_verify_done(map, &version); | |
271 | PAGE_WAKEUP_DONE(m); | |
272 | ||
273 | UNLOCK_AND_DEALLOCATE; | |
274 | ||
275 | #undef UNLOCK_AND_DEALLOCATE | |
276 | #undef RELEASE_PAGE | |
9bccf70c A |
277 | if (funnel_set) |
278 | thread_funnel_set( curflock, TRUE); | |
1c79356b A |
279 | return (KERN_SUCCESS); |
280 | } | |
281 |