feat: nearly complete POSIX.1-2008 compliant terminal interface implementation
[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
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(PG_ALIGNED(start), "not page aligned");
14     assert_msg(PG_ALIGNED(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(PG_ALIGNED(start), "not page aligned");
25     assert_msg(PG_ALIGNED(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         vfs_pclose(region->mfile, region->proc_vms->pid);
79     }
80
81     if (region->index) {
82         *region->index = NULL;
83     }
84
85     vfree(region);
86 }
87
88 void
89 region_release_all(vm_regions_t* lead)
90 {
91     struct mm_region *pos, *n;
92
93     llist_for_each(pos, n, lead, head)
94     {
95         region_release(pos);
96     }
97 }
98
99 void
100 region_copy_mm(struct proc_mm* src, struct proc_mm* dest)
101 {
102     struct mm_region *pos, *n, *dup;
103
104     llist_for_each(pos, n, &src->regions, head)
105     {
106         dup = valloc(sizeof(struct mm_region));
107         memcpy(dup, pos, sizeof(*pos));
108
109         dup->proc_vms = dest;
110
111         if (dup->mfile) {
112             vfs_ref_file(dup->mfile);
113         }
114
115         if (dup->region_copied) {
116             dup->region_copied(dup);
117         }
118
119         llist_append(&dest->regions, &dup->head);
120     }
121 }
122
123 struct mm_region*
124 region_get(vm_regions_t* lead, unsigned long vaddr)
125 {
126     if (llist_empty(lead)) {
127         return NULL;
128     }
129
130     struct mm_region *pos, *n;
131
132     vaddr = PG_ALIGN(vaddr);
133
134     llist_for_each(pos, n, lead, head)
135     {
136         if (pos->start <= vaddr && vaddr < pos->end) {
137             return pos;
138         }
139     }
140     return NULL;
141 }