From e03273756d473edcee58f51130867a32d6d38baa Mon Sep 17 00:00:00 2001 From: sBubshait Date: Thu, 5 Dec 2024 17:52:01 +0000 Subject: [PATCH] Update frame table to add a pinned flag and protect those from being evicted --- src/vm/frame.c | 56 +++++++++++++++++++++++++++++++++++++++++++------- src/vm/frame.h | 2 ++ 2 files changed, 51 insertions(+), 7 deletions(-) diff --git a/src/vm/frame.c b/src/vm/frame.c index 98339f8..a1cb2c2 100644 --- a/src/vm/frame.c +++ b/src/vm/frame.c @@ -37,6 +37,8 @@ struct frame_metadata void *frame; /* The kernel virtual address holding the frame. */ void *upage; /* The user virtual address pointing to the frame. */ struct thread *owner; /* Pointer to the thread that owns the frame. */ + bool pinned; + struct hash_elem hash_elem; /* Tracks the position of the frame metadata within 'frame_table', whose key is the kernel virtual address of the frame. */ @@ -50,6 +52,7 @@ hash_less_func frame_metadata_less; static struct list_elem *lru_next (struct list_elem *e); static struct list_elem *lru_prev (struct list_elem *e); +static struct frame_metadata *frame_metadata_get (void *frame); static struct frame_metadata *get_victim (void); /* Initialize the frame system by initializing the frame (hash) table with @@ -143,11 +146,34 @@ frame_alloc (enum palloc_flags flags, void *upage, struct thread *owner) frame_metadata->upage = upage; frame_metadata->owner = owner; + frame_metadata->pinned = false; lock_release (&lru_lock); return frame_metadata->frame; } +void +frame_pin (void *frame) +{ + struct frame_metadata *frame_metadata = frame_metadata_get (frame); + if (frame_metadata == NULL) + PANIC ("Attempted to pin a frame at an unallocated kernel address '%p'\n", + frame); + + frame_metadata->pinned = true; +} + +void +frame_unpin (void *frame) +{ + struct frame_metadata *frame_metadata = frame_metadata_get (frame); + if (frame_metadata == NULL) + PANIC ("Attempted to unpin a frame at an unallocated kernel address '%p'\n", + frame); + + frame_metadata->pinned = false; +} + /* Attempt to deallocate a frame for a user process by removing it from the frame table as well as lru_list, and freeing the underlying page memory & metadata struct. Panics if the frame isn't active in memory. */ @@ -201,6 +227,10 @@ get_victim (void) upage = frame_metadata->upage; e = lru_next (e); + /* Skip pinned frames */ + if (frame_metadata->pinned) + continue; + if (!pagedir_is_accessed (pd, upage)) break; @@ -228,14 +258,26 @@ frame_metadata_hash (const struct hash_elem *e, void *aux UNUSED) bool frame_metadata_less (const struct hash_elem *a_, const struct hash_elem *b_, void *aux UNUSED) - { - struct frame_metadata *a = - hash_entry (a_, struct frame_metadata, hash_elem); - struct frame_metadata *b = - hash_entry (b_, struct frame_metadata, hash_elem); +{ + struct frame_metadata *a = + hash_entry (a_, struct frame_metadata, hash_elem); + struct frame_metadata *b = + hash_entry (b_, struct frame_metadata, hash_elem); - return a->frame < b->frame; - } + return a->frame < b->frame; +} + +static struct frame_metadata * +frame_metadata_get (void *frame) +{ + struct frame_metadata key_metadata; + key_metadata.frame = frame; + + struct hash_elem *e = hash_find (&frame_table, &key_metadata.hash_elem); + if (e == NULL) return NULL; + + return hash_entry (e, struct frame_metadata, hash_elem); +} /* Returns the next recently used element after the one provided, which is achieved by iterating through lru_list like a circular queue diff --git a/src/vm/frame.h b/src/vm/frame.h index 93081d3..4aea61d 100644 --- a/src/vm/frame.h +++ b/src/vm/frame.h @@ -6,6 +6,8 @@ void frame_init (void); void *frame_alloc (enum palloc_flags, void *, struct thread *); +void frame_pin (void *frame); +void frame_unpin (void *frame); void frame_free (void *frame); #endif /* vm/frame.h */