feat: a pseudo shell environment for basic interacting and testing purpose
[lunaix-os.git] / lunaix-os / kernel / mm / vmm.c
1 #include <hal/cpu.h>
2 #include <klibc/string.h>
3 #include <lunaix/mm/pmm.h>
4 #include <lunaix/mm/vmm.h>
5 #include <lunaix/spike.h>
6
7 void
8 vmm_init()
9 {
10     // XXX: something here?
11 }
12
13 x86_page_table*
14 vmm_init_pd()
15 {
16     x86_page_table* dir =
17       (x86_page_table*)pmm_alloc_page(KERNEL_PID, PP_FGPERSIST);
18     for (size_t i = 0; i < PG_MAX_ENTRIES; i++) {
19         dir->entry[i] = PTE_NULL;
20     }
21
22     // 递归映射,方便我们在软件层面进行查表地址转换
23     dir->entry[PG_MAX_ENTRIES - 1] = NEW_L1_ENTRY(T_SELF_REF_PERM, dir);
24
25     return dir;
26 }
27
28 int
29 vmm_set_mapping(uintptr_t mnt,
30                 uintptr_t va,
31                 uintptr_t pa,
32                 pt_attr attr,
33                 int options)
34 {
35     assert((uintptr_t)va % PG_SIZE == 0);
36
37     uintptr_t l1_inx = L1_INDEX(va);
38     uintptr_t l2_inx = L2_INDEX(va);
39     x86_page_table* l1pt = (x86_page_table*)(mnt | (1023 << 12));
40     x86_page_table* l2pt = (x86_page_table*)(mnt | (l1_inx << 12));
41
42     // See if attr make sense
43     assert(attr <= 128);
44
45     if (!l1pt->entry[l1_inx]) {
46         x86_page_table* new_l1pt_pa = pmm_alloc_page(KERNEL_PID, PP_FGPERSIST);
47
48         // 物理内存已满!
49         if (!new_l1pt_pa) {
50             return 0;
51         }
52
53         // This must be writable
54         l1pt->entry[l1_inx] =
55           NEW_L1_ENTRY(attr | PG_WRITE | PG_PRESENT, new_l1pt_pa);
56
57         memset((void*)l2pt, 0, PG_SIZE);
58     } else {
59         x86_pte_t pte = l2pt->entry[l2_inx];
60         if (pte && (options & VMAP_IGNORE)) {
61             return 1;
62         }
63     }
64
65     if (mnt == PD_REFERENCED) {
66         cpu_invplg(va);
67     }
68
69     if ((options & VMAP_NOMAP)) {
70         return 1;
71     }
72
73     l2pt->entry[l2_inx] = NEW_L2_ENTRY(attr, pa);
74     return 1;
75 }
76
77 uintptr_t
78 vmm_del_mapping(uintptr_t mnt, uintptr_t va)
79 {
80     assert(((uintptr_t)va & 0xFFFU) == 0);
81
82     uint32_t l1_index = L1_INDEX(va);
83     uint32_t l2_index = L2_INDEX(va);
84
85     // prevent unmap of recursive mapping region
86     if (l1_index == 1023) {
87         return 0;
88     }
89
90     x86_page_table* l1pt = (x86_page_table*)(mnt | (1023 << 12));
91
92     x86_pte_t l1pte = l1pt->entry[l1_index];
93
94     if (l1pte) {
95         x86_page_table* l2pt = (x86_page_table*)(mnt | (l1_index << 12));
96         x86_pte_t l2pte = l2pt->entry[l2_index];
97
98         cpu_invplg(va);
99         l2pt->entry[l2_index] = PTE_NULL;
100
101         return PG_ENTRY_ADDR(l2pte);
102     }
103
104     return 0;
105 }
106
107 int
108 vmm_lookup(uintptr_t va, v_mapping* mapping)
109 {
110     uint32_t l1_index = L1_INDEX(va);
111     uint32_t l2_index = L2_INDEX(va);
112
113     x86_page_table* l1pt = (x86_page_table*)L1_BASE_VADDR;
114     x86_pte_t l1pte = l1pt->entry[l1_index];
115
116     if (l1pte) {
117         x86_pte_t* l2pte =
118           &((x86_page_table*)L2_VADDR(l1_index))->entry[l2_index];
119         if (l2pte) {
120             mapping->flags = PG_ENTRY_FLAGS(*l2pte);
121             mapping->pa = PG_ENTRY_ADDR(*l2pte);
122             mapping->pn = mapping->pa >> PG_SIZE_BITS;
123             mapping->pte = l2pte;
124             mapping->va = va;
125             return 1;
126         }
127     }
128     return 0;
129 }
130
131 void*
132 vmm_v2p(void* va)
133 {
134     uint32_t l1_index = L1_INDEX(va);
135     uint32_t l2_index = L2_INDEX(va);
136
137     x86_page_table* l1pt = (x86_page_table*)L1_BASE_VADDR;
138     x86_pte_t l1pte = l1pt->entry[l1_index];
139
140     if (l1pte) {
141         x86_pte_t* l2pte =
142           &((x86_page_table*)L2_VADDR(l1_index))->entry[l2_index];
143         if (l2pte) {
144             return PG_ENTRY_ADDR(*l2pte) | ((uintptr_t)va & 0xfff);
145         }
146     }
147     return 0;
148 }
149
150 void*
151 vmm_mount_pd(uintptr_t mnt, void* pde)
152 {
153     x86_page_table* l1pt = (x86_page_table*)L1_BASE_VADDR;
154     l1pt->entry[(mnt >> 22)] = NEW_L1_ENTRY(T_SELF_REF_PERM, pde);
155     cpu_invplg(mnt);
156     return mnt;
157 }
158
159 void*
160 vmm_unmount_pd(uintptr_t mnt)
161 {
162     x86_page_table* l1pt = (x86_page_table*)L1_BASE_VADDR;
163     l1pt->entry[(mnt >> 22)] = 0;
164     cpu_invplg(mnt);
165 }