Linux 操作系统内核代码(一)

Linux 操作系统(一)

  • boot.s与head.s
    • BIOS
    • boot.s
      • Overview
      • load
      • load head.s
      • mov head.s
      • prepare for the protected mode
    • head.s
      • 初始化寄存器
      • 初始化IDT、GDT
        • 初始化IDT

boot.s与head.s

BIOS

开机以后首先执行BIOS,BIOS完成了一下三个任务:

  1. 自检:检查硬件
  2. 把引导盘第一个扇区(512B)加载到内存0x7c00处
  3. 加载中断描述符表到0x00处

boot.s

Overview

Linux 操作系统内核代码(一)_第1张图片

boot.s共512字节,以0xAA55结尾,是由BIOS加载进内存的,完成了以下4项工作;(注:此时系统处于实模式

load

  • 0x7c00处的跳转语句:硬件的跳转与软件不同,这里的jump是一个隐式赋值语句,其中cs被赋值为0x7c0,ip被赋值为5;
  • 下面一些列就是初始化各个寄存器。

load head.s

Linux 操作系统内核代码(一)_第2张图片

  • int 0x13:这是个中断,通过0x13中断将head.s从启动盘软驱加载到内存0x10000处。
  • 0x13=19所以在中断描述符表中的第19个描述符开始(每个中断描述符4B)——每行4个描述符,第19个在第5行,由于描述符是从第0个开始算,所以0x13中断指的是第5行最后一个中断FE E3 00 F0
  • 大端存储:所以CS=F0 00, IP=E3 FE;
  • 指令地址=CS<<4 + IP——执行完int 0x13后执行的指令(中断处理程序)地址为000fe3fe(注:二进制左移4位即16进制左移1位
  • 计算:F000<<4=F0000;F0000+E3FE=0xFE3FE;
  • 如何从中断处理程序回到int 0x13下条指令?——执行0x13事将下一条指令IP压入栈中,栈地址为SS:SP即SS<<4+SP
  • 下图中可以看到压栈前sp=0x400;ss=0x7c0,所以栈顶为7c00+400=0x800;

Linux 操作系统内核代码(一)_第3张图片

  • 下图可以看出压栈后栈顶为7c00+3fa=0x7ffa;
    Linux 操作系统内核代码(一)_第4张图片

  • 栈中依次被压入了:EFLAGS;CS;IP
    Linux 操作系统内核代码(一)_第5张图片

  • 当想从中断处理程序返回时就可以弹出栈顶内容获得下条指令的地址;

mov head.s

Linux 操作系统内核代码(一)_第6张图片

  • 由于0x00处有中断描述符表,所以head.s没有直接加载到0x00处。

prepare for the protected mode

由于boot.s只有512B所以这里只进行简单的初始化,复杂初始化留给head.s。

  • lidt(load IDT)将ds:0x0069处的内容填入IDT(此时ds=0x7c0,所以实际上是将地址0x7c69处的内容填入IDT)
    在这里插入图片描述
  • lgdt(load GDT)同理,0x7c6f处代码为:
    在这里插入图片描述
  • 代码中的gdt地址处的代码:
    Linux 操作系统内核代码(一)_第7张图片
    根据GDT格式:
    在这里插入图片描述
    填入后为:
    Linux 操作系统内核代码(一)_第8张图片
  • 设置CR0寄存器,最后一位表示保护模式和实模式。
    在这里插入图片描述
  • boot.s load head.s to the 0x0 in the memory and then initialize gdt, change the CR0, when jumpi , the hardware scans the CR0 and know it’s in protected mode then cs=8, ip = 0;
  • 实模式cs16位,而保护模式32位,因此保护模式下CS用法与实模式不同。
  • Segment Selector
Index (13b) TL(1b) RPL(2b)

将0x8填入其中可知Index = 1;CS作为索引查GDT表。

  • 其中的RPL代表特权模式,00为内核模式,11为用户模式。
  • jumpi即完成了赋值又跳转到head.s第一条指令了。

head.s

初始化寄存器

在这里插入图片描述

  • 初始化DS,由于现在是执行0x0处的代码段,数据段也从原来的0x7c0处更改为现在的0x0,即GDT中的0x2处。
  • lss是load SS
  • init_stack:
    Linux 操作系统内核代码(一)_第9张图片
  • init_stack上一句是指往内存中写128次4B的0,即0.5k个0用于预留的栈空间。

初始化IDT、GDT

初始化IDT

  • 代码1:
    Linux 操作系统内核代码(一)_第10张图片

  • 这里的lea(load effective address)语句是为edx赋值

  • ignore_int——ds:0x114,其中ds=0x10,查过GDT表后得到edx=0x0+0x114=0x114

  • eax=0x80000;ax = 0x0000

  • dx=0x114,所以movw dx ax后,eax=0x80114

  • 接下来给dx赋值后,edx=0x8E00

  • idt——ds:0x198,所以edi=0x0+0x198=0x198

  • ecx=256

  • 代码2:
    Linux 操作系统内核代码(一)_第11张图片

  • (edi)是IDT表地址,经过上边的赋值后eax可以被填入IDT表(由于这个表的形式,所以不得不折腾一下寄存器才能填入)

  • edx是(edi)即IDT表基地址的高4B位置,edi+8及偏移8B准备填写下8B

  • 一共填256次知道ecx为0

  • lidt 是把lidt_opcode填入IDT表:
    Linux 操作系统内核代码(一)_第12张图片

  • 256项,每项8字节,由于从0开始算所以减1

  • idt处填了2k个0;

欢迎大家交流和指正,后续继续完善!

你可能感兴趣的:(操作系统,计算机系统,操作系统,内核,linux)