mmu.c 1.9 KB
Newer Older
P
Parallels 已提交
1 2
#include "nemu.h"
#include "memory/memory.h"
Z
Zihao Yu 已提交
3
#include "csr.h"
P
Parallels 已提交
4 5 6 7 8 9 10 11 12 13 14 15

typedef union PageTableEntry {
  struct {
    uint32_t valid  : 1;
    uint32_t read   : 1;
    uint32_t write  : 1;
    uint32_t exec   : 1;
    uint32_t user   : 1;
    uint32_t global : 1;
    uint32_t access : 1;
    uint32_t dirty  : 1;
    uint32_t rsw    : 2;
Z
Zihao Yu 已提交
16 17
    uint64_t ppn    :44;
    uint32_t pad    :10;
P
Parallels 已提交
18
  };
Z
Zihao Yu 已提交
19
  uint64_t val;
P
Parallels 已提交
20 21
} PTE;

Z
Zihao Yu 已提交
22 23
#define PGSHFT 12
#define PGBASE(pn) (pn << PGSHFT)
P
Parallels 已提交
24

Z
Zihao Yu 已提交
25
// Sv39 page walk
Z
Zihao Yu 已提交
26 27 28 29 30 31 32 33 34
#define PTW_LEVEL 3
#define PTE_SIZE 8
#define VPNMASK 0x1ff
static inline uintptr_t VPNiSHFT(int i) {
  return (PGSHFT) + 9 * i;
}
static inline uintptr_t VPNi(vaddr_t va, int i) {
  return (va >> VPNiSHFT(i)) & VPNMASK;
}
P
Parallels 已提交
35

Z
Zihao Yu 已提交
36 37 38 39 40 41 42 43 44 45 46
static word_t page_walk(vaddr_t vaddr, bool is_write) {
  word_t pg_base = PGBASE(satp->ppn);
  PTE pte;
  int level;
  for (level = PTW_LEVEL - 1; level >= 0; level --) {
    pte.val	= paddr_read(pg_base + VPNi(vaddr, level) * PTE_SIZE, PTE_SIZE);
    if (!pte.valid) {
      panic("level %d: pc = " FMT_WORD ", vaddr = " FMT_WORD ", pg_base = " FMT_WORD ", pte = " FMT_WORD,
          level, cpu.pc, vaddr, pg_base, pte.val);
    }
    pg_base = PGBASE(pte.ppn);
P
Parallels 已提交
47 48
  }

Z
Zihao Yu 已提交
49 50 51 52 53 54
  //if (!pte.access || (pte.dirty == 0 && is_write)) {
  //  pte.access = 1;
  //  pte.dirty |= is_write;
  //  paddr_write(pt_base + addr->pt_idx * 4, pte.val, 4);
  //}

Z
Zihao Yu 已提交
55
  return pg_base;
P
Parallels 已提交
56 57 58 59 60 61
}

static inline paddr_t page_translate(vaddr_t addr, bool is_write) {
  return page_walk(addr, is_write) | (addr & PAGE_MASK);
}

Z
Zihao Yu 已提交
62
word_t isa_vaddr_read(vaddr_t addr, int len) {
Z
Zihao Yu 已提交
63 64
  assert(satp->mode == 0 || satp->mode == 8);
  paddr_t paddr = (satp->mode == 8 ? page_translate(addr, false) : addr);
P
Parallels 已提交
65 66 67
  return paddr_read(paddr, len);
}

Z
Zihao Yu 已提交
68
void isa_vaddr_write(vaddr_t addr, word_t data, int len) {
Z
Zihao Yu 已提交
69 70
  assert(satp->mode == 0 || satp->mode == 8);
  paddr_t paddr = (satp->mode == 8 ? page_translate(addr, true) : addr);
P
Parallels 已提交
71 72
  paddr_write(paddr, data, len);
}