1/*
2 * Copyright 2016, Data61
3 * Commonwealth Scientific and Industrial Research Organisation (CSIRO)
4 * ABN 41 687 119 230.
5 *
6 * This software may be distributed and modified according to the terms of
7 * the BSD 2-Clause license. Note that NO WARRANTY is provided.
8 * See "LICENSE_BSD2.txt" for details.
9 *
10 * @TAG(D61_BSD)
11 */
12
13#include "../../common.h"
14#include "../../state.h"
15#include "vspace.h"
16#include "../memserv/window.h"
17#include "../process/pid.h"
18#include "../process/process.h"
19#include <autoconf.h>
20#include <refos/refos.h>
21#include <sel4utils/vspace.h>
22
23/*! @file
24    @brief Client address space objects. */
25
26#define VSPACE_WINDOW_VERBOSE_DEBUG true
27
28/* -------------------- VSpace Helper Library Callback Functions ---------------------------------*/
29
30static void
31vs_vspace_allocated_object_bookkeeping_callback(void *allocated_object_cookie, vka_object_t object)
32{
33    struct vs_vspace *vs = (struct vs_vspace *) allocated_object_cookie;
34    assert(vs && vs->magic == REFOS_VSPACE_MAGIC);
35
36    /* Create our own copy of this allocated object struct. */
37    vka_object_t *kobj = kmalloc(sizeof(vka_object_t));
38    if (!kobj) {
39        ROS_WARNING("Could not allocate new vka_object_t to book keep vspace allocated object.");
40        ROS_WARNING("Object will be LEAKED.");
41        return;
42    }
43    memcpy(kobj, &object, sizeof(vka_object_t));
44
45    /* Add to end of free list. */
46    cvector_add(&vs->kobjVSpaceAllocatedFreelist, (cvector_item_t) kobj);
47}
48
49
50/* ---------------------------------- VSpace struct ----------------------------------------------*/
51
52int
53vs_initialise(struct vs_vspace *vs, uint32_t pid)
54{
55    assert(vs);
56    dvprintf("    Initialising a vspace...\n");
57    memset(vs, 0, sizeof(*vs));
58    int error = ESUCCESS;
59
60    vs->magic = REFOS_VSPACE_MAGIC;
61    vs->ref = 1;
62    vs->pid = pid;
63
64    /* Initialise the free list vector. */
65    cvector_init(&vs->kobjVSpaceAllocatedFreelist);
66
67    /* Initialise window association list. */
68    w_associate_init(&vs->windows);
69
70    /* Assign a kernel page directory. */
71    dvprintf("        Assigning new kernel page directory objects...\n");
72    struct pd_info pdi = pd_assign(&procServ.PDList);
73    if (!pdi.kpdObject | !pdi.kcnodeObject) {
74        ROS_ERROR("Failed to allocate page directory for new process.");
75        error = ENOMEM;
76        goto exit1;
77    }
78    vs->kpd = pdi.kpdObject;
79
80    /* Create the CSpace path associated with this address space's root CNode. */
81    cspacepath_t pathTemp;
82    vs->cspaceUnguarded = pdi.kcnodeObject;
83    vs->cspaceSize = REFOS_CSPACE_RADIX;
84    vka_cspace_make_path(&procServ.vka, vs->cspaceUnguarded, &pathTemp);
85
86    /* Mint a guarded cspace from the created cspace. */
87    dvprintf("        Allocating cslot for guarded cspace...\n");
88    error = vka_cspace_alloc_path(&procServ.vka, &vs->cspace);
89    if (error) {
90        ROS_ERROR("Failed to allocate guarded cspace cslot: error %d\n", error);
91        error = ENOMEM;
92        goto exit2;
93    }
94
95    dvprintf("        Minting guarded cspace...\n");
96    vs->cspaceGuardData = seL4_CapData_Guard_new(0, REFOS_CSPACE_GUARD);
97    error = vka_cnode_mint(&vs->cspace, &pathTemp, seL4_AllRights, vs->cspaceGuardData);
98    assert(error == seL4_NoError);
99    (void) error;
100
101    /* Self-reference so the thread knows about its own cspace. */
102    dvprintf("        Copying self-reference cap into REFOS_CSPACE cslot...\n");
103    error = seL4_CNode_Copy(
104            vs->cspace.capPtr, REFOS_CSPACE, REFOS_CDEPTH,
105            vs->cspace.root, vs->cspace.capPtr, vs->cspace.capDepth,
106            seL4_AllRights
107    );
108    if (error) {
109        ROS_ERROR("Could not copy self reference cspace cap: error %d\n", error);
110        error = EINVALID;
111        goto exit3;
112    }
113
114    /* Create a vspace object to keep reservations book-keeping. */
115    dvprintf("        Initialising child sel4utils vspace struct...\n");
116    error = sel4utils_get_vspace (
117            &procServ.vspace, &vs->vspace, &vs->vspaceData,
118            &procServ.vka, vs->kpd,
119            vs_vspace_allocated_object_bookkeeping_callback, (void*) vs
120    );
121    if (error) {
122        ROS_ERROR("Failed to initialise sel4utils vspace struct: %d\n", error);
123        error = ENOMEM;
124        goto exit3;
125    }
126
127    dvprintf("        VSpace setup OK, new vspace is ready to go.\n");
128    return ESUCCESS;
129
130    /* Exit stack. */
131exit3:
132    vka_cnode_delete(&vs->cspace);
133    vka_cspace_free(&procServ.vka, vs->cspace.capPtr);
134exit2:
135    vka_cnode_revoke(&pathTemp);
136    pd_free(&procServ.PDList, vs->kpd);
137exit1:
138    return error;
139}
140
141static void
142vs_release(struct vs_vspace *vs)
143{
144    assert(vs && vs->magic == REFOS_VSPACE_MAGIC);
145    assert(vs->magic == REFOS_VSPACE_MAGIC);
146    assert(vs->ref == 0);
147    dvprintf("     Releasing VSpace PID %d...\n", vs->pid);
148    cspacepath_t pathTemp;
149
150    /* Clear the associated windows list. */
151    dvprintf("         Clearing VSpace associated window list...\n");
152    for (int i = 0; i < vs->windows.numIndex; i++) {
153        vs_unmap_window(vs, vs->windows.associated[i].winID);
154    }
155    w_associate_release_associated_all_windows(&procServ.windowList, &vs->windows);
156
157    /* Free the allocated vspace book-keeping objects. */
158    dvprintf("         Releasing VSpace list of vspace bookkeeping kobjs...\n");
159    int c = cvector_count(&vs->kobjVSpaceAllocatedFreelist);
160    for (int i = 0; i < c; i++) {
161        vka_object_t *kobj = (vka_object_t *) cvector_get(&vs->kobjVSpaceAllocatedFreelist, i);
162        assert(kobj);
163        vka_cspace_make_path(&procServ.vka, kobj->cptr, &pathTemp);
164        vka_cnode_revoke(&pathTemp);
165        vka_cnode_delete(&pathTemp);
166        vka_free_object(&procServ.vka, kobj);
167        kfree(kobj);
168        cvector_set(&vs->kobjVSpaceAllocatedFreelist, i, (cvector_item_t) NULL);
169    }
170    cvector_reset(&vs->kobjVSpaceAllocatedFreelist);
171
172    /* Teardown the vspace. */
173    vspace_tear_down(&vs->vspace, VSPACE_FREE);
174
175    /* Free the allocated kernel objects. */
176    dvprintf("         Releasing VSpace kobjs...\n");
177    vka_cnode_revoke(&vs->cspace);
178    vka_cnode_delete(&vs->cspace);
179    vka_cspace_free(&procServ.vka, vs->cspace.capPtr);
180
181    /* Note the unguarded original CNode capability belongs to the PD, we don't have ownership of
182       that. pd_free here will release it back into the pool to be reused. */
183    dvprintf("         Releasing PD kobjs...\n");
184    pd_free(&procServ.PDList, vs->kpd);
185    memset(vs, 0, sizeof(struct vs_vspace));
186}
187
188void
189vs_ref(struct vs_vspace *vs)
190{
191    assert(vs && vs->magic == REFOS_VSPACE_MAGIC);
192    vs->ref++;
193}
194
195void
196vs_unref(struct vs_vspace *vs)
197{
198    assert(vs && vs->magic == REFOS_VSPACE_MAGIC);
199    vs->ref--;
200    if (vs->ref <= 0) {
201        /* Release this vspace. */
202        vs_release(vs);
203    }
204}
205
206void
207vs_track_obj(struct vs_vspace *vs, vka_object_t object)
208{
209    assert(vs && vs->magic == REFOS_VSPACE_MAGIC);
210    vs_vspace_allocated_object_bookkeeping_callback((void *)vs, object);;
211}
212/* ---------------------------------- VSpace windows ---------------------------------------------*/
213
214int
215vs_create_window(struct vs_vspace *vs, vaddr_t vaddr, vaddr_t size, seL4_Word permissions,
216                 bool cacheable, int *winID)
217{
218    assert(vs && vs->magic == REFOS_VSPACE_MAGIC);
219    assert(winID != NULL);
220    *winID = W_INVALID_WINID;
221    int error = EINVALID;
222
223    /* Check the window segment with window association list for any conflicts. */
224    if (w_associate_check(&vs->windows, vaddr, size) == false) {
225        dvprintf("memory window overlaps with another one.\n");
226
227        #if VSPACE_WINDOW_VERBOSE_DEBUG
228        dvprintf("������������������������������������������������������������������������������ Detailed Report ������������������������������������������������������������������������\n");
229        dvprintf("attempted to create window 0x%x ��������� 0x%x.\n", vaddr, vaddr + size);
230        w_associate_print(&vs->windows);
231        dvprintf("���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������\n");
232        #endif
233
234        return EINVALIDWINDOW;
235    }
236
237    /* Create the seL4 vspace reservation. */
238    reservation_t r = vspace_reserve_range_at(&vs->vspace, (void*) vaddr, (size_t) size,
239            w_convert_permission_to_caprights(permissions), cacheable);
240    if (r.res == NULL) {
241        dvprintf("vspace reservation failed.\n");
242        return EINVALIDWINDOW;
243    }
244
245    /* Add to global window list. */
246    struct w_window *window = w_create_window(&procServ.windowList, size, vs->pid,
247                                              permissions, &vs->vspace, r, cacheable);
248    if (!window) {
249        ROS_ERROR("window creation failed.\n");
250        error = ENOMEM;
251        goto exit0;
252    }
253    assert(window->wID != W_INVALID_WINID);
254
255    /* Now associate the window. */
256    error = w_associate(&vs->windows, window->wID, vaddr, size);
257    if (error) {
258        ROS_ERROR("Window associate failed.");
259        assert(!"Window associate failed even after check. This is likely a bug.");
260        error = EINVALID;
261        goto exit1;
262    }
263
264    *winID = window->wID;
265    return ESUCCESS;
266
267    /* Exit stack. */
268exit1:
269    /* Note that ownership of reservation is transferred to window. */
270    w_delete_window(&procServ.windowList, window->wID);
271    return error;
272exit0:
273    vspace_free_reservation(&vs->vspace, r);
274    return error;
275}
276
277void
278vs_delete_window(struct vs_vspace *vs, int wID)
279{
280    assert(vs && vs->magic == REFOS_VSPACE_MAGIC);
281
282    /* Find the associated window. */
283    struct w_associated_window *awindow = w_associate_find_winID(&vs->windows, wID);
284    if (!awindow || awindow->winID != wID) {
285        ROS_WARNING("vs_delete_window: no such window exists.");
286        return;
287    }
288
289    /* Unmap everything in the associated window. */
290    vs_unmap_window(vs, wID);
291
292    /* Unassociate this window. */
293    w_unassociate(&vs->windows, wID);
294
295    /* Delete the window from the global window list. */
296    int error = w_delete_window(&procServ.windowList, wID);
297    assert(error == ESUCCESS);
298    (void) error;
299}
300
301int
302vs_resize_window(struct vs_vspace *vs, int wID, vaddr_t size)
303{
304    assert(vs && vs->magic == REFOS_VSPACE_MAGIC);
305    if (!size) {
306        return EINVALIDPARAM;
307    }
308
309    /* Find the associated window. */
310    struct w_associated_window *awindow = w_associate_find_winID(&vs->windows, wID);
311    if (!awindow || awindow->winID != wID) {
312        ROS_WARNING("vs_resize_window: no such window assoc exists.");
313        return EINVALIDWINDOW;
314    }
315
316    /* Find the global window structure. */
317    struct w_window* window = w_get_window(&procServ.windowList, wID);
318    if (!window) {
319        ROS_WARNING("vs_resize_window: no such window exists.");
320        return EINVALIDWINDOW;
321    }
322    assert(awindow->offset == (vaddr_t) reservation_to_res(window->reservation)->start);
323
324    if (size > awindow->size) {
325        /* If the new size is larger, we need to check the new portion of the window. */
326        vaddr_t sizeIncrease = size - awindow->size;
327        if (!w_associate_check(&vs->windows, awindow->offset + awindow->size, sizeIncrease)) {
328            dvprintf("memory window resize fail: overlaps another window.\n");
329
330            #if VSPACE_WINDOW_VERBOSE_DEBUG
331            dvprintf("������������������������������������������������������������������������������ Detailed Report ������������������������������������������������������������������������\n");
332            dvprintf("attempted to resize window 0x%x ��������� 0x%x to 0x%x.\n", awindow->offset,
333                    awindow->offset + awindow->size, awindow->offset + size);
334            w_associate_print(&vs->windows);
335            dvprintf("���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������\n");
336            #endif
337
338            return EINVALIDPARAM;
339        }
340    } else if (size < awindow->size) {
341        /* If new size is smaller, we need to unmap. */
342        vaddr_t sizeDecrease = awindow->size - size;
343        int npages = (sizeDecrease / REFOS_PAGE_SIZE) + ((sizeDecrease % REFOS_PAGE_SIZE) ? 1 : 0);
344        int error = vs_unmap(vs, REFOS_PAGE_ALIGN(awindow->offset + size), npages);
345        if (error) {
346            ROS_WARNING("vs_resize_window: failed to map window.");
347            return error;
348        }
349    }
350
351    /* Actually perform the window resize. This will also update the vspace reservation. */
352    int error = w_resize_window(window, awindow->offset, size);
353    if (error) {
354        ROS_WARNING("vs_resize_window: failed to resize window. Shouldn't happen.");
355        return error;
356    }
357
358    awindow->size = size;
359    return ESUCCESS;
360}
361
362/* ---------------------------------- VSpace mapping ---------------------------------------------*/
363
364int
365vs_map(struct vs_vspace *vs, vaddr_t vaddr, seL4_CPtr frames[], int nFrames)
366{
367    assert(vs && vs->magic == REFOS_VSPACE_MAGIC);
368    int error = EINVALID;
369    vaddr = REFOS_PAGE_ALIGN(vaddr);
370
371    /* Check the window association to make sure there exists a window there. */
372    struct w_associated_window *awindow = w_associate_find_range(&vs->windows, vaddr,
373            nFrames * REFOS_PAGE_SIZE);
374    if (!awindow) {
375        dvprintf("could not find window association.\n");
376
377        #if VSPACE_WINDOW_VERBOSE_DEBUG
378        dvprintf("������������������������������������������������������������������������������ Detailed Report ������������������������������������������������������������������������\n");
379        dvprintf("attempted to map vaddr range 0x%x ��������� 0x%x.\n", vaddr,
380                vaddr + nFrames * REFOS_PAGE_SIZE);
381        w_associate_print(&vs->windows);
382        dvprintf("���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������\n");
383        #endif
384
385        return EINVALIDWINDOW;
386    }
387
388    /* Retrieve the window structure. */
389    struct w_window* window = w_get_window(&procServ.windowList, awindow->winID);
390    if (!window) {
391        dvprintf("could not find window.\n");
392        assert(!"window book keeping bug. Should not happen.");
393        return EINVALIDWINDOW;
394    }
395    assert(window->vspace == &vs->vspace);
396
397    /* Check that every frame in the region is unmapped. */
398    vaddr = REFOS_PAGE_ALIGN(vaddr);
399    for (vaddr_t va = 0; va < nFrames; va++) {
400        seL4_CPtr existingFrame = vspace_get_cap(&vs->vspace,
401                (void*) (vaddr + va * REFOS_PAGE_SIZE));
402        if (existingFrame) {
403            /* There's already mapped frame here. */
404            return EUNMAPFIRST;
405        }
406    }
407
408    /* Make a copy of every cap given. */
409    seL4_CPtr* frameCopy = malloc(sizeof(seL4_CPtr) * nFrames);
410    if (!frameCopy) {
411        ROS_ERROR("Could not allocate frame copy array, procserv out of memory.\n");
412        return ENOMEM;
413    }
414    memset(frameCopy, 0, sizeof(seL4_CPtr) * nFrames);
415    for (int i = 0; i < nFrames; i++) {
416        vka_cspace_alloc(&procServ.vka, &frameCopy[i]);
417        if (!frameCopy[i]) {
418            ROS_ERROR("Could not allocate cspace to copy array.\n");
419            error = ENOMEM;
420            goto exit1;
421        }
422        cspacepath_t pathDest, pathSrc;
423        vka_cspace_make_path(&procServ.vka, frameCopy[i], &pathDest);
424        vka_cspace_make_path(&procServ.vka, frames[i], &pathSrc);
425        vka_cnode_copy(&pathDest, &pathSrc, seL4_AllRights);
426    }
427
428    /* Map pages at the vspace reservation. */
429    error = vspace_map_pages_at_vaddr(&vs->vspace, frameCopy, NULL, (void*) vaddr, nFrames,
430                                          seL4_PageBits, window->reservation);
431    if (error) {
432        dvprintf("could not map pages into vaddr 0x%x. error: %d\n", (uint32_t) vaddr, error);
433        error = EUNMAPFIRST;
434        goto exit1;
435    }
436
437    /* Flush the page caches. */
438    procserv_flush(frameCopy, nFrames);
439
440    dvprintf("mapping vaddr 0x%x OK.\n", (uint32_t) vaddr);
441    free(frameCopy);
442    return ESUCCESS;
443
444    /* Exit stack. */
445exit1:
446    for (int i = 0; i < nFrames; i++) {
447        if (frameCopy[i]) {
448            cspacepath_t path;
449            vka_cspace_make_path(&procServ.vka, frameCopy[i], &path);
450            vka_cnode_revoke(&path);
451            vka_cnode_delete(&path);
452            vka_cspace_free(&procServ.vka, frameCopy[i]);
453        }
454    }
455    free(frameCopy);
456    return error;
457}
458
459int
460vs_map_across_vspace(struct vs_vspace *vsSrc, vaddr_t vaddrSrc, struct w_window *windowDest,
461                     uint32_t windowDestOffset, struct proc_pcb **outClientPCB)
462{
463    assert(vsSrc && vsSrc->magic == REFOS_VSPACE_MAGIC);
464    assert(windowDest && windowDest->magic == W_MAGIC);
465
466    /* Find the cap in the source vspace's pagetable. */
467    seL4_CPtr frameCap = vspace_get_cap(&vsSrc->vspace, (void*) vaddrSrc);
468    if (!frameCap) {
469        dvprintf("vs_map_across_vspace could not find source frame.\n");
470        return EINVALIDPARAM;
471    }
472
473    /* Verify that the offset is within the window limits. */
474    if (windowDestOffset >= windowDest->size) {
475        ROS_ERROR("invalid window offset address!\n");
476        return EINVALIDPARAM;
477    }
478
479    /* Find the client which this window lives in. */
480    struct proc_pcb *clientPCB = pid_get_pcb(&procServ.PIDList, windowDest->clientOwnerPID);
481    if (!clientPCB) {
482        ROS_ERROR("could not find window's corresponding client.\n");
483        return EINVALIDWINDOW;
484    }
485    if (outClientPCB) {
486        (*outClientPCB) = clientPCB;
487    }
488
489    /* Check that this client actually has its own window mapped. */
490    struct w_associated_window *wa = w_associate_find_winID(&clientPCB->vspace.windows,
491                                                            windowDest->wID);
492    if (!wa) {
493        ROS_ERROR("client did not map its window, so invalid map call.\n");
494        return EINVALIDWINDOW;
495    }
496
497    return vs_map(&clientPCB->vspace, wa->offset + windowDestOffset, &frameCap, 1);
498}
499
500int
501vs_map_device(struct vs_vspace *vs, struct w_window *window, uint32_t windowOffset,
502              uint32_t paddr , uint32_t size, bool cached)
503{
504    assert(vs && vs->magic == REFOS_VSPACE_MAGIC);
505    assert(window && window->magic == W_MAGIC);
506
507    if (size != REFOS_PAGE_SIZE) {
508        ROS_WARNING("Large device frames not supported yet.");
509        assert(!"Large device frames not implemented.");
510        return EUNIMPLEMENTED;
511    }
512
513    /* Verify that the offset is within the window limits. */
514    if (windowOffset + size > window->size) {
515        ROS_ERROR("invalid window offset address!\n");
516        return EINVALIDPARAM;
517    }
518
519    /* Check that this client actually has its own window mapped. */
520    struct proc_pcb* clientPCB = pid_get_pcb(&procServ.PIDList, window->clientOwnerPID);
521    if (!clientPCB) {
522        ROS_ERROR("invalid window owner!\n");
523        return EINVALID;
524    }
525    assert(clientPCB->magic == REFOS_PCB_MAGIC);
526    if (&clientPCB->vspace != vs) {
527        return EACCESSDENIED;
528    }
529    struct w_associated_window *wa = w_associate_find_winID(&clientPCB->vspace.windows,
530                                                            window->wID);
531    if (!wa) {
532        ROS_ERROR("client did not map its window, so invalid map call.\n");
533        return EINVALIDWINDOW;
534    }
535
536    /* Check window cacheable state matches with requested cached state. */
537    if (cached != window->cacheable) {
538        ROS_WARNING("Window cachable and frame cache request mismatch. Access denied.");
539        return EACCESSDENIED;
540    }
541
542    /* Find the device cap. */
543    cspacepath_t deviceFrame = procserv_find_device((void*) paddr, size);
544    if (deviceFrame.capPtr == 0) {
545        ROS_WARNING("No such device.");
546        return EFILENOTFOUND;
547    }
548    dvprintf("Device 0x%x found at cslot 0x%x...\n", paddr, deviceFrame.capPtr);
549
550    /* Map the device frame. */
551    vaddr_t vaddr = wa->offset + windowOffset;
552    int error = vs_map(vs, vaddr, &deviceFrame.capPtr, 1);
553    if (error != ESUCCESS) {
554        ROS_WARNING("Failed to map device.");
555        return error;
556    }
557
558    vka_cnode_delete(&deviceFrame);
559    vka_cspace_free(&procServ.vka, deviceFrame.capPtr);
560    return ESUCCESS;
561}
562
563static void
564vs_unmap_frame(struct vs_vspace *vs, vaddr_t vaddr)
565{
566    assert(vs && vs->magic == REFOS_VSPACE_MAGIC);
567
568    /* Find the cap in the vspace's pagetable. */
569    seL4_CPtr frameCap = vspace_get_cap(&vs->vspace, (void*) vaddr);
570    if (!frameCap) {
571        return;
572    }
573
574    /* Unmap the page & clear the pagetable entries. */
575    vspace_unmap_pages(&vs->vspace, (void*) vaddr, 1, seL4_PageBits, VSPACE_PRESERVE);
576
577    /* Revoke and delete the cap. */
578    cspacepath_t path;
579    vka_cspace_make_path(&procServ.vka, frameCap, &path);
580    vka_cnode_revoke(&path);
581    vka_cnode_delete(&path);
582    vka_cspace_free(&procServ.vka, frameCap);
583
584    dvprintf("vs_unmap_frame 0x%x OK.\n", (uint32_t) vaddr);
585}
586
587int
588vs_unmap(struct vs_vspace *vs, vaddr_t vaddr, int nFrames)
589{
590    assert(vs && vs->magic == REFOS_VSPACE_MAGIC);
591
592    /* Check the window association to make sure there exists a window there. */
593    struct w_associated_window *awindow = w_associate_find_range(&vs->windows, vaddr,
594            nFrames * REFOS_PAGE_SIZE);
595    if (!awindow) {
596        dvprintf("could not find window association for vaddr 0x%x.\n", (uint32_t) vaddr);
597        return EINVALIDWINDOW;
598    }
599
600    /* Retrieve the window structure. */
601    struct w_window* window = w_get_window(&procServ.windowList, awindow->winID);
602    if (!window) {
603        dvprintf("could not find window.\n");
604        assert(!"window book keeping bug. Should not happen.");
605        return EINVALIDWINDOW;
606    }
607    assert(window->vspace == &vs->vspace);
608
609    /* Unmap pages in vspace. */
610    for (vaddr_t va = 0; va < nFrames; va++) {
611        vs_unmap_frame(vs, vaddr + va * REFOS_PAGE_SIZE);
612    }
613    return ESUCCESS;
614}
615
616void
617vs_unmap_window(struct vs_vspace *vs, int wID)
618{
619    assert(vs && vs->magic == REFOS_VSPACE_MAGIC);
620
621    /* Find the associated window. */
622    struct w_associated_window *awindow = w_associate_find_winID(&vs->windows, wID);
623    if (!awindow || awindow->winID != wID) {
624        return;
625    }
626
627    /* Retrieve the window structure. */
628    struct w_window* window = w_get_window(&procServ.windowList, awindow->winID);
629    if (!window) {
630        dvprintf("could not find window.\n");
631        assert(!"window book keeping bug. Should not happen.");
632        return;
633    }
634    assert(window->vspace == &vs->vspace);
635
636    /* Unmap everything in the associated window. */
637    int nFrames = (awindow->size / REFOS_PAGE_SIZE) + ((awindow->size % REFOS_PAGE_SIZE) ? 1 : 0);
638    for (vaddr_t va = 0; va < nFrames; va++) {
639        vs_unmap_frame(vs, awindow->offset + va * REFOS_PAGE_SIZE);
640    }
641}
642
643cspacepath_t
644vs_get_frame(struct vs_vspace *vs, vaddr_t vaddr)
645{
646    assert(vs && vs->magic == REFOS_VSPACE_MAGIC);
647    cspacepath_t path;
648    memset(&path, 0, sizeof(cspacepath_t));
649    seL4_CPtr frameCap = vspace_get_cap(&vs->vspace, (void*) vaddr);
650    vka_cspace_make_path(&procServ.vka, frameCap, &path);
651    return path;
652}
653