6.S081——virtual memory part——xv6 source code complete analysis series (4)

0.briefly speaking

Click to jump to the previous blog

Ok, now to the next topic, which isPhysical memory allocator (kernel/kalloc.c). After a brief introduction to the physical memory allocator in the kernel state, I will briefly introduce the two header files riscv.h and memorylayout.h, because they are quite special.Direct reading may lose integrity

1.kernel/memorylayout.h (79 rows) <-----------(simple summary)
2.kernel/vm.c (434 rows)
3.kernel/kalloc.c (82 rows) < -----------(The code to be read in this blog)
4.kernel/exec.c (154 rows)
5.kernel/riscv.h (366 rows) <------- ----(simple summary)

3.kernel/kalloc.c

3.1 end[]

Like vm.c, the beginning here is aglobal variable declaration, end markedStart location of free physical memory

// 译:内核之后的第一个地址,由kernel.ld定义
extern char end[]; // first address after kernel.
                   // defined by kernel.ld.

Since the comment saysThe end label is defined in kernel.ld, might as well go and have a look :)

/*......*/
/*以上部分省略*/
.bss : {
    
    
    . = ALIGN(16);
    *(.sbss .sbss.*) /* do not need to distinguish this from .bss */
    . = ALIGN(16);
    *(.bss .bss.*)
  }

  PROVIDE(end = .);

The end label is defined at kernel.ld:43, which is defined inAfter all kernel code and data segments, just check the kernel address spaceIt's easier to realize that
insert image description here

3.2 struct run & kmem

These two structures show us that inFree physical memory in the kernelIn what way it is organized, it is actually a simple linked list, which strings together free pages one by one. Regarding this organization method, there is a more detailed description in the xv6 book. Each run structure is stored in the corresponding free page, occupying the size of a pointer, pointing to its successor , andThe freelist pointer points to the beginning of the entire free list,As shown below,A hollow dot indicates a null pointer

insert image description here

The source code is as follows:

// run结构体就是一个指向自身的指针,用于指向下一个空闲页表开始位置
struct run {
    
    
  struct run *next;
};

// 管理物理内存的结构
// 有一把锁lock保证访问时的互斥性
// 以及一个指向
struct {
    
    
  struct spinlock lock;
  struct run *freelist;
} kmem;

3.3 kfree function

First look at the kfree function, this is becauseThe freerange function and the kinit function call it, In fact, what kfree does is very simple, that is, to recycle the page into the free list by using the header insertion method .

// Free the page of physical memory pointed at by pa,
// which normally should have been returned by a
// call to kalloc().  (The exception is when
// initializing the allocator; see kinit above.)
// 译:释放pa指向的页的物理内存,它通常是由调用kalloc返回的
// 特殊情况是初始化分配器时,见上面的kinit函数
void
kfree(void *pa)
{
    
    
  struct run *r;
  
  // 如果要释放的内存不是页对齐的,或者不在自由内存范围内,陷入panic
  if(((uint64)pa % PGSIZE) != 0 || (char*)pa < end || (uint64)pa >= PHYSTOP)
    panic("kfree");

  // Fill with junk to catch dangling refs.
  // 将要回收的这一页填满无用的数据
  // 这一步主要是为了防止在本页内存释放之后仍有进程尝试访问之,无用数据会导致进程快速崩溃
  // 这在xv6 book中有所解释
  memset(pa, 1, PGSIZE);
  
  // 将pa强制转型为run类型的指针,准备回收到链表中
  r = (struct run*)pa;
  
  // 头插法,将回收的页作为链表第一项插入到空闲链表中
  // 注意使用锁机制来保持动作的安全性
  acquire(&kmem.lock);
  r->next = kmem.freelist;
  kmem.freelist = r;
  release(&kmem.lock);
}

3.4 freerange function

This function is used toin pagesRelease the physical memory in the range of [pa_start, pa_end] . pa_start and pa_end functionsDoesn't have to be perfectly page-aligned, this function will first use the PGROUNDUP macro to force the page to be aligned, and thenRelease page by page to the end page

Think about a question, why use the function of rounding up?
- This is a conservative strategy,The essence is still worrying about releasing useful pages, even looking at the termination condition in the for loop: p + PGSIZE <= (char*)pa_end , alsoFollow the same conservative strategy. Because the address passed in by the caller may be unaligned, this address may be exactly in the middle of a certain page, and the address space below this address may still have useful data. If it is aligned downward, the useful page may be released together, thus lead to errors.

——Another important reason is that a page is the smallest unit of memory management, so PTE can only point to an aligned page, soThe memory must also be page-aligned when releasing and applying for memory

void
freerange(void *pa_start, void *pa_end)
{
    
    
  char *p;
  // 向上对齐,防止释放有用的页面
  p = (char*)PGROUNDUP((uint64)pa_start);

  // 逐页释放到终点页面,注意终止条件p + PGSIZE <= pa_end
  // 这本质上也加入了保护措施,防止释放有用页
  for(; p + PGSIZE <= (char*)pa_end; p += PGSIZE)
    kfree(p);
}

3.5 heat

The kinit function is a function to initialize the physical memory allocator when the kernel starts , onlyAfter kinitOnly memory can be allocated by the memory manager.

Note here that in the function of kernel/main.c, the kinit function is called before the page table mechanism is opened, soThe virtual address here is equal to the physical address. With the subsequent deployment of the kernel page table by the kvminit function, when the page table is opened using the kvminithart function, the pointers are all virtual addresses at this time, but since the kernel page table isdirect mappingYes, so they are still equal to physical addresses after three-level page table translation.

void
kinit()
{
    
    
  initlock(&kmem.lock, "kmem");
  
  // 释放从end到PHYSTOP之间的所有物理内存
  // 回收进空闲链表freelist中
  freerange(end, (void*)PHYSTOP);
}

Also, an OS should beKnow the memory of the system directly from the hardware information, but xv6 directly assumes that the memory is only 128MB. So PHYSTOP is defined as follows, this contains all kernel code and data and available RAM size:

#define KERNBASE 0x80000000L
#define PHYSTOP (KERNBASE + 128*1024*1024)

3.6 kalloc function

The kalloc function is specifically responsible forAllocate a page of unused physical memory and return, the main operation is to pick a node from the head of the free list and return .

// Allocate one 4096-byte page of physical memory.
// Returns a pointer that the kernel can use.
// Returns 0 if the memory cannot be allocated.
void *
kalloc(void)
{
    
    
  struct run *r;
  
  // 加锁保证操作安全
  acquire(&kmem.lock);
  // 取下链表头部的第一个节点,即第一个空闲页
  r = kmem.freelist;
  if(r)
    kmem.freelist = r->next;
  release(&kmem.lock);
  
  // 如果r不为空,表示成功分配到了内存
  // 将其填满随机数据后返回
  if(r)
    memset((char*)r, 5, PGSIZE); // fill with junk
  return (void*)r;
}

4.kernel/memorylayout.h & kernel/riscv.h

These two files are not intended to be expanded here, because they are some fine macro definitions and embedded assembly statements , among which some macros related to the address space layout are defined in the memorylayout.h header file, and riscv.h defines many Embedded assembly statements. When we read the code later, it may be better to cut in time.

SoThe code about the virtual memory part of Xv6 has come to an end here, next time it's time for us to work on trap mechanics :)

Guess you like

Origin blog.csdn.net/zzy980511/article/details/130107673