Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions pintos/include/threads/thread.h
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ struct thread {
struct list fdt_block_list;

struct file* current_file;
void* user_rsp;
#endif
#ifdef VM
/* Table for whole virtual memory owned by thread. */
Expand Down
27 changes: 25 additions & 2 deletions pintos/include/vm/vm.h
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
#ifndef VM_VM_H
#define VM_VM_H
#include <stdbool.h>
#include <stddef.h>
#include "threads/palloc.h"
#include "threads/synch.h"
#include "lib/kernel/hash.h"
#include "lib/kernel/list.h"
#include "lib/kernel/bitmap.h"
#include "filesys/off_t.h"

enum vm_type {
Expand Down Expand Up @@ -36,6 +40,7 @@ enum vm_type {
struct page_operations;
struct thread;
struct file;
struct disk;

#define VM_TYPE(type) ((type) & 7)

Expand All @@ -47,10 +52,11 @@ struct page {
const struct page_operations *operations;
void *va; /* Address in terms of user space */
struct frame *frame; /* Back reference for frame */

/* Your implementation */
struct hash_elem hash_elem;
bool writable;
struct thread *owner;
bool cow; /* Copy-on-write marker for shared pages */

/* Per-type data are binded into the union.
* Each function automatically detects the current union */
Expand All @@ -64,10 +70,26 @@ struct page {
};
};

/* The representation of "frame" */
struct frame {
void *kva;
struct page *page;
struct list_elem frame_elem;
bool pinned;
bool on_table;
size_t refs; /* How many shared users reference this frame */
};

struct frame_table {
struct list frames;
struct lock lock;
struct list_elem *clock_hand;
};

struct swap_table {
struct bitmap *slots;
struct lock lock;
struct disk *disk;
size_t sectors_per_slot;
};

/* The function table for page operations.
Expand Down Expand Up @@ -106,6 +128,7 @@ bool spt_remove_page (struct supplemental_page_table *spt, struct page *page);
void vm_init (void);
bool vm_try_handle_fault (struct intr_frame *f, void *addr, bool user,
bool write, bool not_present);
void vm_frame_free (struct frame *frame);

#define vm_alloc_page(type, upage, writable) \
vm_alloc_page_with_initializer ((type), (upage), (writable), NULL, NULL)
Expand Down
1 change: 1 addition & 0 deletions pintos/threads/thread.c
Original file line number Diff line number Diff line change
Expand Up @@ -501,6 +501,7 @@ static void init_thread(struct thread* t, const char* name, int priority) {
#ifdef USERPROG
list_init(&t->child_list);
list_init(&t->fdt_block_list);
t->user_rsp = NULL;
#endif
#ifdef VM
list_init(&t->mmap_list);
Expand Down
7 changes: 5 additions & 2 deletions pintos/userprog/exception.c
Original file line number Diff line number Diff line change
Expand Up @@ -138,8 +138,11 @@ page_fault (struct intr_frame *f) {

/* Determine cause. */
not_present = (f->error_code & PF_P) == 0;
write = (f->error_code & PF_W) != 0;
user = (f->error_code & PF_U) != 0;
write = (f->error_code & PF_W) != 0;
user = (f->error_code & PF_U) != 0;

if (user)
thread_current()->user_rsp = f->rsp;

#ifdef VM
/* For project 3 and later. */
Expand Down
1 change: 1 addition & 0 deletions pintos/userprog/syscall.c
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ void syscall_init(void) {

/* The main system call interface */
void syscall_handler(struct intr_frame* f) {
thread_current()->user_rsp = f->rsp;
thread_current()->tf = *f;
uint64_t arg1 = f->R.rdi, arg2 = f->R.rsi, arg3 = f->R.rdx, arg4 = f->R.r10, arg5 = f->R.r8;
switch (f->R.rax) {
Expand Down
16 changes: 14 additions & 2 deletions pintos/userprog/validate.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
#include "userprog/validate.h"

#include "threads/thread.h"

#include "vm/vm.h"

#include "threads/vaddr.h"

static int64_t get_user(const uint8_t* uaddr);
Expand All @@ -20,7 +23,16 @@ bool valid_address(const void* uaddr, bool write) {
return true;

page_addr = pg_round_down (uaddr);
return pml4_is_writable (t->pml4, page_addr);
if (pml4_is_writable (t->pml4, page_addr))
return true;

#ifdef VM
struct page *page = spt_find_page (&t->spt, page_addr);
if (page != NULL && page->cow)
return true;
#endif

return false;
}

static int64_t get_user(const uint8_t* uaddr) {
Expand All @@ -43,4 +55,4 @@ static int64_t put_user(uint8_t* udst, uint8_t byte) {
: "=&a"(error_code), "=m"(*udst)
: "q"(byte));
return error_code;
}
}
98 changes: 86 additions & 12 deletions pintos/vm/anon.c
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
/* anon.c: Implementation of page for non-disk image (a.k.a. anonymous page). */

#include "vm/vm.h"
#include "threads/vaddr.h"
#include "devices/disk.h"

#define SECTORS_PER_PAGE (PGSIZE / DISK_SECTOR_SIZE)

/* DO NOT MODIFY BELOW LINE */
static struct disk *swap_disk;
static struct bitmap *swap_bitmap;
static struct lock swap_lock;
static bool anon_swap_in (struct page *page, void *kva);
static bool anon_swap_out (struct page *page);
static void anon_destroy (struct page *page);
Expand All @@ -20,44 +25,113 @@ static const struct page_operations anon_ops = {
/* Initialize the data for anonymous pages */
void vm_anon_init (void) {
swap_disk = disk_get (1, 1);

ASSERT(swap_disk != NULL);

size_t swap_size = disk_size (swap_disk) / SECTORS_PER_PAGE;
swap_bitmap = bitmap_create (swap_size);

ASSERT(swap_bitmap != NULL);

lock_init(&swap_lock);
}

/* Initialize the file mapping */
bool anon_initializer (struct page *page, enum vm_type type, void *kva) {
struct anon_page *anon_page;
struct anon_page *anon_page = &page->anon;

page->operations = &anon_ops;
// anon_page = &page->anon;
// anon_page->swap_idx = BITMAP_ERROR;
anon_page->swap_idx = BITMAP_ERROR;
return true;
}

/* Swap in the page by read contents from the swap disk. */
static bool
anon_swap_in (struct page *page, void *kva) {
static bool anon_swap_in (struct page *page, void *kva) {
struct anon_page *anon_page = &page->anon;
size_t swap_idx;
disk_sector_t start_sector;

ASSERT (page != NULL);
ASSERT (page->frame != NULL);

if (kva == NULL)
return false;

swap_idx = anon_page->swap_idx;

if (swap_idx == BITMAP_ERROR)
return true;

lock_acquire (&swap_lock);

if (!bitmap_test (swap_bitmap, swap_idx)) {
lock_release (&swap_lock);
return false;
}

start_sector = swap_idx * SECTORS_PER_PAGE;

for (size_t i = 0; i < SECTORS_PER_PAGE; i++) {
disk_read (swap_disk, start_sector + i, kva + DISK_SECTOR_SIZE * i);
}

bitmap_reset (swap_bitmap, swap_idx);
anon_page->swap_idx = BITMAP_ERROR;

lock_release (&swap_lock);
return true;
}

/* Swap out the page by writing contents to the swap disk. */
static bool
anon_swap_out (struct page *page) {
static bool anon_swap_out (struct page *page) {
struct anon_page *anon_page = &page->anon;
struct frame *frame = page->frame;
size_t swap_idx;
disk_sector_t start_sector;
struct thread *t = page->owner;

ASSERT (page != NULL);
ASSERT (frame != NULL);
ASSERT (frame->refs == 0);

if (t == NULL)
t = thread_current ();

lock_acquire (&swap_lock);
swap_idx = bitmap_scan_and_flip (swap_bitmap, 0, 1, false);

if (swap_idx == BITMAP_ERROR) {
lock_release (&swap_lock);
PANIC ("full");
}

start_sector = swap_idx * SECTORS_PER_PAGE;

for (size_t i = 0; i < SECTORS_PER_PAGE; i++) {
disk_write (swap_disk, start_sector + i, frame->kva + DISK_SECTOR_SIZE * i);
}

anon_page->swap_idx = swap_idx;
lock_release (&swap_lock);

pml4_clear_page (t->pml4, page->va);
frame->page = NULL;
page->frame = NULL;
return true;
}

/* Destroy the anonymous page. PAGE will be freed by the caller. */
static void anon_destroy (struct page *page) {
struct anon_page *anon_page = &page->anon;

ASSERT (page != NULL);

if (page->frame != NULL) {
struct thread *t = thread_current ();
struct thread *t = page->owner;

if (t == NULL)
t = thread_current ();

pml4_clear_page (t->pml4, page->va);
palloc_free_page (page->frame->kva);
free (page->frame);
vm_frame_free (page->frame);
page->frame = NULL;
}
}
8 changes: 5 additions & 3 deletions pintos/vm/file.c
Original file line number Diff line number Diff line change
Expand Up @@ -61,21 +61,23 @@ static bool file_backed_swap_in (struct page *page, void *kva) {
/* Swap out the page by writeback contents to the file. */
static bool file_backed_swap_out (struct page *page) {
struct frame *frame = page->frame;
struct thread *t = thread_current ();
struct thread *t = page->owner;
struct file_page *file_page = &page->file;

if (frame == NULL)
return true;

if (t == NULL)
t = thread_current ();

if (file_page->read_bytes > 0 && pml4_is_dirty (t->pml4, page->va)) {
lock_acquire (&file_lock);
file_write_at (file_page->file, frame->kva, file_page->read_bytes, file_page->ofs);
lock_release (&file_lock);
}

pml4_clear_page (t->pml4, page->va);
// palloc_free_page (frame->kva);
// free (frame);
frame->page = NULL;
page->frame = NULL;
return true;
}
Expand Down
68 changes: 68 additions & 0 deletions pintos/vm/frame.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
#include "vm/vm.h"
#include "threads/malloc.h"

extern struct frame_table frame_table;

void frame_table_add (struct frame *frame) {
if (frame == NULL || frame->on_table)
return;

lock_acquire (&frame_table.lock);

if (!frame->on_table) {
list_push_back (&frame_table.frames, &frame->frame_elem);
frame->on_table = true;

if (frame_table.clock_hand == NULL)
frame_table.clock_hand = &frame->frame_elem;
}

lock_release (&frame_table.lock);
}

static void frame_table_remove (struct frame *frame) {
bool hand;
struct list_elem *next;
bool empty;

if (frame == NULL)
return;

lock_acquire (&frame_table.lock);

if (!frame->on_table) {
lock_release (&frame_table.lock);
return;
}

hand = frame_table.clock_hand == &frame->frame_elem;
next = list_next (&frame->frame_elem);
list_remove (&frame->frame_elem);

empty = list_empty (&frame_table.frames);

if (empty)
frame_table.clock_hand = NULL;

if (!empty && hand) {
frame_table.clock_hand = (next == list_end (&frame_table.frames))
? list_begin (&frame_table.frames) : next;
}

frame->on_table = false;
lock_release (&frame_table.lock);
}

void vm_frame_free (struct frame *frame) {
if (frame == NULL)
return;

if (frame->refs > 0) {
frame->refs--;
return;
}

frame_table_remove (frame);
palloc_free_page (frame->kva);
free (frame);
}
1 change: 1 addition & 0 deletions pintos/vm/targets.mk
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ vm_SRC += vm/uninit.c # Uninitialized page
vm_SRC += vm/anon.c # Anonymous page
vm_SRC += vm/file.c # File mapped page
vm_SRC += vm/inspect.c # Testing utility
vm_SRC += vm/frame.c # Frame helpers
Loading