🗒️Xv6-Klloc

2023-4-23|2023-5-22
Anthony
Anthony
type
status
date
slug
summary
tags
category
icon
password
本Blog基于任职于美国波特兰洲立大学的教授@hhp3
在Youtube上对xv6内核的讲解视频
本期讲解xv6中的内存分配,视频链接在下面
 
 

预备知识

在xv6中所有的内存分配都以一个4kb的块为单位,它们维持在一个空列表上
notion image
 
这是一张xv6的地址空间和虚拟空间映射表,根据此,我们可以更好地可视化xv6中的地址空间
xv6-virtual address - physical address
xv6-virtual address - physical address

相关函数

有关的函数都位于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的头部,释放锁。所以说新的空间是在空闲列表的头部的
 
💡
你可以把空闲列表当作一个乒乓球筒,每次拿球都是从顶部拿,放球也是放在顶部。
 
 

本次讲解到这里就结束啦,如果你觉得讲的还算可以,欢迎你转发给你的朋友们。如果有说的不对的,也欢迎大家指出🥰
 
Xv6-Page TableXv6-Scheduling