首页 > 其他分享 >NEMU PA 3-2 实验报告

NEMU PA 3-2 实验报告

时间:2023-02-25 12:33:32浏览次数:61  
标签:GDT 分段 NEMU 描述符 PA 寄存器 机制 实验报告

一、实验目的

在上一章节我们完成了Cache的实现,但是这只是在速度上提高了取指和存取操作数的效率,而在访问的安全性上没有得到有效提升。

在PA3-2中我们要完成的,就是在NEMU中实现分段机制

二、实验任务

首先老规矩,我们来了解一下分段机制是啥,以及它的作用:

  • 为啥需要“分段机制”?

    代码、数据都放在内存里,没有任何限制和保护。会导致很多问题,如数组越界覆盖了代码,恶意程序故意修改代码和数据。也就是说我们如果不做对代码的分段,不把它分开一个个段并明确每个段的作用的话,那么我随便改了改EIP,就可以跳转到任意我想要跳转的地方去执行。内存可以随意读写是非常危险的。

  • 分段机制的直接阐释:将内存划分为具有不同功能的内存区域,把同一种功能和访问控制类型的数据归类放在一起,统一提供保护,为不同的程序规定不同的访问权限

  • 分段机制的实现需要:段表(GDT和LDT),NEMU中指的是全局描述符表GDT。

好了,我们了解了分段机制,那么回到访存机制上,我们要把访存和分段机制结合起来,就需要在访存时提供三个信息,以及要怎么得到这些信息:

  • 要访问内存的哪个段:要先从段表那里查询得到段基址
  • 访问的数据相对段基址的偏移量是多少:用来检查越界情况
  • 程序自身的权限等级是多少:用来检查权限是否满足

要实现这一套保护的机制,需要操作系统和计算机双方的配合。其中,各个段的段基址,界限和权限要求等信息,由操作系统(即NEMU中的kernel)初始化并保存在内存中一个特别的称为全局描述符表,简称GDT,的数据结构中。GDT中的每一行对应一个表项,称为段描述符。

我们来看看NEMU是怎么具体实现的:

  • 首先,启动时NEMU的访存方式是类似实地址模式,即当前的vaddr和最后的paddr一模一样,没有经过任何的权限检查和转换;(注意这和i386的实地址模式是不同的,区别如下)

  • x86的机器开机后首先进入实模式,加载操作系统,操作系统初始化段表,拨动一个‘开关’,从实模式切换到保护模式(开启分段机制);

  • 进入保护模式后,程序给出48位虚拟地址vaddr(16位段选择符 + 32位有效地址),使用段选择符来查段表,然后根据段表信息进行段级地址转换得到线性(现在就是物理)地址laddr

好的,这就是分段机制开启的大体流程。我们来细看几个要点:

  • “开关”是什么?

    这个开关是CPU中CR0寄存器中的PE位。它控制着实模式和保护模式的转换,当PE置为0时,采用实地址模式;当PE置为1时,采用保护地址模式。

  • 段选择符怎么得到?

    段选择符是存储在16bit的段寄存器中的index信息。有六个不同的段寄存器,即CS, SS, DS, ES, FS, GS六个段寄存器,每个寄存器指向某个段描述符,段寄存器的实现格式如下:

  • 段描述符又是啥样子?

    一个个64位的段描述符组成了GDT:

    为什么描述段基地址的Base以及段大小的Limit字段会被拆成这种丑陋的结构?
    因为需要兼容286架构...

  • 要怎么找到GDT

    通过CPU中的GDTR寄存器来找到GDT的首地址和界限,然后根据段寄存器给出的段选择符来找GDT表项(段描述符)。

总体的思路如图:

好,我们现在在NEMU中要做的是:

  1. include/config.h头文件中添加宏定义IA32_SEGmake clean

  2. CPU_STATE中添加对GDTRCR0的模拟以及在init_cpu()中进行初始化为0;

  3. CPU_STATE中添加对6个段寄存器的模拟在init_cpu()中进行初始化为0,注意除了要模拟其16位的可见部分,还要模拟其隐藏部分,顺序不能有错;

  4. 实现包括lgdt、针对控制寄存器和段寄存器的特殊mov以及ljmp指令;

  5. 实现segment_translate()loag_sreg()函数,并在vaddr_read()vaddr_write()函数中添加保护模式下的虚拟地址向线性地址转换的过程;

  6. 通过make test_pa-3-2执行并通过各测试用例。

三、思考题

我们在实现NEMU的分段机制前观察了开启SEG宏后kernel的变化。其中有两条语句的意义要了解的:

  • lgdt va_to_pa(gdtdesc)在干什莫?

    va_to_pa是一个地址转换的宏,lgdt指令是“Load Global Descriptor Table Register”,即装载GDTR。

  • ljmp $GDT_ENTRY(1), $va_to_pa(start_cond)又在干什莫?

    GDT_ENTRY也是一个宏:

    ljmp指令的意义在于装载CS和EIP寄存器。

    要注意的一个点是,汇编中的ljmp指令是AT&T的格式,在i386手册上是找不到这条指令的。而用objdump反汇编出来对照后看,ljmp对应的指令是JMP ptr16:16即一个 far jump。(详细看博文:https://blog.csdn.net/weixin_39677203/article/details/111268072)

标签:GDT,分段,NEMU,描述符,PA,寄存器,机制,实验报告
From: https://www.cnblogs.com/grapefruit-cat/p/17154133.html

相关文章

  • NEMU PA 3-1 实验报告
    一、实验目的在前面的PA1中,我们实现了CPU和FPU,在PA2中我们实现了对指令的解码和对ELF的装载,以及进一步完善了CLI调试器。那么在整个PA3中,我们将要着力于内存的相关处理,如C......
  • sshpass安装
    方法一:运行yum-yinstallsshpass方法二:离线安装:下载安装包sshpass-1.06-2.el7.x86_64.rpm执行命令:rpm-ivhsshpass-1.06-2.el7.x86_64.rpm 安装后可以使......
  • FE日志出现Error happened when receiving packet
    问题现象FE节点挂掉,在FE的日志里面有发现如下的异常,暂时不确定该异常是否会导致FE挂掉。starrocks版本:2.2.82023-02-2511:07:29,742WARN(starrocks-mysql-nio-poo......
  • Windows黑客编程之Bypass UAC
    描述用管理员权限运行CompMgmtLauncher.exe,由于它是白名单程序,不会被UAC拦截,可以直接以管理员权限运行CompMgmtLauncher的功能是去遍历指定注册表路径下的程序,并启动只......
  • The bean ‘api‘, defined in class path resource [com/common/swagger/SwaggerAuto
    Thebean‘api‘,definedinclasspathresource[com/common/swagger/SwaggerAutoConf1.解决办法-1将重复的bean覆盖掉加一个这个注解spring.main.allow-bean-definit......
  • Spring for Apache Kafka: @KafkaListener 的使用示例(消费)
    版本Version2.7.8-- 阅读Version2.7.8的SpringforApacheKafka官方文档,检出其中的注解@KafkaListener的使用方式。关键词:ConsumerRecord、Message、......
  • PAT Basic 1007. 素数对猜想
    PATBasic1007.素数对猜想1.题目描述:让我们定义\(d_n\)为:\(d_n=p_{n+1}−p_n\),其中\(p_i\)是第\(i\)个素数。显然有\(d_1=1\),且对于\(n>1\)有\(d_n\)是偶数。“素数对......
  • PAT Basic 1006. 换个格式输出整数
    PATBasic1006.换个格式输出整数1.题目描述:让我们用字母 B 来表示“百”、字母 S 表示“十”,用 12...n 来表示不为零的个位数字 n(<10),换个格式来输出任一个不超......
  • What's past is prologue
        凡是过去,皆为序章。爱所有人,信任少数人,不负任何人。我荒废了时间,时间便把我荒废了。 在灰暗的日子中,不要让冷酷的命运窃喜;命运既然来凌辱我们,就应该用处之泰......
  • PAT Basic 1005. 继续(3n+1)猜想
    PATBasic1005.继续(3n+1)猜想1.题目描述:卡拉兹(Callatz)猜想已经在1001中给出了描述。在这个题目里,情况稍微有些复杂。当我们验证卡拉兹猜想的时候,为了避免重复计算......