fault.c revision 1.11 1 /* $NetBSD: fault.c,v 1.11 2002/03/15 22:19:49 reinoud Exp $ */
2
3 /*
4 * Copyright (c) 1994-1997 Mark Brinicombe.
5 * Copyright (c) 1994 Brini.
6 * All rights reserved.
7 *
8 * This code is derived from software written for Brini by Mark Brinicombe
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by Brini.
21 * 4. The name of the company nor the name of the author may be used to
22 * endorse or promote products derived from this software without specific
23 * prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY BRINI ``AS IS'' AND ANY EXPRESS OR IMPLIED
26 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
27 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
28 * IN NO EVENT SHALL BRINI OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
29 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
30 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
31 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 * SUCH DAMAGE.
36 *
37 * RiscBSD kernel project
38 *
39 * fault.c
40 *
41 * Fault handlers
42 *
43 * Created : 28/11/94
44 */
45
46 #include "opt_ddb.h"
47 #include "opt_pmap_debug.h"
48
49 #include <sys/types.h>
50 #include <sys/param.h>
51 #include <sys/systm.h>
52 #include <sys/proc.h>
53 #include <sys/user.h>
54 #include <sys/kernel.h>
55
56 #include <uvm/uvm_extern.h>
57
58 #include <machine/frame.h>
59 #include <arm/arm32/katelib.h>
60 #include <machine/cpu.h>
61 #include <machine/intr.h>
62 #ifdef DDB
63 #include <machine/db_machdep.h>
64 #endif
65
66 #include <arch/arm/arm/disassem.h>
67 #include <arm/arm32/machdep.h>
68
69 int cowfault __P((vaddr_t));
70 int fetchuserword __P((u_int address, u_int *location));
71 extern char fusubailout[];
72
73 static void report_abort __P((const char *, u_int, u_int, u_int));
74
75 /* Abort code */
76
77 /* Define text descriptions of the different aborts */
78
79 static const char *aborts[16] = {
80 "Write buffer fault",
81 "Alignment fault",
82 "Write buffer fault",
83 "Alignment fault",
84 "Bus error (LF section)",
85 "Translation fault (section)",
86 "Bus error (page)",
87 "Translation fault (page)",
88 "Bus error (section)",
89 "Domain error (section)",
90 "Bus error (page)",
91 "Domain error (page)",
92 "Bus error trans (L1)",
93 "Permission error (section)",
94 "Bus error trans (L2)",
95 "Permission error (page)"
96 };
97
98 static void
99 report_abort(prefix, fault_status, fault_address, fault_pc)
100 const char *prefix;
101 u_int fault_status;
102 u_int fault_address;
103 u_int fault_pc;
104 {
105 #ifndef DEBUG
106 if (prefix == NULL) {
107 #endif
108 if (prefix)
109 printf("%s ", prefix);
110 printf("Data abort: '%s' status=%03x address=%08x PC=%08x\n",
111 aborts[fault_status & FAULT_TYPE_MASK],
112 fault_status & 0xfff, fault_address, fault_pc);
113 #ifndef DEBUG
114 }
115 #endif
116 }
117
118 static __volatile int data_abort_expected;
119 static __volatile int data_abort_received;
120
121 int
122 badaddr_read(void *addr, size_t size, void *rptr)
123 {
124 u_long rcpt;
125 int rv;
126
127 /* Tell the Data Abort handler that we're expecting one. */
128 data_abort_received = 0;
129 data_abort_expected = 1;
130
131 cpu_drain_writebuf();
132
133 /* Read from the test address. */
134 switch (size) {
135 case sizeof(uint8_t):
136 __asm __volatile("ldrb %0, [%1]"
137 : "=r" (rcpt)
138 : "r" (addr));
139 break;
140
141 case sizeof(uint16_t):
142 __asm __volatile("ldrh %0, [%1]"
143 : "=r" (rcpt)
144 : "r" (addr));
145 break;
146
147 case sizeof(uint32_t):
148 __asm __volatile("ldr %0, [%1]"
149 : "=r" (rcpt)
150 : "r" (addr));
151 break;
152
153 default:
154 data_abort_expected = 0;
155 panic("badaddr: invalid size (%lu)\n", (u_long) size);
156 }
157
158 /* Disallow further Data Aborts. */
159 data_abort_expected = 0;
160
161 rv = data_abort_received;
162 data_abort_received = 0;
163
164 /* Copy the data back if no fault occurred. */
165 if (rptr != NULL && rv == 0) {
166 switch (size) {
167 case sizeof(uint8_t):
168 *(uint8_t *) rptr = rcpt;
169 break;
170
171 case sizeof(uint16_t):
172 *(uint16_t *) rptr = rcpt;
173 break;
174
175 case sizeof(uint32_t):
176 *(uint32_t *) rptr = rcpt;
177 break;
178 }
179 }
180
181 /* Return true if the address was invalid. */
182 return (rv);
183 }
184
185 /*
186 * void data_abort_handler(trapframe_t *frame)
187 *
188 * Abort handler called when read/write occurs at an address of
189 * a non existent or restricted (access permissions) memory page.
190 * We first need to identify the type of page fault.
191 */
192
193 #define TRAP_CODE ((fault_status & 0x0f) | (fault_address & 0xfffffff0))
194
195 void
196 data_abort_handler(frame)
197 trapframe_t *frame;
198 {
199 struct proc *p;
200 struct pcb *pcb;
201 u_int fault_address;
202 u_int fault_status;
203 u_int fault_pc;
204 u_int fault_instruction;
205 int fault_code;
206 int user;
207 int error;
208 void *onfault;
209
210 /*
211 * If we were expecting a Data Abort, signal that we got
212 * one, adjust the PC to skip the faulting insn, and
213 * return.
214 */
215 if (data_abort_expected) {
216 data_abort_received = 1;
217 frame->tf_pc += INSN_SIZE;
218 return;
219 }
220
221 /*
222 * Must get fault address and status from the CPU before
223 * re-enabling interrupts. (Interrupt handlers may take
224 * R/M emulation faults.)
225 */
226 fault_address = cpu_faultaddress();
227 fault_status = cpu_faultstatus();
228 fault_pc = frame->tf_pc;
229
230 /*
231 * Enable IRQ's (disabled by CPU on abort) if trapframe
232 * shows they were enabled.
233 */
234 if (!(frame->tf_spsr & I32_bit))
235 enable_interrupts(I32_bit);
236
237 #ifdef DEBUG
238 if ((GetCPSR() & PSR_MODE) != PSR_SVC32_MODE)
239 panic("data_abort_handler: not in SVC32 mode");
240 #endif
241
242 /* Update vmmeter statistics */
243 uvmexp.traps++;
244
245 /* Extract the fault code from the fault status */
246 fault_code = fault_status & FAULT_TYPE_MASK;
247
248 /* Get the current proc structure or proc0 if there is none */
249 if ((p = curproc) == NULL)
250 p = &proc0;
251
252 /*
253 * can't use curpcb, as it might be NULL; and we have p in
254 * a register anyway
255 */
256 pcb = &p->p_addr->u_pcb;
257
258 /* fusubailout is used by [fs]uswintr to avoid page faulting */
259 if (pcb->pcb_onfault
260 && ((fault_code != FAULT_TRANS_S && fault_code != FAULT_TRANS_P &&
261 fault_code != FAULT_PERM_S && fault_code != FAULT_PERM_P)
262 || pcb->pcb_onfault == fusubailout)) {
263
264 copyfault:
265 #ifdef DEBUG
266 printf("Using pcb_onfault=%p addr=%08x st=%08x p=%p\n",
267 pcb->pcb_onfault, fault_address, fault_status, p);
268 #endif
269 frame->tf_pc = (u_int)pcb->pcb_onfault;
270 if ((frame->tf_spsr & PSR_MODE) == PSR_USR32_MODE)
271 panic("Yikes pcb_onfault=%p during USR mode fault\n",
272 pcb->pcb_onfault);
273 return;
274 }
275
276 /* More debug stuff */
277
278 fault_instruction = ReadWord(fault_pc);
279
280 #ifdef PMAP_DEBUG
281 if (pmap_debug_level >= 0) {
282 report_abort(NULL, fault_status, fault_address, fault_pc);
283 printf("Instruction @V%08x = %08x\n",
284 fault_pc, fault_instruction);
285 }
286 #endif
287
288 /* Call the cpu specific abort fixup routine */
289 error = cpu_dataabt_fixup(frame);
290 if (error == ABORT_FIXUP_RETURN)
291 return;
292 if (error == ABORT_FIXUP_FAILED) {
293 printf("pc = 0x%08x, opcode 0x%08x, insn = ", fault_pc, *((u_int *)fault_pc));
294 disassemble(fault_pc);
295 printf("data abort handler: fixup failed for this instruction\n");
296 }
297
298 #ifdef PMAP_DEBUG
299 if (pmap_debug_level >= 0)
300 printf("fault in process %p\n", p);
301 #endif
302
303 #ifdef DEBUG
304 /* Is this needed ? */
305 if (pcb != curpcb) {
306 printf("data_abort: Alert ! pcb(%p) != curpcb(%p)\n",
307 pcb, curpcb);
308 printf("data_abort: Alert ! proc(%p), curproc(%p)\n",
309 p, curproc);
310 }
311 #endif /* DEBUG */
312
313 /* Were we in user mode when the abort occurred ? */
314 if ((frame->tf_spsr & PSR_MODE) == PSR_USR32_MODE) {
315 /*
316 * Note that the fault was from USR mode.
317 */
318 user = 1;
319 p->p_addr->u_pcb.pcb_tf = frame;
320 } else
321 user = 0;
322
323 /* check if this was a failed fixup */
324 if (error == ABORT_FIXUP_FAILED) {
325 if (user) {
326 trapsignal(p, SIGSEGV, TRAP_CODE);
327 userret(p);
328 return;
329 };
330 panic("Data abort fixup failed in kernel - we're dead\n");
331 };
332
333 /* Now act on the fault type */
334 switch (fault_code) {
335 case FAULT_WRTBUF_0: /* Write Buffer Fault */
336 case FAULT_WRTBUF_1: /* Write Buffer Fault */
337 /* If this happens forget it no point in continuing */
338
339 /* FALLTHROUGH */
340
341 case FAULT_ALIGN_0: /* Alignment Fault */
342 case FAULT_ALIGN_1: /* Alignment Fault */
343 /*
344 * Really this should just kill the process.
345 * Alignment faults are turned off in the kernel
346 * in order to get better performance from shorts with
347 * GCC so an alignment fault means somebody has played
348 * with the control register in the CPU. Might as well
349 * panic as the kernel was not compiled for aligned accesses.
350 */
351
352 /* FALLTHROUGH */
353
354 case FAULT_BUSERR_0: /* Bus Error LF Section */
355 case FAULT_BUSERR_1: /* Bus Error Page */
356 case FAULT_BUSERR_2: /* Bus Error Section */
357 case FAULT_BUSERR_3: /* Bus Error Page */
358 /* What will accutally cause a bus error ? */
359 /* Real bus errors are not a process problem but hardware */
360
361 /* FALLTHROUGH */
362
363 case FAULT_DOMAIN_S: /* Section Domain Error Fault */
364 case FAULT_DOMAIN_P: /* Page Domain Error Fault*/
365 /*
366 * Right well we dont use domains, everything is
367 * always a client and thus subject to access permissions.
368 * If we get a domain error then we have corrupts PTE's
369 * so we might as well die !
370 * I suppose eventually this should just kill the process
371 * who owns the PTE's but if this happens it implies a
372 * kernel problem.
373 */
374
375 /* FALLTHROUGH */
376
377 case FAULT_BUSTRNL1: /* Bus Error Trans L1 Fault */
378 case FAULT_BUSTRNL2: /* Bus Error Trans L2 Fault */
379 /*
380 * These faults imply that the PTE is corrupt.
381 * Likely to be a kernel fault so we had better stop.
382 */
383
384 /* FALLTHROUGH */
385
386 default :
387 /* Are there any combinations I have missed ? */
388 report_abort(NULL, fault_status, fault_address, fault_pc);
389
390 we_re_toast:
391 /*
392 * Were are dead, try and provide some debug
393 * information before dying.
394 */
395 #ifdef DDB
396 printf("Unhandled trap (frame = %p)\n", frame);
397 report_abort(NULL, fault_status, fault_address, fault_pc);
398 kdb_trap(-1, frame);
399 return;
400 #else
401 panic("Unhandled trap (frame = %p)", frame);
402 #endif /* DDB */
403
404 case FAULT_TRANS_P: /* Page Translation Fault */
405 case FAULT_PERM_P: /* Page Permission Fault */
406 case FAULT_TRANS_S: /* Section Translation Fault */
407 case FAULT_PERM_S: /* Section Permission Fault */
408 /*
409 * Page/section translation/permission fault -- need to fault in
410 * the page and possibly the page table page.
411 */
412 {
413 register vaddr_t va;
414 register struct vmspace *vm = p->p_vmspace;
415 register struct vm_map *map;
416 int rv;
417 vm_prot_t ftype;
418 extern struct vm_map *kernel_map;
419
420 va = trunc_page((vaddr_t)fault_address);
421
422 #ifdef PMAP_DEBUG
423 if (pmap_debug_level >= 0)
424 printf("page fault: addr=V%08lx ", va);
425 #endif
426
427 /*
428 * It is only a kernel address space fault iff:
429 * 1. user == 0 and
430 * 2. pcb_onfault not set or
431 * 3. pcb_onfault set but supervisor space fault
432 * The last can occur during an exec() copyin where the
433 * argument space is lazy-allocated.
434 */
435 if (!user &&
436 (va >= VM_MIN_KERNEL_ADDRESS || va < VM_MIN_ADDRESS)) {
437 /* Was the fault due to the FPE/IPKDB ? */
438 if ((frame->tf_spsr & PSR_MODE) == PSR_UND32_MODE) {
439 report_abort("UND32", fault_status,
440 fault_address, fault_pc);
441 trapsignal(p, SIGSEGV, TRAP_CODE);
442
443 /*
444 * Force exit via userret()
445 * This is necessary as the FPE is an extension
446 * to userland that actually runs in a
447 * priveledged mode but uses USR mode
448 * permissions for its accesses.
449 */
450 userret(p);
451 return;
452 }
453 map = kernel_map;
454 } else
455 map = &vm->vm_map;
456
457 #ifdef PMAP_DEBUG
458 if (pmap_debug_level >= 0)
459 printf("vmmap=%p ", map);
460 #endif
461
462 if (map == NULL)
463 panic("No map for fault address va = 0x%08lx", va);
464
465 /*
466 * We need to know whether the page should be mapped
467 * as R or R/W. The MMU does not give us the info as
468 * to whether the fault was caused by a read or a write.
469 * This means we need to disassemble the instruction
470 * responsible and determine if it was a read or write
471 * instruction.
472 */
473 /* STR instruction ? */
474 if ((fault_instruction & 0x0c100000) == 0x04000000)
475 ftype = VM_PROT_WRITE;
476 /* STM or CDT instruction ? */
477 else if ((fault_instruction & 0x0a100000) == 0x08000000)
478 ftype = VM_PROT_WRITE;
479 /* STRH, STRSH or STRSB instruction ? */
480 else if ((fault_instruction & 0x0e100090) == 0x00000090)
481 ftype = VM_PROT_WRITE;
482 /* SWP instruction ? */
483 else if ((fault_instruction & 0x0fb00ff0) == 0x01000090)
484 ftype = VM_PROT_READ | VM_PROT_WRITE;
485 else
486 ftype = VM_PROT_READ;
487
488 #ifdef PMAP_DEBUG
489 if (pmap_debug_level >= 0)
490 printf("fault protection = %d\n", ftype);
491 #endif
492
493 if ((ftype & VM_PROT_WRITE) ?
494 pmap_modified_emulation(map->pmap, va) :
495 pmap_handled_emulation(map->pmap, va))
496 goto out;
497
498 if (current_intr_depth > 0) {
499 #ifdef DDB
500 printf("Non-emulated page fault with intr_depth > 0\n");
501 report_abort(NULL, fault_status, fault_address, fault_pc);
502 kdb_trap(-1, frame);
503 return;
504 #else
505 panic("Fault with intr_depth > 0");
506 #endif /* DDB */
507 }
508
509 onfault = pcb->pcb_onfault;
510 pcb->pcb_onfault = NULL;
511 rv = uvm_fault(map, va, 0, ftype);
512 pcb->pcb_onfault = onfault;
513 if (rv == 0)
514 goto out;
515
516 if (user == 0) {
517 if (pcb->pcb_onfault)
518 goto copyfault;
519 printf("[u]vm_fault(%p, %lx, %x, 0) -> %x\n",
520 map, va, ftype, rv);
521 goto we_re_toast;
522 }
523
524 report_abort("", fault_status, fault_address, fault_pc);
525 if (rv == ENOMEM) {
526 printf("UVM: pid %d (%s), uid %d killed: "
527 "out of swap\n", p->p_pid, p->p_comm,
528 p->p_cred && p->p_ucred ?
529 p->p_ucred->cr_uid : -1);
530 trapsignal(p, SIGKILL, TRAP_CODE);
531 } else
532 trapsignal(p, SIGSEGV, TRAP_CODE);
533 break;
534 }
535 }
536
537 out:
538 /* Call userret() if it was a USR mode fault */
539 if (user)
540 userret(p);
541 }
542
543
544 /*
545 * void prefetch_abort_handler(trapframe_t *frame)
546 *
547 * Abort handler called when instruction execution occurs at
548 * a non existent or restricted (access permissions) memory page.
549 * If the address is invalid and we were in SVC mode then panic as
550 * the kernel should never prefetch abort.
551 * If the address is invalid and the page is mapped then the user process
552 * does no have read permission so send it a signal.
553 * Otherwise fault the page in and try again.
554 */
555
556 extern int kernel_debug;
557
558 void
559 prefetch_abort_handler(frame)
560 trapframe_t *frame;
561 {
562 register u_int fault_pc;
563 register struct proc *p;
564 register struct pcb *pcb;
565 u_int fault_instruction;
566 pt_entry_t *pte;
567 int error;
568
569 /*
570 * Enable IRQ's (disabled by the abort) This always comes
571 * from user mode so we know interrupts were not disabled.
572 * But we check anyway.
573 */
574 if (!(frame->tf_spsr & I32_bit))
575 enable_interrupts(I32_bit);
576
577 #ifdef DEBUG
578 if ((GetCPSR() & PSR_MODE) != PSR_SVC32_MODE)
579 panic("prefetch_abort_handler: not in SVC32 mode");
580 #endif
581
582 /* Update vmmeter statistics */
583 uvmexp.traps++;
584
585 /* Call the cpu specific abort fixup routine */
586 error = cpu_prefetchabt_fixup(frame);
587 if (error == ABORT_FIXUP_RETURN)
588 return;
589 if (error == ABORT_FIXUP_FAILED)
590 panic("prefetch abort fixup failed\n");
591
592 /* Get the current proc structure or proc0 if there is none */
593 if ((p = curproc) == 0) {
594 p = &proc0;
595 #ifdef DEBUG
596 printf("Prefetch abort with curproc == 0\n");
597 #endif
598 }
599
600 #ifdef PMAP_DEBUG
601 if (pmap_debug_level >= 0)
602 printf("prefetch fault in process %p %s\n", p, p->p_comm);
603 #endif
604 /*
605 * can't use curpcb, as it might be NULL; and we have p in a
606 * register anyway
607 */
608 pcb = &p->p_addr->u_pcb;
609 if (pcb == 0)
610 panic("prefetch_abort_handler: no pcb ... we're toast !\n");
611
612 #ifdef DEBUG
613 if (pcb != curpcb) {
614 printf("data_abort: Alert ! pcb(%p) != curpcb(%p)\n",
615 pcb, curpcb);
616 printf("data_abort: Alert ! proc(%p), curproc(%p)\n",
617 p, curproc);
618 }
619 #endif /* DEBUG */
620
621 /* Get fault address */
622 fault_pc = frame->tf_pc;
623
624 /* Was the prefectch abort from USR32 mode ? */
625 if ((frame->tf_spsr & PSR_MODE) == PSR_USR32_MODE) {
626 p->p_addr->u_pcb.pcb_tf = frame;
627 } else {
628 /*
629 * All the kernel code pages are loaded at boot time
630 * and do not get paged
631 */
632 panic("Prefetch abort in non-USR mode (frame=%p PC=0x%08x)\n",
633 frame, fault_pc);
634 }
635
636 #ifdef PMAP_DEBUG
637 if (pmap_debug_level >= 0)
638 printf("prefetch_abort: PC = %08x\n", fault_pc);
639 #endif
640 /* Ok validate the address, can only execute in USER space */
641 if (fault_pc < VM_MIN_ADDRESS || fault_pc >= VM_MAXUSER_ADDRESS) {
642 #ifdef DEBUG
643 printf("prefetch: pc (%08x) not in user process space\n",
644 fault_pc);
645 #endif
646 trapsignal(p, SIGSEGV, fault_pc);
647 userret(p);
648 return;
649 }
650
651 /* Is the page already mapped ? */
652 /* This is debugging for rev K SA110 silicon */
653 pte = pmap_pte(p->p_vmspace->vm_map.pmap, (vaddr_t)fault_pc);
654 if (pte && *pte != 0) {
655 if (kernel_debug & 1) {
656 printf("prefetch_abort: page is already mapped - pte=%p *pte=%08x\n",
657 pte, *pte);
658 printf("prefetch_abort: pc=%08x proc=%p process=%s\n", fault_pc, p, p->p_comm);
659 printf("prefetch_abort: far=%08x fs=%x\n", cpu_faultaddress(), cpu_faultstatus());
660 printf("prefetch_abort: trapframe=%08x\n", (u_int)frame);
661 }
662 #ifdef DDB
663 if (kernel_debug & 2)
664 Debugger();
665 #endif
666 }
667
668 /* Ok read the fault address. This will fault the page in for us */
669 if (fetchuserword(fault_pc, &fault_instruction) != 0) {
670 #ifdef DEBUG
671 printf("prefetch: faultin failed for address %08x\n",
672 fault_pc);
673 #endif
674 trapsignal(p, SIGSEGV, fault_pc);
675 } else {
676
677 #ifdef DIAGNOSTIC
678 /* More debug stuff */
679
680 #ifdef PMAP_DEBUG
681 if (pmap_debug_level >= 0) {
682 printf("Instruction @V%08x = %08x\n", fault_pc,
683 fault_instruction);
684 disassemble(fault_pc);
685 printf("return addr=%08x", frame->tf_pc);
686 pte = pmap_pte(p->p_vmspace->vm_map.pmap,
687 (vaddr_t)fault_pc);
688 if (pte)
689 printf(" pte=%p *pte=%08x\n", pte, *pte);
690 else
691 printf("\n");
692
693 }
694 #endif /* PMAP_DEBUG */
695 #endif /* DIAGNOSTIC */
696 }
697
698 userret(p);
699 }
700
701 int
702 cowfault(va)
703 vaddr_t va;
704 {
705 struct vmspace *vm;
706 int error;
707
708 if (va >= VM_MAXUSER_ADDRESS)
709 return (EFAULT);
710
711 /* uvm_fault can't be called from within an interrupt */
712 KASSERT(current_intr_depth == 0);
713
714 vm = curproc->p_vmspace;
715 error = uvm_fault(&vm->vm_map, va, 0, VM_PROT_WRITE);
716 return error;
717 }
718
719 /* End of fault.c */
720