Skip to content

Commit

Permalink
add swap
Browse files Browse the repository at this point in the history
  • Loading branch information
yangminz committed Jul 31, 2021
1 parent f18e73a commit fec09ad
Show file tree
Hide file tree
Showing 3 changed files with 151 additions and 2 deletions.
85 changes: 85 additions & 0 deletions src/hardware/cpu/mmu.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@
static uint64_t page_walk(uint64_t vaddr_value);
static void page_fault_handler(pte4_t *pte, address_t vaddr);

int swap_in(uint64_t daddr, uint64_t ppn);
int swap_out(uint64_t daddr, uint64_t ppn);

// consider this function va2pa as functional
uint64_t va2pa(uint64_t vaddr)
{
Expand Down Expand Up @@ -151,9 +154,12 @@ static uint64_t page_walk(uint64_t vaddr_value)
static void page_fault_handler(pte4_t *pte, address_t vaddr)
{
// select one victim physical page to swap to disk
assert(pte->present == 0);

// this is the selected ppn for vaddr
int ppn = -1;
pte4_t *victim = NULL;
uint64_t daddr = 0xffffffffffffffff;

// 1. try to request one free physical page from DRAM
// kernel's responsibility
Expand Down Expand Up @@ -181,7 +187,86 @@ static void page_fault_handler(pte4_t *pte, address_t vaddr)

// 2. no free physical page: select one clean page (LRU) and overwrite
// in this case, there is no DRAM - DISK transaction
int lru_ppn = -1;
int lru_time = -1;
for (int i = 0; i < MAX_NUM_PHYSICAL_PAGE; ++ i)
{
if (page_map[i].dirty == 0 &&
lru_time < page_map[i].time)
{
lru_time = page_map[i].time;
lru_ppn = i;
}
}

if (-1 != lru_ppn && lru_ppn < MAX_NUM_PHYSICAL_PAGE)
{
ppn = lru_ppn;

// reversed mapping
victim = page_map[ppn].pte4;

victim->pte_value = 0;
victim->present = 0;
victim->daddr = page_map[ppn].daddr;

// load page from disk to physical memory first
daddr = pte->daddr;
swap_in(pte->daddr, ppn);

pte->pte_value = 0;
pte->present = 1;
pte->ppn = ppn;
pte->dirty = 0;

page_map[ppn].allocated = 1;
page_map[ppn].time = 0;
page_map[ppn].dirty = 0;
page_map[ppn].pte4 = pte;
page_map[ppn].daddr = daddr;

return;
}

// 3. no free nor clean physical page: select one LRU victim
// write back (swap out) the DIRTY victim to disk
lru_ppn = -1;
lru_time = -1;
for (int i = 0; i < MAX_NUM_PHYSICAL_PAGE; ++ i)
{
if (lru_time < page_map[i].time)
{
lru_time = page_map[i].time;
lru_ppn = i;
}
}

assert(0 <= lru_ppn && lru_ppn < MAX_NUM_PHYSICAL_PAGE);

ppn = lru_ppn;

// reversed mapping
victim = page_map[ppn].pte4;

// write back
swap_out(page_map[ppn].daddr, ppn);

victim->pte_value = 0;
victim->present = 0;
victim->daddr = page_map[ppn].daddr;

// load page from disk to physical memory first
daddr = pte->daddr;
swap_in(daddr, ppn);

pte->pte_value = 0;
pte->present = 1;
pte->ppn = ppn;
pte->dirty = 0;

page_map[ppn].allocated = 1;
page_map[ppn].time = 0;
page_map[ppn].dirty = 0;
page_map[ppn].pte4 = pte;
page_map[ppn].daddr = daddr;
}
60 changes: 60 additions & 0 deletions src/hardware/memory/swap.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/* BCST - Introduction to Computer Systems
* Author: yangminz@outlook.com
* Github: https://github.com/yangminz/bcst_csapp
* Bilibili: https://space.bilibili.com/4564101
* Zhihu: https://www.zhihu.com/people/zhao-yang-min
* This project (code repository and videos) is exclusively owned by yangminz
* and shall not be used for commercial and profitting purpose
* without yangminz's permission.
*/

// Dynamic Random Access Memory
#include <string.h>
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include "headers/cpu.h"
#include "headers/memory.h"
#include "headers/common.h"
#include "headers/address.h"

// each swap file is swap page
// each line of this swap page is one uint64
#define SWAP_PAGE_FILE_LINES 512

// disk address counter
static uint64_t internal_swap_daddr = 0;

int swap_in(uint64_t daddr, uint64_t ppn)
{
FILE *fr = NULL;
char filename[128];
sprintf(filename, "../files/swap/page-%ld.txt", daddr);
fr = fopen(filename, "r");
assert(fr != NULL);

uint64_t ppn_ppo = ppn << PHYSICAL_PAGE_OFFSET_LENGTH;
char buf[64] = {'0'};
for (int i = 0; i < SWAP_PAGE_FILE_LINES; ++ i)
{
char *str = fgets(buf, 64, fr);
*((uint64_t *)(&pm[ppn_ppo + i * 8])) = string2uint(str);
}
fclose(fr);
}

int swap_out(uint64_t daddr, uint64_t ppn)
{
FILE *fw = NULL;
char filename[128];
sprintf(filename, "../files/swap/page-%ld.txt", daddr);
fw = fopen(filename, "w");
assert(fw != NULL);

uint64_t ppn_ppo = ppn << PHYSICAL_PAGE_OFFSET_LENGTH;
for (int i = 0; i < SWAP_PAGE_FILE_LINES; ++ i)
{
fprintf(fw, "0x%16lx\n", *((uint64_t *)(&pm[ppn_ppo + i * 8])));
}
fclose(fw);
}
8 changes: 6 additions & 2 deletions src/headers/memory.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ typedef union
struct
{
uint64_t _present : 1;
uint64_t swap_id : 63; // disk address
uint64_t daddr : 63; // disk address
};
} pte123_t; // PGD, PUD, PMD

Expand Down Expand Up @@ -96,7 +96,7 @@ typedef union
struct
{
uint64_t _present : 1; // present = 0
uint64_t swap_id : 63; // disk address
uint64_t daddr : 63; // disk address
};
} pte4_t; // PT

Expand All @@ -107,7 +107,11 @@ typedef struct
int dirty;
int time; // LRU cache

// real world: mapping to anon_vma or address_space
// we simply the situation here
// TODO: if multiple processes are using this page? E.g. Shared library
pte4_t *pte4; // the reversed mapping: from PPN to page table entry
uint64_t daddr; // binding the revesed mapping with mapping to disk
} pd_t;

// for each pagable (swappable) physical page
Expand Down

0 comments on commit fec09ad

Please sign in to comment.