285debce407359fbd5ef14654fab724e5a4d96fe
[lunaix-os.git] / lunaix-os / kernel / mm / vmap.c
1 #include <lunaix/mm/pmm.h>
2 #include <lunaix/mm/vmm.h>
3 #include <lunaix/spike.h>
4
5 #define VMAP_START PG_MOUNT_BASE + MEM_4MB
6 #define VMAP_END VMS_SELF
7
8 static uintptr_t start = VMAP_START;
9
10 void*
11 vmm_vmap(uintptr_t paddr, size_t size, pt_attr attr)
12 {
13     // next fit
14     assert_msg((paddr & 0xfff) == 0, "vmap: bad alignment");
15     size = ROUNDUP(size, PG_SIZE);
16
17     uintptr_t current_addr = start;
18     size_t examed_size = 0, wrapped = 0;
19     x86_page_table* pd = (x86_page_table*)L1_BASE_VADDR;
20
21     while (!wrapped || current_addr >= start) {
22         size_t l1inx = L1_INDEX(current_addr);
23         if (!(pd->entry[l1inx])) {
24             // empty 4mb region
25             examed_size += MEM_4MB;
26             current_addr = (current_addr & 0xffc00000) + MEM_4MB;
27         } else {
28             x86_page_table* ptd = (x86_page_table*)(L2_VADDR(l1inx));
29             size_t i = L2_INDEX(current_addr), j = 0;
30             for (; i < PG_MAX_ENTRIES && examed_size < size; i++, j++) {
31                 if (!ptd->entry[i]) {
32                     examed_size += PG_SIZE;
33                 } else if (examed_size) {
34                     // found a discontinuity, start from beginning
35                     examed_size = 0;
36                     j++;
37                     break;
38                 }
39             }
40             current_addr += j << 12;
41         }
42
43         if (examed_size >= size) {
44             goto done;
45         }
46
47         if (current_addr >= VMAP_END) {
48             wrapped = 1;
49             examed_size = 0;
50             current_addr = VMAP_START;
51         }
52     }
53
54     return NULL;
55
56 done:
57     uintptr_t alloc_begin = current_addr - examed_size;
58     for (size_t i = 0; i < size; i += PG_SIZE) {
59         vmm_set_mapping(VMS_SELF, alloc_begin + i, paddr + i, PG_PREM_RW, 0);
60         pmm_ref_page(KERNEL_PID, paddr + i);
61     }
62     start = alloc_begin + size;
63
64     return (void*)alloc_begin;
65 }