summaryrefslogtreecommitdiff
path: root/sys/sys/vm/vm.c
blob: 25c41420809218dc1481baddfa22dce645667477 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
#include <vm.h>
#include <stddef.h>
#include <kalloc.h>
#include <stdio.h>
#include <asm.h>

pagetable_t *kpt;

#define VPN(vaddr, level) \
	(((uintptr_t)vaddr >> (12 + (9 * level))) & 0x1ff)

#define PPN(paddr, level) \
	(((uintptr_t)paddr >> (12 + (9 * level))) & \
		((level == 2) ? 0x3ffffff : 0x1ff))

void 
kptinit(void)
{
	kpt = kzalloc();
}

void 
kptinithart(void)
{
	FLUSH_TLB();
	write_satp(MODE_SV39, (uintptr_t)kpt); 
	FLUSH_TLB();
}

void 
vmap(pagetable_t *root, uintptr_t vaddr, uintptr_t paddr, int bits, int level)
{
	if (pte_is_branch(bits))
		printf("error: pte_is_branch\n"); return;

	pt_entry_t *e = walkpt(root, vaddr, 1);
	if (pte_is_valid(*e))
		printf("warning: mapping already exists for this address\n");

	*e = PA2PTE(paddr) | PAGEBITS_VALID | bits;
}

pt_entry_t *
walkpt(pagetable_t *root, uintptr_t vaddr, int alloc) {
	pt_entry_t *pt = root->entries;
	for (int level = 2; level > 0; level--) {
		pt_entry_t *e = &pt[VPN(vaddr, level)];
		if (!pte_is_valid(*e)) {
			if (!alloc)
				return NULL;
			pt = kzalloc();
			*e = PA2PTE(pt) | PAGEBITS_VALID;
			continue;
		}
		pt = (pt_entry_t *)PTE2PA(*e);

	}
	/* now we should be at level 0, and e should point to our entry */ 
	return &pt[VPN(vaddr, 0)];
}