1#include <global.h>
2#include <mem/alloc.h>
3#include <mem/domain.h>
4#include <mem/hhdm.h>
5#include <mem/movealloc.h>
6#include <mem/pmm.h>
7#include <mem/vmm.h>
8#include <string.h>
9#include <thread/dpc.h>
10
11#include "mem/slab/internal.h"
12
13extern struct movealloc_callback_node __skernel_movealloc_callbacks[];
14extern struct movealloc_callback_node __ekernel_movealloc_callbacks[];
15
16static void movealloc_init_chain(void) {
17 list_head_init(h: &global.movealloc_chain.list);
18 struct movealloc_callback_node *start = __skernel_movealloc_callbacks;
19 struct movealloc_callback_node *end = __ekernel_movealloc_callbacks;
20 for (struct movealloc_callback_node *n = start; n < end; n++) {
21 list_node_init(n: &n->list);
22 list_head_push_back(h: &global.movealloc_chain.list, n: &n->list);
23 }
24}
25
26void movealloc_exec_all(void) {
27 movealloc_init_chain();
28 struct list_node *iter;
29 list_for_each(iter, &global.movealloc_chain.list) {
30 struct movealloc_callback_node *node =
31 movealloc_callback_node_from_list_node(iter);
32 node->callback(node->a, node->b);
33 }
34}
35
36static void change_slab_backing_page(void *ptr) {
37 if (valloc_ptr_in_slab_validate(ptr))
38 panic("Moved allocations cannot come from slab");
39}
40
41void movealloc_full(domain_id_t new_domain, void *ptr, struct vmm_request rq) {
42 if (global.current_bootstage >= BOOTSTAGE_COMPLETE)
43 panic(INVALID_CONTEXT, "movealloc after boot completes");
44
45 struct domain *d = global.domains[new_domain];
46 size_t size = vsize(ptr);
47 size_t pages = PAGES_NEEDED_FOR(size);
48 vaddr_t aligned_down = PAGE_ALIGN_DOWN(ptr);
49 paddr_t phys_addrs[pages];
50
51 struct vmm_request remap_rq = rq;
52 remap_rq.page_flags = PAGE_WRITE | PAGE_PRESENT;
53 remap_rq.page_size = VMM_MAP_PAGE_SIZE_4KB;
54 remap_rq.vmm_flags |= VMM_FLAG_MODIFY_LEAF;
55
56 for (size_t i = 0; i < pages; i++) {
57 vaddr_t vaddr = aligned_down + i * PAGE_SIZE;
58 paddr_t paddr = vmm_get_phys_full(virt: vaddr, rq);
59 paddr_t new_phys = domain_alloc_from_domain(cd: d, pages: 1);
60 if (!new_phys)
61 panic("movealloc failed!");
62
63 vaddr_t new_virt = hhdm_paddr_to_vaddr(p: new_phys);
64 void *pvaddr = (void *) vaddr;
65 void *pnew_virt = (void *) new_virt;
66 memcpy(pnew_virt, pvaddr, PAGE_SIZE);
67 vmm_map_page_full(virt: vaddr, phys: new_phys, rq: remap_rq);
68 enforce(vmm_get_phys_full(vaddr, rq) == new_phys);
69
70 phys_addrs[i] = paddr;
71 }
72
73 for (size_t i = 0; i < pages; i++) {
74 pmm_free_page(addr: phys_addrs[i]);
75 }
76
77 change_slab_backing_page(ptr);
78}
79