1 #include "mm.h"
2 #include "slab.h"
3 #include "internal.h"
4 
5 /**
6  * @brief 获取一块新的vma结构体,并将其与指定的mm进行绑定
7  *
8  * @param mm 与VMA绑定的内存空间分布结构体
9  * @return struct vm_area_struct* 新的VMA
10  */
vm_area_alloc(struct mm_struct * mm)11 struct vm_area_struct *vm_area_alloc(struct mm_struct *mm)
12 {
13     struct vm_area_struct *vma = (struct vm_area_struct *)kmalloc(sizeof(struct vm_area_struct), 0);
14     if (vma)
15         vma_init(vma, mm);
16     return vma;
17 }
18 
19 /**
20  * @brief 从链表中删除指定的vma结构体
21  *
22  * @param vma
23  */
vm_area_del(struct vm_area_struct * vma)24 void vm_area_del(struct vm_area_struct *vma)
25 {
26     if (vma->vm_mm == NULL)
27         return;
28     __vma_unlink_list(vma->vm_mm, vma);
29 }
30 
31 /**
32  * @brief 释放vma结构体
33  *
34  * @param vma 待释放的vma结构体
35  */
vm_area_free(struct vm_area_struct * vma)36 void vm_area_free(struct vm_area_struct *vma)
37 {
38     if (vma->vm_prev == NULL && vma->vm_next == NULL) // 如果当前是剩余的最后一个vma
39         vma->vm_mm->vmas = NULL;
40     kfree(vma);
41 }
42 
43 /**
44  * @brief 将vma结构体插入mm_struct的链表之中
45  *
46  * @param mm 内存空间分布结构体
47  * @param vma 待插入的VMA结构体
48  * @param prev 链表的前一个结点
49  */
__vma_link_list(struct mm_struct * mm,struct vm_area_struct * vma,struct vm_area_struct * prev)50 void __vma_link_list(struct mm_struct *mm, struct vm_area_struct *vma, struct vm_area_struct *prev)
51 {
52     struct vm_area_struct *next = NULL;
53     vma->vm_prev = prev;
54     if (prev) // 若指定了前一个结点,则直接连接
55     {
56         next = prev->vm_next;
57         prev->vm_next = vma;
58     }
59     else // 否则将vma直接插入到给定的mm的vma链表之中
60     {
61         next = mm->vmas;
62         mm->vmas = vma;
63     }
64 
65     vma->vm_next = next;
66 
67     if (next != NULL)
68         next->vm_prev = vma;
69 }
70 
71 /**
72  * @brief 将vma给定结构体从vma链表的结点之中删除
73  *
74  * @param mm 内存空间分布结构体
75  * @param vma 待插入的VMA结构体
76  */
__vma_unlink_list(struct mm_struct * mm,struct vm_area_struct * vma)77 void __vma_unlink_list(struct mm_struct *mm, struct vm_area_struct *vma)
78 {
79     struct vm_area_struct *prev, *next;
80     next = vma->vm_next;
81     prev = vma->vm_prev;
82     if (prev)
83         prev->vm_next = next;
84     else // 当前vma是链表中的第一个vma
85         mm->vmas = next;
86 
87     if (next)
88         next->vm_prev = prev;
89 }
90 
91 /**
92  * @brief 查找第一个符合“addr < vm_end”条件的vma
93  *
94  * @param mm 内存空间分布结构体
95  * @param addr 虚拟地址
96  * @return struct vm_area_struct* 符合条件的vma
97  */
vma_find(struct mm_struct * mm,uint64_t addr)98 struct vm_area_struct *vma_find(struct mm_struct *mm, uint64_t addr)
99 {
100     struct vm_area_struct *vma = mm->vmas;
101     struct vm_area_struct *result = NULL;
102     while (vma != NULL)
103     {
104         if (vma->vm_end > addr)
105         {
106             result = vma;
107             break;
108         }
109         vma = vma->vm_next;
110     }
111     return result;
112 }
113 
114 /**
115  * @brief 插入vma
116  *
117  * @param mm
118  * @param vma
119  * @return int
120  */
vma_insert(struct mm_struct * mm,struct vm_area_struct * vma)121 int vma_insert(struct mm_struct *mm, struct vm_area_struct *vma)
122 {
123 
124     struct vm_area_struct *prev;
125 
126     prev = vma_find(mm, vma->vm_start);
127 
128     if (prev && prev->vm_start <= vma->vm_start && prev->vm_end >= vma->vm_end)
129     {
130         // 已经存在了相同的vma
131         return -EEXIST;
132     }
133     // todo: bugfix: 这里的第二种情况貌似从来不会满足
134     else if (prev && ((vma->vm_start >= prev->vm_start && vma->vm_start <= prev->vm_end) || (prev->vm_start <= vma->vm_end && prev->vm_start >= vma->vm_start)))
135     {
136         //部分重叠
137         if ((!CROSS_2M_BOUND(vma->vm_start, prev->vm_start)) && (!CROSS_2M_BOUND(vma->vm_end, prev->vm_end))&& vma->vm_end)
138         {
139             //合并vma 并改变链表vma的范围
140             kdebug("before combining vma:vm_start = %#018lx, vm_end = %#018lx\n", vma->vm_start, vma->vm_end);
141 
142             prev->vm_start = (vma->vm_start < prev->vm_start )? vma->vm_start : prev->vm_start;
143             prev->vm_end = (vma->vm_end > prev->vm_end) ? vma->vm_end : prev->vm_end;
144             // 计算page_offset
145             prev->page_offset = prev->vm_start - (prev->vm_start & PAGE_2M_MASK);
146             kdebug("combined vma:vm_start = %#018lx, vm_end = %#018lx\nprev:vm_start = %018lx, vm_end = %018lx\n", vma->vm_start, vma->vm_end, prev->vm_start, prev->vm_end);
147             kinfo("vma has same part\n");
148             return __VMA_MERGED;
149         }
150     }
151 
152     // prev = vma_find(mm, vma->vm_start);
153 
154     if (prev == NULL) // 要将当前vma插入到链表的尾部
155     {
156         struct vm_area_struct *ptr = mm->vmas;
157         while (ptr)
158         {
159             if (ptr->vm_next)
160                 ptr = ptr->vm_next;
161             else
162             {
163                 prev = ptr;
164                 break;
165             }
166         }
167     }
168     else
169         prev = prev->vm_prev;
170     __vma_link_list(mm, vma, prev);
171     return 0;
172 }
173 
174 /**
175  * @brief 创建anon_vma,并将其与页面结构体进行绑定
176  * 若提供的页面结构体指针为NULL,则只创建,不绑定
177  *
178  * @param page 页面结构体的指针
179  * @param lock_page 是否将页面结构体加锁
180  * @return struct anon_vma_t* 创建好的anon_vma
181  */
__anon_vma_create_alloc(struct Page * page,bool lock_page)182 struct anon_vma_t *__anon_vma_create_alloc(struct Page *page, bool lock_page)
183 {
184     struct anon_vma_t *anon_vma = (struct anon_vma_t *)kmalloc(sizeof(struct anon_vma_t), 0);
185     if (unlikely(anon_vma == NULL))
186         return NULL;
187     memset(anon_vma, 0, sizeof(struct anon_vma_t));
188 
189     list_init(&anon_vma->vma_list);
190     semaphore_init(&anon_vma->sem, 1);
191 
192     // 需要和page进行绑定
193     if (page != NULL)
194     {
195         if (lock_page == true) // 需要加锁
196         {
197             uint64_t rflags;
198             spin_lock(&page->op_lock);
199             page->anon_vma = anon_vma;
200             spin_unlock(&page->op_lock);
201         }
202         else
203             page->anon_vma = anon_vma;
204 
205         anon_vma->page = page;
206     }
207     return anon_vma;
208 }
209 
210 /**
211  * @brief 将指定的vma加入到anon_vma的管理范围之中
212  *
213  * @param anon_vma 页面的anon_vma
214  * @param vma 待加入的vma
215  * @return int 返回码
216  */
__anon_vma_add(struct anon_vma_t * anon_vma,struct vm_area_struct * vma)217 int __anon_vma_add(struct anon_vma_t *anon_vma, struct vm_area_struct *vma)
218 {
219     semaphore_down(&anon_vma->sem);
220     list_add(&anon_vma->vma_list, &vma->anon_vma_list);
221     vma->anon_vma = anon_vma;
222     atomic_inc(&anon_vma->ref_count);
223     semaphore_up(&anon_vma->sem);
224     return 0;
225 }
226 
227 /**
228  * @brief 释放anon vma结构体
229  *
230  * @param anon_vma 待释放的anon_vma结构体
231  * @return int 返回码
232  */
__anon_vma_free(struct anon_vma_t * anon_vma)233 int __anon_vma_free(struct anon_vma_t *anon_vma)
234 {
235     if (anon_vma->page != NULL)
236     {
237         spin_lock(&anon_vma->page->op_lock);
238         anon_vma->page->anon_vma = NULL;
239         spin_unlock(&anon_vma->page->op_lock);
240     }
241     kfree(anon_vma);
242 
243     return 0;
244 }
245 
246 /**
247  * @brief 从anon_vma的管理范围中删除指定的vma
248  * (在进入这个函数之前,应该要对anon_vma加锁)
249  * @param vma 将要取消对应的anon_vma管理的vma结构体
250  * @return int 返回码
251  */
__anon_vma_del(struct vm_area_struct * vma)252 int __anon_vma_del(struct vm_area_struct *vma)
253 {
254     // 当前vma没有绑定anon_vma
255     if (vma->anon_vma == NULL)
256         return -EINVAL;
257 
258     list_del(&vma->anon_vma_list);
259     atomic_dec(&vma->anon_vma->ref_count);
260 
261     // 若当前anon_vma的引用计数归零,则意味着可以释放内存页
262     if (unlikely(atomic_read(&vma->anon_vma->ref_count) == 0)) // 应当释放该anon_vma
263     {
264         // 若页面结构体是mmio创建的,则释放页面结构体
265         if (vma->anon_vma->page->attr & PAGE_DEVICE)
266             kfree(vma->anon_vma->page);
267         else
268             free_pages(vma->anon_vma->page, 1);
269         __anon_vma_free(vma->anon_vma);
270     }
271 
272     // 清理当前vma的关联数据
273     vma->anon_vma = NULL;
274     list_init(&vma->anon_vma_list);
275 }
276