ld-tool portability fix: MacOS build experience
[lunaix-os.git] / lunaix-os / kernel / mm / region.c
1 #include <lunaix/mm/region.h>
2 #include <lunaix/mm/valloc.h>
3 #include <lunaix/spike.h>
4 #include <lunaix/process.h>
5
6 #include <sys/mm/mempart.h>
7
8 #include <klibc/string.h>
9
10 struct mm_region*
11 region_create(ptr_t start, ptr_t end, u32_t attr)
12 {
13     assert_msg(!va_offset(start), "not page aligned");
14     assert_msg(!va_offset(end), "not page aligned");
15     struct mm_region* region = valloc(sizeof(struct mm_region));
16     *region =
17       (struct mm_region){ .attr = attr, .start = start, .end = end - 1 };
18     return region;
19 }
20
21 struct mm_region*
22 region_create_range(ptr_t start, size_t length, u32_t attr)
23 {
24     assert_msg(!va_offset(start), "not page aligned");
25     assert_msg(!va_offset(length), "not page aligned");
26     struct mm_region* region = valloc(sizeof(struct mm_region));
27     *region = (struct mm_region){ .attr = attr,
28                                   .start = start,
29                                   .end = ROUNDUP(start + length, MEM_PAGE) };
30     return region;
31 }
32
33 struct mm_region*
34 region_dup(struct mm_region* origin)
35 {
36     struct mm_region* region = valloc(sizeof(struct mm_region));
37     *region = *origin;
38
39     if (region->mfile) {
40         vfs_ref_file(region->mfile);
41     }
42
43     llist_init_head(&region->head);
44     return region;
45 }
46
47 void
48 region_add(vm_regions_t* lead, struct mm_region* vmregion)
49 {
50     if (llist_empty(lead)) {
51         llist_append(lead, &vmregion->head);
52         return;
53     }
54
55     struct mm_region *pos, *n;
56     ptr_t cur_end = 0;
57
58     llist_for_each(pos, n, lead, head)
59     {
60         if (vmregion->start >= cur_end && vmregion->end <= pos->start) {
61             break;
62         }
63         cur_end = pos->end;
64     }
65
66     // XXX caution. require mm_region::head to be the lead of struct
67     llist_append(&pos->head, &vmregion->head);
68 }
69
70 void
71 region_release(struct mm_region* region)
72 {
73     if (region->destruct_region) {
74         region->destruct_region(region);
75     }
76
77     if (region->mfile) {
78         struct proc_mm* mm = region->proc_vms;
79         vfs_pclose(region->mfile, mm->proc->pid);
80     }
81
82     if (region->index) {
83         *region->index = NULL;
84     }
85
86     vfree(region);
87 }
88
89 void
90 region_release_all(vm_regions_t* lead)
91 {
92     struct mm_region *pos, *n;
93
94     llist_for_each(pos, n, lead, head)
95     {
96         region_release(pos);
97     }
98 }
99
100 void
101 region_copy_mm(struct proc_mm* src, struct proc_mm* dest)
102 {
103     struct mm_region *pos, *n, *dup;
104
105     llist_for_each(pos, n, &src->regions, head)
106     {
107         dup = valloc(sizeof(struct mm_region));
108         memcpy(dup, pos, sizeof(*pos));
109
110         dup->proc_vms = dest;
111
112         if (dup->mfile) {
113             vfs_ref_file(dup->mfile);
114         }
115
116         if (dup->region_copied) {
117             dup->region_copied(dup);
118         }
119
120         llist_append(&dest->regions, &dup->head);
121     }
122 }
123
124 struct mm_region*
125 region_get(vm_regions_t* lead, unsigned long vaddr)
126 {
127     if (llist_empty(lead)) {
128         return NULL;
129     }
130
131     struct mm_region *pos, *n;
132
133     vaddr = page_aligned(vaddr);
134
135     llist_for_each(pos, n, lead, head)
136     {
137         if (pos->start <= vaddr && vaddr < pos->end) {
138             return pos;
139         }
140     }
141     return NULL;
142 }