🗒️Xv6-Klloc
2023-4-23|2023-5-22
Anthony
type
status
date
slug
summary
tags
category
icon
password
本Blog基于任职于美国波特兰洲立大学的教授@hhp3在Youtube上对xv6内核的讲解视频本期讲解xv6中的内存分配,视频链接在下面
预备知识
在xv6中所有的内存分配都以一个4kb的块为单位,它们维持在一个空列表上

这是一张xv6的地址空间和虚拟空间映射表,根据此,我们可以更好地可视化xv6中的地址空间

相关函数
有关的函数都位于kernel/kalloc.c
结构体
首先我们查看
kalloc.c
,在这个程序的头部有一些定义好的变量和结构体其中
struct run *freelist
是指向空闲列表的指针
struct run
中包含一个指向下一个页表/块 的指针*next
kmem
结构体将spinlock
和指向空闲列表的指针绑定在一起,这意味着当我们操作空闲列表时,这个操作是需要上锁的。
extern char end[]
这是在系统建立的时候,end被设置成用于指向第一个可用地址的指针。具体而言,这个地址就是在kernel
的可执行代码,text section
,data section
之后的第一个地址。
- 如果你还记得刚才那一张xv6的地址空间图,你就会知道
text section
对应的是kernel text
,data section
对应的是kernel data
, 所谓第一个可用地址就在Kernel data
的上面,xv6
中可供分配的空间(128M)
就是Free memory
这里面最重要的两个函数,一个是
kalloc()
,这个函数的主要功能就是从freelist
上拿出可用的页表。另一个就是kfree()
,主要功能是回收页表,把这些空页表重新放回到freelist
中去。kinit()
在这个函数中,我们初始化了
lock
,然后调用freeange()
释放掉在第一个可用字节和物理空间顶端(PHYSTOP)
之间的空间。KERNBASE
就是第一个可用的地址,我们很容易就可以看出来xv6
中可分配的内存空间是128M
freearagne()
该函数通过调用
kfree
,负责释放第一个可用地址和物理顶端的空间。它首先接受
*pa_start
(其实就是第一个可用地址)和*pa_end
(就是物理顶端)。然后和页表的格式对齐(向上对齐),就是4k的倍数kalloc()
在该函数中,我们首先获取
spinlock
。还记得kmem
吗,就是那个把指向freelist
的指针和锁绑定在一起的结构体。- 通过
r = kmem.freelist
我们获取到了指向空闲列表的指针,也就是空闲列表的第一个空闲页表/块。
- 然后判断这个地址
r
是不是真的有,如果存在的话,就把指向空闲列表的指针往后移动一位。(学过数据结构的都知道吧,就是简单链表操作,现在链表头往后挪了,那也就相当于拿出了一块)所以说xv6分配新空间是从空闲列表的头部开始拿的
- 刚刚只是操作了链表,我们还没有真的分配空间(memset)。我们使用memset将新分配的空间用5填满。
kfree()
该函数接受一个物理地址
pa
。- 首先进行
pa
(physical address)的合法性检验,确保pa
与页表的边缘对齐(在页表的头部),确保pa
不会太大超出物理空间,不会太小小于最初的字节
- 然后将要释放的空间首先用”1”填满,这是为了能够让后续的代码想要使用它的时候能够发现错误,比较我们不希望使用已经释放掉了的空间。
- 接下来获取到指向这块空间的指针,然后获取
spinlock
将这块空间插在freelist的头部,释放锁。所以说新的空间是在空闲列表的头部的
你可以把空闲列表当作一个乒乓球筒,每次拿球都是从顶部拿,放球也是放在顶部。
本次讲解到这里就结束啦,如果你觉得讲的还算可以,欢迎你转发给你的朋友们。如果有说的不对的,也欢迎大家指出🥰