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
16void movealloc_init_chain(void) {
17 INIT_LIST_HEAD(list: &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 INIT_LIST_HEAD(list: &n->list);
22 list_add_tail(new: &n->list, head: &global.movealloc_chain.list);
23 }
24}
25
26void movealloc_exec_all(void) {
27 movealloc_init_chain();
28 struct list_head *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 (slab_size_to_index(size: ksize(ptr)) != -1)
38 panic("Moved allocations cannot come from slab");
39}
40
41void movealloc_internal(size_t new_domain, void *ptr, enum vmm_flags flags) {
42 if (global.current_bootstage >= BOOTSTAGE_COMPLETE)
43 panic("movealloc cannot be called after boot completes");
44
45 struct domain *d = global.domains[new_domain];
46 size_t size = ksize(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 for (size_t i = 0; i < pages; i++) {
52 vaddr_t vaddr = aligned_down + i * PAGE_SIZE;
53 paddr_t paddr = vmm_get_phys(vaddr, flags);
54 paddr_t new_phys = domain_alloc_from_domain(cd: d, pages: 1);
55 if (!new_phys)
56 panic("movealloc failed!");
57
58 vaddr_t new_virt = hhdm_paddr_to_vaddr(p: new_phys);
59 void *pvaddr = (void *) vaddr;
60 void *pnew_virt = (void *) new_virt;
61 memcpy(pnew_virt, pvaddr, PAGE_SIZE);
62 vmm_map_page(vaddr, new_phys, PAGE_WRITE | PAGE_PRESENT,
63 flags | VMM_FLAG_MODIFY_LEAF);
64 kassert(vmm_get_phys(vaddr, flags) == new_phys);
65
66 phys_addrs[i] = paddr;
67 }
68
69 for (size_t i = 0; i < pages; i++) {
70 pmm_free_page(addr: phys_addrs[i]);
71 }
72
73 change_slab_backing_page(ptr);
74}
75