Skip to content
Snippets Groups Projects
Commit 0907dd8d authored by gback's avatar gback
Browse files

Implement TLB shootdown

- also refactored ipi.c to not export functions related to other
  functional components.
- TLB shootdown is done automatically in pagedir.c as needed.
parent 28fef27f
No related branches found
No related tags found
No related merge requests found
......@@ -84,6 +84,21 @@ shutdown_reboot (void)
}
}
/* Received a shutdown signal from another CPU
For now, it's just going to disable interrupts and spin so that
the CPU stats remain consistent for the CPU that called shutdown() */
void
shutdown_handle_ipi (void)
{
ASSERT(cpu_started_others);
/* CPU0 needs to stay on in order to handle interrupts. Otherwise
if an AP calls shutdown, it may get stuck trying to print to console */
if (get_cpu ()->id == 0)
return;
while (1)
;
}
/* Powers down the machine we're running on,
as long as we're running on Bochs or QEMU. */
void
......
......@@ -15,5 +15,6 @@ void shutdown (void);
void shutdown_configure (enum shutdown_type);
void shutdown_reboot (void) NO_RETURN;
void shutdown_power_off (void) NO_RETURN;
void shutdown_handle_ipi (void);
#endif /* devices/shutdown.h */
......@@ -139,6 +139,7 @@ main (void)
#ifdef USERPROG
exception_init ();
syscall_init ();
pagedir_init ();
#endif
serial_init_queue ();
......
......@@ -9,6 +9,15 @@
#include "threads/synch.h"
#include "lib/atomic-ops.h"
#include "threads/mp.h"
#include "devices/shutdown.h"
#ifdef USERPROG
#include "userprog/pagedir.h"
#endif
static void ipi_debug (struct intr_frame *f UNUSED);
static void ipi_schedule (struct intr_frame *f UNUSED);
static void ipi_tlbflush (struct intr_frame *f UNUSED);
static void ipi_shutdown (struct intr_frame *f UNUSED);
/* Register interrupt handlers for the inter-processor
interrupts that we support */
......@@ -17,29 +26,32 @@ ipi_init ()
{
intr_register_ipi (T_IPI + IPI_SHUTDOWN, ipi_shutdown,
"#IPI SHUTDOWN");
intr_register_ipi (T_IPI + IPI_TLB, ipi_tlbflush,
"#IPI TLB");
intr_register_ipi (T_IPI + IPI_DEBUG, ipi_debug,
"#IPI DEBUG");
intr_register_ipi (T_IPI + IPI_SCHEDULE, ipi_schedule,
"#IPI SCHEDULE");
}
/* Received a shutdown signal from another CPU
For now, it's just going to disable interrupts and spin so that
the CPU stats remain consistent for the CPU that called shutdown() */
void
/* Received a shutdown signal from another CPU. */
static void
ipi_shutdown (struct intr_frame *f UNUSED)
{
ASSERT(cpu_started_others);
/* CPU0 needs to stay on in order to handle interrupts. Otherwise
if an AP calls shutdown, it may get stuck trying to print to console */
if (get_cpu ()->id == 0)
return;
while (1)
;
shutdown_handle_ipi ();
}
/* Received a request to flush TLB. */
static void
ipi_tlbflush (struct intr_frame *f UNUSED)
{
#ifdef USERPROG
pagedir_handle_tlbflush_request ();
#endif
}
/* Preempt the currently running thread */
void
static void
ipi_schedule (struct intr_frame *f UNUSED)
{
ASSERT (cpu_started_others);
......@@ -47,7 +59,7 @@ ipi_schedule (struct intr_frame *f UNUSED)
}
/* For debugging. Prints the backtrace of the thread running on the current CPU */
void
static void
ipi_debug (struct intr_frame *f UNUSED)
{
ASSERT (cpu_started_others);
......
......@@ -4,8 +4,5 @@
#include "threads/interrupt.h"
void ipi_init (void);
void ipi_shutdown (struct intr_frame *);
void ipi_debug (struct intr_frame *);
void ipi_schedule (struct intr_frame *);
#endif /* THREADS_IPI_H_ */
......@@ -5,10 +5,15 @@
#include "threads/init.h"
#include "threads/pte.h"
#include "threads/palloc.h"
#include "threads/synch.h"
#include "threads/cpu.h"
#include "devices/lapic.h"
#include "lib/kernel/x86.h"
#include "lib/atomic-ops.h"
static uint32_t *active_pd (void);
static void invalidate_pagedir (uint32_t *);
static void invalidate_pagedir_others (uint32_t *pd);
/* Creates a new page directory that has mappings for kernel
virtual addresses, but none for user virtual addresses.
......@@ -244,7 +249,7 @@ active_pd (void)
return ptov (pd);
}
/* Seom page table changes can cause the CPU's translation
/* Some page table changes can cause the CPU's translation
lookaside buffer (TLB) to become out-of-sync with the page
table. When this happens, we have to "invalidate" the TLB by
re-activating it.
......@@ -261,4 +266,55 @@ invalidate_pagedir (uint32_t *pd)
"Translation Lookaside Buffers (TLBs)". */
pagedir_activate (pd);
}
else
{
/* The PD is not active on the current CPU, but it could be
active on other CPUs. Inform the other CPUs that they
need to invalidate any TLB entries related to this PD.
If Pintos supported multi-threaded processes, this PD
could be active on both this and other CPUs.
*/
invalidate_pagedir_others (pd);
}
}
static struct {
struct lock lock; /* only owner of this lock can initiate TLB flush. */
uint32_t *pd; /* pagedir to be invalidated */
int remaining; /* remaining number of CPUs that must acknowledge IPI_TLB */
} tlb_flush_state;
/* Initialize the lock used to protect the TLB flushing protocol. */
void
pagedir_init (void)
{
lock_init (&tlb_flush_state.lock);
}
static void
invalidate_pagedir_others (uint32_t *pd)
{
lock_acquire (&tlb_flush_state.lock);
tlb_flush_state.remaining = ncpu - 1;
tlb_flush_state.pd = pd;
barrier ();
lapic_send_ipi_to_all_but_self (IPI_TLB);
/* We busy-wait here rather than blocking the calling thread
because we expect to be spinning for a short time only. */
while (atomic_load (&tlb_flush_state.remaining) > 0)
;
lock_release (&tlb_flush_state.lock);
}
/* This method will be called from the IPI TLB_FLUSH interrupt
handler on CPUs to which a request to flush their TLB was sent.
*/
void
pagedir_handle_tlbflush_request (void)
{
if (active_pd () == tlb_flush_state.pd)
pagedir_activate (active_pd ());
atomic_deci (&tlb_flush_state.remaining);
}
......@@ -4,6 +4,7 @@
#include <stdbool.h>
#include <stdint.h>
void pagedir_init (void);
uint32_t *pagedir_create (void);
void pagedir_destroy (uint32_t *pd);
bool pagedir_set_page (uint32_t *pd, void *upage, void *kpage, bool rw);
......@@ -14,5 +15,6 @@ void pagedir_set_dirty (uint32_t *pd, const void *upage, bool dirty);
bool pagedir_is_accessed (uint32_t *pd, const void *upage);
void pagedir_set_accessed (uint32_t *pd, const void *upage, bool accessed);
void pagedir_activate (uint32_t *pd);
void pagedir_handle_tlbflush_request (void);
#endif /* userprog/pagedir.h */
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment