sagalinux学习之/kernel目录

这篇分析有点长了,慢慢看~~。

请随手携带一本《32位微机原理》宝典,以备查询。

这是kernel目录下的Makefile,很简单

CFLAGS = -I../include/ -c -Wall -fno-stack-protector -o

all:	kernel.o page.o idt.o printk.o keyboard.o irq.o i8259.o console.o

clean:
	rm -f *.o *~

kernel.o:
	gcc ${CFLAGS} kernel.o kernel.c

page.o:
	gcc ${CFLAGS} page.o page.c

idt.o:
	gcc ${CFLAGS} idt.o idt.c

printk.o:
	gcc ${CFLAGS} printk.o printk.c

keyboard.o:
	gcc ${CFLAGS} keyboard.o keyboard.c

irq.o:
	gcc ${CFLAGS} irq.o irq.c

i8259.o:
	nasm -felf i8259.s

console.o:
	gcc ${CFLAGS} console.o console.c


我们先来看目录下的kernel.c文件,主函数就在这里,也就是sagalinux的“内核"核心。。。。我们从主函数发散出去逐个研究。

#include "kernel/idt.h"
#include "kernel/page.h"
#include "kernel/kernel.h"
#include "kernel/keyboard.h"
#include "kernel/console.h"

int main(void)
{
  //  int i;
  
  char* message = "\nWelcome!\n";
  char* kernel_release = "Kernel on an i386\n\n";
  char* fake_login = "[LinuxSaga]# ";

  page_init();//初始化页机制,开启分页,映射了0~16M的物理页
  trap_init();//初始化陷阱门
  keyboard_init();//初始化键盘
  con_clear();//清除终端的所有字符

  printk("%s",message);
  printk("%s",kernel_release);
  printk("%s",fake_login);

  //  i = 3 / 0;
  while(1);
  return 0;
}


简单吧,下面是每一个初始化函数的详细

/kernel/page.c	用于初始化页表,页表中描述一个4K的物理页的一个描述项叫做PTE,PTE大小为4B,
如果PTE在一个4K的物理页中连续存放,形成一个表,我们用PDE来描述这个PTE表,一个PDE大小为4B。
就是这一回事。
#include "kernel/page.h"//一些宏定义
#include "asm/system.h"

//初始化页表
void page_init()
{

  int pages = NR_PGT;//PTE表的描述项PDE的个数
                     // NR_PGT 为4,创建4个PTE表的描述项(PDE),每个PDE占4B,描述了一个PTE表,每个PTE描述了一个4K的页,这样总共可以访问4*1024*4K即16M大小的内存
		
  unsigned int page_offset = PAGE_OFFSET;//#define PAGE_OFFSET (unsigned int)0x2000 (8K)


                               //PDE项的开始物理地址,PGD_BASE=0x1000(4K),也就是说PDE位于物理内存的第二个页框内(每个page为4K)
  unsigned int* pgd = PGD_BASE;//#define PGD_BASE (unsigned int*)0x1000 PGD_BASE 是一个指针,指向unsigned int类型,指针的值是0x1000
			       //赋值之后pgd指向了0x1000这个内存地址,注意pgd这个指针变量占用4B,			

  
  unsigned int phy_add = 0x0000;// 从物理地址的最低端开始建立PTE项的映射,映射内存地址0~16M

  // PTE表从物理内存8K处开始,每个PTE表有1024项,占满一个物理页。共有4个PTE表,且连续存放
  unsigned int* pgt_entry = (unsigned int*)0x2000; //PTE表的开始地址(8K)
  
  // 填充页目录表PDE项
  // 这里依次创建4(pages=4)个页目录表PDE,一个PDE就是一个PTE表的描述项
  //(每个PTE表有1024项,1024*4B=4K,占一个物理页)
  while (pages--)
    {
      *pgd++ = page_offset |PTE_USR|PTE_RW|PTE_PRE;
      page_offset += 0x1000;//继续描述下一个PTE表
    }

  //PDE表,有四项PDE:0x1000~0x2000
  //PTE表:共四个表,位于0x2000~0x3000, 0x3000~0x4000, 0x4000~0x5000, 0x5000~0x6000

  pgd = PGD_BASE;//恢复pgd为PDE表基地址0x1000,4K

  // 在页表中填写页到物理地址的映射关系,映射了16M大小的物理内存 即0~16M的物理内存
//共映射了0x1000(4K)个PTE,每个PTE指向一个4K的物理页,共4K*4K=16M内存
  //这里因为PTE表是连续的,所以可以直接给所有的PTE赋值,(*pgt_entry++)
  while (phy_add < 0x1000000) {//0x1000000=16M
    *pgt_entry++ = phy_add |PTE_USR|PTE_RW|PTE_PRE;//下一个PTE项,每个PTE项描述了一个物理页
    phy_add += 0x1000;//下一个物理页,共有4K个PTE,每个PTE一次赋值,共循环了4K次
  }
	//嵌入式汇编语法
//__asm__(assembler template 
//	: output operands /* optional *// 
//	: input operands /* optional */ 
//	: list of clobbered registers /* optional */ 
//);
  // 启用页机制, cr3指向页目录根PDE表的开始
  __asm__ __volatile__ ("movl %0, %%cr3;"//pgd-->cr3,PDT基地址
			"movl %%cr0, %%eax;"
			"orl  $0x80000000, %%eax;"
			"movl %%eax, %%cr0;"	//eax-->cr0,cr0最高位置1,用于开启分页
			:
			:"r"(pgd)//%0代表pgd
			:"memory","%eax");
//Invalidate TLB before and after setting up page tables
//使TLB无效,在多核处理器上,避免其他cpu引用到无效的页表
  invalidate_tlb();
}

回到主函数中下一个trap_init()函数,位于./kernel/idt.c中

#include "kernel/idt.h"
#include "kernel/kernel.h"
#include 
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值