#include <swap.h>
|
|
#include <swapfs.h>
|
|
#include <swap_fifo.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <memlayout.h>
|
|
#include <pmm.h>
|
|
#include <mmu.h>
|
|
|
|
// the valid vaddr for check is between 0~CHECK_VALID_VADDR-1
|
|
#define CHECK_VALID_VIR_PAGE_NUM 5
|
|
#define BEING_CHECK_VALID_VADDR 0X1000
|
|
#define CHECK_VALID_VADDR (CHECK_VALID_VIR_PAGE_NUM+1)*0x1000
|
|
// the max number of valid physical page for check
|
|
#define CHECK_VALID_PHY_PAGE_NUM 4
|
|
// the max access seq number
|
|
#define MAX_SEQ_NO 10
|
|
|
|
static struct swap_manager *sm;
|
|
size_t max_swap_offset;
|
|
|
|
volatile int swap_init_ok = 0;
|
|
|
|
unsigned int swap_page[CHECK_VALID_VIR_PAGE_NUM];
|
|
|
|
unsigned int swap_in_seq_no[MAX_SEQ_NO],swap_out_seq_no[MAX_SEQ_NO];
|
|
|
|
static void check_swap(void);
|
|
|
|
int
|
|
swap_init(void)
|
|
{
|
|
swapfs_init();
|
|
|
|
if (!(1024 <= max_swap_offset && max_swap_offset < MAX_SWAP_OFFSET_LIMIT))
|
|
{
|
|
panic("bad max_swap_offset %08x.\n", max_swap_offset);
|
|
}
|
|
|
|
|
|
sm = &swap_manager_fifo;
|
|
int r = sm->init();
|
|
|
|
if (r == 0)
|
|
{
|
|
swap_init_ok = 1;
|
|
cprintf("SWAP: manager = %s\n", sm->name);
|
|
check_swap();
|
|
}
|
|
|
|
return r;
|
|
}
|
|
|
|
int
|
|
swap_init_mm(struct mm_struct *mm)
|
|
{
|
|
return sm->init_mm(mm);
|
|
}
|
|
|
|
int
|
|
swap_tick_event(struct mm_struct *mm)
|
|
{
|
|
return sm->tick_event(mm);
|
|
}
|
|
|
|
int
|
|
swap_map_swappable(struct mm_struct *mm, uintptr_t addr, struct Page *page, int swap_in)
|
|
{
|
|
return sm->map_swappable(mm, addr, page, swap_in);
|
|
}
|
|
|
|
int
|
|
swap_set_unswappable(struct mm_struct *mm, uintptr_t addr)
|
|
{
|
|
return sm->set_unswappable(mm, addr);
|
|
}
|
|
|
|
volatile unsigned int swap_out_num=0;
|
|
|
|
int
|
|
swap_out(struct mm_struct *mm, int n, int in_tick)
|
|
{
|
|
int i;
|
|
for (i = 0; i != n; ++ i)
|
|
{
|
|
uintptr_t v;
|
|
//struct Page **ptr_page=NULL;
|
|
struct Page *page;
|
|
// cprintf("i %d, SWAP: call swap_out_victim\n",i);
|
|
int r = sm->swap_out_victim(mm, &page, in_tick);
|
|
if (r != 0) {
|
|
cprintf("i %d, swap_out: call swap_out_victim failed\n",i);
|
|
break;
|
|
}
|
|
//assert(!PageReserved(page));
|
|
|
|
//cprintf("SWAP: choose victim page 0x%08x\n", page);
|
|
|
|
v=page->pra_vaddr;
|
|
pte_t *ptep = get_pte(mm->pgdir, v, 0);
|
|
assert((*ptep & PTE_P) != 0);
|
|
|
|
if (swapfs_write( (page->pra_vaddr/PGSIZE+1)<<8, page) != 0) {
|
|
cprintf("SWAP: failed to save\n");
|
|
sm->map_swappable(mm, v, page, 0);
|
|
continue;
|
|
}
|
|
else {
|
|
cprintf("swap_out: i %d, store page in vaddr 0x%x to disk swap entry %d\n", i, v, page->pra_vaddr/PGSIZE+1);
|
|
*ptep = (page->pra_vaddr/PGSIZE+1)<<8;
|
|
free_page(page);
|
|
}
|
|
|
|
tlb_invalidate(mm->pgdir, v);
|
|
}
|
|
return i;
|
|
}
|
|
|
|
int
|
|
swap_in(struct mm_struct *mm, uintptr_t addr, struct Page **ptr_result)
|
|
{
|
|
struct Page *result = alloc_page();
|
|
assert(result!=NULL);
|
|
|
|
pte_t *ptep = get_pte(mm->pgdir, addr, 0);
|
|
// cprintf("SWAP: load ptep %x swap entry %d to vaddr 0x%08x, page %x, No %d\n", ptep, (*ptep)>>8, addr, result, (result-pages));
|
|
|
|
int r;
|
|
if ((r = swapfs_read((*ptep), result)) != 0)
|
|
{
|
|
assert(r!=0);
|
|
}
|
|
cprintf("swap_in: load disk swap entry %d with swap_page in vadr 0x%x\n", (*ptep)>>8, addr);
|
|
*ptr_result=result;
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
static inline void
|
|
check_content_set(void)
|
|
{
|
|
*(unsigned char *)0x1000 = 0x0a;
|
|
assert(pgfault_num==1);
|
|
*(unsigned char *)0x1010 = 0x0a;
|
|
assert(pgfault_num==1);
|
|
*(unsigned char *)0x2000 = 0x0b;
|
|
assert(pgfault_num==2);
|
|
*(unsigned char *)0x2010 = 0x0b;
|
|
assert(pgfault_num==2);
|
|
*(unsigned char *)0x3000 = 0x0c;
|
|
assert(pgfault_num==3);
|
|
*(unsigned char *)0x3010 = 0x0c;
|
|
assert(pgfault_num==3);
|
|
*(unsigned char *)0x4000 = 0x0d;
|
|
assert(pgfault_num==4);
|
|
*(unsigned char *)0x4010 = 0x0d;
|
|
assert(pgfault_num==4);
|
|
}
|
|
|
|
static inline int
|
|
check_content_access(void)
|
|
{
|
|
int ret = sm->check_swap();
|
|
return ret;
|
|
}
|
|
|
|
struct Page * check_rp[CHECK_VALID_PHY_PAGE_NUM];
|
|
pte_t * check_ptep[CHECK_VALID_PHY_PAGE_NUM];
|
|
unsigned int check_swap_addr[CHECK_VALID_VIR_PAGE_NUM];
|
|
|
|
extern free_area_t free_area;
|
|
|
|
#define free_list (free_area.free_list)
|
|
#define nr_free (free_area.nr_free)
|
|
|
|
static void
|
|
check_swap(void)
|
|
{
|
|
//backup mem env
|
|
int ret, count = 0, total = 0, i;
|
|
list_entry_t *le = &free_list;
|
|
while ((le = list_next(le)) != &free_list) {
|
|
struct Page *p = le2page(le, page_link);
|
|
assert(PageProperty(p));
|
|
count ++, total += p->property;
|
|
}
|
|
assert(total == nr_free_pages());
|
|
cprintf("BEGIN check_swap: count %d, total %d\n",count,total);
|
|
|
|
//now we set the phy pages env
|
|
struct mm_struct *mm = mm_create();
|
|
assert(mm != NULL);
|
|
|
|
extern struct mm_struct *check_mm_struct;
|
|
assert(check_mm_struct == NULL);
|
|
|
|
check_mm_struct = mm;
|
|
|
|
pde_t *pgdir = mm->pgdir = boot_pgdir;
|
|
assert(pgdir[0] == 0);
|
|
|
|
struct vma_struct *vma = vma_create(BEING_CHECK_VALID_VADDR, CHECK_VALID_VADDR, VM_WRITE | VM_READ);
|
|
assert(vma != NULL);
|
|
|
|
insert_vma_struct(mm, vma);
|
|
|
|
//setup the temp Page Table vaddr 0~4MB
|
|
cprintf("setup Page Table for vaddr 0X1000, so alloc a page\n");
|
|
pte_t *temp_ptep=NULL;
|
|
temp_ptep = get_pte(mm->pgdir, BEING_CHECK_VALID_VADDR, 1);
|
|
assert(temp_ptep!= NULL);
|
|
cprintf("setup Page Table vaddr 0~4MB OVER!\n");
|
|
|
|
for (i=0;i<CHECK_VALID_PHY_PAGE_NUM;i++) {
|
|
check_rp[i] = alloc_page();
|
|
assert(check_rp[i] != NULL );
|
|
assert(!PageProperty(check_rp[i]));
|
|
}
|
|
list_entry_t free_list_store = free_list;
|
|
list_init(&free_list);
|
|
assert(list_empty(&free_list));
|
|
|
|
//assert(alloc_page() == NULL);
|
|
|
|
unsigned int nr_free_store = nr_free;
|
|
nr_free = 0;
|
|
for (i=0;i<CHECK_VALID_PHY_PAGE_NUM;i++) {
|
|
free_pages(check_rp[i],1);
|
|
}
|
|
assert(nr_free==CHECK_VALID_PHY_PAGE_NUM);
|
|
|
|
cprintf("set up init env for check_swap begin!\n");
|
|
//setup initial vir_page<->phy_page environment for page relpacement algorithm
|
|
|
|
|
|
pgfault_num=0;
|
|
|
|
check_content_set();
|
|
assert( nr_free == 0);
|
|
for(i = 0; i<MAX_SEQ_NO ; i++)
|
|
swap_out_seq_no[i]=swap_in_seq_no[i]=-1;
|
|
|
|
for (i= 0;i<CHECK_VALID_PHY_PAGE_NUM;i++) {
|
|
check_ptep[i]=0;
|
|
check_ptep[i] = get_pte(pgdir, (i+1)*0x1000, 0);
|
|
//cprintf("i %d, check_ptep addr %x, value %x\n", i, check_ptep[i], *check_ptep[i]);
|
|
assert(check_ptep[i] != NULL);
|
|
assert(pte2page(*check_ptep[i]) == check_rp[i]);
|
|
assert((*check_ptep[i] & PTE_P));
|
|
}
|
|
cprintf("set up init env for check_swap over!\n");
|
|
// now access the virt pages to test page relpacement algorithm
|
|
ret=check_content_access();
|
|
assert(ret==0);
|
|
|
|
//restore kernel mem env
|
|
for (i=0;i<CHECK_VALID_PHY_PAGE_NUM;i++) {
|
|
free_pages(check_rp[i],1);
|
|
}
|
|
|
|
//free_page(pte2page(*temp_ptep));
|
|
|
|
mm_destroy(mm);
|
|
|
|
nr_free = nr_free_store;
|
|
free_list = free_list_store;
|
|
|
|
|
|
le = &free_list;
|
|
while ((le = list_next(le)) != &free_list) {
|
|
struct Page *p = le2page(le, page_link);
|
|
count --, total -= p->property;
|
|
}
|
|
cprintf("count is %d, total is %d\n",count,total);
|
|
//assert(count == 0);
|
|
|
|
cprintf("check_swap() succeeded!\n");
|
|
}
|