Implement VM #63

Merged
td1223 merged 94 commits from vm/merged/themis into master 2024-12-06 05:07:14 +00:00
16 changed files with 452 additions and 108 deletions
Showing only changes of commit 1e236a5c47 - Show all commits

View File

@@ -15,6 +15,7 @@
#include "threads/switch.h" #include "threads/switch.h"
#include "threads/synch.h" #include "threads/synch.h"
#include "threads/vaddr.h" #include "threads/vaddr.h"
#include "vm/page.h"
#ifdef USERPROG #ifdef USERPROG
#include "userprog/process.h" #include "userprog/process.h"
#include "userprog/syscall.h" #include "userprog/syscall.h"
@@ -264,7 +265,8 @@ thread_create (const char *name, int priority,
if (!hash_init (&t->open_files, fd_hash, fd_less, NULL) if (!hash_init (&t->open_files, fd_hash, fd_less, NULL)
|| !hash_init (&t->child_results, process_result_hash, || !hash_init (&t->child_results, process_result_hash,
process_result_less, t)) process_result_less, t)
|| !hash_init (&t->pages, page_hash, page_less, NULL))
{ {
palloc_free_page (t); palloc_free_page (t);
free (t->result); free (t->result);

View File

@@ -5,13 +5,13 @@
#include "userprog/gdt.h" #include "userprog/gdt.h"
#include "threads/interrupt.h" #include "threads/interrupt.h"
#include "threads/thread.h" #include "threads/thread.h"
#include "userprog/pagedir.h"
#ifdef VM #ifdef VM
#include "vm/stackgrowth.h" #include "vm/stackgrowth.h"
#include "vm/frame.h" #include "vm/frame.h"
#include "vm/page.h" #include "vm/page.h"
#include "devices/swap.h" #include "devices/swap.h"
#include "threads/vaddr.h" #include "threads/vaddr.h"
#include "userprog/pagedir.h"
#endif #endif
/* Number of page faults processed. */ /* Number of page faults processed. */
@@ -19,6 +19,7 @@ static long long page_fault_cnt;
static void kill (struct intr_frame *); static void kill (struct intr_frame *);
static void page_fault (struct intr_frame *); static void page_fault (struct intr_frame *);
bool try_fetch_page (void *upage, bool write);
/* Registers handlers for interrupts that can be caused by user /* Registers handlers for interrupts that can be caused by user
programs. programs.
@@ -156,6 +157,7 @@ page_fault (struct intr_frame *f)
#ifdef VM #ifdef VM
struct thread *t = thread_current (); struct thread *t = thread_current ();
void *upage = pg_round_down (fault_addr);
if (user) if (user)
{ {
if (not_present) if (not_present)
@@ -167,7 +169,6 @@ page_fault (struct intr_frame *f)
if (page_in_swap (t, fault_addr)) if (page_in_swap (t, fault_addr))
{ {
size_t swap_slot = page_get_swap (t, fault_addr); size_t swap_slot = page_get_swap (t, fault_addr);
void *upage = pg_round_down (fault_addr);
void *kpage = frame_alloc (0, upage, t); void *kpage = frame_alloc (0, upage, t);
swap_in (kpage, swap_slot); swap_in (kpage, swap_slot);
@@ -192,6 +193,15 @@ page_fault (struct intr_frame *f)
f->eax = 0xffffffff; f->eax = 0xffffffff;
return; return;
} }
/* If the fault address is in a user page that is not present, then it might
just need to be lazily loaded. So, we check our SPT to see if the page
is expected to have data loaded in memory. */
if (not_present && is_user_vaddr (upage) && upage != NULL)
{
if (try_fetch_page (upage, write))
return;
}
#endif #endif
/* To implement virtual memory, delete the rest of the function /* To implement virtual memory, delete the rest of the function
@@ -205,3 +215,32 @@ page_fault (struct intr_frame *f)
kill (f); kill (f);
} }
bool
try_fetch_page (void *upage, bool write)
{
/* Check if the page is in the supplemental page table. That is, it is a page
that is expected to be in memory. */
struct page_entry *page = page_get (upage);
if (page == NULL)
return false;
/* An attempt to write to a non-writeable should fail. */
if (write && !page->writable)
return false;
/* Load the page into memory based on the type of data it is expecting. */
bool success = false;
switch (page->type) {
case PAGE_EXECUTABLE:
success = page_load (page, page->writable);
break;
default:
return false;
}
if (success && page->writable &&
!pagedir_is_writable(thread_current()->pagedir, upage))
pagedir_set_writable(thread_current()->pagedir, upage, true);
return success;
}

View File

@@ -1,6 +1,8 @@
#ifndef USERPROG_EXCEPTION_H #ifndef USERPROG_EXCEPTION_H
#define USERPROG_EXCEPTION_H #define USERPROG_EXCEPTION_H
#include <stdbool.h>
/* Page fault error code bits that describe the cause of the exception. */ /* Page fault error code bits that describe the cause of the exception. */
#define PF_P 0x1 /* 0: not-present page. 1: access rights violation. */ #define PF_P 0x1 /* 0: not-present page. 1: access rights violation. */
#define PF_W 0x2 /* 0: read, 1: write. */ #define PF_W 0x2 /* 0: read, 1: write. */
@@ -8,5 +10,7 @@
void exception_init (void); void exception_init (void);
void exception_print_stats (void); void exception_print_stats (void);
bool
try_fetch_page (void *upage, bool write);
#endif /* userprog/exception.h */ #endif /* userprog/exception.h */

View File

@@ -24,6 +24,7 @@
#include "threads/vaddr.h" #include "threads/vaddr.h"
#include "threads/synch.h" #include "threads/synch.h"
#include "devices/timer.h" #include "devices/timer.h"
#include "vm/page.h"
#ifdef VM #ifdef VM
#include "vm/frame.h" #include "vm/frame.h"
#endif #endif
@@ -118,6 +119,7 @@ process_execute (const char *cmd)
static void *get_usr_kpage (enum palloc_flags flags, void *upage); static void *get_usr_kpage (enum palloc_flags flags, void *upage);
static void free_usr_kpage (void *kpage); static void free_usr_kpage (void *kpage);
bool install_page (void *upage, void *kpage, bool writable);
static bool process_init_stack (char *cmd_saveptr, void **esp, char *file_name); static bool process_init_stack (char *cmd_saveptr, void **esp, char *file_name);
static void *push_to_stack (void **esp, void *data, size_t data_size); static void *push_to_stack (void **esp, void *data, size_t data_size);
@@ -363,6 +365,7 @@ process_exit (void)
/* Clean up all open files */ /* Clean up all open files */
hash_destroy (&cur->open_files, fd_cleanup); hash_destroy (&cur->open_files, fd_cleanup);
hash_destroy (&cur->pages, page_cleanup);
/* Close the executable file, implicitly allowing it to be written to. */ /* Close the executable file, implicitly allowing it to be written to. */
if (cur->exec_file != NULL) if (cur->exec_file != NULL)
@@ -620,7 +623,6 @@ load (const char *file_name, void (**eip) (void), void **esp)
done: done:
/* We arrive here whether the load is successful or not. */ /* We arrive here whether the load is successful or not. */
file_close (file);
lock_release (&filesys_lock); lock_release (&filesys_lock);
return success; return success;
} }
@@ -694,7 +696,6 @@ load_segment (struct file *file, off_t ofs, uint8_t *upage,
ASSERT (pg_ofs (upage) == 0); ASSERT (pg_ofs (upage) == 0);
ASSERT (ofs % PGSIZE == 0); ASSERT (ofs % PGSIZE == 0);
file_seek (file, ofs);
while (read_bytes > 0 || zero_bytes > 0) while (read_bytes > 0 || zero_bytes > 0)
{ {
/* Calculate how to fill this page. /* Calculate how to fill this page.
@@ -703,43 +704,15 @@ load_segment (struct file *file, off_t ofs, uint8_t *upage,
size_t page_read_bytes = read_bytes < PGSIZE ? read_bytes : PGSIZE; size_t page_read_bytes = read_bytes < PGSIZE ? read_bytes : PGSIZE;
size_t page_zero_bytes = PGSIZE - page_read_bytes; size_t page_zero_bytes = PGSIZE - page_read_bytes;
/* Check if virtual page already allocated */ /* Add the page metadata to the SPT to be lazy loaded later on */
struct thread *t = thread_current (); if (page_insert (file, ofs, upage, page_read_bytes, page_zero_bytes,
uint8_t *kpage = pagedir_get_page (t->pagedir, upage); writable, PAGE_EXECUTABLE) == NULL)
if (kpage == NULL){
/* Get a new page of memory. */
kpage = get_usr_kpage (0, upage);
if (kpage == NULL){
return false; return false;
}
/* Add the page to the process's address space. */
if (!install_page (upage, kpage, writable))
{
free_usr_kpage (kpage);
return false;
}
} else {
/* Check if writable flag for the page should be updated */
if(writable && !pagedir_is_writable(t->pagedir, upage)){
pagedir_set_writable(t->pagedir, upage, writable);
}
}
/* Load data into the page. */
if (file_read (file, kpage, page_read_bytes) != (int) page_read_bytes){
return false;
}
memset (kpage + page_read_bytes, 0, page_zero_bytes);
/* Advance. */ /* Advance. */
read_bytes -= page_read_bytes; read_bytes -= page_read_bytes;
zero_bytes -= page_zero_bytes; zero_bytes -= page_zero_bytes;
ofs += PGSIZE;
upage += PGSIZE; upage += PGSIZE;
} }
return true; return true;

View File

@@ -260,4 +260,3 @@ lru_prev (struct list_elem *e)
return list_prev (e); return list_prev (e);
} }

View File

@@ -154,4 +154,3 @@ page_get_swap (struct thread *owner, void *upage)
/* Masks the address bits and returns truncated value. */ /* Masks the address bits and returns truncated value. */
return ((*pte & PTE_ADDR) >> ADDR_START_BIT); return ((*pte & PTE_ADDR) >> ADDR_START_BIT);
} }