1433d6423SLionel Sambuc
2433d6423SLionel Sambuc #define _SYSTEM 1
3433d6423SLionel Sambuc
4433d6423SLionel Sambuc #include <minix/callnr.h>
5433d6423SLionel Sambuc #include <minix/com.h>
6433d6423SLionel Sambuc #include <minix/config.h>
7433d6423SLionel Sambuc #include <minix/const.h>
8433d6423SLionel Sambuc #include <minix/ds.h>
9433d6423SLionel Sambuc #include <minix/endpoint.h>
10433d6423SLionel Sambuc #include <minix/minlib.h>
11433d6423SLionel Sambuc #include <minix/type.h>
12433d6423SLionel Sambuc #include <minix/ipc.h>
13433d6423SLionel Sambuc #include <minix/sysutil.h>
14433d6423SLionel Sambuc #include <minix/syslib.h>
15433d6423SLionel Sambuc #include <minix/safecopies.h>
16433d6423SLionel Sambuc #include <minix/bitmap.h>
17433d6423SLionel Sambuc #include <minix/vfsif.h>
18433d6423SLionel Sambuc
19433d6423SLionel Sambuc #include <machine/vmparam.h>
20433d6423SLionel Sambuc
21433d6423SLionel Sambuc #include <errno.h>
22433d6423SLionel Sambuc #include <string.h>
23433d6423SLionel Sambuc #include <stdio.h>
24433d6423SLionel Sambuc #include <fcntl.h>
25433d6423SLionel Sambuc #include <signal.h>
26433d6423SLionel Sambuc #include <assert.h>
27433d6423SLionel Sambuc
28433d6423SLionel Sambuc #include "glo.h"
29433d6423SLionel Sambuc #include "proto.h"
30433d6423SLionel Sambuc #include "util.h"
31433d6423SLionel Sambuc #include "region.h"
32433d6423SLionel Sambuc
33433d6423SLionel Sambuc struct pf_state {
34433d6423SLionel Sambuc endpoint_t ep;
35433d6423SLionel Sambuc vir_bytes vaddr;
36433d6423SLionel Sambuc u32_t err;
37433d6423SLionel Sambuc };
38433d6423SLionel Sambuc
39433d6423SLionel Sambuc struct hm_state {
40433d6423SLionel Sambuc endpoint_t caller; /* KERNEL or process? if NONE, no callback */
41433d6423SLionel Sambuc endpoint_t requestor; /* on behalf of whom? */
42433d6423SLionel Sambuc int transid; /* VFS transaction id if valid */
43433d6423SLionel Sambuc struct vmproc *vmp; /* target address space */
44433d6423SLionel Sambuc vir_bytes mem, len; /* memory range */
45433d6423SLionel Sambuc int wrflag; /* must it be writable or not */
46433d6423SLionel Sambuc int valid; /* sanity check */
47433d6423SLionel Sambuc int vfs_avail; /* may vfs be called to satisfy this range? */
48433d6423SLionel Sambuc #define VALID 0xc0ff1
49433d6423SLionel Sambuc };
50433d6423SLionel Sambuc
51433d6423SLionel Sambuc static void handle_memory_continue(struct vmproc *vmp, message *m,
52433d6423SLionel Sambuc void *arg, void *statearg);
53f202792eSDavid van Moolenbroek static int handle_memory_step(struct hm_state *hmstate, int retry);
54433d6423SLionel Sambuc static void handle_memory_final(struct hm_state *state, int result);
55433d6423SLionel Sambuc
56433d6423SLionel Sambuc /*===========================================================================*
57433d6423SLionel Sambuc * pf_errstr *
58433d6423SLionel Sambuc *===========================================================================*/
pf_errstr(u32_t err)59433d6423SLionel Sambuc char *pf_errstr(u32_t err)
60433d6423SLionel Sambuc {
61433d6423SLionel Sambuc static char buf[100];
62433d6423SLionel Sambuc
630a6a1f1dSLionel Sambuc snprintf(buf, sizeof(buf), "err 0x%lx ", (long)err);
64433d6423SLionel Sambuc if(PFERR_NOPAGE(err)) strcat(buf, "nopage ");
65433d6423SLionel Sambuc if(PFERR_PROT(err)) strcat(buf, "protection ");
66433d6423SLionel Sambuc if(PFERR_WRITE(err)) strcat(buf, "write");
67433d6423SLionel Sambuc if(PFERR_READ(err)) strcat(buf, "read");
68433d6423SLionel Sambuc
69433d6423SLionel Sambuc return buf;
70433d6423SLionel Sambuc }
71433d6423SLionel Sambuc
72433d6423SLionel Sambuc static void pf_cont(struct vmproc *vmp, message *m, void *arg, void *statearg);
73433d6423SLionel Sambuc
74433d6423SLionel Sambuc static void handle_memory_continue(struct vmproc *vmp, message *m, void *arg, void *statearg);
75433d6423SLionel Sambuc
handle_pagefault(endpoint_t ep,vir_bytes addr,u32_t err,int retry)76433d6423SLionel Sambuc static void handle_pagefault(endpoint_t ep, vir_bytes addr, u32_t err, int retry)
77433d6423SLionel Sambuc {
78433d6423SLionel Sambuc struct vmproc *vmp;
79433d6423SLionel Sambuc int s, result;
80433d6423SLionel Sambuc struct vir_region *region;
81433d6423SLionel Sambuc vir_bytes offset;
82433d6423SLionel Sambuc int p, wr = PFERR_WRITE(err);
83433d6423SLionel Sambuc int io = 0;
84433d6423SLionel Sambuc
85433d6423SLionel Sambuc if(vm_isokendpt(ep, &p) != OK)
86433d6423SLionel Sambuc panic("handle_pagefault: endpoint wrong: %d", ep);
87433d6423SLionel Sambuc
88433d6423SLionel Sambuc vmp = &vmproc[p];
89433d6423SLionel Sambuc assert(vmp->vm_flags & VMF_INUSE);
90433d6423SLionel Sambuc
91433d6423SLionel Sambuc /* See if address is valid at all. */
92433d6423SLionel Sambuc if(!(region = map_lookup(vmp, addr, NULL))) {
93433d6423SLionel Sambuc if(PFERR_PROT(err)) {
94433d6423SLionel Sambuc printf("VM: pagefault: SIGSEGV %d protected addr 0x%lx; %s\n",
95433d6423SLionel Sambuc ep, addr, pf_errstr(err));
96433d6423SLionel Sambuc } else {
97433d6423SLionel Sambuc assert(PFERR_NOPAGE(err));
98433d6423SLionel Sambuc printf("VM: pagefault: SIGSEGV %d bad addr 0x%lx; %s\n",
99433d6423SLionel Sambuc ep, addr, pf_errstr(err));
100433d6423SLionel Sambuc sys_diagctl_stacktrace(ep);
101433d6423SLionel Sambuc }
102433d6423SLionel Sambuc if((s=sys_kill(vmp->vm_endpoint, SIGSEGV)) != OK)
103433d6423SLionel Sambuc panic("sys_kill failed: %d", s);
104433d6423SLionel Sambuc if((s=sys_vmctl(ep, VMCTL_CLEAR_PAGEFAULT, 0 /*unused*/)) != OK)
105433d6423SLionel Sambuc panic("do_pagefaults: sys_vmctl failed: %d", ep);
106433d6423SLionel Sambuc return;
107433d6423SLionel Sambuc }
108433d6423SLionel Sambuc
109433d6423SLionel Sambuc /* If process was writing, see if it's writable. */
110433d6423SLionel Sambuc if(!(region->flags & VR_WRITABLE) && wr) {
111433d6423SLionel Sambuc printf("VM: pagefault: SIGSEGV %d ro map 0x%lx %s\n",
112433d6423SLionel Sambuc ep, addr, pf_errstr(err));
113433d6423SLionel Sambuc if((s=sys_kill(vmp->vm_endpoint, SIGSEGV)) != OK)
114433d6423SLionel Sambuc panic("sys_kill failed: %d", s);
115433d6423SLionel Sambuc if((s=sys_vmctl(ep, VMCTL_CLEAR_PAGEFAULT, 0 /*unused*/)) != OK)
116433d6423SLionel Sambuc panic("do_pagefaults: sys_vmctl failed: %d", ep);
117433d6423SLionel Sambuc return;
118433d6423SLionel Sambuc }
119433d6423SLionel Sambuc
120433d6423SLionel Sambuc assert(addr >= region->vaddr);
121433d6423SLionel Sambuc offset = addr - region->vaddr;
122433d6423SLionel Sambuc
123433d6423SLionel Sambuc /* Access is allowed; handle it. */
124433d6423SLionel Sambuc if(retry) {
125433d6423SLionel Sambuc result = map_pf(vmp, region, offset, wr, NULL, NULL, 0, &io);
126433d6423SLionel Sambuc assert(result != SUSPEND);
127433d6423SLionel Sambuc } else {
128433d6423SLionel Sambuc struct pf_state state;
129433d6423SLionel Sambuc state.ep = ep;
130433d6423SLionel Sambuc state.vaddr = addr;
131433d6423SLionel Sambuc state.err = err;
132433d6423SLionel Sambuc result = map_pf(vmp, region, offset, wr, pf_cont,
133433d6423SLionel Sambuc &state, sizeof(state), &io);
134433d6423SLionel Sambuc }
135433d6423SLionel Sambuc if (io)
136433d6423SLionel Sambuc vmp->vm_major_page_fault++;
137433d6423SLionel Sambuc else
138433d6423SLionel Sambuc vmp->vm_minor_page_fault++;
139433d6423SLionel Sambuc
140433d6423SLionel Sambuc if(result == SUSPEND) {
141433d6423SLionel Sambuc return;
142433d6423SLionel Sambuc }
143433d6423SLionel Sambuc
144433d6423SLionel Sambuc if(result != OK) {
145433d6423SLionel Sambuc printf("VM: pagefault: SIGSEGV %d pagefault not handled\n", ep);
146433d6423SLionel Sambuc if((s=sys_kill(ep, SIGSEGV)) != OK)
147433d6423SLionel Sambuc panic("sys_kill failed: %d", s);
148433d6423SLionel Sambuc if((s=sys_vmctl(ep, VMCTL_CLEAR_PAGEFAULT, 0 /*unused*/)) != OK)
149433d6423SLionel Sambuc panic("do_pagefaults: sys_vmctl failed: %d", ep);
150433d6423SLionel Sambuc return;
151433d6423SLionel Sambuc }
152433d6423SLionel Sambuc
153433d6423SLionel Sambuc pt_clearmapcache();
154433d6423SLionel Sambuc
155433d6423SLionel Sambuc /* Pagefault is handled, so now reactivate the process. */
156433d6423SLionel Sambuc if((s=sys_vmctl(ep, VMCTL_CLEAR_PAGEFAULT, 0 /*unused*/)) != OK)
157433d6423SLionel Sambuc panic("do_pagefaults: sys_vmctl failed: %d", ep);
158433d6423SLionel Sambuc }
159433d6423SLionel Sambuc
160433d6423SLionel Sambuc
pf_cont(struct vmproc * vmp,message * m,void * arg,void * statearg)161433d6423SLionel Sambuc static void pf_cont(struct vmproc *vmp, message *m,
162433d6423SLionel Sambuc void *arg, void *statearg)
163433d6423SLionel Sambuc {
164433d6423SLionel Sambuc struct pf_state *state = statearg;
165433d6423SLionel Sambuc int p;
166433d6423SLionel Sambuc if(vm_isokendpt(state->ep, &p) != OK) return; /* signal */
167433d6423SLionel Sambuc handle_pagefault(state->ep, state->vaddr, state->err, 1);
168433d6423SLionel Sambuc }
169433d6423SLionel Sambuc
handle_memory_continue(struct vmproc * vmp,message * m,void * arg,void * statearg)170433d6423SLionel Sambuc static void handle_memory_continue(struct vmproc *vmp, message *m,
171433d6423SLionel Sambuc void *arg, void *statearg)
172433d6423SLionel Sambuc {
173433d6423SLionel Sambuc int r;
174433d6423SLionel Sambuc struct hm_state *state = statearg;
175433d6423SLionel Sambuc assert(state);
176433d6423SLionel Sambuc assert(state->caller != NONE);
177433d6423SLionel Sambuc assert(state->valid == VALID);
178433d6423SLionel Sambuc
179433d6423SLionel Sambuc if(m->VMV_RESULT != OK) {
180433d6423SLionel Sambuc printf("VM: handle_memory_continue: vfs request failed\n");
181433d6423SLionel Sambuc handle_memory_final(state, m->VMV_RESULT);
182433d6423SLionel Sambuc return;
183433d6423SLionel Sambuc }
184433d6423SLionel Sambuc
185f202792eSDavid van Moolenbroek r = handle_memory_step(state, TRUE /*retry*/);
186433d6423SLionel Sambuc
187433d6423SLionel Sambuc assert(state->valid == VALID);
188433d6423SLionel Sambuc
189433d6423SLionel Sambuc if(r == SUSPEND) {
190433d6423SLionel Sambuc return;
191433d6423SLionel Sambuc }
192433d6423SLionel Sambuc
193433d6423SLionel Sambuc assert(state->valid == VALID);
194433d6423SLionel Sambuc
195433d6423SLionel Sambuc handle_memory_final(state, r);
196433d6423SLionel Sambuc }
197433d6423SLionel Sambuc
handle_memory_final(struct hm_state * state,int result)198433d6423SLionel Sambuc static void handle_memory_final(struct hm_state *state, int result)
199433d6423SLionel Sambuc {
200*2109df27SDavid van Moolenbroek int r, flag;
201433d6423SLionel Sambuc
202433d6423SLionel Sambuc assert(state);
203433d6423SLionel Sambuc assert(state->valid == VALID);
204433d6423SLionel Sambuc
205433d6423SLionel Sambuc if(state->caller == KERNEL) {
206433d6423SLionel Sambuc if((r=sys_vmctl(state->requestor, VMCTL_MEMREQ_REPLY, result)) != OK)
207433d6423SLionel Sambuc panic("handle_memory_continue: sys_vmctl failed: %d", r);
208433d6423SLionel Sambuc } else if(state->caller != NONE) {
209433d6423SLionel Sambuc /* Send a reply msg */
210433d6423SLionel Sambuc message msg;
211433d6423SLionel Sambuc memset(&msg, 0, sizeof(msg));
212433d6423SLionel Sambuc msg.m_type = result;
213433d6423SLionel Sambuc
214433d6423SLionel Sambuc if(IS_VFS_FS_TRANSID(state->transid)) {
215433d6423SLionel Sambuc assert(state->caller == VFS_PROC_NR);
216433d6423SLionel Sambuc /* If a transaction ID was set, reset it */
217433d6423SLionel Sambuc msg.m_type = TRNS_ADD_ID(msg.m_type, state->transid);
218*2109df27SDavid van Moolenbroek flag = AMF_NOREPLY;
219*2109df27SDavid van Moolenbroek } else
220*2109df27SDavid van Moolenbroek flag = 0;
221433d6423SLionel Sambuc
222*2109df27SDavid van Moolenbroek /*
223*2109df27SDavid van Moolenbroek * Use AMF_NOREPLY only if there was a transaction ID, which
224*2109df27SDavid van Moolenbroek * signifies that VFS issued the request asynchronously.
225*2109df27SDavid van Moolenbroek */
226*2109df27SDavid van Moolenbroek if(asynsend3(state->caller, &msg, flag) != OK) {
227433d6423SLionel Sambuc panic("handle_memory_final: asynsend3 failed");
228433d6423SLionel Sambuc }
229433d6423SLionel Sambuc
230433d6423SLionel Sambuc assert(state->valid == VALID);
231433d6423SLionel Sambuc
232433d6423SLionel Sambuc /* fail fast if anyone tries to access this state again */
233433d6423SLionel Sambuc memset(state, 0, sizeof(*state));
234433d6423SLionel Sambuc }
235433d6423SLionel Sambuc }
236433d6423SLionel Sambuc
237433d6423SLionel Sambuc /*===========================================================================*
238433d6423SLionel Sambuc * do_pagefaults *
239433d6423SLionel Sambuc *===========================================================================*/
do_pagefaults(message * m)240433d6423SLionel Sambuc void do_pagefaults(message *m)
241433d6423SLionel Sambuc {
242433d6423SLionel Sambuc handle_pagefault(m->m_source, m->VPF_ADDR, m->VPF_FLAGS, 0);
243433d6423SLionel Sambuc }
244433d6423SLionel Sambuc
handle_memory_once(struct vmproc * vmp,vir_bytes mem,vir_bytes len,int wrflag)245433d6423SLionel Sambuc int handle_memory_once(struct vmproc *vmp, vir_bytes mem, vir_bytes len,
246433d6423SLionel Sambuc int wrflag)
247433d6423SLionel Sambuc {
248433d6423SLionel Sambuc int r;
249433d6423SLionel Sambuc r = handle_memory_start(vmp, mem, len, wrflag, NONE, NONE, 0, 0);
250433d6423SLionel Sambuc assert(r != SUSPEND);
251433d6423SLionel Sambuc return r;
252433d6423SLionel Sambuc }
253433d6423SLionel Sambuc
handle_memory_start(struct vmproc * vmp,vir_bytes mem,vir_bytes len,int wrflag,endpoint_t caller,endpoint_t requestor,int transid,int vfs_avail)254433d6423SLionel Sambuc int handle_memory_start(struct vmproc *vmp, vir_bytes mem, vir_bytes len,
255433d6423SLionel Sambuc int wrflag, endpoint_t caller, endpoint_t requestor, int transid,
256433d6423SLionel Sambuc int vfs_avail)
257433d6423SLionel Sambuc {
258433d6423SLionel Sambuc int r;
259433d6423SLionel Sambuc struct hm_state state;
260433d6423SLionel Sambuc vir_bytes o;
261433d6423SLionel Sambuc
262433d6423SLionel Sambuc if((o = mem % PAGE_SIZE)) {
263433d6423SLionel Sambuc mem -= o;
264433d6423SLionel Sambuc len += o;
265433d6423SLionel Sambuc }
266433d6423SLionel Sambuc
267433d6423SLionel Sambuc len = roundup(len, PAGE_SIZE);
268433d6423SLionel Sambuc
269433d6423SLionel Sambuc state.vmp = vmp;
270433d6423SLionel Sambuc state.mem = mem;
271433d6423SLionel Sambuc state.len = len;
272433d6423SLionel Sambuc state.wrflag = wrflag;
273433d6423SLionel Sambuc state.requestor = requestor;
274433d6423SLionel Sambuc state.caller = caller;
275433d6423SLionel Sambuc state.transid = transid;
276433d6423SLionel Sambuc state.valid = VALID;
277433d6423SLionel Sambuc state.vfs_avail = vfs_avail;
278433d6423SLionel Sambuc
279f202792eSDavid van Moolenbroek r = handle_memory_step(&state, FALSE /*retry*/);
280433d6423SLionel Sambuc
281433d6423SLionel Sambuc if(r == SUSPEND) {
282433d6423SLionel Sambuc assert(caller != NONE);
283433d6423SLionel Sambuc assert(vfs_avail);
284433d6423SLionel Sambuc } else {
285433d6423SLionel Sambuc handle_memory_final(&state, r);
286433d6423SLionel Sambuc }
287433d6423SLionel Sambuc
288433d6423SLionel Sambuc return r;
289433d6423SLionel Sambuc }
290433d6423SLionel Sambuc
291433d6423SLionel Sambuc /*===========================================================================*
292433d6423SLionel Sambuc * do_memory *
293433d6423SLionel Sambuc *===========================================================================*/
do_memory(void)294433d6423SLionel Sambuc void do_memory(void)
295433d6423SLionel Sambuc {
296433d6423SLionel Sambuc endpoint_t who, who_s, requestor;
297433d6423SLionel Sambuc vir_bytes mem, mem_s;
298433d6423SLionel Sambuc vir_bytes len;
299433d6423SLionel Sambuc int wrflag;
300433d6423SLionel Sambuc
301433d6423SLionel Sambuc while(1) {
302433d6423SLionel Sambuc int p, r = OK;
303433d6423SLionel Sambuc struct vmproc *vmp;
304433d6423SLionel Sambuc
305433d6423SLionel Sambuc r = sys_vmctl_get_memreq(&who, &mem, &len, &wrflag, &who_s,
306433d6423SLionel Sambuc &mem_s, &requestor);
307433d6423SLionel Sambuc
308433d6423SLionel Sambuc switch(r) {
309433d6423SLionel Sambuc case VMPTYPE_CHECK:
310433d6423SLionel Sambuc {
311433d6423SLionel Sambuc int transid = 0;
312433d6423SLionel Sambuc int vfs_avail;
313433d6423SLionel Sambuc
314433d6423SLionel Sambuc if(vm_isokendpt(who, &p) != OK)
315433d6423SLionel Sambuc panic("do_memory: bad endpoint: %d", who);
316433d6423SLionel Sambuc vmp = &vmproc[p];
317433d6423SLionel Sambuc
318433d6423SLionel Sambuc assert(!IS_VFS_FS_TRANSID(transid));
319433d6423SLionel Sambuc
320433d6423SLionel Sambuc /* is VFS blocked? */
321433d6423SLionel Sambuc if(requestor == VFS_PROC_NR) vfs_avail = 0;
322433d6423SLionel Sambuc else vfs_avail = 1;
323433d6423SLionel Sambuc
324433d6423SLionel Sambuc handle_memory_start(vmp, mem, len, wrflag,
325433d6423SLionel Sambuc KERNEL, requestor, transid, vfs_avail);
326433d6423SLionel Sambuc
327433d6423SLionel Sambuc break;
328433d6423SLionel Sambuc }
329433d6423SLionel Sambuc
330433d6423SLionel Sambuc default:
331433d6423SLionel Sambuc return;
332433d6423SLionel Sambuc }
333433d6423SLionel Sambuc }
334433d6423SLionel Sambuc }
335433d6423SLionel Sambuc
handle_memory_step(struct hm_state * hmstate,int retry)336f202792eSDavid van Moolenbroek static int handle_memory_step(struct hm_state *hmstate, int retry)
337433d6423SLionel Sambuc {
338433d6423SLionel Sambuc struct vir_region *region;
339f202792eSDavid van Moolenbroek vir_bytes offset, length, sublen;
340f202792eSDavid van Moolenbroek int r;
341433d6423SLionel Sambuc
342433d6423SLionel Sambuc /* Page-align memory and length. */
343433d6423SLionel Sambuc assert(hmstate);
344433d6423SLionel Sambuc assert(hmstate->valid == VALID);
345433d6423SLionel Sambuc assert(!(hmstate->mem % VM_PAGE_SIZE));
346433d6423SLionel Sambuc assert(!(hmstate->len % VM_PAGE_SIZE));
347433d6423SLionel Sambuc
348433d6423SLionel Sambuc while(hmstate->len > 0) {
349433d6423SLionel Sambuc if(!(region = map_lookup(hmstate->vmp, hmstate->mem, NULL))) {
350433d6423SLionel Sambuc #if VERBOSE
351433d6423SLionel Sambuc map_printmap(hmstate->vmp);
352433d6423SLionel Sambuc printf("VM: do_memory: memory doesn't exist\n");
353433d6423SLionel Sambuc #endif
354433d6423SLionel Sambuc return EFAULT;
355433d6423SLionel Sambuc } else if(!(region->flags & VR_WRITABLE) && hmstate->wrflag) {
356433d6423SLionel Sambuc #if VERBOSE
357433d6423SLionel Sambuc printf("VM: do_memory: write to unwritable map\n");
358433d6423SLionel Sambuc #endif
359433d6423SLionel Sambuc return EFAULT;
360f202792eSDavid van Moolenbroek }
361f202792eSDavid van Moolenbroek
362433d6423SLionel Sambuc assert(region->vaddr <= hmstate->mem);
363433d6423SLionel Sambuc assert(!(region->vaddr % VM_PAGE_SIZE));
364433d6423SLionel Sambuc offset = hmstate->mem - region->vaddr;
365f202792eSDavid van Moolenbroek length = hmstate->len;
366f202792eSDavid van Moolenbroek if (offset + length > region->length)
367f202792eSDavid van Moolenbroek length = region->length - offset;
368433d6423SLionel Sambuc
369f202792eSDavid van Moolenbroek /*
370f202792eSDavid van Moolenbroek * Handle one page at a time. While it seems beneficial to
371f202792eSDavid van Moolenbroek * handle multiple pages in one go, the opposite is true:
372f202792eSDavid van Moolenbroek * map_handle_memory will handle one page at a time anyway, and
373f202792eSDavid van Moolenbroek * if we give it the whole range multiple times, it will have
374f202792eSDavid van Moolenbroek * to recheck pages it already handled. In addition, in order
375f202792eSDavid van Moolenbroek * to handle one-shot pages, we need to know whether we are
376f202792eSDavid van Moolenbroek * retrying a single page, and that is not possible if this is
377f202792eSDavid van Moolenbroek * hidden in map_handle_memory.
378f202792eSDavid van Moolenbroek */
379f202792eSDavid van Moolenbroek while (length > 0) {
380f202792eSDavid van Moolenbroek sublen = VM_PAGE_SIZE;
381f202792eSDavid van Moolenbroek
382f202792eSDavid van Moolenbroek assert(sublen <= length);
383f202792eSDavid van Moolenbroek assert(offset + sublen <= region->length);
384f202792eSDavid van Moolenbroek
385f202792eSDavid van Moolenbroek /*
386f202792eSDavid van Moolenbroek * Upon the second try for this range, do not allow
387f202792eSDavid van Moolenbroek * calling into VFS again. This prevents eternal loops
388f202792eSDavid van Moolenbroek * in case the FS messes up, and allows one-shot pages
389f202792eSDavid van Moolenbroek * to be mapped in on the second call.
390f202792eSDavid van Moolenbroek */
391433d6423SLionel Sambuc if((region->def_memtype == &mem_type_mappedfile &&
392f202792eSDavid van Moolenbroek (!hmstate->vfs_avail || retry)) ||
393f202792eSDavid van Moolenbroek hmstate->caller == NONE) {
394f202792eSDavid van Moolenbroek r = map_handle_memory(hmstate->vmp, region,
395f202792eSDavid van Moolenbroek offset, sublen, hmstate->wrflag, NULL,
396f202792eSDavid van Moolenbroek NULL, 0);
397433d6423SLionel Sambuc assert(r != SUSPEND);
398433d6423SLionel Sambuc } else {
399f202792eSDavid van Moolenbroek r = map_handle_memory(hmstate->vmp, region,
400f202792eSDavid van Moolenbroek offset, sublen, hmstate->wrflag,
401f202792eSDavid van Moolenbroek handle_memory_continue, hmstate,
402f202792eSDavid van Moolenbroek sizeof(*hmstate));
403433d6423SLionel Sambuc }
404433d6423SLionel Sambuc
405433d6423SLionel Sambuc if(r != OK) return r;
406433d6423SLionel Sambuc
407433d6423SLionel Sambuc hmstate->len -= sublen;
408433d6423SLionel Sambuc hmstate->mem += sublen;
409f202792eSDavid van Moolenbroek
410f202792eSDavid van Moolenbroek offset += sublen;
411f202792eSDavid van Moolenbroek length -= sublen;
412f202792eSDavid van Moolenbroek retry = FALSE;
413433d6423SLionel Sambuc }
414433d6423SLionel Sambuc }
415433d6423SLionel Sambuc
416433d6423SLionel Sambuc return OK;
417433d6423SLionel Sambuc }
418433d6423SLionel Sambuc
419