1 #include <lunaix/mm/procvm.h>
2 #include <lunaix/mm/valloc.h>
3 #include <lunaix/mm/region.h>
4 #include <lunaix/mm/page.h>
5 #include <lunaix/mm/mmap.h>
6 #include <lunaix/process.h>
8 #include <sys/mm/mm_defs.h>
10 #include <klibc/string.h>
13 procvm_create(struct proc_info* proc) {
14 struct proc_mm* mm = vzalloc(sizeof(struct proc_mm));
21 llist_init_head(&mm->regions);
25 static inline unsigned int
26 __ptep_advancement(struct leaflet* leaflet, int level)
28 size_t shifts = MAX(MAX_LEVEL - level - 1, 1) * LEVEL_SHIFT;
29 return (1 << (leaflet_order(leaflet) % shifts)) - 1;
33 vmscpy(ptr_t dest_mnt, ptr_t src_mnt, bool only_kernel)
35 pte_t* ptep_dest = mkl0tep(mkptep_va(dest_mnt, 0));
36 pte_t* ptep = mkl0tep(mkptep_va(src_mnt, 0));
37 pte_t* ptepd_kernel = mkl0tep(mkptep_va(dest_mnt, KERNEL_RESIDENT));
38 pte_t* ptep_kernel = mkl0tep(mkptep_va(src_mnt, KERNEL_RESIDENT));
40 // Build the self-reference on dest vms
41 pte_t* ptep_sms = mkptep_va(VMS_SELF, (ptr_t)ptep_dest);
42 pte_t* ptep_ssm = mkptep_va(VMS_SELF, (ptr_t)ptep_sms);
43 pte_t pte_sms = mkpte_prot(KERNEL_DATA);
45 pte_sms = alloc_kpage_at(ptep_ssm, pte_sms, 0);
46 set_pte(ptep_sms, pte_sms);
48 tlb_flush_kernel((ptr_t)dest_mnt);
52 ptep_dest += ptep_vfn(ptep_kernel);
59 struct leaflet* leaflet;
61 while (ptep < ptep_kernel)
65 if (pte_isnull(pte)) {
69 if (pt_last_level(level) || pte_huge(pte)) {
70 set_pte(ptep_dest, pte);
72 if (pte_isloaded(pte)) {
73 leaflet = pte_leaflet(pte);
74 assert(leaflet_refcount(leaflet));
76 if (leaflet_ppfn(leaflet) == pte_ppfn(pte)) {
77 leaflet_borrow(leaflet);
81 else if (!pt_last_level(level)) {
82 alloc_kpage_at(ptep_dest, pte, 0);
84 ptep = ptep_step_into(ptep);
85 ptep_dest = ptep_step_into(ptep_dest);
92 if (ptep_vfn(ptep) == MAX_PTEN - 1) {
94 ptep = ptep_step_out(ptep);
95 ptep_dest = ptep_step_out(ptep_dest);
103 // Ensure we step back to L0T
105 assert(ptep_dest == ptepd_kernel);
107 // Carry over the kernel (exclude last two entry)
108 while (ptep_vfn(ptep) < MAX_PTEN - 2) {
110 assert(!pte_isnull(pte));
112 // Ensure it is a next level pagetable,
113 // we MAY relax this later allow kernel
114 // to have huge leaflet mapped at L0T
115 leaflet = pte_leaflet_aligned(pte);
116 assert(leaflet_order(leaflet) == 0);
118 set_pte(ptep_dest, pte);
119 leaflet_borrow(leaflet);
125 return pte_paddr(*(ptep_dest + 1));
129 vmsfree(ptr_t vm_mnt)
131 struct leaflet* leaflet;
132 pte_t* ptep_head = mkl0tep(mkptep_va(vm_mnt, 0));
133 pte_t* ptep_kernel = mkl0tep(mkptep_va(vm_mnt, KERNEL_RESIDENT));
136 pte_t* ptep = ptep_head;
137 while (ptep < ptep_kernel)
140 ptr_t pa = pte_paddr(pte);
142 if (pte_isnull(pte)) {
146 if (!pt_last_level(level) && !pte_huge(pte)) {
147 ptep = ptep_step_into(ptep);
153 if (pte_isloaded(pte)) {
154 leaflet = pte_leaflet_aligned(pte);
155 leaflet_return(leaflet);
157 ptep += __ptep_advancement(leaflet, level);
161 if (ptep_vfn(ptep) == MAX_PTEN - 1) {
162 ptep = ptep_step_out(ptep);
163 leaflet = pte_leaflet_aligned(pte_at(ptep));
165 assert(leaflet_order(leaflet) == 0);
166 leaflet_return(leaflet);
174 leaflet = pte_leaflet_aligned(ptep_head[MAX_PTEN - 1]);
175 leaflet_return(leaflet);
179 __attach_to_current_vms(struct proc_mm* guest_mm)
181 struct proc_mm* mm_current = vmspace(__current);
183 assert(!mm_current->guest_mm);
184 mm_current->guest_mm = guest_mm;
189 __detach_from_current_vms(struct proc_mm* guest_mm)
191 struct proc_mm* mm_current = vmspace(__current);
193 assert(mm_current->guest_mm == guest_mm);
194 mm_current->guest_mm = NULL;
200 procvm_dupvms_mount(struct proc_mm* mm) {
204 struct proc_mm* mm_current = vmspace(__current);
206 __attach_to_current_vms(mm);
208 mm->heap = mm_current->heap;
209 mm->vm_mnt = VMS_MOUNT_1;
210 mm->vmroot = vmscpy(VMS_MOUNT_1, VMS_SELF, false);
212 region_copy_mm(mm_current, mm);
216 procvm_mount(struct proc_mm* mm)
221 vms_mount(VMS_MOUNT_1, mm->vmroot);
223 __attach_to_current_vms(mm);
225 mm->vm_mnt = VMS_MOUNT_1;
229 procvm_unmount(struct proc_mm* mm)
233 vms_unmount(VMS_MOUNT_1);
234 struct proc_mm* mm_current = vmspace(__current);
236 mm_current->guest_mm = NULL;
243 procvm_initvms_mount(struct proc_mm* mm)
247 __attach_to_current_vms(mm);
249 mm->vm_mnt = VMS_MOUNT_1;
250 mm->vmroot = vmscpy(VMS_MOUNT_1, VMS_SELF, true);
254 procvm_unmount_release(struct proc_mm* mm) {
255 ptr_t vm_mnt = mm->vm_mnt;
256 struct mm_region *pos, *n;
257 llist_for_each(pos, n, &mm->regions, head)
259 mem_sync_pages(vm_mnt, pos, pos->start, pos->end - pos->start, 0);
267 __detach_from_current_vms(mm);
271 procvm_mount_self(struct proc_mm* mm)
274 assert(!mm->guest_mm);
276 mm->vm_mnt = VMS_SELF;
280 procvm_unmount_self(struct proc_mm* mm)
282 assert(mm->vm_mnt == VMS_SELF);
288 procvm_enter_remote(struct remote_vmctx* rvmctx, struct proc_mm* mm,
289 ptr_t remote_base, size_t size)
291 ptr_t vm_mnt = mm->vm_mnt;
294 pfn_t size_pn = pfn(size + MEM_PAGE);
295 assert(size_pn < REMOTEVM_MAX_PAGES);
297 struct mm_region* region = region_get(&mm->regions, remote_base);
298 assert(region && region_contains(region, remote_base + size));
300 rvmctx->vms_mnt = vm_mnt;
301 rvmctx->page_cnt = size_pn;
303 remote_base = page_aligned(remote_base);
304 rvmctx->remote = remote_base;
305 rvmctx->local_mnt = PG_MOUNT_VAR;
307 pte_t* rptep = mkptep_va(vm_mnt, remote_base);
308 pte_t* lptep = mkptep_va(VMS_SELF, rvmctx->local_mnt);
309 unsigned int pattr = region_pteprot(region);
311 for (size_t i = 0; i < size_pn; i++)
313 pte_t pte = vmm_tryptep(rptep, PAGE_SIZE);
314 if (pte_isloaded(pte)) {
319 ptr_t pa = ppage_addr(pmm_alloc_normal(0));
320 set_pte(lptep, mkpte(pa, KERNEL_DATA));
321 set_pte(rptep, mkpte(pa, pattr));
329 procvm_copy_remote_transaction(struct remote_vmctx* rvmctx,
330 ptr_t remote_dest, void* local_src, size_t sz)
332 if (remote_dest < rvmctx->remote) {
336 ptr_t offset = remote_dest - rvmctx->remote;
337 if (pfn(offset + sz) >= rvmctx->page_cnt) {
341 memcpy((void*)(rvmctx->local_mnt + offset), local_src, sz);
347 procvm_exit_remote(struct remote_vmctx* rvmctx)
349 pte_t* lptep = mkptep_va(VMS_SELF, rvmctx->local_mnt);
350 vmm_unset_ptes(lptep, rvmctx->page_cnt);