OpenCores
URL https://opencores.org/ocsvn/c0or1k/c0or1k/trunk

Subversion Repositories c0or1k

[/] [c0or1k/] [trunk/] [conts/] [posix/] [mm0/] [mm/] [pagers.c] - Blame information for rev 2

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 2 drasko
/*
2
 * Copyright (C) 2008 Bahadir Balban
3
 */
4
#include <l4/macros.h>
5
#include <l4/lib/list.h>
6
#include L4LIB_INC_ARCH(syscalls.h)
7
#include L4LIB_INC_ARCH(syslib.h)
8
#include <malloc/malloc.h>
9
#include <mm/alloc_page.h>
10
#include <vm_area.h>
11
#include <string.h>
12
#include <globals.h>
13
#include <file.h>
14
#include <init.h>
15
#include <l4/api/errno.h>
16
#include <fs.h>
17
 
18
struct page *page_init(struct page *page)
19
{
20
        /* Reset page */
21
        memset(page, 0, sizeof(*page));
22
        page->refcnt = -1;
23
        spin_lock_init(&page->lock);
24
        link_init(&page->list);
25
 
26
        return page;
27
}
28
 
29
struct page *find_page(struct vm_object *obj, unsigned long pfn)
30
{
31
        struct page *p;
32
 
33
        list_foreach_struct(p, &obj->page_cache, list)
34
                if (p->offset == pfn)
35
                        return p;
36
 
37
        return 0;
38
}
39
 
40
/*
41
 * Deletes all pages in a page cache, assumes pages are from the
42
 * page allocator, and page structs are from the page_array, which
43
 * is the default situation.
44
 */
45
int default_release_pages(struct vm_object *vm_obj)
46
{
47
        struct page *p, *n;
48
 
49
        list_foreach_removable_struct(p, n, &vm_obj->page_cache, list) {
50
                list_remove_init(&p->list);
51
                BUG_ON(p->refcnt);
52
 
53
                /* Reinitialise the page */
54
                page_init(p);
55
 
56
                /* Return page back to allocator */
57
                free_page((void *)page_to_phys(p));
58
 
59
                /* Reduce object page count */
60
                BUG_ON(--vm_obj->npages < 0);
61
        }
62
        return 0;
63
}
64
 
65
int file_page_out(struct vm_object *vm_obj, unsigned long page_offset)
66
{
67
        struct vm_file *f = vm_object_to_file(vm_obj);
68
        struct page *page;
69
        void *paddr;
70
        int err;
71
 
72
        /* Check first if the file has such a page at all */
73
        if (__pfn(page_align_up(f->length) <= page_offset)) {
74
                printf("%s: %s: Trying to look up page %lu, but file length "
75
                       "is %lu bytes.\n", __TASKNAME__, __FUNCTION__,
76
                       page_offset, f->length);
77
                BUG();
78
        }
79
 
80
        /* If the page is not in the page cache, simply return. */
81
        if (!(page = find_page(vm_obj, page_offset)))
82
                return 0;
83
 
84
        /* If the page is not dirty, simply return */
85
        if (!(page->flags & VM_DIRTY))
86
                return 0;
87
 
88
        paddr = (void *)page_to_phys(page);
89
 
90
        //printf("%s/%s: Writing to vnode %lu, at pgoff 0x%lu, %d pages, buf at %p\n",
91
        //      __TASKNAME__, __FUNCTION__, f->vnode->vnum, page_offset, 1, vaddr);
92
 
93
        /* Syscall to vfs to write page back to file. */
94
        if ((err = vfs_write(f->vnode, page_offset, 1,
95
                             phys_to_virt(paddr))) < 0)
96
                return err;
97
 
98
        /* Clear dirty flag */
99
        page->flags &= ~VM_DIRTY;
100
 
101
        return 0;
102
}
103
 
104
struct page *file_page_in(struct vm_object *vm_obj, unsigned long page_offset)
105
{
106
        struct vm_file *f = vm_object_to_file(vm_obj);
107
        struct page *page;
108
        void *paddr;
109
        int err;
110
 
111
        /* Check first if the file has such a page at all */
112
        if (__pfn(page_align_up(f->length) <= page_offset)) {
113
                printf("%s: %s: Trying to look up page %lu, but file length "
114
                       "is %lu bytes.\n", __TASKNAME__, __FUNCTION__,
115
                       page_offset, f->length);
116
                BUG();
117
        }
118
 
119
        /* Call vfs only if the page is not resident in page cache. */
120
        if (!(page = find_page(vm_obj, page_offset))) {
121
                /* Allocate a new page */
122
                paddr = alloc_page(1);
123
                page = phys_to_page(paddr);
124
 
125
                /* Call to vfs to read into the page. */
126
                if ((err = vfs_read(f->vnode, page_offset,
127
                                    1, phys_to_virt(paddr))) < 0) {
128
 
129
                        free_page(paddr);
130
                        return PTR_ERR(err);
131
                }
132
 
133
        //      printf("%s/%s: Reading into vnode %lu, at pgoff 0x%lu, %d pages, buf at %p\n",
134
        //             __TASKNAME__, __FUNCTION__, f->vnode->vnum, page_offset, 1, vaddr);
135
 
136
                /* Update vm object details */
137
                vm_obj->npages++;
138
 
139
                /* Update page details */
140
                page_init(page);
141
                page->refcnt++;
142
                page->owner = vm_obj;
143
                page->offset = page_offset;
144
                page->virtual = 0;
145
 
146
                /* Add the page to owner's list of in-memory pages */
147
                BUG_ON(!list_empty(&page->list));
148
                insert_page_olist(page, vm_obj);
149
        }
150
 
151
        return page;
152
}
153
 
154
/*
155
 * All non-mmapable char devices are handled by this.
156
 * VFS calls those devices to read their pages
157
 */
158
struct vm_pager file_pager = {
159
        .ops = {
160
                .page_in = file_page_in,
161
                .page_out = file_page_out,
162
                .release_pages = default_release_pages,
163
        },
164
};
165
 
166
 
167
/* A proposal for shadow vma container, could be part of vm_file->priv_data */
168
struct vm_swap_node {
169
        struct vm_file *swap_file;
170
        struct task_ids task_ids;
171
        struct address_pool *pool;
172
};
173
 
174
/*
175
 * This should save swap_node/page information either in the pte or in a global
176
 * list of swap descriptors, and then write the page into the possibly one and
177
 * only swap file.
178
 */
179
struct page *swap_page_in(struct vm_object *vm_obj, unsigned long file_offset)
180
{
181
        struct page *p;
182
 
183
        /* No swapping yet, so the page is either here or not here. */
184
        if (!(p = find_page(vm_obj, file_offset)))
185
                return PTR_ERR(-EINVAL);
186
        else
187
                return p;
188
}
189
 
190
struct vm_pager swap_pager = {
191
        .ops = {
192
                .page_in = swap_page_in,
193
                .release_pages = default_release_pages,
194
        },
195
};
196
 
197
/*
198
 * Just releases the page structures since the actual pages are
199
 * already in memory as read-only.
200
 */
201
int bootfile_release_pages(struct vm_object *vm_obj)
202
{
203
        struct page *p, *n;
204
 
205
        list_foreach_removable_struct(p, n, &vm_obj->page_cache, list) {
206
                list_remove(&p->list);
207
                BUG_ON(p->refcnt);
208
 
209
                /* Reinitialise the page */
210
                page_init(p);
211
 
212
                /*
213
                 * We don't free the page because it doesn't
214
                 * come from the page allocator
215
                 */
216
                // free_page((void *)page_to_phys(p));
217
 
218
 
219
                /* Reduce object page count */
220
                BUG_ON(--vm_obj->npages < 0);
221
        }
222
        return 0;
223
}
224
 
225
#if 0
226
/* Returns the page with given offset in this vm_object */
227
struct page *bootfile_page_in(struct vm_object *vm_obj,
228
                              unsigned long offset)
229
{
230
        struct vm_file *boot_file = vm_object_to_file(vm_obj);
231
        struct svc_image *img = boot_file->priv_data;
232
        struct page *page;
233
 
234
        /* Check first if the file has such a page at all */
235
        if (__pfn(page_align_up(boot_file->length) <= offset)) {
236
                printf("%s: %s: Trying to look up page %lu, but file length "
237
                       "is %lu bytes.\n", __TASKNAME__, __FUNCTION__,
238
                       offset, boot_file->length);
239
                BUG();
240
        }
241
 
242
        /* The page is not resident in page cache. */
243
        if (!(page = find_page(vm_obj, offset))) {
244
                page = phys_to_page(img->phys_start + __pfn_to_addr(offset));
245
 
246
                /* Update page */
247
                page_init(page);
248
                page->refcnt++;
249
                page->owner = vm_obj;
250
                page->offset = offset;
251
 
252
                /* Update object */
253
                vm_obj->npages++;
254
 
255
                /* Add the page to owner's list of in-memory pages */
256
                BUG_ON(!list_empty(&page->list));
257
                insert_page_olist(page, vm_obj);
258
        }
259
 
260
        return page;
261
}
262
 
263
struct vm_pager bootfile_pager = {
264
        .ops = {
265
                .page_in = bootfile_page_in,
266
                .release_pages = bootfile_release_pages,
267
        },
268
};
269
 
270
void bootfile_destroy_priv_data(struct vm_file *bootfile)
271
{
272
 
273
}
274
 
275
/* From bare boot images, create mappable device files */
276
int init_boot_files(struct initdata *initdata)
277
{
278
        struct bootdesc *bd = initdata->bootdesc;
279
        struct vm_file *boot_file;
280
        struct svc_image *img;
281
 
282
        link_init(&initdata->boot_file_list);
283
 
284
        for (int i = 0; i < bd->total_images; i++) {
285
                img = &bd->images[i];
286
                boot_file = vm_file_create();
287
 
288
                /* Allocate private data */
289
                boot_file->priv_data = kzalloc(sizeof(*img));
290
                memcpy(boot_file->priv_data, img, sizeof(*img));
291
 
292
                boot_file->length = img->phys_end - img->phys_start;
293
                boot_file->type = VM_FILE_BOOTFILE;
294
                boot_file->destroy_priv_data =
295
                        bootfile_destroy_priv_data;
296
 
297
                /* Initialise the vm object */
298
                boot_file->vm_obj.flags = VM_OBJ_FILE;
299
                boot_file->vm_obj.pager = &bootfile_pager;
300
 
301
                /* Add the file to initdata's bootfile list */
302
                list_insert_tail(&boot_file->list, &initdata->boot_file_list);
303
        }
304
 
305
        return 0;
306
}
307
#endif
308
 
309
/*
310
 * FIXME:
311
 * Problem is that devzero is a character device and we don't have a
312
 * character device subsystem yet.
313
 *
314
 * Therefore even though the vm_file for devzero requires a vnode,
315
 * currently it has no vnode field, and the information (the zero page)
316
 * that needs to be stored in the dynamic vnode is now stored in the
317
 * field file_private_data in the vm_file, which really needs to be
318
 * removed.
319
 */
320
 
321
/* Returns the page with given offset in this vm_object */
322
struct page *devzero_page_in(struct vm_object *vm_obj,
323
                             unsigned long page_offset)
324
{
325
        struct vm_file *devzero = vm_object_to_file(vm_obj);
326
        struct page *zpage = devzero->private_file_data;
327
 
328
        BUG_ON(!(devzero->type & VM_FILE_DEVZERO));
329
 
330
        /* Update zero page struct. */
331
        spin_lock(&zpage->lock);
332
        BUG_ON(zpage->refcnt < 0);
333
        zpage->refcnt++;
334
        spin_unlock(&zpage->lock);
335
 
336
        return zpage;
337
}
338
 
339
struct vm_pager devzero_pager = {
340
        .ops = {
341
                .page_in = devzero_page_in,
342
        },
343
};
344
 
345
struct vm_file *get_devzero(void)
346
{
347
        struct vm_file *f;
348
 
349
        list_foreach_struct(f, &global_vm_files.list, list)
350
                if (f->type == VM_FILE_DEVZERO)
351
                        return f;
352
        return 0;
353
}
354
 
355
int init_devzero(void)
356
{
357
        void *zphys, *zvirt;
358
        struct page *zpage;
359
        struct vm_file *devzero;
360
 
361
        /* Allocate and initialise the zero page */
362
        zphys = alloc_page(1);
363
        zpage = phys_to_page(zphys);
364
        zvirt = (void *)phys_to_virt(zphys);
365
        memset(zvirt, 0, PAGE_SIZE);
366
 
367
        /*
368
         * FIXME:
369
         * Flush the dcache if virtual data cache
370
         */
371
 
372
        /* Allocate and initialise devzero file */
373
        devzero = vm_file_create();
374
        devzero->type = VM_FILE_DEVZERO;
375
        devzero->private_file_data = zpage;
376
        devzero->length = page_align(~0UL); /* So we dont wraparound to 0! */
377
        devzero->vm_obj.npages = __pfn(devzero->length);
378
        devzero->vm_obj.pager = &devzero_pager;
379
        devzero->vm_obj.flags = VM_OBJ_FILE;
380
 
381
        /* Initialise zpage */
382
        zpage->refcnt++;
383
        zpage->owner = &devzero->vm_obj;
384
 
385
        global_add_vm_file(devzero);
386
        return 0;
387
}
388
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.