[rCore学习笔记 027]地址空间

写在前面

本随笔是非常菜的菜鸡写的。如有问题请及时提出。

可以联系:1160712160@qq.com

GitHhub:https://github.com/WindDevil (目前啥也没有

引言

兜兜转转又是新的一章的开始,还是首先要看官方手册里的理论介绍和内容.

这里主要还是提纲挈领地摘抄里面的部分内容,在下面用更小的标题表现.

本章目的

本章展现了操作系统为实现“理想”而要扩展的一系列功能:

  • 通过动态内存分配,提高了应用程序对内存的动态使用效率
  • 通过页表的虚实内存映射机制,简化了编译器对应用的地址空间设置
  • 通过页表的虚实内存映射机制,加强了应用之间,应用与内核之间的内存隔离,增强了系统安全
  • 通过页表的虚实内存映射机制,可以实现空分复用 (提出,但没有实现)

需求

在大多数应用(也就是应用开发者)的视角中,它们会独占一整个 CPU 和特定(连续或不连续)的内存空间。当然,通过上一章的学习,我们知道在现代操作系统中,出于公平性的考虑,我们极少会让独占 CPU 这种情况发生。所以应用自认为的独占 CPU 只是内核想让应用看到的一种 幻象 (Illusion) ,而 CPU 计算资源被 时分复用 (TDM, Time-Division Multiplexing) 的实质被内核通过恰当的抽象隐藏了起来,对应用不可见。

与之相对,我们目前还没有对内存管理功能进行进一步拓展,仅仅是把程序放到某处的物理内存中。在内存访问方面,所有的应用都直接通过物理地址访问物理内存,这使得应用开发者需要了解繁琐的物理地址空间布局,访问内存也很不方便。在上一章中,出于任务切换的需要,所有的应用都在初始化阶段被加载到内存中并同时驻留下去直到它们全部运行结束。而且,所有的应用都直接通过物理地址访问物理内存。

这会带来以下问题:

  • 首先,内核提供给应用的内存访问接口不够透明,也不好用。由于应用直接访问物理内存,这需要它在构建的时候就清楚所运行计算机的物理内存空间布局,还需规划自己需要被加载到哪个地址运行。为了避免冲突可能还需要应用的开发者们对此进行协商,这显然是一件在今天看来不够通用且极端麻烦的事情。
  • 其次,内核并没有对应用的访存行为进行任何保护措施,每个应用都有计算机系统中整个物理内存的读写权力。即使应用被限制在 U 特权级下运行,它还是能够造成很多麻烦:比如它可以读写其他应用的数据来窃取信息或者破坏其它应用的正常运行;甚至它还可以修改内核的代码段来替换掉原本的 trap_handler 函数,来挟持内核执行恶意代码。总之,这造成系统既不安全、也不稳定。
  • 再次,目前应用的内存使用空间在其运行前已经限定死了,内核不能灵活地给应用程序提供的运行时动态可用内存空间。比如一个应用结束后,这个应用所占的空间就被释放了,但这块空间无法动态地给其它还在运行的应用使用。

解决方案

为了简化应用开发,防止应用胡作非为,本章将更好地管理物理内存,并提供给应用一个抽象出来的更加透明易用、也更加安全的访存接口,这就是基于分页机制的虚拟内存。站在应用程序运行的角度看,就是存在一个从“0”地址开始的非常大的可读/可写/可执行的地址空间(Address Space),而站在操作系统的角度看,每个应用被局限在分配给它的物理内存空间中运行,无法读写其它应用和操作系统所在的内存空间。

硬件支持

实现地址空间的第一步就是实现分页机制,建立好虚拟内存和物理内存的页映射关系。此过程需要硬件支持,硬件细节与具体CPU相关,涉及地址映射机制等,相对比较复杂。

需要思考的问题

总体而言,我们需要思考如下问题:

  • 硬件中物理内存的范围是什么?
  • 哪些物理内存空间需要建立页映射关系?
  • 如何建立页表使能分页机制?
  • 如何确保 OS 能够在分页机制使能前后的不同时间段中都能正常寻址和执行代码?
  • 页目录表(一级)的起始地址设置在哪里?
  • 二级/三级等页表的起始地址设置在哪里,需要多大空间?
  • 如何设置页目录表项/页表项的内容?
  • 如果要让每个任务有自己的地址空间,那每个任务是否要有自己的页表?
  • 代表应用程序的任务和操作系统需要有各自的页表吗?
  • 在有了页表之后,任务和操作系统之间应该如何传递数据?

体验环节

经典切换代码到第四章分支,然后一举运行:

cd ~/App/rCore-Tutorial-v3
git checkout ch4
cd os
make run

这里注意如果不能切换到ch4很有可能是因为没丢弃或者保存分支,尝试使用git checkout .指令.

运行结果:

[rustsbi] RustSBI version 0.3.1, adapting to RISC-V SBI v1.0.0
.______       __    __      _______.___________.  _______..______   __
|   _  \     |  |  |  |    /       |           | /       ||   _  \ |  |
|  |_)  |    |  |  |  |   |   (----`---|  |----`|   (----`|  |_)  ||  |
|      /     |  |  |  |    \   \       |  |      \   \    |   _  < |  |
|  |\  \----.|  `--'  |.----)   |      |  |  .----)   |   |  |_)  ||  |
| _| `._____| \______/ |_______/       |__|  |_______/    |______/ |__|
[rustsbi] Implementation     : RustSBI-QEMU Version 0.2.0-alpha.2
[rustsbi] Platform Name      : riscv-virtio,qemu
[rustsbi] Platform SMP       : 1
[rustsbi] Platform Memory    : 0x80000000..0x88000000
[rustsbi] Boot HART          : 0
[rustsbi] Device Tree Region : 0x87000000..0x87000f02
[rustsbi] Firmware Address   : 0x80000000
[rustsbi] Supervisor Address : 0x80200000
[rustsbi] pmp01: 0x00000000..0x80000000 (-wr)
[rustsbi] pmp02: 0x80000000..0x80200000 (---)
[rustsbi] pmp03: 0x80200000..0x88000000 (xwr)
[rustsbi] pmp04: 0x88000000..0x00000000 (-wr)
[kernel] Hello, world!
.text [0x80200000, 0x8020c000)
.rodata [0x8020c000, 0x80210000)
.data [0x80210000, 0x80266000)
.bss [0x80266000, 0x80577000)
mapping .text section
mapping .rodata section
mapping .data section
mapping .bss section
mapping physical memory
mapping memory-mapped registers
[kernel] back to world!
remap_test passed!
init TASK_MANAGER
num_app = 7
power_3 [10000/300000]
power_3 [20000/300000]
power_3 [30000/300000]
power_3 [40000/300000]
power_3 [50000/300000]
power_3 [60000/300000]
power_3 [70000/300000]
power_3 [80000/300000]
power_3 [90000/300000]
power_3 [100000/300000]
power_3 [110000/300000]
power_3 [120000/300000]
power_3 [130000/300000]
power_3 [140000/300000]
power_3 [150000/300000]
power_3 [160000/300000]
power_3 [170000/300000]
power_3 [180000/300000]
power_3 [190000/300000]
power_3 [200000/300000]
power_3 [210000/300000]
power_3 [220000/300000]
power_3 [230000/300000]
power_3 [240000/300000]
power_3 [250000/300000]
power_3 [260000/300000]
power_3 [270000/300000]
power_3 [280000/300000]
power_3 [290000/300000]
power_3 [300000/300000]
3^300000 = 612461288(MOD 998244353)
Test power_3 OK!
[kernel] Application exited with code 0
power_5 [10000/210000]
power_5 [20000/210000]
power_5 [30000/210000]
power_5 [40000/210000]
power_5 [50000/210000]
power_5 [60000/210000]
power_5 [70000/210000]
power_5 [80000/210000]
power_5 [90000/210000]
power_5 [100000/210000]
power_5 [110000/210000]
power_5 [120000/210000]
power_5 [130000/210000]
power_5 [140000/210000]
power_5 [150000/210000]
power_7 [10000/240000]
power_7 [20000/240000]
power_7 [30000/240000]
power_7 [40000/240000]
power_7 [50000/240000]
power_7 [60000/240000]
power_7 [70000/240000]
power_7 [80000/240000]
power_7 [90000/240000]
power_7 [100000/240000]
power_7 [110000/240000]
power_7 [120000/240000]
power_7 [130000/240000]
power_7 [140000/240000]
power_7 [150000/240000]
power_7 [160000/240000]
power_7 [170000/240000]
power_7 [180000/240000]
power_7 [190000/240000]
power_7 [200000/240000]
power_7 [210000/240000]
power_7 [220000/240000]
power_7 [230000/240000]
power_7 [240000/240000]
7^240000 = 304164893(MOD 998244353)
Test power_7 OK!
[kernel] Application exited with code 0load_fault APP running...Into Test load_fault, we will insert an invalid load operation...
Kernel should kill this application!
[kernel] PageFault in application, bad addr = 0x0, bad instruction = 0x100c0, kernel killed it.store_fault APP running...Into Test store_fault, we will insert an invalid store operation...
Kernel should kill this application!
[kernel] PageFault in application, bad addr = 0x0, bad instruction = 0x100c0, kernel killed it.
Test sbrk start.
origin break point = 17000
one page allocated,  break point = 18000
try write to allocated page
write ok
10 page allocated,  break point = 22000
11 page DEALLOCATED,  break point = 17000
try DEALLOCATED more one page, should be failed.
Test sbrk almost OK!
now write to deallocated page, should cause page fault.
[kernel] PageFault in application, bad addr = 0x17000, bad instruction = 0x1124a, kernel killed it.
power_5 [160000/210000]
power_5 [170000/210000]
power_5 [180000/210000]
power_5 [190000/210000]
power_5 [200000/210000]
power_5 [210000/210000]
5^210000 = 527227302(MOD 998244353)
Test power_5 OK!
[kernel] Application exited with code 0
Test sleep OK!
[kernel] Application exited with code 0
All applications completed!

本章框图

这里需要和上一章的框图进行对比才能知道本章做了什么改进.

这是本章框图:

这是上章框图:

可以看到的不同分为两个部分:

  1. 硬件需求不同
  2. 系统架构不同

硬件需求

观察框图,可以看到本章的框图中要求:

  1. CPU with MMU 要求 CPU 含有MMU,也即内存管理单元(Memory Management Unit)是计算机硬件的一部分,主要负责处理内存管理和虚拟地址到物理地址的转换。
  2. MEM with PageTable,要求内存支持页表,Page Table 是操作系统用于管理虚拟内存的一种数据结构,它记录了虚拟地址与物理地址之间的映射关系。Page Table 需要硬件支持,特别是 MMU(Memory Management Unit)来实现虚拟地址到物理地址的快速转换。

总而言之就是需要MMU.

系统架构

本章框图中增加了:

  1. APP层和OS层的跳板Trampline
  2. 每个APP的地址空间
  3. 内核的地址空间
  4. 物理页帧分配

等功能.

这里摘自官方手册:

在具体实现上,扩展了 TaskManager 的管理范围,每个 Task 的上下文 Task Context 还包括该任务的地址空间,在切换任务时,也要切换任务的地址空间。新增的内存管理模块主要包括与内核中动态内存分配相关的页帧分配、堆分配,以及表示应用地址空间的 Apps MemSets 类型和内核自身地址空间的 Kernel MemSet类型。 MemSet 类型所包含的页表 PageTable 建立了虚实地址映射关系,而另外一个 MemArea 表示任务的合法空间范围。

建议

代码的阅读顺序参考官方手册.

这里代码繁多,尤其是涉及到内存的变换之后就会面临对前面所有的数据结构的大范围的重写,对trap的处理和对__switch的重构.

建议多看代码,多理清问题,这样才能顺利度过这最难的一章.

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

如何查找 18 个月之前的 Apple 订单 All In One

如何查找 18 个月之前的 Apple 订单 All In One 为什么 Apple Store 不支持查找 18 个月之前的订单?如何查找 18 个月之前的 Apple 订单 All In One为什么 Apple Store 不支持查找 18 个月之前的订单?errorssolutionsemail history ✅demos(🐞 反爬虫测试!打击盗版⚠️)…

编程日记 更改redis存储默认序列化器

编程日记 更改redis存储默认序列化器 package com.haole.usercenter.service;import com.haole.usercenter.model.domain.User; import jakarta.annotation.Resource; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.springframewor…

结对对对项目

结对对对项目这个作业属于哪个课程 软件工程课程这个作业要求在哪里 个人项目 - 作业 - 计科22级34班 - 班级博客 - 博客园 (cnblogs.com)这个作业的目标 按照要求写一个四则运算生成器成员一 3122004883许億驰任务列表1. 实现命令行程序:创建一个命令行程序,能够生成小学四则…

闯关提交02

任务:Python实现wordcount1 import re2 from collections import defaultdict3 4 def wordcount(text):5 # 将文本转换为小写6 text = text.lower()7 8 # 使用正则表达式分割单词9 words = re.findall(r\b\w+\b, text) 10 11 # 使用 defaultdict…

M:接口耗时很短,页面数据回显慢?

1、页面卡顿,需要好长一段时间才能加载完成,可能是资源请求过多,再加上请求响应慢的原因。 每个浏览器都有资源请求并发数的限制,如何查看请求阻塞情况 到前端如何针对该限制进行优化? 先看问题: 1、设置服务端请求耗时(3S)客户端并发调用20个请求。(预留问题-见下方:…

中秋 -2024/9/17

今天是中秋假期最后一天,今天主要学习了动态规划算法,写了几个模板题 新算法学了迪杰斯特拉(Dijkstra)算法,只是过程了解了过程,还是不能用代码描述出来 寻找最短路径的算法

干盛辉的第一次作业

这个作业属于哪个课程 https://edu.cnblogs.com/campus/zjlg/rjjc这个作业的目标 介绍自己并进行评估,阐明自己的技能、薄弱点,表明期望的课程收获以及课程实践角色扮演姓名-学号 干盛辉-2022329301011一、自我介绍 (1)个人信息 大家好,我叫干盛辉,来自于浙江温州,是 22…

vscode配置java简易教程

java的新手快速配置一、下载jdk java官方地址:https://www.oracle.com/java/technologies/downloads/ 选择适合自己电脑的版本,并下载到一个自己喜欢的地方。二、配置环境变量 记住自己 jdk 的地址,例:我的 jdk 下载到了 D:\app\java 1、JAVA_HOME配置 点击 win 键后,搜索…

GitHub 配置 ssh key 的步骤及原理解释

原文:Github 配置 ssh key 的步骤(大白话+包含原理解释)本文涉及 SSH 相关知识,建议先阅读 SSH 原理与运用(一):远程登录 或者将其作为扩展资料。 前言 在 GitHub 上配置 ssh key 很容易,网上一大堆教程,但基本没有详细解释其原理的,为什么要配?每使用一台主机都要配…

贪吃蛇作业

贪吃蛇界面: 代码:import pygame import random import sys import tkinter as tk from tkinter import messagebox # 初始化pygame pygame.init() # 设置屏幕大小 screen_width = 640 screen_height = 480 screen = pygame.display.set_mode((screen_widt…

数据集的收集

我在这里找到了一个数据集的网站:https://www.kaggle.com/datasets 我这里找到了三个小数据集为例子分别如下: 我写的数据分析如下: 1.数据集名称房价回归数据集来源 https://www.kaggle.com/datasets/prokshitha/home-value-insights?resource=download数据集描述该数据集…

数字签名是什么?

原文:数字签名是什么?文中涉及的密码学基本知识,可以参见对称加密和非对称加密的区别。鲍勃有两把钥匙,一把是公钥,另一把是私钥。鲍勃把公钥送给他的朋友们——帕蒂、道格、苏珊——每人一把。苏珊要给鲍勃写一封保密的信。她写完后用鲍勃的公钥加密,就可以达到保密的效…