《操作系统真象还原》调试总结篇

文章目录

    • 前言
    • 第11章调试
    • 我们操作系统目前的内存管理现状

前言

上一章结尾调试还没有完成,本章开始前需要先完成上一章代码的调试。

总的来说,我们的操作系统目前有三大块内容:线程-进程内容、内存管理内容、中断内容。当然这三部分肯定不可能是独立的,线程切换需要时钟中断实现,线程创建需要向内存管理申请内存,等等。我只是暂时分块方便梳理。


第11章调试

分析上章结尾的截图,发现数字一直是0,可能是用户进程没有成功创建,进程通过线程创建,我们先确认线程有无问题。

注释掉创建进程的两行代码,系统运行正常,那么我们的多线程应该没有问题。

调试了一下,发现有这么一个运行结果

这行哨兵是:ASSERT(pthread != NULL);

分析一下,数字不变,说明用户进程没有正常运行。两个线程切换正常,但是在某种情况下,pthread==NULL。process_activate只在schedule中调用过,传进来的参数应该是下一个线程/进程next,说明有一次传参失败。在ab线程切换的时候少打印了一个空格,也需要注意

next的来源是就绪队列的队头,正好之前写过相应的测试函数,我们调用一下,看看什么是怎么个情况

这是一次调试过程,不过无果,贴出来吧

<bochs:2> info tab
cr3: 0x00000021a000
0xbffff000-0xbfffffff -> 0x000008100000-0x000008100fff
0xc0000000-0xc00fffff -> 0x000000000000-0x0000000fffff
0xc0100000-0xc0133fff -> 0x000000200000-0x000000233fff
0xffeff000-0xffefffff -> 0x000000234000-0x000000234fff
0xfff00000-0xffffefff -> 0x000000101000-0x0000001fffff
0xfffff000-0xffffffff -> 0x00000021a000-0x00000021afff
<bochs:3> info gdt
Global Descriptor Table (base=0xc0000903, limit=55):
GDT[0x0000]=??? descriptor hi=0x00000000, lo=0x00000000
GDT[0x0008]=Code segment, base=0x00000000, limit=0xffffffff, Execute-Only, Non-Conforming, Accessed, 32-bit
GDT[0x0010]=Data segment, base=0x00000000, limit=0xffffffff, Read/Write, Accessed
GDT[0x0018]=Data segment, base=0xc00b8000, limit=0x00007fff, Read/Write, Accessed
GDT[0x0020]=32-Bit TSS (Busy) at 0xc0006340, length 0x0006b
GDT[0x0028]=Code segment, base=0x00000000, limit=0xffffffff, Execute-Only, Non-Conforming, Accessed, 32-bit
GDT[0x0030]=Data segment, base=0x00000000, limit=0xffffffff, Read/Write, Accessed
You can list individual entries with 'info gdt [NUM]' or groups with 'info gdt [NUM] [NUM]'
<bochs:4> sreg
es:0x0033, dh=0x00cff300, dl=0x0000ffff, valid=1Data segment, base=0x00000000, limit=0xffffffff, Read/Write, Accessed
cs:0x0008, dh=0x00cf9900, dl=0x0000ffff, valid=1Code segment, base=0x00000000, limit=0xffffffff, Execute-Only, Non-Conforming, Accessed, 32-bit
ss:0x0010, dh=0x00cf9300, dl=0x0000ffff, valid=31Data segment, base=0x00000000, limit=0xffffffff, Read/Write, Accessed
ds:0x0033, dh=0x00cff300, dl=0x0000ffff, valid=31Data segment, base=0x00000000, limit=0xffffffff, Read/Write, Accessed
fs:0x0033, dh=0x00cff300, dl=0x0000ffff, valid=1Data segment, base=0x00000000, limit=0xffffffff, Read/Write, Accessed
gs:0x0018, dh=0xc0c0930b, dl=0x80000007, valid=1Data segment, base=0xc00b8000, limit=0x00007fff, Read/Write, Accessed
ldtr:0x0000, dh=0x00008200, dl=0x0000ffff, valid=1
tr:0x0020, dh=0xc0808b00, dl=0x6340006b, valid=1
gdtr:base=0xc0000903, limit=0x37
idtr:base=0xc0006180, limit=0x17f
<bochs:5> r
eax: 0xc0101d10 -1072685808
ebx: 0xc0101cfc -1072685828
ecx: 0x00000000 0
edx: 0x00000000 0
esp: 0xc0101cb4 -1072685900
ebp: 0xc0101ccc -1072685876
esi: 0x00000000 0
edi: 0xc0001804 -1073735676
eip: 0xc0002374
eflags 0x00000046: id vip vif ac vm rf nt IOPL=0 of df if tf sf ZF af PF cf

通过上面的信息,分析出了一些疑点:

内存映射相关:是否有内存缺页,cpu是否运行到了没有建立好映射的虚拟地址?用户进程无法正确运行

TSS相关:ESP0是否正确记录?

特权级相关:特权级是否正确切换?我们的cs还在内核态?

调试一上午没有弄出来😡,暂时搁置吧,先刷一下今天的力扣。

2025年5月2日09点18分更新:今天继续调试。给自己设了一个底线,如果今天没有解决这个问题,就先打个补丁暂时略过。

页表信息:

<bochs:17> info tab
cr3: 0x000000218000
0xc0000000-0xc00fffff -> 0x000000000000-0x0000000fffff
0xc0100000-0xc0133fff -> 0x000000200000-0x000000233fff
0xfff00000-0xffffefff -> 0x000000101000-0x0000001fffff
0xfffff000-0xffffffff -> 0x000000218000-0x000000218fff

观察第5行。我们初始的页表结构物理地址基址是0x00100000,这是内核页表结构。我们先创建了一个用户进程,打上断点,发现此时cr3指向0x000000218000,页目录表位置是0x000000218000-0x000000218fff,说明我们给用户进程创建了新的页表结构。说明创建新的内存页的功能正常。

说一下最后发现的问题吧,在loader的库文件boot.inc(是的,第四章的一个小小的参数的不完备)里,有一行宏定义:

PG_US_U		equ 100b ;最开始设置的000b,这是修改后的
PG_US_S		equ 100b

当时设置的参数错误,花费了我两天时间去调试,其中心酸一言难尽啊。

18点58分,调试成功,运行结果截图:

多的话也不说了,总之就是很累,还好最后问题解决了!!!!!


我们操作系统目前的内存管理现状

简略回顾寻址:

cr3存页目录物理基址,前10位(0xffc00000)用来寻址页目录表

pde页目录项,前20位(0xfffff000)用来寻址页表

pde页表项,前20位用来寻址具体的页

虚拟地址取低12位和pde寻得的页结合,得到最后的物理地址。

先说物理地址:我们的操作系统内核都在物理内存0-4mb(第0个页表覆盖范围,4mb=0x400000),准确的说,在物理内存0-1mb(第0个页表覆盖范围,1mb=0x100000)。

二级页表的结构:一张页目录表在最低地址,后面跟着1k个页表,每个页表1k项。对于我们的系统,那张页目录表的起始位置(基址)是物理地址0x00100000。

在加载内核之前,我们在loader中开启分页模式之前,我们创建了两个页目录项(pde),这两项是页目录表第0项和第768项,它们都指向同一个地址,这个地址就是页目录基址+4000(0x1000),代表的是第0个页表的起始地址。

为什么是0和768?总的而言,我们的页表的排序标准是按虚拟地址从低到高的,虚拟地址0-4gb对应0-1kb页表,也就是0-1k页目录项。

所以,在第0项pde中,记录的物理地址是第0个页表的物理地址,最大可以对应实际的0-4mb物理内存。记录的最大可以对应的虚拟地址是0x00000000-0x003fffff,也就是0-4mb。

同样,768项,记录的物理地址是第0个页表的物理地址,最大可以对应实际的0-4mb物理内存。只是记录的最大可以对应的虚拟地址是0xc0000000-0xc03fffff,也就是3gb–3gb+4mb。

然后,我们额外处理了一个特殊的页目录项:1023项,我们使用被称为递归映射的方法,让页目录表的1023项指向页目录表本身的物理基址。

但是,我们创建的页目录项对应了页表,页表却不一定创建了1k个页表项(pte,用来完整映射4mb内存)。观察我们的loader.s,发现我们随后创建了256个项(覆盖1mb的内内存),现在是:0和768的pde->(不完整的)第0页表->0-1mb物理内存。

然后loader.s创建了第769项-1022项(共256-1-1=254)个页目录项,希望它们对应254个页表,再进一步对应虚拟的3gb-4gb地址(然而实际上没有创建这些页表的页目录,因而后面的对应不成立)。

接着我们开启了内存分页,因而后面所有的内存(地址)默认情况下都是在说虚拟内存。但是需要注意,到现在为止,我们只实现了非常非常短的物理-虚拟映射,事实上,在我们开启分页后,只有0-0x000fffff和0xc0000000-0xc00fffff能完整的走完虚拟-物理完整寻址过程。剩下的虚拟地址无法找到对应的物理地址,出现缺页错误(pf)。

接下来到了我们memory.c文件,第一次编写是在开启内核多线程之前,核心问题是解决为新开辟的线程申请内存的问题。

在这之前我们引入了位图这个结构来管理内存,位图唯一的作用就是指示某段资源是否被使用**(被使用是1,没被使用是0)**。目前我们用它来管理内存(可以管理物理内存或虚拟内存)。我们定义了两个结构体:pool(用来管理物理内存?),virtual_addr(用来管理虚拟内存),它们内部都包含bitmap。

vaddr_get:从用户/内核pool申请虚拟内存页,返回虚拟地址

pde_ptr:得到某个虚拟地址的页目录项指针

pte_ptr:得到某个虚拟地址的页表项指针

palloc:从某个物理内存池申请一页物理内存页,返回物理地址

page_table_add:建立一个物理地址和一个虚拟地址的映射关系,即最终实现虚拟地址-页目录项-页表项-物理地址的关系构建。

malloc_page:完整的分配页过程,包括申请虚拟页,申请物理页,将二者建立映射。最终返回起始虚拟地址

get_kernel_pages:对malloc_page的调用,代表从内核内存池申请内存。这个函数会在创建线程时调用。

以上的函数,目前实现给内核线程分配内存。这部分涉及到的页表还都是内核页表,也就是我们在loader里实现的1mb页表。

然后我们进入到用户进程的研究领域。对于用户进程,有两个主要的问题,一个是特权级切换与任务调度切换的问题,一个是用户进程内存管理的问题。我们这部分研究内存问题。

用户进程的内存管理相比于内核线程,主要是多了一个页表结构问题。相关代码在memory、process、tss三个源文件里面。

memory.c是辅助,下面是用户进程新增的函数。

get_user_page:用户内存池中申请地址。

get_a_page:同样是关联物理地址和虚拟地址,对象是目前运行的进线程。内部区分了内核线程和用户进程,调用了page_table_add。

addr_v2p:获取虚拟地址对应的物理地址。

process.c是核心,内部包含内联汇编,最终完成创建页表的功能。下面是内部函数。

start_process:第一个重要函数。作用就是构建一个用户进程。方法是先完整的初始化一个中断栈,然后通过内联汇编,让cpu执行一次iretw中断返回,这样从0特权级来到3特权级,把这个中断栈中的数据压入到了cpu里面。

其实这个函数严格来说不属于内存管理部分,属于是任务切换部分,我这里顺带提一下。

简单复习内联汇编:基本格式是

指令:输出操作数列表(储存汇编执行后得到的结果):输入操作数列表(储存给汇编的条件):破坏的内容。另外涉及到约束和修饰符,不再一一介绍。

page_dir_activate:第二个重要函数。这个是正儿八经的内存管理相关函数,作用是激活页表。同样用了内联汇编,更新cr3寄存器的值。

process_activate:完成激活页表和更新esp。激活页表调用上面的page_dir_activate,更新esp调用update_tss_esp

所谓的激活页表,严格来说是更新cr3寄存器的值,确保了有页目录表基址。但是整个页表结构还没有建立好。

create_page_dir:这个函数用来实际创建用户进程页表结构中的页目录结构,包括三个过程。首先第一步,先从内核内存池?申请一页的内存,这页内存存用户进程的页目录表。然后第二步,把目前页表的页目录表的后256项复制到新申请的内存位置,也就是将新的页表的后1gb虚拟内存映射到内核空间。最后第三步,获取新的页表的页目录基址并返回,并且安排好新的页表的递归映射。

目前,用户进程页表结构中,cr3和页目录表安排的比较合理了,但是页表这个层级是否还不完善?还只有1个页目录项的1个页表的256个页,对应1mb的内存空间。

(如果我没有猜错的话,我们整个操作系统,包括内核和用户进程,应该只会在0-1mb的物理内存上进行。)

内存相关就说这么多吧,文字没有经过润色,病句不少,格式也比较混乱,大家将就着看吧。本来我计划整个操作系统写完后再写总结的,结果为了调试代码提前写了内存部分的总结,那就发出来给大家看看。
户进程页表结构中,cr3和页目录表安排的比较合理了,但是页表这个层级是否还不完善?还只有1个页目录项的1个页表的256个页,对应1mb的内存空间。

(如果我没有猜错的话,我们整个操作系统,包括内核和用户进程,应该只会在0-1mb的物理内存上进行。)

内存相关就说这么多吧,文字没有经过润色,病句不少,格式也比较混乱,大家将就着看吧。本来我计划整个操作系统写完后再写总结的,结果为了调试代码提前写了内存部分的总结,那就发出来给大家看看。

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

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

相关文章

【Machine Learning Q and AI 读书笔记】- 01 嵌入、潜空间和表征

Machine Learning Q and AI 中文译名 大模型技术30讲&#xff0c;主要总结了大模型相关的技术要点&#xff0c;结合学术和工程化&#xff0c;对LLM从业者来说&#xff0c;是一份非常好的学习实践技术地图. 本文是Machine Learning Q and AI 读书笔记的第1篇&#xff0c;对应原…

Flutter 学习之旅 之 Flutter 和 Android 原生 实现数据交互的MethodChanel和EventChannel方式的简单整理

Flutter 学习之旅 之 Flutter 和 Android 原生 实现数据交互的MethodChanel和EventChannel方式的简单整理 目录 Flutter 学习之旅 之 Flutter 和 Android 原生 实现数据交互的MethodChanel和EventChannel方式的简单整理 一、简单介绍 二、Flutter 和 Android 原生之间的数据…

outlook for mac本地邮件存放在哪儿?

尽管 PST 格式通常与 Microsoft Outlook 联系在一起&#xff0c;但认为它也在 Mac OS 上存储邮箱数据是一种误解。实际上&#xff0c;Outlook for Mac 不会将邮件存储为 PST 文件。无法在 Outlook for Mac 中找到 PST 文件位置&#xff0c;因为它不使用 PST 文件来存储邮箱数据…

数字时代,如何为个人信息与隐私筑牢安全防线?

首席数据官高鹏律师团队编著 在当今数字化时代&#xff0c;个人信息和隐私保护至关重要。我们在享受数字生活带来的便利时&#xff0c;也面临着个人信息泄露、隐私被侵犯的风险。下面将从先进技术和法律途径两个方面&#xff0c;探讨如何严格保护个人信息和隐私。 一、先进技…

MongoDB的图形化工具robo3t,navicat

MongoDB 常用的两个图形化工具 —— Robo 3T 和 Navicat 的详细介绍、区别和基本使用方法&#xff1a; &#x1f9f0; 一、Robo 3T&#xff08;原 Robomongo&#xff09; &#x1f4cc; 简介 Robo 3T 是一款专注于 MongoDB 的轻量级可视化客户端。由原 Robomongo 团队开发&am…

Qt QWebEngine应用和网页的交互

一、QWebEngine简介 1、Qt WebEngine模块提供了一个Web浏览器引擎&#xff0c;可以轻松地将万维网上的内容嵌入到没有本机Web引擎的平台上的Qt应用程序中。 2、Qt WebEngine提供了用于渲染HTML&#xff0c;XHTML和SVG文档的C 类和QML类型&#xff0c;它们使用级联样式表&#…

d202552-sql

一、184. 部门工资最高的员工 - 力扣&#xff08;LeetCode&#xff09; 要找到每个部门工资最高的 使用窗口函数 加排序函数 排序函数用rank dense_rank都行 把最高相同的找出来就行 select *, dense_rank() over(partition by departmentId order by Salary desc) as rank …

AntSK:基于大模型的一体化AI知识库解决方案深度解析

随着大模型&#xff08;如GPT、LLM&#xff09;技术的飞速发展&#xff0c;企业对智能知识管理和专属AI助手的需求日益增长。AntSK 正是在这一背景下诞生的企业级AI一体机解决方案。本文将从技术架构、核心功能、创新点和应用场景等方面&#xff0c;深入解析 AntSK 如何助力企业…

在Electron中爬取CSDN首页的文章信息

背景 之前分享了Electron入门的相关文章&#xff1a;https://gitee.com/ruirui-study/electron-demo 后来&#xff0c;我就想在里面多做一些演示给大家看&#xff0c;集成了以下功能及演示&#xff1a; 窗口管理、各种方法封装托盘管理菜单管理获取屏幕演示多窗口及通信演示…

bfs处理 推多米诺

前言&#xff1a;这个题目本来打算一次遍历来写&#xff0c;但是写的时候发现有点难搞&#xff0c;后面发现是 bfs &#xff0c;但是这个bfs 不是很好处理&#xff0c;后面看了题解&#xff0c;颇有感触 这个和堆处理的最短路是一样的&#xff0c;在取出一个位置的时候才对其进…

【Java IO流】File类基础详解

参考笔记&#xff1a;java File类基础 万字详解&#xff08;通俗易懂&#xff09;-CSDN博客 目录 1.前言 2. File类介绍 3. File类构造方法 4.File类常用的方法案例演示 4.1 创建文件/文件夹的方法 4.2 删除文件/文件夹的方法 4.3 判断文件/文件夹是否存在的方法 4.4 …

【业务领域】InfiniBand协议总结

InfiniBand协议总结 InfiniBand协议是什么&#xff1f;Infiniband产生的原因Mellanox公司介绍及其新闻基于TCP/IP的网络与IB网络的比较IB标准的优势什么是InfiniBand网络什么是InfiniBand架构Mellanox IB卡介绍InfiniBand速率发展介绍InfiniBand网络主要上层协议InfiniBand管理…

蒙特卡罗方法(Monte Carlo Method)​​:基于随机采样的数值计算与模拟技术

​​核心思想​​ 蒙特卡罗方法通过​​随机采样​​和​​统计模拟​​解决数学、物理、工程等领域的复杂问题&#xff0c;其核心是利用​​大数定律​​——当样本量足够大时&#xff0c;样本均值会收敛于期望值。 ​​关键特点​​&#xff1a; ​​无维度诅咒​​&#x…

【资料分享】全志T536(异构多核ARMCortex-A55+玄铁E907 RISC-V)工业核心板硬件说明书

前 言 本文为创龙科技SOM-TLT536工业核心板硬件说明书,主要提供SOM-TLT536工业核心板的产品功能特点、技术参数、引脚定义等内容,以及为用户提供相关电路设计指导。 为便于阅读,下表对文档出现的部分术语进行解释;对于广泛认同释义的术语,在此不做注释。

【2025年五一数学建模竞赛】A题 完整论文 模型建立与求解

目录 2025年五一数学建模竞赛 A题基于历史数据与模式识别的道路车流量推测模型研究摘要一、问题的背景和重述1.1问题的背景1.2问题的重述 二、问题的分析三、模型假设四、符号及变量说明五、模型的建立与求解问题一&#xff1a;基于线性回归的支路车流量推测问题二&#xff1a;…

MySQL初阶:数据库基础,数据库和表操作,数据库中的数据类型

1.数据库基础 数据库是一个客户端——服务器结构的程序。 服务器是真正的主体&#xff0c;负责保存和管理数据&#xff0c;数据都存储在硬盘上 数据库处理的主要内容是数据的存储&#xff0c;查找&#xff0c;修改&#xff0c;排序&#xff0c;统计等。 关系型数据库&#…

“会话技术”——Cookie_(2/2)原理与使用细节

经过Cookie的快速入门与代码使用。如果想深入理解Cookie的技术实现&#xff0c;就得去理解它的原理。 且有些时候使用Cookie&#xff0c;还要根据需求设置存活期限以及确定Cookie获取范围等其他细节。最后&#xff0c;我们会总结Cookie这门客户端会话技术的作用。 一、原理 注…

DBeaver连接人大金仓数据库V9

1、官网下载驱动jdbc 打开官网地址&#xff0c;找到下面的V9R1-JDBC&#xff0c;点击后面的下载即可&#xff0c;保存到本地 2、解压最新版的驱动程序 3、把***_JDBC文件夹内的驱动程序复制到DBeaver安装目录下的plugins文件夹里 4、打开dbeaver程序&#xff0c;增加kingbase…

服务器丢包率测试保姆级教程:从Ping到网络打流仪实战

测试服务器丢包率是网络性能诊断的重要环节&#xff0c;丢包通常由网络拥塞、硬件故障、配置错误或线路质量差导致。以下是多种测试方法的详细步骤和工具说明&#xff1a; 一、基础工具测试&#xff08;无需专业设备&#xff09; 1. 使用 ping 命令 命令示例&#xff1a; bash…

n8n 使用 AI Agent 和 MCP 社区节点

n8n 使用 AI Agent 和 MCP 社区节点 0. 前提条件1. 创建一个 "在聊天消息时" 节点2. 创建一个 "AI Agent" 节点 0. 前提条件 请参考 n8n 安装 n8n-nodes-mcp 社区节点 安装 MCP 社区节点。 1. 创建一个 “在聊天消息时” 节点 单击 “测试聊天”&#xf…