summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormanuel <manuel@mausz.at>2012-06-21 16:47:23 +0200
committermanuel <manuel@mausz.at>2012-06-21 16:47:23 +0200
commite11b2ef0c606ab516a4344aeea1dbba22cb1fe5d (patch)
treeb4973f4dca916113c82a4a172f6f729d41cf4430
parente9e69def589375c3d0e51b532268b27d3d403bbf (diff)
downloadprogos-e11b2ef0c606ab516a4344aeea1dbba22cb1fe5d.tar.gz
progos-e11b2ef0c606ab516a4344aeea1dbba22cb1fe5d.tar.bz2
progos-e11b2ef0c606ab516a4344aeea1dbba22cb1fe5d.zip
initial implementation of memory mapped files
-rw-r--r--Makefile.build3
-rw-r--r--userprog/process.c18
-rw-r--r--userprog/process.h2
-rw-r--r--userprog/syscall.c62
-rw-r--r--vm/mmap.c116
-rw-r--r--vm/mmap.h31
-rw-r--r--vm/page.c43
-rw-r--r--vm/page.h27
8 files changed, 241 insertions, 61 deletions
diff --git a/Makefile.build b/Makefile.build
index e68e721..4854124 100644
--- a/Makefile.build
+++ b/Makefile.build
@@ -62,7 +62,8 @@ userprog_SRC += userprog/gdt.c # GDT initialization.
62userprog_SRC += userprog/tss.c # TSS management. 62userprog_SRC += userprog/tss.c # TSS management.
63 63
64# No virtual memory code yet. 64# No virtual memory code yet.
65vm_SRC = vm/page.c 65vm_SRC = vm/page.c
66vm_SRC += vm/mmap.c
66 67
67# Filesystem code. 68# Filesystem code.
68filesys_SRC = filesys/filesys.c # Filesystem core. 69filesys_SRC = filesys/filesys.c # Filesystem core.
diff --git a/userprog/process.c b/userprog/process.c
index 2771e76..f399038 100644
--- a/userprog/process.c
+++ b/userprog/process.c
@@ -130,6 +130,8 @@ start_process (void *aux)
130 thread->process = process; 130 thread->process = process;
131 131
132 page_table_init (&thread->page_table); 132 page_table_init (&thread->page_table);
133 if (!mmap_table_init (&process->mmap_table))
134 goto signal;
133 135
134 /* Initialize interrupt frame and load executable. */ 136 /* Initialize interrupt frame and load executable. */
135 memset (&if_, 0, sizeof if_); 137 memset (&if_, 0, sizeof if_);
@@ -149,6 +151,14 @@ start_process (void *aux)
149 /* If process startup failed, quit. */ 151 /* If process startup failed, quit. */
150 if (thread->process == NULL) { 152 if (thread->process == NULL) {
151 if (process != NULL) { 153 if (process != NULL) {
154 //TODO: free mmap table + page table?
155
156 /* close/free memory mapped files */
157 //mmap_table_free (&process->mmap_table);
158
159 /* free page table */
160 //page_table_free (&thread->page_table);
161
152 if (process->fd_table.fds != NULL) 162 if (process->fd_table.fds != NULL)
153 palloc_free_page (process->fd_table.fds); 163 palloc_free_page (process->fd_table.fds);
154 palloc_free_page (process); 164 palloc_free_page (process);
@@ -232,6 +242,9 @@ process_exit (void)
232 lock_release (&filesys_lock); 242 lock_release (&filesys_lock);
233 } 243 }
234 244
245 /* close/free memory mapped files */
246 mmap_table_free (&proc->mmap_table);
247
235 int fd; 248 int fd;
236 for (fd = 2; fd <= proc->fd_table.fd_max; fd++) { 249 for (fd = 2; fd <= proc->fd_table.fd_max; fd++) {
237 process_close_file (fd); 250 process_close_file (fd);
@@ -254,6 +267,7 @@ process_exit (void)
254 pagedir_destroy (pd); 267 pagedir_destroy (pd);
255 } 268 }
256 269
270 /* free page table */
257 page_table_free (&thread->page_table); 271 page_table_free (&thread->page_table);
258 272
259 /* Destroy the process structure if the parent is not alive 273 /* Destroy the process structure if the parent is not alive
@@ -560,8 +574,8 @@ load_segment (struct file *file, off_t ofs, uint8_t *upage,
560 size_t page_zero_bytes = PGSIZE - page_read_bytes; 574 size_t page_zero_bytes = PGSIZE - page_read_bytes;
561 575
562 /* add segment to page table for on demand loading */ 576 /* add segment to page table for on demand loading */
563 if (!page_table_insert_segment (file, ofs, upage, page_read_bytes, 577 if (!page_table_insert_segment (&thread_current ()->page_table, file, ofs,
564 page_zero_bytes, writable)) 578 upage, page_read_bytes, writable))
565 return false; 579 return false;
566 580
567 /* Advance. */ 581 /* Advance. */
diff --git a/userprog/process.h b/userprog/process.h
index 5fcd80e..bac9a60 100644
--- a/userprog/process.h
+++ b/userprog/process.h
@@ -2,6 +2,7 @@
2#define USERPROG_PROCESS_H 2#define USERPROG_PROCESS_H
3 3
4#include "threads/thread.h" 4#include "threads/thread.h"
5#include "vm/mmap.h"
5 6
6#define STACK_SIZE (1 << 23) /* 8MB maximum stack size */ 7#define STACK_SIZE (1 << 23) /* 8MB maximum stack size */
7 8
@@ -27,6 +28,7 @@ struct process {
27 /* files */ 28 /* files */
28 struct file *executable; /* Loaded executable, if any. */ 29 struct file *executable; /* Loaded executable, if any. */
29 struct fd_table fd_table; /* File descriptor table */ 30 struct fd_table fd_table; /* File descriptor table */
31 struct mmap_table mmap_table; /* Memory mapped files table */
30 32
31 /* Owned by syscall.c */ 33 /* Owned by syscall.c */
32 void* syscall_buffer; 34 void* syscall_buffer;
diff --git a/userprog/syscall.c b/userprog/syscall.c
index 7f8c397..14cbaab 100644
--- a/userprog/syscall.c
+++ b/userprog/syscall.c
@@ -14,7 +14,8 @@
14#include "userprog/pagedir.h" 14#include "userprog/pagedir.h"
15#include "userprog/process.h" 15#include "userprog/process.h"
16#include "userprog/syscall.h" 16#include "userprog/syscall.h"
17#include "lib/user/syscall.h" 17#include "vm/mmap.h"
18#include "vm/page.h"
18 19
19#define STACK_SLOT_SIZE sizeof(int) 20#define STACK_SLOT_SIZE sizeof(int)
20 21
@@ -226,8 +227,8 @@ syscall_handler (struct intr_frame *f)
226 goto fail; 227 goto fail;
227 } 228 }
228 syscall_sp = sp; 229 syscall_sp = sp;
229 result = fp (sp, &segfault); 230 result = fp (sp, &segfault);
230 if (segfault) 231 if (segfault)
231 goto fail; 232 goto fail;
232 f->eax = result; 233 f->eax = result;
233 return; 234 return;
@@ -574,11 +575,64 @@ syscall_close (void *sp, bool *segfault)
574static int 575static int
575syscall_mmap (void *sp, bool *segfault) 576syscall_mmap (void *sp, bool *segfault)
576{ 577{
577 return 0; 578 int fd;
579 void *addr, *offset;
580 struct file *file, *file2;
581 off_t len;
582
583 /* get arguments */
584 if (! copy_from_user (&fd, STACK_ADDR (sp,1)) ||
585 ! copy_from_user (&addr, STACK_ADDR (sp, 2))) {
586 *segfault = true;
587 return -1;
588 }
589
590 /* address must be valid and page-aligned */
591 if (addr == NULL || pg_ofs (addr))
592 return -1;
593
594 /* file descriptors 0 and 1 are reserved */
595 if (fd == 0 || fd == 1)
596 return -1;
597
598 /* get file */
599 file = process_get_file (fd);
600 if (file == NULL)
601 return -1;
602
603 /* file length must be positiv */
604 len = file_length (file);
605 if (len <= 0)
606 return -1;
607
608 /* check if the pages don't overlap any existing pages */
609 offset = addr;
610 while(offset < addr + len)
611 {
612 if (page_table_fetch (&thread_current ()->page_table, offset))
613 return -1;
614 offset += PGSIZE;
615 }
616
617 process_lock_filesys ();
618 file2 = file_reopen (file);
619 process_unlock_filesys ();
620
621 return (file2 == NULL) ? -1 :
622 mmap_table_insert (&process_current()->mmap_table, addr, file2, len);
578} 623}
579 624
580static int 625static int
581syscall_munmap (void *sp, bool *segfault) 626syscall_munmap (void *sp, bool *segfault)
582{ 627{
628 mapid_t mapping;
629
630 /* get arguments */
631 if (! copy_from_user (&mapping, STACK_ADDR (sp,1))) {
632 *segfault = true;
633 return 0;
634 }
635
636 mmap_table_remove (&process_current()->mmap_table, mapping);
583 return 0; 637 return 0;
584} 638}
diff --git a/vm/mmap.c b/vm/mmap.c
new file mode 100644
index 0000000..9e7ae47
--- /dev/null
+++ b/vm/mmap.c
@@ -0,0 +1,116 @@
1#include <string.h>
2#include "filesys/file.h"
3#include "threads/thread.h"
4#include "threads/vaddr.h"
5#include "threads/malloc.h"
6#include "threads/palloc.h"
7#include "vm/mmap.h"
8#include "vm/page.h"
9
10static struct mmap_table_entry *mmap_table_get (struct mmap_table *table,
11 mapid_t mapid);
12
13/* initialize memory mapped files table */
14bool
15mmap_table_init (struct mmap_table *table)
16{
17 table->ids = palloc_get_page (PAL_ZERO);
18 if (table->ids == NULL)
19 return false;
20 table->id_cap = PGSIZE / sizeof (table->ids[0]);
21 table->id_free = 0;
22 table->id_max = -1;
23 return true;
24}
25
26/* frees the content of mmap table */
27void
28mmap_table_free (struct mmap_table *table)
29{
30 //TODO
31 palloc_free_page (table->ids);
32}
33
34/* inserts a new mmap entry in the mmap table
35 returns -1 if entry is invalid or already in the table */
36mapid_t
37mmap_table_insert (struct mmap_table *table, void *addr, struct file *file,
38 off_t len)
39{
40 off_t ofs = 0;
41 size_t page_read_bytes;
42 struct mmap_table_entry *mme;
43 mapid_t mapid;
44
45 /* no more entries left */
46 if (table->id_free >= table->id_cap)
47 return -1;
48
49 mme = malloc (sizeof *mme);
50 if (mme == NULL)
51 return -1;
52
53 mapid = table->id_free++;
54 mme->addr = addr;
55 mme->file = file;
56 table->ids[mapid] = mme;
57
58 /* create needed pages in page table */
59 while (len > 0)
60 {
61 page_read_bytes = (len < PGSIZE) ? len : PGSIZE;
62
63 if (!page_table_insert_segment (&thread_current ()->page_table, file, ofs,
64 addr, page_read_bytes, true))
65 return -1;
66
67 /* Advance. */
68 len -= PGSIZE;
69 ofs += page_read_bytes;
70 addr += PGSIZE;
71 }
72
73 /* update index of free/max mapid index */
74 if (mapid > table->id_max)
75 table->id_max = mapid;
76 while (table->ids[table->id_free] != NULL)
77 {
78 table->id_free++;
79 if (table->id_free >= table->id_cap)
80 break;
81 }
82
83 return mapid;
84}
85
86static struct mmap_table_entry *
87mmap_table_get (struct mmap_table *table, mapid_t mapid)
88{
89 if (mapid < 0 || mapid >= table->id_cap || !table->ids[mapid])
90 return NULL;
91 return table->ids[mapid];
92}
93
94bool
95mmap_table_remove (struct mmap_table *table, mapid_t mapid)
96{
97 struct mmap_table_entry *mme = mmap_table_get(table, mapid);
98 if (mme == NULL)
99 return false;
100
101 table->ids[mapid] = NULL;
102
103 //TODO
104
105 /* update index of free/max file descriptor index */
106 if (mapid < table->id_free)
107 table->id_free = mapid;
108 while (table->ids[table->id_max] == NULL)
109 {
110 table->id_max--;
111 if (table->id_max < 0)
112 break;
113 }
114
115 return true;
116}
diff --git a/vm/mmap.h b/vm/mmap.h
new file mode 100644
index 0000000..bee364e
--- /dev/null
+++ b/vm/mmap.h
@@ -0,0 +1,31 @@
1#ifndef VM_MMAP_H
2#define VM_MMAP_H
3
4#include <debug.h>
5#include "filesys/off_t.h"
6#include "lib/user/syscall.h"
7
8/* we use the same structure as fd_table thus the capacity is fixed to
9 1024 (PGSIZE/4) */
10struct mmap_table
11{
12 struct mmap_table_entry **ids;
13 int id_free; /* lowest-index free */
14 int id_max; /* highest-index used */
15 int id_cap; /* mmap table capacity */
16};
17
18/* a single entry in the mmap table */
19struct mmap_table_entry
20{
21 void *addr;
22 struct file *file;
23};
24
25bool mmap_table_init (struct mmap_table *table);
26void mmap_table_free (struct mmap_table *table);
27mapid_t mmap_table_insert (struct mmap_table *table, void *addr,
28 struct file *file, off_t len);
29bool mmap_table_remove (struct mmap_table *table, mapid_t mapping);
30
31#endif
diff --git a/vm/page.c b/vm/page.c
index 336353e..2853497 100644
--- a/vm/page.c
+++ b/vm/page.c
@@ -2,6 +2,7 @@
2#include "filesys/file.h" 2#include "filesys/file.h"
3#include "userprog/process.h" 3#include "userprog/process.h"
4#include "threads/thread.h" 4#include "threads/thread.h"
5#include "threads/vaddr.h"
5#include "threads/malloc.h" 6#include "threads/malloc.h"
6#include "threads/palloc.h" 7#include "threads/palloc.h"
7#include "vm/page.h" 8#include "vm/page.h"
@@ -11,8 +12,6 @@ static bool page_table_cmp_less (const struct hash_elem *a, const struct hash_el
11 void *aux UNUSED); 12 void *aux UNUSED);
12static void page_table_entry_free (struct hash_elem *e, void *aux UNUSED); 13static void page_table_entry_free (struct hash_elem *e, void *aux UNUSED);
13static bool page_table_insert (struct hash *ht, struct page_table_entry *pte); 14static bool page_table_insert (struct hash *ht, struct page_table_entry *pte);
14static bool page_load_segment (struct page_table_entry *pte);
15static bool page_load_mmf (struct page_table_entry *pte);
16 15
17/* initialize page table structure */ 16/* initialize page table structure */
18void 17void
@@ -69,23 +68,20 @@ page_table_insert (struct hash *ht, struct page_table_entry *pte)
69/* inserts a new entry of type segment into the page table 68/* inserts a new entry of type segment into the page table
70 returns false if entry is invalid or already in the table */ 69 returns false if entry is invalid or already in the table */
71bool 70bool
72page_table_insert_segment (struct file *file, off_t ofs, uint8_t *upage, 71page_table_insert_segment (struct hash *ht, struct file *file, off_t ofs,
73 uint32_t read_bytes, uint32_t zero_bytes, bool writable) 72 uint8_t *upage, uint32_t read_bytes, bool writable)
74{ 73{
75 struct page_table_entry *pte = malloc (sizeof *pte); 74 struct page_table_entry *pte = malloc (sizeof *pte);
76 if (pte == NULL) 75 if (pte == NULL)
77 return false; 76 return false;
78 77
79 pte->upage = upage; 78 pte->upage = upage;
80 pte->type = PAGE_SEGMENT;
81 pte->loaded = false; 79 pte->loaded = false;
82 pte->segment.file = file; 80 pte->segment.file = file;
83 pte->segment.ofs = ofs; 81 pte->segment.ofs = ofs;
84 pte->segment.read_bytes = read_bytes; 82 pte->segment.read_bytes = read_bytes;
85 pte->segment.zero_bytes = zero_bytes;
86 pte->segment.writable = writable; 83 pte->segment.writable = writable;
87 84 return page_table_insert (ht, pte);
88 return page_table_insert (&thread_current ()->page_table, pte);
89} 85}
90 86
91/* fetch an entry from the page table. returns NULL if not found */ 87/* fetch an entry from the page table. returns NULL if not found */
@@ -105,28 +101,11 @@ page_table_fetch (struct hash *ht, void *upage)
105bool 101bool
106page_load (struct page_table_entry *pte) 102page_load (struct page_table_entry *pte)
107{ 103{
104 struct segment *data;
108 if (pte->loaded) 105 if (pte->loaded)
109 return true; 106 return true;
110 107
111 switch (pte->type) 108 data = &pte->segment;
112 {
113 case PAGE_SEGMENT:
114 return page_load_segment (pte);
115 case PAGE_MEMORY_MAPPED_FILE:
116 return page_load_mmf (pte);
117 default:
118 ASSERT (false);
119 break;
120 }
121 return false;
122}
123
124/* load the segment data page */
125static bool
126page_load_segment (struct page_table_entry *pte)
127{
128 struct segment *data = &pte->segment;
129
130 file_seek (data->file, data->ofs); 109 file_seek (data->file, data->ofs);
131 110
132 /* Get a page of memory. */ 111 /* Get a page of memory. */
@@ -141,7 +120,7 @@ page_load_segment (struct page_table_entry *pte)
141 palloc_free_page (kpage); 120 palloc_free_page (kpage);
142 return false; 121 return false;
143 } 122 }
144 memset (kpage + data->read_bytes, 0, data->zero_bytes); 123 memset (kpage + data->read_bytes, 0, PGSIZE - data->read_bytes);
145 124
146 /* Add the page to the process's address space. */ 125 /* Add the page to the process's address space. */
147 if (!process_install_page (pte->upage, kpage, data->writable)) 126 if (!process_install_page (pte->upage, kpage, data->writable))
@@ -153,11 +132,3 @@ page_load_segment (struct page_table_entry *pte)
153 pte->loaded = true; 132 pte->loaded = true;
154 return true; 133 return true;
155} 134}
156
157/* load the memory mappged file page */
158static bool
159page_load_mmf (struct page_table_entry *pte)
160{
161 //TODO: implement
162 return false;
163}
diff --git a/vm/page.h b/vm/page.h
index 9cea048..da1398c 100644
--- a/vm/page.h
+++ b/vm/page.h
@@ -10,24 +10,15 @@ struct page_table_entry
10{ 10{
11 void *upage; /* virtual address of page */ 11 void *upage; /* virtual address of page */
12 bool loaded; /* indicates if page is loaded */ 12 bool loaded; /* indicates if page is loaded */
13 enum
14 {
15 PAGE_SEGMENT,
16 PAGE_MEMORY_MAPPED_FILE,
17 } type; /* type of page */
18 13
19 union 14 /* structure needed for lazy loading of data segments and mmapped files */
15 struct segment
20 { 16 {
21 /* structure needed for lazy loading of data segments */ 17 struct file *file;
22 struct segment 18 off_t ofs;
23 { 19 uint32_t read_bytes;
24 struct file *file; 20 bool writable;
25 off_t ofs; 21 } segment;
26 uint32_t read_bytes;
27 uint32_t zero_bytes;
28 bool writable;
29 } segment;
30 };
31 22
32 struct hash_elem elem; /* Hash element. */ 23 struct hash_elem elem; /* Hash element. */
33}; 24};
@@ -35,8 +26,8 @@ struct page_table_entry
35void page_table_init (struct hash *ht); 26void page_table_init (struct hash *ht);
36void page_table_free (struct hash *ht); 27void page_table_free (struct hash *ht);
37struct page_table_entry *page_table_fetch (struct hash *ht, void *upage); 28struct page_table_entry *page_table_fetch (struct hash *ht, void *upage);
38bool page_table_insert_segment (struct file *file, off_t ofs, uint8_t *upage, 29bool page_table_insert_segment (struct hash *ht, struct file *file, off_t ofs,
39 uint32_t read_bytes, uint32_t zero_bytes, bool writable); 30 uint8_t *upage, uint32_t read_bytes, bool writable);
40bool page_load (struct page_table_entry *pte); 31bool page_load (struct page_table_entry *pte);
41 32
42#endif 33#endif