我是靠谱客的博主 孝顺日记本,最近开发中收集的这篇文章主要介绍UNIX v6源代码分析调试之二:单步调试系统代码 main函数之 kinit1,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

    环境搭建完成,该学习Main.c的main函数了。先贴上main函数的实现。

int
main(void)
{
  kinit1(end, P2V(4*1024*1024)); // phys page allocator
  kvmalloc();      // kernel page table
  mpinit();        // collect info about this machine
  lapicinit();
  seginit();       // set up segments
  cprintf("ncpu%d: starting xv6nn", cpu->id);
  picinit();       // interrupt controller
  ioapicinit();    // another interrupt controller
  consoleinit();   // I/O devices & their interrupts
  uartinit();      // serial port
  pinit();         // process table
  tvinit();        // trap vectors
  binit();         // buffer cache
  fileinit();      // file table
  iinit();         // inode cache
  ideinit();       // disk
  if(!ismp)
    timerinit();   // uniprocessor timer
  startothers();   // start other processors
  kinit2(P2V(4*1024*1024), P2V(PHYSTOP)); // must come after startothers()
  userinit();      // first user process
  // Finish setting up this processor in mpmain.
  mpmain();
}

     这里调用了很多初始化的函数。操作系统的初始化其实是很繁重的工作,很多时候也隐藏着各种知识点。

     这么多函数,贪多嚼不烂,一个一个函数进行调试和学习吧。

     首先是 kinit1 函数的实现。

kinit1(end, P2V(4*1024*1024)); // phys page allocator

void
kinit1(void *vstart, void *vend)
{
  initlock(&kmem.lock, "kmem");
  kmem.use_lock = 0;
  freerange(vstart, vend);
}

  kinit1 函数就是内核内存的初始化,把虚拟内存地址vstart到vend的地址进行初始化。

  首先入参vstart为end,end的值是多少呢,又是怎么来的呢?

extern char end[]; // first address after kernel loaded from ELF file

  end是全局变量,但是在Unix v6代码中只有声明,没有定义。先单步看看end的值是多少吧,如下图:


我们知道内核的虚拟起始地址是0x80100000,这里end的值为0x801126fc。通过一番查找,发现end是ld链接器的内置变量。

这个变量用来表示elf文件装载到内存之后的起始地址。在Kernel.ld中对end变量进行赋值,这里bss段加载完成之后即为end的地址。

	.bss : {
		*(.bss)
	}

	PROVIDE(end = .);


执行objdump命令,可以看到.bss段起始地址0x8010b5a0+0x0000715c = 0x801126fc, 等于end的地址。

接着看freerange函数。

void
freerange(void *vstart, void *vend)
{
  char *p;
  p = (char*)PGROUNDUP((uint)vstart);
  for(; p + PGSIZE <= (char*)vend; p += PGSIZE)
    kfree(p);
}

这里每次释放PGSIZE(4K)字节的大小。然后形成free的链表。这些free的链表即用来分配内存。

void
kfree(char *v)
{
  struct run *r;

  if((uint)v % PGSIZE || v < end || v2p(v) >= PHYSTOP)
    panic("kfree");

  // Fill with junk to catch dangling refs.
  memset(v, 1, PGSIZE);

  if(kmem.use_lock)
    acquire(&kmem.lock);
  r = (struct run*)v;
  r->next = kmem.freelist;
  kmem.freelist = r;
  if(kmem.use_lock)
    release(&kmem.lock);
}

kfree即把要释放的内存初始化为1,同时把释放的内存形成链表的形式。具体如下图:


我这里仍然有一个疑问,就是内存链表这样表示有什么好处呢?是为了操作方便还是以前并不流行使用位图来表示,如果有理解的同学,可以告知一下。

最后

以上就是孝顺日记本为你收集整理的UNIX v6源代码分析调试之二:单步调试系统代码 main函数之 kinit1的全部内容,希望文章能够帮你解决UNIX v6源代码分析调试之二:单步调试系统代码 main函数之 kinit1所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(41)

评论列表共有 0 条评论

立即
投稿
返回
顶部