Linux操作系统, 构建自己的内核——3. 由实模式进入保护模式之32位寻址

这个课程讲的是怎么由实模式进入保护模式,正如文章所说,学完之后完全是云里雾里。
简单记录一下自己所学,希望继续学习下去能够柳暗花明吧。

课程链接:
网易课程:java开发操作系统内核:由实模式进入保护模式之32位寻址
CSDN博客:java开发操作系统内核:由实模式进入保护模式之32位寻址
建议这个课程一定要看网易的视频,只看文章完全看不懂。

1. 知识储备

内存分段分页机制理解

2. 代码

boot.asm

org  0x7c00;

LOAD_ADDR  EQU  0X8000

entry:
    mov  ax, 0
    mov  ss, ax
    mov  ds, ax
    mov  es, ax
    mov  si, ax

readFloppy:
    mov          CH, 0        ;CH 用来存储柱面号(读取位置要与java代码写入img文件时写入的位置一致)
    mov          DH, 0        ;DH 用来存储磁头号
    mov          CL, 2        ;CL 用来存储扇区号

    mov          BX, LOAD_ADDR       ; ES:BX 数据存储缓冲区

    mov          AH, 0x02      ;  AH = 02 表示要做的是读盘操作
    mov          AL,  1        ; AL 表示要连续读取几个扇区
    mov          DL, 0         ;驱动器编号,一般我们只有一个软盘驱动器,所以写死   
                               ;为0
    INT          0x13          ;调用BIOS中断实现磁盘读取功能

    JC           fin

    jmp          LOAD_ADDR



fin:
    HLT
    jmp  fin

kernel.asm

%macro Descriptor 3
    dw    %2  &  0FFFFh
    dw    %1  &  0FFFFh
    db   (%1>>16) & 0FFh
    dw   ((%2 >> 8) & 0F00h) | (%3 & 0F0FFh)
    db   (%1 >> 24) & 0FFh
%endmacro


DA_32		EQU	4000h	; 32 位段//不太明白这个32位段表示啥意思?
DA_C		EQU	98h	; 存在的只执行代码段属性值
DA_DRW		EQU	92h	; 存在的可读写数据段属性值


org   0x9000

;//为啥要直接跳转到LABEL_BEGIN呢?下面的定义GDT相关的代码不用执行吗
jmp   LABEL_BEGIN

[SECTION .gdt]
;利用上面定义的宏来定义结构体,和下面定义GdtPtr的方式一样
;                                  段基址          段界限                属性
LABEL_GDT:          Descriptor        0,            0,                   0  
LABEL_DESC_CODE32:  Descriptor        0,      SegCode32Len - 1,       DA_C + DA_32
LABEL_DESC_VIDEO:   Descriptor     0B8000h,         0ffffh,            DA_DRW

;$表示当前地址
GdtLen     equ    $ - LABEL_GDT
GdtPtr     dw     GdtLen - 1
           dd     0

;计算段选项符。其实就是对应的段在GDT表中的偏移
SelectorCode32    equ   LABEL_DESC_CODE32 -  LABEL_GDT
SelectorVideo     equ   LABEL_DESC_VIDEO  -  LABEL_GDT

[SECTION  .s16]
[BITS  16]
LABEL_BEGIN:
;现在的cs寄存器是0吗?那是不是可以直接给ax赋0?
;改成0试了一下确实可以正常运行.
     mov   ax, cs
     mov   ds, ax
     mov   es, ax
     mov   ss, ax
     mov   sp, 0100h

     ;这一段代码表示的是实模式下的寻址:cs*16+偏移地址
     ;重复cpu在实模式下的寻址计算方法,得到当前段的地址,再通过偏移得到LABEL_SEG_CODE32的地址。
     ;将要运行的代码段LABEL_SEG_CODE32的地址写入GDT表中
     xor   eax, eax
     mov   ax,  cs
     shl   eax, 4
     add   eax, LABEL_SEG_CODE32
     mov   word [LABEL_DESC_CODE32 + 2], ax
     shr   eax, 16
     mov   byte [LABEL_DESC_CODE32 + 4], al
     mov   byte [LABEL_DESC_CODE32 + 7], ah

     ;创建GdtPtr
     xor   eax, eax
     mov   ax, ds
     shl   eax, 4
     add   eax,  LABEL_GDT
     mov   dword  [GdtPtr + 2], eax

     ;保存GDP表的地址和长度到寄存器中:寄存器GDTR用来存放GDT的入口地址,以及长度
     lgdt  [GdtPtr]

     cli   ;关中断

     in    al,  92h
     or    al,  00000010b
     out   92h, al

     mov   eax, cr0
     or    eax , 1
     mov   cr0, eax

     ;跳转,通过SelectorCode32到GDT表中查找代码的位置
     ;现在已经进入保护模式,寻址方式也已经发生了改变。
     jmp   dword  SelectorCode32: 0

     [SECTION .s32]
     [BITS  32]
LABEL_SEG_CODE32:
    mov   ax, SelectorVideo
    mov   gs, ax
    mov   si, msg
    mov   ebx, 10
    mov   ecx, 2
showChar:
    mov   edi, (80*11)
    add   edi, ebx
    mov   eax, edi
    mul   ecx
    mov   edi, eax
    mov   ah, 0ch
    mov   al, [si]
    cmp   al, 0
    je    end
    add   ebx,1
    add   si, 1
    mov   [gs:edi], ax
    jmp    showChar
end: 
    jmp   $
    msg:
    DB     "Protect Mode, write by copbint!", 0

SegCode32Len   equ  $ - LABEL_SEG_CODE32

3. 效果

1)先分别编译:

 nasm -o kernel.bat kernel.asm
 nasm -o boot.bat boot.asm

2)再运行作者提供的java程序,制作img文件。

3)设置虚拟机从img文件启动
在这里插入图片描述

4. 疑问

1) 讲实模式到保护模式的切换,为什么要引入GDT表呢?

这两者似乎没有必然的关系啊?不理解。。。
20190830补充:
答:
保护模式下必须使用分段的寻址方式,GDT表是分段寻址的必要前提,所以必须要构造GDT表。

5. 保护模式下操作5M地址内存

后面紧接着有一个课程是如何向5M地址空间的内存写入数据并读出,展示的是保护模式的寻址能力,相比于本篇文章,没啥新东西。故略过。
保护模式超强的寻址功能:天空任鸟飞

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值