计算机系统结构与操作系统实验三(4-1)-获取物理容量

news2024/12/23 14:19:11

📍实验要求

获得物理内存容量,代码中共有3种获得物理内存容量方式,程序流程是第1种方式如果失败则采用第2种方式,第2种如果失败则采用第3种,想方法验证最终是采用了哪种方式?给出分析过程

📍实验过程

创建文件夹及相关文件,该实验我分三个部分完成:3-4-1、3-4-2、3-4-3
在这里插入图片描述

📍📍mbr.S

;主引导程序 
;------------------------------------------------------------
%include "boot.inc"
SECTION MBR vstart=0x7c00         
   mov ax,cs      
   mov ds,ax
   mov es,ax
   mov ss,ax
   mov fs,ax
   mov sp,0x7c00
   mov ax,0xb800
   mov gs,ax

; 清屏
;利用0x06号功能,上卷全部行,则可清屏。
; -----------------------------------------------------------
;INT 0x10   功能号:0x06	   功能描述:上卷窗口
;------------------------------------------------------
;输入:
;AH 功能号= 0x06
;AL = 上卷的行数(如果为0,表示全部)
;BH = 上卷行属性
;(CL,CH) = 窗口左上角的(X,Y)位置
;(DL,DH) = 窗口右下角的(X,Y)位置
;无返回值:
   mov     ax, 0600h
   mov     bx, 0700h
   mov     cx, 0                   ; 左上角: (0, 0)
   mov     dx, 184fh		   ; 右下角: (80,25),
				   ; 因为VGA文本模式中,一行只能容纳80个字符,25行。
				   ; 下标从0开始,所以0x18=24,0x4f=79
   int     10h                     ; int 10h

      ; 输出字符串:1 MBR
   mov byte [gs:0x00],'M'
   mov byte [gs:0x01],0xA4

   mov byte [gs:0x02],'B'
   mov byte [gs:0x03],0xA4

   mov byte [gs:0x04],'R'
   mov byte [gs:0x05],0xA4	   ;A表示绿色背景闪烁,4表示前景色为红色

   mov byte [gs:0x06],'-'
   mov byte [gs:0x07],0xA4

   mov byte [gs:0x08],'l'
   mov byte [gs:0x09],0xA4
   
   mov byte [gs:0x0a],'u'
   mov byte [gs:0x0b],0xA4

   mov byte [gs:0x0c],'o'
   mov byte [gs:0x0d],0xA4

   mov byte [gs:0x0e],'h'
   mov byte [gs:0x0f],0xA4

   mov byte [gs:0x10],'a'
   mov byte [gs:0x11],0xA4

   mov byte [gs:0x12],'o'
   mov byte [gs:0x13],0xA4

   mov byte [gs:0x14],'j'
   mov byte [gs:0x15],0xA4

   mov byte [gs:0x16],'i'
   mov byte [gs:0x17],0xA4

   mov byte [gs:0x18],'a'
   mov byte [gs:0x19],0xA4
	 
   mov eax,LOADER_START_SECTOR	 ; 起始扇区lba地址
   mov bx,LOADER_BASE_ADDR       ; 写入的地址
   mov cx,4			 ; 待读入的扇区数
   call rd_disk_m_16		 ; 以下读取程序的起始部分(一个扇区)
  
   jmp LOADER_BASE_ADDR + 0x300
       
;-------------------------------------------------------------------------------
;功能:读取硬盘n个扇区
rd_disk_m_16:	   
;-------------------------------------------------------------------------------
				       ; eax=LBA扇区号
				       ; ebx=将数据写入的内存地址
				       ; ecx=读入的扇区数
      mov esi,eax	  ;备份eax
      mov di,cx		  ;备份cx
;读写硬盘:
;1步:设置要读取的扇区数
      mov dx,0x1f2
      mov al,cl
      out dx,al            ;读取的扇区数

      mov eax,esi	   ;恢复ax

;2步:将LBA地址存入0x1f3 ~ 0x1f6

      ;LBA地址7~0位写入端口0x1f3
      mov dx,0x1f3                       
      out dx,al                          

      ;LBA地址15~8位写入端口0x1f4
      mov cl,8
      shr eax,cl
      mov dx,0x1f4
      out dx,al

      ;LBA地址23~16位写入端口0x1f5
      shr eax,cl
      mov dx,0x1f5
      out dx,al

      shr eax,cl
      and al,0x0f	   ;lba第24~27or al,0xe0	   ; 设置74位为1110,表示lba模式
      mov dx,0x1f6
      out dx,al

;3步:向0x1f7端口写入读命令,0x20 
      mov dx,0x1f7
      mov al,0x20                        
      out dx,al

;4步:检测硬盘状态
  .not_ready:
      ;同一端口,写时表示写入命令字,读时表示读入硬盘状态
      nop
      in al,dx
      and al,0x88	   ;4位为1表示硬盘控制器已准备好数据传输,第7位为1表示硬盘忙
      cmp al,0x08
      jnz .not_ready	   ;若未准备好,继续等。

;5步:从0x1f0端口读数据
      mov ax, di
      mov dx, 256
      mul dx
      mov cx, ax	   ; di为要读取的扇区数,一个扇区有512字节,每次读入一个字,
			   ; 共需di*512/2次,所以di*256
      mov dx, 0x1f0
  .go_on_read:
      in ax,dx
      mov [bx],ax
      add bx,2		  
      loop .go_on_read
      ret

   times 510-($-$$) db 0
   db 0x55,0xaa

📍📍loader.S

   %include "boot.inc"
   section loader vstart=LOADER_BASE_ADDR
   LOADER_STACK_TOP equ LOADER_BASE_ADDR
   
;构建gdt及其内部的描述符
   GDT_BASE:   dd    0x00000000 
	       dd    0x00000000

   CODE_DESC:  dd    0x0000FFFF 
	       dd    DESC_CODE_HIGH4

   DATA_STACK_DESC:  dd    0x0000FFFF
		     dd    DESC_DATA_HIGH4

   VIDEO_DESC: dd    0x80000007	       ; limit=(0xbffff-0xb8000)/4k=0x7
	       dd    DESC_VIDEO_HIGH4  ; 此时dpl为0

   GDT_SIZE   equ   $ - GDT_BASE
   GDT_LIMIT   equ   GDT_SIZE -	1 
   times 60 dq 0					 ; 此处预留60个描述符的空位(slot)
   SELECTOR_CODE equ (0x0001<<3) + TI_GDT + RPL0         ; 相当于(CODE_DESC - GDT_BASE)/8 + TI_GDT + RPL0
   SELECTOR_DATA equ (0x0002<<3) + TI_GDT + RPL0	 ; 同上
   SELECTOR_VIDEO equ (0x0003<<3) + TI_GDT + RPL0	 ; 同上 

   ; total_mem_bytes用于保存内存容量,以字节为单位,此位置比较好记。
   ; 当前偏移loader.bin文件头0x200字节,loader.bin的加载地址是0x900,
   ; 故total_mem_bytes内存中的地址是0xb00.将来在内核中咱们会引用此地址
   total_mem_bytes dd 0					 
   ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

   ;以下是定义gdt的指针,前2字节是gdt界限,后4字节是gdt起始地址
   gdt_ptr  dw  GDT_LIMIT 
	    dd  GDT_BASE

   ;人工对齐:total_mem_bytes4字节+gdt_ptr6字节+ards_buf244字节+ards_nr2,256字节
   ards_buf times 244 db 0
   ards_nr dw 0		      ;用于记录ards结构体数量

loader_start:
   
;-------  int 15h eax = 0000E820h ,edx = 534D4150h ('SMAP') 获取内存布局  -------

   xor ebx, ebx		      ;第一次调用时,ebx值要为0
   mov edx, 0x534d4150	      ;edx只赋值一次,循环体中不会改变
   mov di, ards_buf	      ;ards结构缓冲区
.e820_mem_get_loop:	      ;循环获取每个ARDS内存范围描述结构
   mov eax, 0x0000e820	      ;执行int 0x15,eax值变为0x534d4150,所以每次执行int前都要更新为子功能号。
   mov ecx, 20		      ;ARDS地址范围描述符结构大小是20字节
   int 0x15
   jc .e820_failed_so_try_e801   ;若cf位为1则有错误发生,尝试0xe801子功能
   add di, cx		      ;使di增加20字节指向缓冲区中新的ARDS结构位置
   inc word [ards_nr]	      ;记录ARDS数量
   cmp ebx, 0		      ;若ebx为0且cf不为1,这说明ards全部返回,当前已是最后一个
   jnz .e820_mem_get_loop

;在所有ards结构中,找出(base_add_low + length_low)的最大值,即内存的容量。
   mov cx, [ards_nr]	      ;遍历每一个ARDS结构体,循环次数是ARDS的数量
   mov ebx, ards_buf 
   xor edx, edx		      ;edx为最大的内存容量,在此先清0
.find_max_mem_area:	      ;无须判断type是否为1,最大的内存块一定是可被使用
   mov eax, [ebx]	      ;base_add_low
   add eax, [ebx+8]	      ;length_low
   add ebx, 20		      ;指向缓冲区中下一个ARDS结构
   cmp edx, eax		      ;冒泡排序,找出最大,edx寄存器始终是最大的内存容量
   jge .next_ards
   mov edx, eax		      ;edx为总内存大小
.next_ards:
   loop .find_max_mem_area
   jmp .mem_get_ok

;------  int 15h ax = E801h 获取内存大小,最大支持4G  ------
; 返回后, ax cx 值一样,以KB为单位,bx dx值一样,以64KB为单位
; 在ax和cx寄存器中为低16M,在bx和dx寄存器中为16MB到4G。
.e820_failed_so_try_e801:
   mov ax,0xe801
   int 0x15
   jc .e801_failed_so_try88   ;若当前e801方法失败,就尝试0x88方法

;1 先算出低15M的内存,ax和cx中是以KB为单位的内存数量,将其转换为以byte为单位
   mov cx,0x400	     ;cx和ax值一样,cx用做乘数
   mul cx 
   shl edx,16
   and eax,0x0000FFFF
   or edx,eax
   add edx, 0x100000 ;ax只是15MB,故要加1MB
   mov esi,edx	     ;先把低15MB的内存容量存入esi寄存器备份

;2 再将16MB以上的内存转换为byte为单位,寄存器bx和dx中是以64KB为单位的内存数量
   xor eax,eax
   mov ax,bx		
   mov ecx, 0x10000	;0x10000十进制为64KB
   mul ecx		;32位乘法,默认的被乘数是eax,积为64,32位存入edx,32位存入eax.
   add esi,eax		;由于此方法只能测出4G以内的内存,32位eax足够了,edx肯定为0,只加eax便可
   mov edx,esi		;edx为总内存大小
   jmp .mem_get_ok

;-----------------  int 15h ah = 0x88 获取内存大小,只能获取64M之内  ----------
.e801_failed_so_try88: 
   ;int 15后,ax存入的是以kb为单位的内存容量
   mov  ah, 0x88
   int  0x15
   jc .error_hlt
   and eax,0x0000FFFF
      
   ;16位乘法,被乘数是ax,积为32.积的高16位在dx中,积的低16位在ax中
   mov cx, 0x400     ;0x400等于1024,将ax中的内存容量换为以byte为单位
   mul cx
   shl edx, 16	     ;把dx移到高16or edx, eax	     ;把积的低16位组合到edx,32位的积
   add edx,0x100000  ;0x88子功能只会返回1MB以上的内存,故实际内存大小要加上1MB

.mem_get_ok:
   mov [total_mem_bytes], edx	 ;将内存换为byte单位后存入total_mem_bytes处。


;-----------------   准备进入保护模式   -------------------
;1 打开A20
;2 加载gdt
;3 将cr0的pe位置1

   ;-----------------  打开A20  ----------------
   in al,0x92
   or al,0000_0010B
   out 0x92,al

   ;-----------------  加载GDT  ----------------
   lgdt [gdt_ptr]

   ;-----------------  cr0第0位置1  ----------------
   mov eax, cr0
   or eax, 0x00000001
   mov cr0, eax

   jmp dword SELECTOR_CODE:p_mode_start	     ; 刷新流水线,避免分支预测的影响,这种cpu优化策略,最怕jmp跳转,
					     ; 这将导致之前做的预测失效,从而起到了刷新的作用。
.error_hlt:		      ;出错则挂起
   hlt

[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_VIDEO
   mov gs, ax

   mov byte [gs:160], 'P'

   jmp $

📍📍include/boot.inc

;-------------	 loader和kernel   ----------

LOADER_BASE_ADDR equ 0x900 
LOADER_START_SECTOR equ 0x2

;--------------   gdt描述符属性  -------------
DESC_G_4K   equ	  1_00000000000000000000000b   
DESC_D_32   equ	   1_0000000000000000000000b
DESC_L	    equ	    0_000000000000000000000b	;  64位代码标记,此处标记为0便可。
DESC_AVL    equ	     0_00000000000000000000b	;  cpu不用此位,暂置为0  
DESC_LIMIT_CODE2  equ 1111_0000000000000000b
DESC_LIMIT_DATA2  equ DESC_LIMIT_CODE2
DESC_LIMIT_VIDEO2  equ 0000_000000000000000b
DESC_P	    equ		  1_000000000000000b
DESC_DPL_0  equ		   00_0000000000000b
DESC_DPL_1  equ		   01_0000000000000b
DESC_DPL_2  equ		   10_0000000000000b
DESC_DPL_3  equ		   11_0000000000000b
DESC_S_CODE equ		     1_000000000000b
DESC_S_DATA equ	  DESC_S_CODE
DESC_S_sys  equ		     0_000000000000b
DESC_TYPE_CODE  equ	      1000_00000000b	;x=1,c=0,r=0,a=0 代码段是可执行的,非依从的,不可读的,已访问位a清0.  
DESC_TYPE_DATA  equ	      0010_00000000b	;x=0,e=0,w=1,a=0 数据段是不可执行的,向上扩展的,可写的,已访问位a清0.

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 + 0x00
DESC_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 + 0x00
DESC_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

一键运行

run.sh记得改成相应目录
在这里插入图片描述
在这里插入图片描述

打开bochs后,先按c启动,然后ctrl+C撤销,再输入xp 0xb00,即可查看物理容量
在这里插入图片描述

📍分析程序是用了哪种方法确定物理容量的

📍📍1.输入 b 0x7c00 进入到主引导程序

在这里插入图片描述

📍📍2.输入n一直调试,跳转到内存中loader加载器的loader_start程序部分

在这里插入图片描述

📍📍3.继续按n调试,如图所示

如果int 0x15返回的CF位为1,说明该中断子功能不可用,则会直接跳转到下一个获取物理内存容量的中断子功能,而这里从红框可以看到jc跳转指令后继续执行了add指令,说明此功能可以用,因此说明通过int 0x15中断子功能0xe820获取物理容量
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/748708.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Vue封装的过渡与动画

vscode中迅速创建Vue快捷键输入vue回车键即可 动画效果 如果在<transition name"hello"></transition>标签添加name属性&#xff0c;那么css属性名生效就得这样写.hello-enter-active和.hello-leave-active&#xff0c;没有name属性就直接.v-enter-acti…

Mac搭建安卓模拟器(支持M1/M2)

引言 最近在研究Vue打包成app&#xff0c;给我的报价器搞一个移动端&#xff0c;奈何没有安卓手机用于测试。所以想到安装一个安卓模拟器。 看了下目前主流的安卓模拟器基本都不支持Mac版本。网易的mumu目前来看还是只支持Intel芯。 1. 简单版&#xff08;仅M系&#xff09;…

3. CSS三角

网页中常见的一些三角形, 使用CSS直接画出来就可以, 不必做成图片或者字体图标。 CSS三角做法代码: div {width: 0;height: 0;/* 兼顾兼容性 line-height: 0;font-size: 0; */border: 50px solid transparent;border-left-color: pink; }

【Linux】初步理解操作系统和进程概念

一.认识操作系统 操作系统是一款纯正的 “搞管理” 的文件。 那操作系统为什么要管理文件&#xff1f; “管理” 又是什么&#xff1f; 它是怎么管理的&#xff1f; 为什么&#xff1f; 1.操作系统帮助用户&#xff0c;管理好底层的软硬件资源&#xff1b; 2.为了给用户提供一个…

搞清楚@RequestBody和@RequestParam的异同,让你的面试不再被问倒!

大家好&#xff0c;我是小米。今天我要给大家分享一个常见的面试题&#xff1a;“RequestBody和RequestParam之间有什么区别&#xff1f;”这个问题在Java Web开发中非常常见&#xff0c;对于初学者来说可能会有些混淆。那么&#xff0c;让我们一起来揭开这个谜团&#xff0c;深…

浅谈变配电监控系统在某火车站中的应用

安科瑞 华楠 摘要&#xff1a;现代变配电监控系统是利用计算机控制技术、通信技术和网络技术等&#xff0c;对智能变配电设备进行数字化信息采集、处理和传输&#xff0c;从而实现对变配电系统高、低压电气设备的远程监控管理&#xff0c;达到配电室的少人或无人值守的目的&am…

【报错】jar包丢失以及project标签报错解决方案

报错&#xff1a; “dependencies.dependency.version for org.springframework.boot:spring-boot-starter-web:jar is missing” “标记名称: project 描述 : The <project> element is the root of the descriptor. The following table lists all of the possible c…

剑指offer(C++)-JZ41:数据流中的中位数(算法-排序)

作者&#xff1a;翟天保Steven 版权声明&#xff1a;著作权归作者所有&#xff0c;商业转载请联系作者获得授权&#xff0c;非商业转载请注明出处 题目描述&#xff1a; 如何得到一个数据流中的中位数&#xff1f;如果从数据流中读出奇数个数值&#xff0c;那么中位数就是所有…

scrapy

scrapy介绍安装--架构 Scrapy 是一个爬虫框架&#xff08;底层代码封装好了&#xff0c;只需要在固定位置写固定代码即可&#xff09;&#xff0c;应用领域比较广泛---》爬虫界的django# 安装 #Windows平台1、pip3 install wheel #安装后&#xff0c;便支持通过wheel文件安装软…

Java的强引用和弱引用

介绍 强引用&#xff1a;引用的对象不会被Java虚拟机强制回收。平时绝大部分对象引用是强引用。 弱引用&#xff1a;在垃圾回收时&#xff0c;弱引用的对象会被Java虚拟机强制回收。 Java API中关于几种引用的类&#xff1a; https://docs.oracle.com/en/java/javase/19/docs…

【JavaSE】- 异常处理

异常处理 1.1异常概念1.2 编译异常1.3 异常处理的方式2.1 try-catch2.2 throws2.3 throw(自定义异常) 1.1异常概念 常见的运行时异常包括 NullPointerException 空指针异常 String name null;System.out.println(name. Length());ArithmeticException 数学运算异常 int num1 …

python_pyqtgraph折线图工具协助分析数据

目录 写在前面&#xff1a; 结果显示 代码实现 导入包、字符串横坐标控件 单边折线图控件 主界面 使用过程 写在前面&#xff1a; 本文开发的工具主要是在平时事务处理中需要查看多列数据差异很大的数据&#xff0c;需要横向对比纵向对比&#xff0c;并且要能及时感知数…

Linux和Shell笔记-1相关概念理解

Unix和Linux关系 UNIX是最早的商业操作系统之一&#xff0c;由贝尔实验室&#xff08;AT&T Bell Laboratories&#xff09;于 1970 年代开发。UNIX 是一个多用户、多任务的操作系统&#xff0c;具有强大的命令行界面和可扩展性。 Linux 是一个开放源代码的类 UNIX 操作系统…

屏蔽表面电阻试验仪

一、产品概述 KDZD608A屏蔽服效率测试装置是对屏蔽服进行屏蔽效率测试的专业设备&#xff0c;用于电力系统、生产厂家、科研单位等。 KDZD608A屏蔽服效率测试装置根据国家标准GB/T 6568-2008《带电作业用屏蔽服装》要求而设计&#xff0c;再结合电力行业标准DLT 976-201…

二、RocketMQ消息存储源码分析

RocketMQ源码深入剖析 6 Broker源码分析 Broker模块涉及到的内容非常多&#xff0c;本课程重点讲解以下技术点&#xff1a; 1、Broker启动流程分析 2、消息存储设计 3、消息写入流程 4、亮点分析&#xff1a;NRS与NRC的功能号设计 5、亮点分析&#xff1a;同步双写数倍性…

视频孪生赋能智慧水利数智化管理

在《关于大力推进智慧水利建设的指导意见》、《“十四五”智慧水利建设规划》中&#xff0c;水利部明确智慧水利建设目标&#xff1a;到2025年建成七大江河数字孪生流域&#xff0c;即&#xff1a; 到2025年&#xff0c;通过建设数字孪生流域、“2N”水利智能业务应用体系、水…

编程会不会被中英文转换干扰?

目录 引言&#xff1a; 解决办法&#xff1a; 图片&#xff1a; 引言&#xff1a; 我在编程的时候总是容易误触&#xff53;&#xff48;&#xff49;&#xff46;&#xff54;&#xff0c;导致代码编译错误&#xff0c;我都不知道哪里出了问题&#xff0c;每次基本要重…

2023志愿填报区块链专业

随着区块链技术的迅速发展&#xff0c;区块链专业毕业生在就业市场上拥有广阔的前景。他们可以在多个领域找到就业机会&#xff0c;从而实现职业发展和稳定的薪资待遇。 首先&#xff0c;金融行业是区块链专业毕业生的主要就业领域之一。银行、证券公司和支付机构等金融机构对…

【Lesson 02】 TiDB Server

目录 0 章节目标 一 TiDB Server架构 二 TiDB Server 作用​ 三 TiDB Server 的进程 1 SQL语句的解析和编译 2 SQL读写相关模块 3 在线DDL相关模块 4 GC机制与相关模块 四 TiDB Server的缓存 1 TIDB的缓存组成 2 TiDB 缓存管理 3 热点小表缓存 4 热点小表缓存-原理 0…

node基于express+mongodb项目的整体结构搭建和逻辑抽离

一、为什么需要逻辑抽离 这是我用express实现的一个缩减版的注册功能,如下&#xff1a; app.js const express require("express"); const app express();// 连接数据库 const mongoose require("mongoose"); // 连接数据库myTest mongoose.connect(…