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/synch.h"
#include "threads/vaddr.h"
#include "vm/page.h"
#ifdef USERPROG
#include "userprog/process.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)
|| !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);
free (t->result);

View File

@@ -5,13 +5,13 @@
#include "userprog/gdt.h"
#include "threads/interrupt.h"
#include "threads/thread.h"
#include "userprog/pagedir.h"
#ifdef VM
#include "vm/stackgrowth.h"
#include "vm/frame.h"
#include "vm/page.h"
#include "devices/swap.h"
#include "threads/vaddr.h"
#include "userprog/pagedir.h"
#endif
/* Number of page faults processed. */
@@ -19,6 +19,7 @@ static long long page_fault_cnt;
static void kill (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
programs.
@@ -156,6 +157,7 @@ page_fault (struct intr_frame *f)
#ifdef VM
struct thread *t = thread_current ();
void *upage = pg_round_down (fault_addr);
if (user)
{
if (not_present)
@@ -167,7 +169,6 @@ page_fault (struct intr_frame *f)
if (page_in_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);
swap_in (kpage, swap_slot);
@@ -192,6 +193,15 @@ page_fault (struct intr_frame *f)
f->eax = 0xffffffff;
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
/* To implement virtual memory, delete the rest of the function
@@ -205,3 +215,32 @@ page_fault (struct intr_frame *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
#define USERPROG_EXCEPTION_H
#include <stdbool.h>
/* 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_W 0x2 /* 0: read, 1: write. */
@@ -8,5 +10,7 @@
void exception_init (void);
void exception_print_stats (void);
bool
try_fetch_page (void *upage, bool write);
#endif /* userprog/exception.h */

View File

@@ -24,6 +24,7 @@
#include "threads/vaddr.h"
#include "threads/synch.h"
#include "devices/timer.h"
#include "vm/page.h"
#ifdef VM
#include "vm/frame.h"
#endif
@@ -118,6 +119,7 @@ process_execute (const char *cmd)
static void *get_usr_kpage (enum palloc_flags flags, void *upage);
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 void *push_to_stack (void **esp, void *data, size_t data_size);
@@ -363,6 +365,7 @@ process_exit (void)
/* Clean up all open files */
hash_destroy (&cur->open_files, fd_cleanup);
hash_destroy (&cur->pages, page_cleanup);
/* Close the executable file, implicitly allowing it to be written to. */
if (cur->exec_file != NULL)
@@ -620,7 +623,6 @@ load (const char *file_name, void (**eip) (void), void **esp)
done:
/* We arrive here whether the load is successful or not. */
file_close (file);
lock_release (&filesys_lock);
return success;
}
@@ -688,58 +690,29 @@ validate_segment (const struct Elf32_Phdr *phdr, struct file *file)
or disk read error occurs. */
static bool
load_segment (struct file *file, off_t ofs, uint8_t *upage,
uint32_t read_bytes, uint32_t zero_bytes, bool writable)
uint32_t read_bytes, uint32_t zero_bytes, bool writable)
{
ASSERT ((read_bytes + zero_bytes) % PGSIZE == 0);
ASSERT (pg_ofs (upage) == 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.
We will read PAGE_READ_BYTES bytes from FILE
and zero the final PAGE_ZERO_BYTES bytes. */
size_t page_read_bytes = read_bytes < PGSIZE ? read_bytes : PGSIZE;
size_t page_zero_bytes = PGSIZE - page_read_bytes;
/* Check if virtual page already allocated */
struct thread *t = thread_current ();
uint8_t *kpage = pagedir_get_page (t->pagedir, upage);
if (kpage == NULL){
/* Get a new page of memory. */
kpage = get_usr_kpage (0, upage);
if (kpage == NULL){
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);
/* Add the page metadata to the SPT to be lazy loaded later on */
if (page_insert (file, ofs, upage, page_read_bytes, page_zero_bytes,
writable, PAGE_EXECUTABLE) == NULL)
return false;
/* Advance. */
read_bytes -= page_read_bytes;
zero_bytes -= page_zero_bytes;
ofs += PGSIZE;
upage += PGSIZE;
}
return true;

View File

@@ -536,4 +536,4 @@ put_user (uint8_t *udst, uint8_t byte)
: "=&a"(error_code), "=m"(*udst)
: "q"(byte));
return error_code != -1;
}
}

View File

@@ -260,4 +260,3 @@ lru_prev (struct list_elem *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. */
return ((*pte & PTE_ADDR) >> ADDR_START_BIT);
}