185 {
186 caddr_t addr = (caddr_t)a;
187 caddr_t page;
188 caddr_t vaddr;
189 struct seg *seg;
190 int error = 0;
191 int err = 0;
192 uint_t prot;
193 uint_t prot_rw = writing ? PROT_WRITE : PROT_READ;
194 int protchanged;
195 on_trap_data_t otd;
196 int retrycnt;
197 struct as *as = p->p_as;
198 enum seg_rw rw;
199
200 /*
201 * Locate segment containing address of interest.
202 */
203 page = (caddr_t)(uintptr_t)((uintptr_t)addr & PAGEMASK);
204 retrycnt = 0;
205 AS_LOCK_ENTER(as, &as->a_lock, RW_WRITER);
206 retry:
207 if ((seg = as_segat(as, page)) == NULL ||
208 !page_valid(seg, page)) {
209 AS_LOCK_EXIT(as, &as->a_lock);
210 return (ENXIO);
211 }
212 SEGOP_GETPROT(seg, page, 0, &prot);
213
214 protchanged = 0;
215 if ((prot & prot_rw) == 0) {
216 protchanged = 1;
217 err = SEGOP_SETPROT(seg, page, PAGESIZE, prot | prot_rw);
218
219 if (err == IE_RETRY) {
220 protchanged = 0;
221 ASSERT(retrycnt == 0);
222 retrycnt++;
223 goto retry;
224 }
225
226 if (err != 0) {
227 AS_LOCK_EXIT(as, &as->a_lock);
228 return (ENXIO);
229 }
230 }
231
232 /*
233 * segvn may do a copy-on-write for F_SOFTLOCK/S_READ case to break
234 * sharing to avoid a copy on write of a softlocked page by another
235 * thread. But since we locked the address space as a writer no other
236 * thread can cause a copy on write. S_READ_NOCOW is passed as the
237 * access type to tell segvn that it's ok not to do a copy-on-write
238 * for this SOFTLOCK fault.
239 */
240 if (writing)
241 rw = S_WRITE;
242 else if (seg->s_ops == &segvn_ops)
243 rw = S_READ_NOCOW;
244 else
245 rw = S_READ;
246
247 if (SEGOP_FAULT(as->a_hat, seg, page, PAGESIZE, F_SOFTLOCK, rw)) {
248 if (protchanged)
249 (void) SEGOP_SETPROT(seg, page, PAGESIZE, prot);
250 AS_LOCK_EXIT(as, &as->a_lock);
251 return (ENXIO);
252 }
253 CPU_STATS_ADD_K(vm, softlock, 1);
254
255 /*
256 * Make sure we're not trying to read or write off the end of the page.
257 */
258 ASSERT(len <= page + PAGESIZE - addr);
259
260 /*
261 * Map in the locked page, copy to our local buffer,
262 * then map the page out and unlock it.
263 */
264 vaddr = mapin(as, addr, writing);
265
266 /*
267 * Since we are copying memory on behalf of the user process,
268 * protect against memory error correction faults.
269 */
270 if (!on_trap(&otd, OT_DATA_EC)) {
291 }
292 no_trap();
293
294 /*
295 * If we're writing to an executable page, we may need to sychronize
296 * the I$ with the modifications we made through the D$.
297 */
298 if (writing && (prot & PROT_EXEC))
299 sync_icache(vaddr, (uint_t)len);
300
301 mapout(as, addr, vaddr, writing);
302
303 if (rw == S_READ_NOCOW)
304 rw = S_READ;
305
306 (void) SEGOP_FAULT(as->a_hat, seg, page, PAGESIZE, F_SOFTUNLOCK, rw);
307
308 if (protchanged)
309 (void) SEGOP_SETPROT(seg, page, PAGESIZE, prot);
310
311 AS_LOCK_EXIT(as, &as->a_lock);
312
313 return (error);
314 }
315
316 int
317 uread(proc_t *p, void *buf, size_t len, uintptr_t a)
318 {
319 return (urw(p, 0, buf, len, a));
320 }
321
322 int
323 uwrite(proc_t *p, void *buf, size_t len, uintptr_t a)
324 {
325 return (urw(p, 1, buf, len, a));
326 }
|
185 {
186 caddr_t addr = (caddr_t)a;
187 caddr_t page;
188 caddr_t vaddr;
189 struct seg *seg;
190 int error = 0;
191 int err = 0;
192 uint_t prot;
193 uint_t prot_rw = writing ? PROT_WRITE : PROT_READ;
194 int protchanged;
195 on_trap_data_t otd;
196 int retrycnt;
197 struct as *as = p->p_as;
198 enum seg_rw rw;
199
200 /*
201 * Locate segment containing address of interest.
202 */
203 page = (caddr_t)(uintptr_t)((uintptr_t)addr & PAGEMASK);
204 retrycnt = 0;
205 AS_LOCK_ENTER(as, RW_WRITER);
206 retry:
207 if ((seg = as_segat(as, page)) == NULL ||
208 !page_valid(seg, page)) {
209 AS_LOCK_EXIT(as);
210 return (ENXIO);
211 }
212 SEGOP_GETPROT(seg, page, 0, &prot);
213
214 protchanged = 0;
215 if ((prot & prot_rw) == 0) {
216 protchanged = 1;
217 err = SEGOP_SETPROT(seg, page, PAGESIZE, prot | prot_rw);
218
219 if (err == IE_RETRY) {
220 protchanged = 0;
221 ASSERT(retrycnt == 0);
222 retrycnt++;
223 goto retry;
224 }
225
226 if (err != 0) {
227 AS_LOCK_EXIT(as);
228 return (ENXIO);
229 }
230 }
231
232 /*
233 * segvn may do a copy-on-write for F_SOFTLOCK/S_READ case to break
234 * sharing to avoid a copy on write of a softlocked page by another
235 * thread. But since we locked the address space as a writer no other
236 * thread can cause a copy on write. S_READ_NOCOW is passed as the
237 * access type to tell segvn that it's ok not to do a copy-on-write
238 * for this SOFTLOCK fault.
239 */
240 if (writing)
241 rw = S_WRITE;
242 else if (seg->s_ops == &segvn_ops)
243 rw = S_READ_NOCOW;
244 else
245 rw = S_READ;
246
247 if (SEGOP_FAULT(as->a_hat, seg, page, PAGESIZE, F_SOFTLOCK, rw)) {
248 if (protchanged)
249 (void) SEGOP_SETPROT(seg, page, PAGESIZE, prot);
250 AS_LOCK_EXIT(as);
251 return (ENXIO);
252 }
253 CPU_STATS_ADD_K(vm, softlock, 1);
254
255 /*
256 * Make sure we're not trying to read or write off the end of the page.
257 */
258 ASSERT(len <= page + PAGESIZE - addr);
259
260 /*
261 * Map in the locked page, copy to our local buffer,
262 * then map the page out and unlock it.
263 */
264 vaddr = mapin(as, addr, writing);
265
266 /*
267 * Since we are copying memory on behalf of the user process,
268 * protect against memory error correction faults.
269 */
270 if (!on_trap(&otd, OT_DATA_EC)) {
291 }
292 no_trap();
293
294 /*
295 * If we're writing to an executable page, we may need to sychronize
296 * the I$ with the modifications we made through the D$.
297 */
298 if (writing && (prot & PROT_EXEC))
299 sync_icache(vaddr, (uint_t)len);
300
301 mapout(as, addr, vaddr, writing);
302
303 if (rw == S_READ_NOCOW)
304 rw = S_READ;
305
306 (void) SEGOP_FAULT(as->a_hat, seg, page, PAGESIZE, F_SOFTUNLOCK, rw);
307
308 if (protchanged)
309 (void) SEGOP_SETPROT(seg, page, PAGESIZE, prot);
310
311 AS_LOCK_EXIT(as);
312
313 return (error);
314 }
315
316 int
317 uread(proc_t *p, void *buf, size_t len, uintptr_t a)
318 {
319 return (urw(p, 0, buf, len, a));
320 }
321
322 int
323 uwrite(proc_t *p, void *buf, size_t len, uintptr_t a)
324 {
325 return (urw(p, 1, buf, len, a));
326 }
|