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