前言

妈的还是没控制住自己,玩了几天,我自己就有一个很臭的毛病,如果玩的话就会一直玩下去,既然如此我直接不玩了,妈的我发誓绝逼不玩了
还好没出现什么BUG,也算是完成了。
关于这一章,我觉得比较重要的是对于全局描述符的设置,在书中我们可以知道,实模式下用户程序可以直接访问内存,这无疑是及其不安全的,并且用户程序与操作系统是同一地位的,这也意味着用户程序可以随意进入操作系统内核,这些都是及其不安全的,所以就有了保护模式,其中由于对段的约束,描述比较多,于是就用8字节的内存区域来描述段,这也就是段描述符,段描述符的属性如下:

为了统一管理段描述符,就有一个全局描述符表来存储这些段描述符,这个全局描述符表就相当于数组,把段描述符存储在里面,然后如何来获取这些段描述符,既然相当由于数组,自然直接通过索引来获取,于是就有段选择子来存储索引,由于考虑到段描述符已经都在GDT里面了,也就是说段寄存器不再需要存储段基址了,所以在保护模式下就让段寄存器存储这个索引。当然全局描述符表肯定也是在内存中,于是需要获取其地址,这里是使用gdtr寄存器来存储其地址,gdtr是一个48位的寄存器,存储了GDT内存的起始地址以及GDT的界限,由于GDT在实模式下也有,所以可以先把GDT的地址暂时放在内存中,之后再装入到gdtr寄存器中,其使用的指令为lgdt 48位内存地址
举个例子吧,假设段选择子为0x8装入了ds寄存器中,访问ds:0x1的地址,由于段选择子的3-15位存储索引,所以0x8=00001000就是000001作为索引,也就是索引1,于是去GDT中找到索引为1的段描述符,假设段描述符中的段基址是0x00,则真正访问的内存地址为0x00+0x1=0x01的物理地址

实验

boot.inc

LOADER_BASE_ADDR equ 0x900
LOADER_START_SECTOR equ 0x2
;段描述符中一些属性
DESC_G_4K equ  1_0000_0000_0000_0000_0000_000b  ;高32位的第23位G:代表粒度
DESC_D_32 equ   1_0000_0000_0000_0000_0000_00b ;在高32位的第22位D/B:代表是不是32位的操作数
DESC_L    equ    0_0000_0000_0000_0000_0000_0b  ;在高32位的第21位L:代表在不在内存中
DESC_AVL  equ     0_0000_0000_0000_0000_0000b ;在高32位的第20位AVL:操作系统管理,不需要管DESC_LIMIT_CODE2  equ 1111_0000_0000_0000_0000b ;代码段的段界限的第二部分
DESC_LIMIT_DATA2  equ DESC_LIMIT_CODE2
DESC_LIMIT_VIDEO2 equ 0000_0000_0000_0000_0000b
DESC_P equ  1_000000000000000b                  ;表示段存在
DESC_DPL_0 equ 00_0000_0000_00000b                ;表示内存段的特权级
DESC_DPL_1 equ 01_0000_0000_00000b                ;表示内存段的特权级
DESC_DPL_2 equ 10_0000_0000_00000b                ;表示内存段的特权级
DESC_DPL_3 equ 11_0000_0000_00000b                ;表示内存段的特权级
DESC_S_CODE equ 1_0000_0000_0000b               ;系统段
DESC_S_DATA   equ DESC_S_CODE                   ;系统段
DESC_S_sys equ 0_0000_0000_0000b                ;系统段
DESC_TYPE_CODE equ 1000_0000_0000b              ;用来指定描述符的类型
DESC_TYPE_DATA equ 0010_0000_0000b
DESC_CODE_HIGH4 equ (0x00<<24)+DESC_G_4K+DESC_D_32+ \
DESC_L+DESC_AVL+DESC_LIMIT_CODE2+ \
DESC_P+DESC_DPL_0+DESC_S_CODE+DESC_TYPE_CODE+0x00DESC_DATA_HIGH4 equ (0x00<<24)+DESC_G_4K+DESC_D_32+ \
DESC_L+DESC_AVL+DESC_LIMIT_DATA2+DESC_P+DESC_DPL_0+DESC_S_DATA+ \
DESC_TYPE_DATA +0X00DESC_VIDEO_HIGH4 equ (0x00<<24)+DESC_G_4K+DESC_D_32+ \
DESC_L+DESC_AVL+DESC_LIMIT_VIDEO2+DESC_P+ \
DESC_DPL_0+DESC_S_DATA+DESC_TYPE_DATA+0X0b;-----选择子属性------------
RPL0 equ 00b
RPL1 equ 01b
RPL2 equ 10b
RPL3 equ 11b
TI_GDT  equ 000b
TI_LDT  equ 100b

mbr.S

%include "boot.inc" ;预处理
SECTION MBR vstart=0x7c00 ;设置段基址mov ax,csmov ds,axmov es,axmov ss,axmov fs,axmov sp,0x7c00mov ax,0xb800mov gs,axmov ax,0x600mov bx,0x700mov cx,0mov dx,0x184fint 0x10;以下都是显存的设置 gs=0xb800 就是可以显示字符的内存地址mov byte [gs:0x00],'1'mov byte [gs:0x01],0xA4mov byte [gs:0x02],' 'mov byte [gs:0x03],0xA4mov byte [gs:0x04],'M'mov byte [gs:0x05],0xA4mov byte [gs:0x06],'B'mov byte [gs:0x07],0xA4mov byte [gs:0x08],'R'mov byte [gs:0x09],0xA4mov eax,LOADER_START_SECTOR ;起始扇区Lba地址mov bx,LOADER_BASE_ADDR    ;写入的地址mov cx,4                  ;待读入的扇区!!!需要改为4call rd_disk_m_16          ;以下读程序的起始部分jmp LOADER_BASE_ADDR       ;将数据加载到内存中后就会转而执行这个,其实也就是loader.bin;----功能:读取硬盘第n个扇区----;eax LBA扇区号;bx=将内存写入的地址;cx=读入的扇区数
rd_disk_m_16:mov esi,eax ;用来备份eax,dimov di,cx   ;di=1mov dx,0x1f2 ;设置扇区的数量的端口mov al,cl    ;al=1,只需要8位out dx,al    ;将al写入dx寄存器中,dx寄存器就是端口mov eax,esi  ;将eax复位mov dx,0x1f3 ;设置LBA的端口out dx,al    ;将LBA的7-0位读入端口去mov cl,8     ;shr eax,cl   ;右移8位mov dx,0x1f4out dx,al    ;将LBA的15-8位存入端口中去shr eax,cl   ;右移8位mov dx,0x1f5 out dx,al    ;将LBA的23-16位存入端口中去shr eax,cl   ;再次右移8位and al,0x0f  ;让低4位不变,因为低4位需要保存LBA的28-24位(LBA总共28位)or al,0xe0   ;将前四位与1110取或,也就是前三位直接固定,保证寻址模式一定是LBAmov dx,0x1f6 ;进入device端口out dx,al    ;将信息读给端口mov dx,0x1f7 ;命令端口mov al,0x20  ;读入扇区的命令out dx,al    ;将命令读入端口.not_ready:nopin al,dx ;将端口中的信息读到al中,注意此时dx=0x1f7不变,此时是status寄存器,也就是状态端口and al,0x88 ;通过第7位(从0开始),也就是第8位(从1开始),判断硬盘是不是忙碌的,也就是是否被占了,1代表被占cmp al,0x08  ;jnz .not_ready ;如果被占取了,就循环  jnz=jmp not equalmov ax,di  ;di=1mov dx,256 mul dx     ;dx=ax*dx 每次读取1个字,也就是两字节,一共512字节,所以需要256次mov cx,ax  ;cx指定循环的次数mov dx,0x1f0 ;数据端口,终于开始读取数据了.go_on_read:     in ax,dx      ;将端口中指定的数据,也就是指定的扇区的数据读入到ax中mov [bx],ax   ;bx寄存器存储的就是0x900也就是loader的内存地址add bx,2      ;每次读两字节loop .go_on_readret            ;返回后就会执行jmp跳转到0x900去了,此时机会执行loader.bintimes 510-($-$$) db 0 ;剩下的数据填充为0db 0x55,0xaa        ;魔数,判断是否为mbr

loader.S

%include "boot.inc"
section loader vstart=LOADER_BASE_ADDR
LOADER_STACK_TOP equ LOADER_BASE_ADDR
jmp loader_start ;构建gdt及其内部的描述符
GDT_BASE:   dd 0x00000000dd 0x00000000
CODE_DESC:  dd 0x0000ffffdd DESC_CODE_HIGH4
DATA_STACK_DESC:    dd 0x0000ffffdd DESC_DATA_HIGH4
VIDEO_DESC: dd 0x80000007dd DESC_VIDEO_HIGH4 GDT_SIZE  equ  $ - GDT_BASE
GDT_LIMIT equ GDT_SIZE-1
times 60 dq 0
SELECTOR_CODE equ (0x0001<<3)+TI_GDT+RPL0
SELECTOR_DATA equ (0x0002<<3)+TI_GDT+RPL0
SELECTOR_VIDEO equ (0x0003<<3)+TI_GDT+RPL0gdt_ptr  dw GDT_LIMIT dd GDT_BASE
loadermsg db '2 loader int real'
loader_start:
;-------------------------------------------
;INT 0X10  功能号:0x13
;--------------------------------------------
;输入:
;AH 子功能号=13H
;BH=页码
;BL=属性
;CX=字符串长度
;(DH,DL)=坐标(行,列)
;es:bp=字符串地址
;al=显示输出方式
;0-------字符串中只含显示字符,其显示属性在bl中,显示后光标位置不变
;1-------字符串只含显示字符,其显示属性在bl中,显示后光标位置改变
;2-------字符串中含显示字符和显示属性,显示后光标位置不变
;3-------字符串中含显示字符和显示属性,显示后光标位置改变
;无返回值mov sp,LOADER_BASE_ADDRmov bp,loadermsg    ;es:bp 字符串地址mov cx,17           ;cx=字符串长度mov ax,0x1301       ;ah=13 al=01hmov bx,0x001f       ;页号为0(bh=0),蓝底粉红字(bl=1fh)mov dx,0x1800       int 0x10;-------准备进入保护模式----------;1 打开A20;2 加载gdt;3 将cr0的pe 为置1;---------------------------打开A20----------in al,0x92or al,0000_0010bout 0x92,al;------------------------加载GDT------------------lgdt [gdt_ptr];;----------------------cr0第0位置1-------------------mov eax,cr0 or eax,0x00000001mov cr0,eaxjmp dword SELECTOR_CODE:p_mode_start[bits 32]p_mode_start:mov ax,SELECTOR_DATAmov ds,axmov es,axmov ss,axmov esp,LOADER_STACK_TOPmov ax,SELECTOR_VIDEO        ;低32位放入显存中mov gs,axmov byte [gs:160],'p'jmp $

实验结果


操作系统真象还原第4章:保护模式入门相关推荐

  1. 《操作系统真象还原》第二章

    <操作系统真象还原>第二章 编写MBR主引导记录 载入内存 过程: (1)程序被加载器(软件或硬件)加载到内存某个区域. (2)CPU的cs:ip寄存器被指向这个程序的起始地址. 从按下主 ...

  2. 《操作系统真象还原》第九章

    <操作系统真象还原>第九章 本篇对应书籍第九章的内容 本篇内容介绍了线程是什么,多线程的原理,多线程用到的核心数据结构,以及通过代码实现了内核多线程的调度 线程是什么? 执行流 过去,计算 ...

  3. 《操作系统真象还原》1-3章 学习记录

    文章目录 前言 一.开始实验前的一些基本问题解答? section的含义? vstart的含义? $ 和 $$区别? 实模式的特点? CPU如何和硬盘进行交互? CPU和IO设备交互方式? 程序载入内 ...

  4. 操作系统真象还原——第5章 从保护模式到内核

    目录 前言 5.1 获取物理内存容量 5.1.1 学习Linux获取内存的方法 5.1.2 实战内存容量检测 5.2 内存分页 为什么需要分页? 一级页表 二级页表 如何设计一个页表 分页机制的代码实 ...

  5. 《操作系统真象还原》第九章 ---- 终进入线程动斧开刀 豁然开朗拨云见日 还需解决同步机制才能长舒气

    文章目录 专栏博客链接 相关查阅博客链接 本书中错误勘误 进程 线程的自我小理解 线程 进程的状态 内核级线程 & 用户级线程 初步实现内核级线程 浪费两三个小时调试的辛酸史 编写thread ...

  6. 操作系统真象还原第2章:编写MBR主引导记录

    前言 这章的内容挺少的,也很简单,如果环境没配置错的话是没啥问题的.但是这章也很精彩,把引导的过程给说了出来,我也是看了几遍把这个过程给大致看懂了. 首先计算机一开机这个时cpu会自动把cs:ip指针 ...

  7. 操作系统真象还原第3章:完善MBR

    前言 这次我出现了一些BUG,导致我忙活了一阵子,还好的是解决了 老规矩还是把整个流程过一遍,当MBR忙活完后,就需要把自己手中的棒交给loader了,MBR的作用就是从硬盘中的内核加载器移动到内存中 ...

  8. 《操作系统真象还原》第二章 ---- 编写MBR主引导记录 初尝编写的快乐 雏形已显!

    文章目录 专栏博客链接 前引 相关术语 理清操作系统启动程序运行流程(部分) 编写MBR引导内容 编译并检验mbr.bin Linux dd 磁盘操作指令与参数 模拟操作试一试 结束语 专栏博客链接 ...

  9. 操作系统真象还原第5章:保护模式进阶,向内核进阶

    前言 由于涉及到马上要搞实习的事情,搞得我十分的浮躁,自己也是频繁失眠,想来还是自己太过懒了,没控制住自己,自己也在这一个多月没搞好,尤其是本来想花几天时间来写一个高性能服务器,也把游双大佬的linu ...

最新文章

  1. StackOverflow 上面最流行的 7 个 Java 问题!
  2. 推荐算法-聚类-K-MEANS
  3. Shell-Scp自动输入密码
  4. oracle 回车、换行符
  5. 通向架构师的道路(第六天)之漫谈基于数据库的权限系统的设计
  6. 利用canvas绘制动态仪表盘
  7. ac 梦幻布丁 启发式合并
  8. 检测同心圆_(二)光线如何被眼睛检测到?
  9. Gartner:阿里云蝉联全球第三、亚太第一
  10. 工作不饱和 ? 给你 8 个程序员接私活的网站
  11. 你真的懂病毒式营销吗
  12. java day19【File类、递归】
  13. 基于扩展性考虑,不同场景选择的不同方案
  14. VC通过函数名调用DLL的标准范例
  15. 数据结构——“双向循环链表“ 易懂刨析双向循环链表(图解+代码)
  16. 水哥王昱珩的教育语录:输不丢人,怕输才丢人
  17. 前端:移动端和PC端的区别
  18. Microsoft CRM 2016 IFD配置
  19. 2023养老展/山东养老服务业展/济南老年用品展/老龄产业展
  20. Ubuntu 18.04 vscode安装网易云音乐插件

热门文章

  1. SQL快出来,收快递啦(分区,case when 连表)
  2. 在线加工(dnc)的含义为加工过程为外接计算机在线输送程序到机床,自动化制造系统试卷 (2)...
  3. 基于微信小程序的教务查询系统的设计与实现
  4. 转】用Maven构建Hadoop项目
  5. egg设置cookie
  6. 计算机游戏蜘蛛纸牌如何还原,ATM自动玩纸牌?或是系统重启显示后台电脑桌面...
  7. 好东东--找到的极品
  8. linux驱动编写--2--应用程序控制led闪烁
  9. 计算机应用基础多媒体技术,计算机应用基础多媒体技术论文
  10. OpenSSL命令大全,CA证书生成,客户端证书生成实例