当前位置: 首页 > news >正文

网站技术维护网站的搜索引擎

网站技术维护,网站的搜索引擎,做国际网站阿里巴巴,河南省工程建设业协会网站文章目录 前言获取物理内存容量利用 BIOS 中断 0x15 子功能 0xe820 获取内存利用 BIOS 中断 0x15 子功能 0xe801 获取内存利用 BIOS 中断 0x15 子功能 0x88 获取内存内存容量检测代码编译运行 结语 前言 经过上一章的学习实践,目前我们已经进入32位保护模式了。本章…

文章目录

    • 前言
    • 获取物理内存容量
      • 利用 BIOS 中断 0x15 子功能 0xe820 获取内存
      • 利用 BIOS 中断 0x15 子功能 0xe801 获取内存
      • 利用 BIOS 中断 0x15 子功能 0x88 获取内存
      • 内存容量检测代码
      • 编译运行
    • 结语

前言

经过上一章的学习实践,目前我们已经进入32位保护模式了。本章的标题是保护模式进阶,向内核迈进,那么就是要在保护模式下进一步编程。

郑钢老师在上一章提到,之前的四章偏向于理论,代码量相对较小,接下来的章节代码量会更多,这对我而言会是一个挑战。

这章内容较多,我打算花2-3天时间完成学习,博客也会分成若干部分,每部分完成一节内容。

第四章知识笔记博客链接:《操作系统真象还原》第四章(1)-CSDN博客

第四章实践部分博客链接:《操作系统真象还原》第四章(2)-CSDN博客

本章参考博客链接:《操作系统真象还原》第五章 ---- 轻取物理内存容量 启用分页畅游虚拟空间 力斧直斩内核先劈一角 闲庭信步摸谈特权级_真象还原 分页 info tab-CSDN博客


获取物理内存容量

保护模式可以访问4GB内存,为了维护这么大的内存空间,就要有相应的内存管理体系。想要管理内存,首先就要先获取内存容量,bios可以通过0x15中断获取内存信息,bios是在实模式下运行的,我们要在进入保护模式之前获取内存容量。

利用 BIOS 中断 0x15 子功能 0xe820 获取内存

子功能 0xE820 的强大之处是返回的内存信息较丰富,包括多个属性字段,所以需要一种格式结构来组织这些数据。内存信息的内容是用地址范围描述符来描述的,用于存储这种描述符的结构称之为地址范围描述符(Address Range Descriptor Structure,ARDS)。

ards长20字节,分为5段,每段4字节,每次调用0x15就会返回一个这样结构的数据。

字节偏移量属性名称描述
0BaseAddrLow第32位基地址
4BaseAddrHigh高32位基地址
8LengthLow低32位内存长度,以字节为单位
12LengthHigh高32位内存长度,以字节为单位
16Type本段内存类型

关于type字段

Type 值名 称描 述
1AddressRangeMemory这段内存可以被操作系统使用
2AddressRangeReserved内存使用中或者被系统保留,操作系统不可以用此内存
其他未定义未定义,将来会用到,目前保留。但是需要操作系统一样将其视为ARR(AddressRangeReserved)

关于0x15中断的0xe820子功能的参数

调用或返回寄存器或状态位参 数 用 途
输入EAX子功能号:EAX 寄存器用来指定子功能号,此处输入为 0xE820
EBXARDS 后续值:内存信息需要按类型分多次返回,由于每次执行一次中断都只返回一种类型内存的 ARDS 结构,所以要记录下一个待返回的内存 ARDS,在下一次中断调用时通过此值告诉 BIOS 该返回哪个 ARDS,这就是后续值的作用。第一次调用时一定要置为 0,EBX具体值我们不用关注,字取决于具体 BIOS 的实现。每次中断返回后,BIOS 会更新此值
ES:DIARDS 缓冲区:BIOS 将获取到的内存信息写入此寄存器指向的内存,每次都以 ARDS 格式返回
ECXARDS 结构的字节大小:用来指示 BIOS 写入的字节数。调用者和 BIOS 都同时支持的大小是 20 字节,将来也许会扩展此结构
EDX固定为签名标记 0x534d4150,此十六进制数字是字符串 SMAP 的 ASCII 码:BIOS 将调用者正在请求的内存信息写入 ES:DI 寄存器所指向的 ARDS 缓冲区后,再用此签名校验其中的信息
输出CF 位若 CF 位为 0 表示调用未出错,CF 为 1,表示调用出错
EAX字符串 SMAP 的 ASCII 码 0x534d4150
ES:DIARDS 缓冲区地址,同输入值是一样的,返回时此结构中已经被BIOS 填充了内存信息
ECXBIOS 写入到 ES:DI 所指向的 ARDS 结构中的字节数,BIOS 最小写入 20 字节
EBX后续值:下一个 ARDS 的位置。每次中断返回后,BIOS 会更新此值,BIOS 通过此值可以找到下一个待返回的 ARDS 结构,咱们不需要改变 EBX 的值,下一次中断调用时还会用到它。在 CF 位为 0 的情况下,若返回后的 EBX 值为 0,表示这是最后一个 ARDS 结构

此中断的调用步骤如下。

  1. 填写好“调用前输入”中列出的寄存器。
  2. 执行中断调用 int 0x15。
  3. 在 CF 位为 0 的情况下,“返回后输出”中对应的寄存器便会有对应的结果。

利用 BIOS 中断 0x15 子功能 0xe801 获取内存

这种方法相对简单,但是只能识别4GB内存,而且数据放到两个寄存器里。低于 15MB 的内存以 1KB 为单位大小来记录,单位数量在寄存器 AX 和 CX 中记录,其中 AX 和 CX 的值是一样的,所以在 15MB 空间以下的实际内存容量=AX*1024。AX、CX 最大值为 0x3c00,即 0x3c00*1024=15MB。16MB~4GB 是以 64KB 为单位大小来记录的,单位数量在寄存器 BX 和 DX 中记录,其中 BX 和 DX 的值是一样的,所以 16MB 以上空间的内存实际大小=BX*64*1024

为什么要分成两部分,分界线是16mb?为了兼容有24根地址总线的80286cpu,此cpu寻址范围是16mb,当时有一些isa设备要利用15-16mb空间作为缓冲区,出现了内存空洞。后续cpu为了兼容286保留了这一特性。

相关参数如下

调用或返回寄存器或状态位描述
输入AX子功能号:0xE801
输出CF若 CF 位为 0 表示调用未出错,CF 为 1,表示调用出错
AX以 1KB 为单位,只显示 15MB 以下的内存容量,故最大值为 0x3c00,即AX 表示的最大内存为 0x3c00*1024=15MB
BX以 64KB 为单位,内存空间 16MB~4GB 中连续的单位数量,即内存大小为 BX*64x1024 字节
CX同AX
DX同BX

此中断的调用步骤如下。

  1. 将 AX 寄存器写入 0xE801。
  2. 执行中断调用 int 0x15。
  3. 在 CF 位为 0 的情况下,“返回后输出”中对应的寄存器便会有对应的结果。

利用 BIOS 中断 0x15 子功能 0x88 获取内存

最后一个获取内存的方法也同样是 BIOS 0x15 中断,子功能号是 0x88。该方法使用最简单,只能识别最大 64MB 的内存。使用的时候结构要加上1MB。

输入:AH 子功能号:0x88

输出:1.CF 位 若 CF 位为 0 表示调用未出错,CF 为 1,表示调用出错

2.AX 以 1KB 为单位大小,内存空间 1MB 之上的连续单位数量,不包括低端1MB 内存。故内存大小为 AX*1024 字节+1MB

此中断的调用步骤如下。

(1)将 AX 寄存器写入 0x88。

(2)执行中断调用 int 0x15。

(3)在 CF 位为 0 的情况下,“返回后输出”中对应的寄存器便会有对应的结果。

内存容量检测代码

关于jxx组指令的参考博客:汇编跳转指令: JMP、JECXZ、JA、JB、JG、JL、JE、JZ、JS、JC、JO、JP 等_jg指令-CSDN博客

%include "boot.inc"
section loader vstart=LOADER_BASE_ADDRLOADER_STACK_TOP equ LOADER_BASE_ADDRjmp loader_start
;-------------------- 这部分完成GDT和4个段描述符的构建 --------------------------------
;编译后程序的地址是越来越高的,所以代码要先开辟低地址再开辟高地址。8字节64位是一个段描述符。dd命令开辟出一个4字节32位空间。
GDT_BASE:dd 0x00000000dd 0x00000000		;第一个段描述符无法使用,开辟出来空着
CODE_DESC:dd 0x0000ffff		;前四位是16位段基址,设置为0,后四位是16位段界限,设置为1。高位在前低位在后dd DESC_CODE_HIGH4	;提前在配置文件中写好的高32位
DATA_STACK_DESC:dd 0x0000ffffdd DESC_DATA_HIGH4	;数据和栈用相同的段描述符,具体说明看博客
VIDEO_DESC:dd 0x80000007		;这部分请看博客里的说明。dd DESC_VIDEO_HIGH4
;-------------------- 这部分完成GDT大小的计算,同时预留出60个段描述符的空间 --------------------------------
;这部分为加载gdt做准备。dq定义4字8字节64位。times是nasm提供的伪指令,作用是循环。以后我们还要向gdt里添加别的表符,这里提前留出位置。GDT_SIZE equ $-GDT_BASEGDT_LIMIT equ GDT_SIZE-1times 59 dq 0times 5 db 0
;-------------------- 这部分完成构建选择子 --------------------------------
;选择子放在段寄存器里,16位大小,高13位是gdt的索引,第2位是ti位,指示索引是gdt的还是ldt的,0、1两位是特权级位。SELECTOR_CODE equ (0x0001<<3)+TI_GDT+RPL0	;0001就是下标1,左移3位相当于*8,因为一个表项是8字节SELECTOR_DATA equ (0x0002<<3)+TI_GDT+RPL0SELECTOR_VIDEO equ (0x0003<<3)+TI_GDT+RPL0
;-------------------- 这部分设置保存内存容量的标号--------------------------------
;关于这个标号的地址,loader.S的起始地址是0x900,这行前面有64个8字节的段描述符,所以这里是0x900+0x200=0xb00total_mem_bytes dd 0	;初始为0,最终变成总内存容量
;-------------------- 这部分完成定义GDT指针 --------------------------------
gdt_ptr:dw GDT_LIMIT	;前2字节是gdt的界限dd GDT_BASE		;后4字节是gdt的起始位置
;-------------------- 这部分实现三种获取内存容量的方法 --------------------------------
;注意我们这次删除了实模式下打印字符串的功能ards_buf times 244 db 0	;设置ards缓冲区,存放ardsards_nr dw 0		;用于记录ards结构体的数量;这两行开辟256字节的空间,人工对齐loader_start:
;-------------------- 方法1:利用0xe820获取内存 --------------------------------
;以下部分,通过0xe801获取所有的ardsxor ebx,ebx		;用异或置零,初始ebx设置为0,后续我们不需要再处理mov edx,0x534d4150	;固定值mov di,ards_buf		;es:di指向缓冲区,es在mbr设置,这里修改di即可
.e820_mem_get_loop:mov eax,0x0000e820	;因为执行完int 0x15后eax,ebx,ecx会变化,所以每次循环都要重新设置mov ecx,20		;返回的字节数,固定为20int 0x15jc .e820_failed_so_try_e801 ;如果e820失败,尝试e801add di,cx		;+20字节指向下一个ardsinc word [ards_nr]	;记录ards数量cmp ebx,0		;如果ebx=0且cf=0,所有ards全部返回jnz .e820_mem_get_loop 	;如果ebx!=0,继续循环
;以下部分,遍历ards,找到最大的32位基地址+内存长度,即为最大内存容量mov cx,[ards_nr]mov ebx,ards_bufxor edx,edx		;edx保存最大内存容量,初始置0
.find_max_mem_area:mov eax,[ebx]		;32位基地址add eax,[ebx+8]		;内存长度add ebx,20		;指向下一个ardscmp edx,eaxjge .next_ards		;如果edx>=eax,跳转到下一个ards,否则让edx=eax,最终效果是找到最大的ardsmov edx,eax
.next_ards:loop .find_max_mem_areajmp .mem_get_ok
;-------------------- 方法2:利用0xe801获取内存 --------------------------------
;返回后,ax=cx单位是1kb,里面是小于16mb的单位数,bx=dx单位是64kb,里面是大于16mb的单位数。最终需要转化为字节数。
.e820_failed_so_try_e801:mov ax,0x0000e801int 0x15jc .e801_failed_so_try88	;如果e801失败,尝试88方法
;以下计算出低于16mb的内存容量大小mov cx,0x400		;1024mul cx			;16位乘法,结果是32位,低16在ax,高16在dxshl edx,16		;左移16位and eax,0x0000ffff	;保留低16位or edx,eax		;拼接edx的高16位和eax低16位,放到edx中add edx,0x100000	;+1mb,原因是获取的内存比实际内存少1mbmov esi,edx		;备份edx
;以下计算16mb以上内存容量大小xor eax,eaxmov ax,bx		;大于16mb的单位数存在bx、dx里mov ecx,0x10000		;单位是64kbmul ecx			;32位乘法,结果是64位,低32位在eax,高32位在edxadd esi,eax		;这种方法的上限就是4gb,所以不必理会高32位,只需要把低32位加进结果即可mov edx,esijmp .mem_get_ok
;-------------------- 方法3:利用0x88获取内存 --------------------------------
;这部分是方法2的简化版,代码参考2,不再写注释
.e801_failed_so_try88:mov ah,0x88int 0x15jc .error_hltand eax,0x0000ffffmov cx,0x400mul cxshl edx,16or edx,eaxadd edx,0x100000
;-------------------- 这部分记录内存容量 --------------------------------
;如果三种方法都失败,跳转到这里,进行一个死循环
.error_hlt:jmp $
;不管使用了哪种子命令,只要成功,都要跳转到这里记录,单位是1字节
.mem_get_ok:mov [total_mem_bytes],edx	;在total_mem_bytes地址记录总内存容量
;-------------------- 这部分完成进入保护模式的三个步骤 --------------------------------in al,0x92 or al,0000_0010B out 0x92,al 		;打开 A20lgdt [gdt_ptr] 		;加载 GDTmov eax, cr0 or eax, 0x00000001 mov cr0, eax		;cr0 第 0 位置 1
;-------------------- 验证是否进入保护模式 --------------------------------jmp dword SELECTOR_CODE:p_mode_start ; 刷新流水线
[bits 32] 
p_mode_start: mov ax,SELECTOR_DATA mov ds,ax mov es,ax mov ss,ax mov esp,LOADER_STACK_TOP mov ax,SELECTOR_VIDEOmov gs,ax mov byte [gs:160], 'P' ;通过显卡打印一个字符,验证是否进入保护模式jmp $

编译运行

这里我顺手调整了一下mbr,所以先编译写入mbr

nasm -I include/ -o mbr.bin mbr.S
dd if=/home/hongbai/bochs/mbr.bin of=/home/hongbai/bochs/bin/c.img bs=512 count=1 conv=notrunc

编译写入loader

nasm -I include/ -o loader.bin loader.S
dd if=/home/hongbai/bochs/loader.bin of=/home/hongbai/bochs/bin/c.img bs=512 count=4 seek=2 conv=notrunc

运行bochs

cd bin
./bochs -f bochsrc.disk

结果截图:

我们先打开bochsrc.disk配置文件,看一下我们给bochs配置了多少内存。内存大小是megs行,我设置的是512mb大小。

在控制台输入ctrl+c,中断bochs运行,再输入xp 0xb00,查看内存容量是否探测成功。结果如下:

0x20000000正是我设置的512MB内存大小,说明程序运行正常。


结语

这一部分没什么好说的,主要就是完成获取内存容量的功能,新增了一些代码。后续还有内存分页,加载内核,特权级几部分内容,我计划在清明假期把它们全部完成,最后写一个大总结。

http://www.cadmedia.cn/news/8230.html

相关文章:

  • 淄博网站建设多杭州seo中心
  • 模板网站建设全过程2345浏览器网站进入
  • 手机站网站建设网络营销推广方案有哪些
  • 中国网站为什么做的那么丑wifi优化大师下载
  • 我想学网站建设网站营销策划
  • 宝鸡网站建设兼职南宁市优化网站公司
  • seo管理系统易语言潍坊百度seo公司
  • 瑞安网站建设电话百度新版本更新下载
  • 怎么看网站是谁家做的网络营销策划书应该怎么写
  • 弧度网站建设沈阳关键词优化价格
  • 无锡免费建设网站营销渠道策略有哪些
  • 机关门户网站建设要求中国免费网站服务器下载
  • 可以做烟草网站百度代理公司查询
  • 网站定制开发收费标准是多少系统优化的例子
  • 双人网页游戏网站成都推广系统
  • 借贷网站建设方案收录网
  • 网站开发与设计教程友情链接交换条件
  • 中山建设网站的公司百度关键词排名爬虫
  • 手机免费图片制作软件站长工具seo优化
  • 全国精品课程建设网站网站代运营价格
  • 网站建设公司一年赚多少网络营销软文
  • 智慧社区背景图自动seo网站源码
  • 绍兴做网站公司seo专业培训班
  • 学校网站建设项目可行性分析最有效的推广学校的方式
  • 网站建设的知识和技能做关键词优化的公司
  • ruby 网站开发市场营销策划方案
  • 一个完整的网站推广方案网络推广网络营销软件
  • 中山市交通建设发展集团网站网站建设找哪家公司好
  • 江夏区建设局网站品牌广告策划方案
  • 网站建设状态栏新发布的新闻