x64多核OS
2025-07-09 17:18:30 1 举报
AI智能生成
手写x64操作系统
作者其他创作
大纲/内容
结合x86笔记看
汇编部分
CPU架构、指令集、汇编、硬编码之间的关系
#住宅还是写字楼: 架构
# 工程图纸: 指令集规范
# 工程材料: 机器码
------------------------ 编译器
施工队A(汇编)、施工队B、施工队C
#住宅还是写字楼: 架构
# 工程图纸: 指令集规范
# 工程材料: 机器码
------------------------ 编译器
施工队A(汇编)、施工队B、施工队C
汇编风格
1.Intel CPU、AMD CPU(CISC复杂指令集)
# Windows: MASM汇编风格
# Unix: NASM汇编风格、ATT
2.ARM CPU(RISC精简指令集)
# ARM汇编
# Mac M1、M2芯片
1.Intel CPU、AMD CPU(CISC复杂指令集)
# Windows: MASM汇编风格
# Unix: NASM汇编风格、ATT
2.ARM CPU(RISC精简指令集)
# ARM汇编
# Mac M1、M2芯片
CPU架构与指令集
CPU架构(如CISC或RISC)和指令集(Instruction Set Architecture, ISA)之间的关系是非常紧密的。CPU架构实际上决定了指令集的设计和实现,二指令集则位CPU提供了执行任务所需的基本操作。
CISC(Complex Instruction Set Computing, 复杂指令集计算)和RISC(Reduced Instruct Set Computing,精简指令集计算)是两种不同的CPU架构设计理念,它们的主要区别在于处理器指令的复杂性。
CISC架构倾向于用较少的更复杂的指令,这些指令可能会在一条指令中完成u东哥操作,如内存访问、算数运算和数据移动等。CISC架构的典型代表是Intel的x86架构,他的指令集中包含了大量的复杂指令
相反,RISC架构使用了较多的简单指令,每条指令集尽可能只完成一个操作。这样可以使得CPU更容易在一个时钟周期内完成一条指令,提高指令的执行速度,RISC架构的典型代表是ARM和MIPS,它们的指令集设计比较简单。
所以,你可以理解为,CPU架构(CISC或RISC)决定了指令集设计的总体策略,而指令集则是这种策略的具体实现
CPU架构(如CISC或RISC)和指令集(Instruction Set Architecture, ISA)之间的关系是非常紧密的。CPU架构实际上决定了指令集的设计和实现,二指令集则位CPU提供了执行任务所需的基本操作。
CISC(Complex Instruction Set Computing, 复杂指令集计算)和RISC(Reduced Instruct Set Computing,精简指令集计算)是两种不同的CPU架构设计理念,它们的主要区别在于处理器指令的复杂性。
CISC架构倾向于用较少的更复杂的指令,这些指令可能会在一条指令中完成u东哥操作,如内存访问、算数运算和数据移动等。CISC架构的典型代表是Intel的x86架构,他的指令集中包含了大量的复杂指令
相反,RISC架构使用了较多的简单指令,每条指令集尽可能只完成一个操作。这样可以使得CPU更容易在一个时钟周期内完成一条指令,提高指令的执行速度,RISC架构的典型代表是ARM和MIPS,它们的指令集设计比较简单。
所以,你可以理解为,CPU架构(CISC或RISC)决定了指令集设计的总体策略,而指令集则是这种策略的具体实现
MASM、NASM、ATT、ARM之间的关系
MASM、NASM、ATT和ARM实际上都和汇编语言相关,但它们在具体的使用和语法上有一些区别:
1.MASM: Microsoft Macro Assembler(MASM)是微软公司开发的一款汇编语言编译器,它为x86架构(如Intel和AMD的处理器)提供了ige汇编环境,并且使用了Intel语法。它还提供了丰富的宏功能,允许用户编写复杂的汇编程序
2.NASM:Netwide Assembler(NASM)是一个开源的x86架构汇编语言编译器。它可以用于编写操作系统、驱动程序等底层程序,和MASM一样,NASM也使用了Intel语法
3.ATT:ATT语法是一种汇编语言的语法,主要在UNIX和Linux系统的GNU ASeembler(GAS)中使用。与Intel语法相比,ATT语法的特点是源操作数和目标操作数的顺序相反,即源操作数在前,目标操作数灾后
4.ARM:ARM并非一种汇编语言或者语法,而是一种处理器架构。ARM架构被广泛应用在嵌入式系统和移动设备中,ARM架构的汇编语言有自己的一套语法规则,与Intel和ATT语法有所不同。
总的来说,MASM和NASM是为x86架构编写汇编代码的工具,它们使用Intel语法;而ATT则是另一种汇编语言的语法,主要在GNU Assembler中使用。ARM则是一种完全不同的处理器架构,有自己的汇编语言和语法结构
MASM、NASM、ATT和ARM实际上都和汇编语言相关,但它们在具体的使用和语法上有一些区别:
1.MASM: Microsoft Macro Assembler(MASM)是微软公司开发的一款汇编语言编译器,它为x86架构(如Intel和AMD的处理器)提供了ige汇编环境,并且使用了Intel语法。它还提供了丰富的宏功能,允许用户编写复杂的汇编程序
2.NASM:Netwide Assembler(NASM)是一个开源的x86架构汇编语言编译器。它可以用于编写操作系统、驱动程序等底层程序,和MASM一样,NASM也使用了Intel语法
3.ATT:ATT语法是一种汇编语言的语法,主要在UNIX和Linux系统的GNU ASeembler(GAS)中使用。与Intel语法相比,ATT语法的特点是源操作数和目标操作数的顺序相反,即源操作数在前,目标操作数灾后
4.ARM:ARM并非一种汇编语言或者语法,而是一种处理器架构。ARM架构被广泛应用在嵌入式系统和移动设备中,ARM架构的汇编语言有自己的一套语法规则,与Intel和ATT语法有所不同。
总的来说,MASM和NASM是为x86架构编写汇编代码的工具,它们使用Intel语法;而ATT则是另一种汇编语言的语法,主要在GNU Assembler中使用。ARM则是一种完全不同的处理器架构,有自己的汇编语言和语法结构
数据宽度
CPU寻址能力经历从16位->32位->64位,导致寄存器兼容16位、32位、64位。
注意:CPU运行一个程序,一般是从内存中将数据读入合适的寄存器,在寄存器中计算好结果,然后将结果写回内存。
CPU寻址能力经历从16位->32位->64位,导致寄存器兼容16位、32位、64位。
注意:CPU运行一个程序,一般是从内存中将数据读入合适的寄存器,在寄存器中计算好结果,然后将结果写回内存。
实现微内核
int 0x10
INT 0x10是一个在x86架构中的BIOS中断调用,用于进行低级的视频服务,这个调用是由IBM的PC BIOS在1981年定义的,以便让应用程序能够与视频硬件进行交互,而无需了解硬件的具体实现细节,它在现代计算机中已经不再使用,但在早期的PC和很多实模式环境中(如DOS),它是对视频硬件进行控制的主要方式
INT 0x10提供了多种视频服务,包括设置显示模式,改变字符颜色、绘制像素,等等,要调用这些服务,通常你需要先在CPU的寄存器中设置一些特定的值,然后执行INT 0x10指令。
INT 0x10是一个在x86架构中的BIOS中断调用,用于进行低级的视频服务,这个调用是由IBM的PC BIOS在1981年定义的,以便让应用程序能够与视频硬件进行交互,而无需了解硬件的具体实现细节,它在现代计算机中已经不再使用,但在早期的PC和很多实模式环境中(如DOS),它是对视频硬件进行控制的主要方式
INT 0x10提供了多种视频服务,包括设置显示模式,改变字符颜色、绘制像素,等等,要调用这些服务,通常你需要先在CPU的寄存器中设置一些特定的值,然后执行INT 0x10指令。
内核整体结构图
实模式内存布局
汇编执行流一
汇编执行流二
调用约定
# __cdecl:参数自右向左,由调用方平栈
# __stdcall:参数自右向左,由被调用方平栈
# __fastcall:前两个参数使用寄存器传参,剩下参数压栈, 被调用方平栈
在x64下(也称为x86-64或AMD64),所有的编译器都忽略__fastcall,因为它们都使用了一种新的默认的调用约定。在Windows平台下,这种调用约定被称为__fastcall或x64 calling convention.根据这种约定,函数的前4个整数或指针参数会在寄存器中传递,参数会按照顺序传递给一下寄存器:
RCX、RDX、R8、R9.如果有更多的参数,或者有浮点数参数它们会被放在堆栈上,返回值将被放在RAX寄存器中。这些规则在Unix和Unix类的系统(例如Linux和macOS)下也是相似,不过这些系统下的调用约定通常被称为System V AMD64 ABI.并且传递参数的寄存器不同。在System V AMD64 ABI中,前6个整数或指针参数会在一下寄存器中传递
RDI、RSI、RDX、RCX、R8、R9
# __cdecl:参数自右向左,由调用方平栈
# __stdcall:参数自右向左,由被调用方平栈
# __fastcall:前两个参数使用寄存器传参,剩下参数压栈, 被调用方平栈
在x64下(也称为x86-64或AMD64),所有的编译器都忽略__fastcall,因为它们都使用了一种新的默认的调用约定。在Windows平台下,这种调用约定被称为__fastcall或x64 calling convention.根据这种约定,函数的前4个整数或指针参数会在寄存器中传递,参数会按照顺序传递给一下寄存器:
RCX、RDX、R8、R9.如果有更多的参数,或者有浮点数参数它们会被放在堆栈上,返回值将被放在RAX寄存器中。这些规则在Unix和Unix类的系统(例如Linux和macOS)下也是相似,不过这些系统下的调用约定通常被称为System V AMD64 ABI.并且传递参数的寄存器不同。在System V AMD64 ABI中,前6个整数或指针参数会在一下寄存器中传递
RDI、RSI、RDX、RCX、R8、R9
内联汇编
内联汇编(Inline Assembly)是将汇编代码直接嵌入到C/C++等高级语言中的一种技术,主要用于直接访问硬件、操作特殊的处理器指令,或者完成一些高级语言难以完成的特定任务,比如下方场景
# 直接访问底层硬件:在一些特殊的情况下,高级语言可能无法提供对某些硬件的直接访问。比如,如果你需要控制特定的硬件急促请你,或者你需要进行某种硬件的特殊配置,那么你可能需要使用内联汇编
# 使用特定的处理器指令: 有时候,处理器厂商会提供一些特殊的指令,这些指令可以实现一些高级语言无法完成的操作,例如,SIMD(单指令,多数据)指令通常需要使用内联汇编来变成
# 性能优化,在某些极端的情况下,内联汇编可以提供比高级语言更好的性能。这通常是因为你可以直接控制处理器的操作,这样可以减少一些不必要的操作,但是请注意这种优化往往需要对底层硬件有很深的理解,而且这种优化往往是非常复杂的
# 实现特殊的程序逻辑:有时候,你可能需要实现一些高语言无法完成的特殊的程序逻辑。例如,你可能需要手动控制栈的布局,或者你可能需要创建一些特殊的数据结构(比如跳跃表)
但是,需要 注意的是,内联汇编需要对汇编语言和底层硬件有深入的理解,并且难以跨平台使用。同时,使用内联汇编编写的代码通常难以理解和维护。因此除非必须,否则尽量避免使用内联汇编
内联汇编(Inline Assembly)是将汇编代码直接嵌入到C/C++等高级语言中的一种技术,主要用于直接访问硬件、操作特殊的处理器指令,或者完成一些高级语言难以完成的特定任务,比如下方场景
# 直接访问底层硬件:在一些特殊的情况下,高级语言可能无法提供对某些硬件的直接访问。比如,如果你需要控制特定的硬件急促请你,或者你需要进行某种硬件的特殊配置,那么你可能需要使用内联汇编
# 使用特定的处理器指令: 有时候,处理器厂商会提供一些特殊的指令,这些指令可以实现一些高级语言无法完成的操作,例如,SIMD(单指令,多数据)指令通常需要使用内联汇编来变成
# 性能优化,在某些极端的情况下,内联汇编可以提供比高级语言更好的性能。这通常是因为你可以直接控制处理器的操作,这样可以减少一些不必要的操作,但是请注意这种优化往往需要对底层硬件有很深的理解,而且这种优化往往是非常复杂的
# 实现特殊的程序逻辑:有时候,你可能需要实现一些高语言无法完成的特殊的程序逻辑。例如,你可能需要手动控制栈的布局,或者你可能需要创建一些特殊的数据结构(比如跳跃表)
但是,需要 注意的是,内联汇编需要对汇编语言和底层硬件有深入的理解,并且难以跨平台使用。同时,使用内联汇编编写的代码通常难以理解和维护。因此除非必须,否则尽量避免使用内联汇编
裸函数
(naked function)是一种特殊的函数类型,它告诉编译器不要为这个函数生成任何形式的Prolog或Epilog代码。换句话说,裸函数只包含开发者提供的代码,编译器不会自动产生函数的进入和退出机制,这些都需要开发者自行处理,这通常在底层编程中非常有用,比如在写操作系统内核、驱动、嵌入式系统等需要精确控制的地方。然而,裸函数也带来了复杂性和风险。由于缺少编译器生成的Prolog和Epilog,开发者必须自己负责所有的堆栈管理和寄存器保存/恢复工作。这要求开发者有深厚的底层只是,且容易出错,一旦出错可能导致严重问题。
此外,裸函数的行为在不同的编译器和平台之间可能会有所不同,一些编译器可能不支持裸函数,或者支持的方式不同。这使得使用裸函数的代码在跨平台上的兼容性较差。现代的操作系统和编译器通常更倾向于使用更标准、更可靠、更易于理解和调试的编程模式,随着硬件性能的提高,我们往往可以接收编译器在Prolog或Epilog中插入的一些额外的开销,以换取代码的可维护性和可移植性。
因此,现代的操作系统和编译器可能不再支持裸函数,这是一个权衡和取舍的结果,在某些情况下,你仍然可以使用特定的编译器扩展或者直接使用汇编语言来实现类似裸函数的功能
(naked function)是一种特殊的函数类型,它告诉编译器不要为这个函数生成任何形式的Prolog或Epilog代码。换句话说,裸函数只包含开发者提供的代码,编译器不会自动产生函数的进入和退出机制,这些都需要开发者自行处理,这通常在底层编程中非常有用,比如在写操作系统内核、驱动、嵌入式系统等需要精确控制的地方。然而,裸函数也带来了复杂性和风险。由于缺少编译器生成的Prolog和Epilog,开发者必须自己负责所有的堆栈管理和寄存器保存/恢复工作。这要求开发者有深厚的底层只是,且容易出错,一旦出错可能导致严重问题。
此外,裸函数的行为在不同的编译器和平台之间可能会有所不同,一些编译器可能不支持裸函数,或者支持的方式不同。这使得使用裸函数的代码在跨平台上的兼容性较差。现代的操作系统和编译器通常更倾向于使用更标准、更可靠、更易于理解和调试的编程模式,随着硬件性能的提高,我们往往可以接收编译器在Prolog或Epilog中插入的一些额外的开销,以换取代码的可维护性和可移植性。
因此,现代的操作系统和编译器可能不再支持裸函数,这是一个权衡和取舍的结果,在某些情况下,你仍然可以使用特定的编译器扩展或者直接使用汇编语言来实现类似裸函数的功能
让你的OS尽情发挥
如何让内核突破512B
GRUB VS BIOS
BIOS是计算机系统中的固件,位于计算机主板上的ROM芯片中,负责硬件的初始化和操作系统的引导
BIOS负责启动过程中的硬件检查(即POST)和启动引导程序,传统BIOS启动模式通常只能启动一个操作系统
GRUB是一种引导加载程序,主要用于在启动时加载操作系统的内核,支持多种操作系统的启动
它通常在硬盘的引导扇区或UEFI固件中,并通过BIOS或UEFI启动
BIOS是计算机系统中的固件,位于计算机主板上的ROM芯片中,负责硬件的初始化和操作系统的引导
BIOS负责启动过程中的硬件检查(即POST)和启动引导程序,传统BIOS启动模式通常只能启动一个操作系统
GRUB是一种引导加载程序,主要用于在启动时加载操作系统的内核,支持多种操作系统的启动
它通常在硬盘的引导扇区或UEFI固件中,并通过BIOS或UEFI启动
MBR VS GPT
MBR(Master Boot Record):
MBR是一种最早的,也是最广泛使用的硬盘分区表结构,它存在于可引导设备(如硬盘、闪存驱动器等)的第一个扇区(扇区0),MBR的主要组成部分包括一个位于MBR的开始位置的引导加载程序,以及一个位于MBRE的结束位置的分区表。分区表可以定义最多四个主分区,或者三个主分区加一个扩展分区。扩展分区可以进一步划分为更多的逻辑分区。然而,MBR存在一些限制。例如,它只能处理最大2TB的硬盘(对于现代大容量硬盘来说这是一个限制),而且只能定义最多四个主分区。
GPT(GUID Partition Table):
GPT是一种现代的,更强到的硬盘分区表结构,它是为了解决MBR的限制而设计ide。GPT是UEFI(统一可扩展固件接口)标准的一部分吗,主要用于替代MBR.GPT的主要优点包括:
# 对大硬盘的支持: GPT可以处理超过2TB的硬盘。事实上,它可以支持的硬盘大小几乎没有实际的限制
# 多分区支持:GPT支持多大128个主分区(在Windows中),远超过MBR的四个主分区限制。
# 更强的数据完整性:GPT包含分区表的CRC校验和备份,可以提高数据的可靠性和完整性。
在现代计算机系统中,特别是使用大容量硬盘和UEFI固件的系统中,GPT通常是推荐的分区表结构。
总结:
# mbr是老版,gpt是新版
# mbr仅支持4个分区,gpt支持128个分区
# mbr支持最大2TB, gpt最大支持无限制
一般搭配:
# bios + mbr
# usefi + gpt
MBR(Master Boot Record):
MBR是一种最早的,也是最广泛使用的硬盘分区表结构,它存在于可引导设备(如硬盘、闪存驱动器等)的第一个扇区(扇区0),MBR的主要组成部分包括一个位于MBR的开始位置的引导加载程序,以及一个位于MBRE的结束位置的分区表。分区表可以定义最多四个主分区,或者三个主分区加一个扩展分区。扩展分区可以进一步划分为更多的逻辑分区。然而,MBR存在一些限制。例如,它只能处理最大2TB的硬盘(对于现代大容量硬盘来说这是一个限制),而且只能定义最多四个主分区。
GPT(GUID Partition Table):
GPT是一种现代的,更强到的硬盘分区表结构,它是为了解决MBR的限制而设计ide。GPT是UEFI(统一可扩展固件接口)标准的一部分吗,主要用于替代MBR.GPT的主要优点包括:
# 对大硬盘的支持: GPT可以处理超过2TB的硬盘。事实上,它可以支持的硬盘大小几乎没有实际的限制
# 多分区支持:GPT支持多大128个主分区(在Windows中),远超过MBR的四个主分区限制。
# 更强的数据完整性:GPT包含分区表的CRC校验和备份,可以提高数据的可靠性和完整性。
在现代计算机系统中,特别是使用大容量硬盘和UEFI固件的系统中,GPT通常是推荐的分区表结构。
总结:
# mbr是老版,gpt是新版
# mbr仅支持4个分区,gpt支持128个分区
# mbr支持最大2TB, gpt最大支持无限制
一般搭配:
# bios + mbr
# usefi + gpt
磁盘寻址的方式
# CHS(Cylinder, 圆柱、Head, 磁头、Sector, 扇区)
CHS是一种传统的磁盘寻址方式,基于磁盘的物理结构,通常用于早期的硬盘和磁盘管理系统。
## CHS有最大的寻址限制,通常不能处理超过8.4GB的 Cylinder最多支持1024个柱面,Header 最多支持256个磁头 Sector每个磁头每个磁道上最多有63个扇区
# LBA28
## LBA28使用28位来表示磁盘上的逻辑块位置,因此能够表示最大约2^28个扇区,每个扇区大小仍然是512,因此最大支持128GB的磁盘容量
# LBA48
## LBA48是LBA28的扩展版本,使用48位来表示磁盘的逻辑块地址,它克服了LBA的容量限制,支持更大的磁盘容量,2^48个扇区,最大支持128TB
# CHS(Cylinder, 圆柱、Head, 磁头、Sector, 扇区)
CHS是一种传统的磁盘寻址方式,基于磁盘的物理结构,通常用于早期的硬盘和磁盘管理系统。
## CHS有最大的寻址限制,通常不能处理超过8.4GB的 Cylinder最多支持1024个柱面,Header 最多支持256个磁头 Sector每个磁头每个磁道上最多有63个扇区
# LBA28
## LBA28使用28位来表示磁盘上的逻辑块位置,因此能够表示最大约2^28个扇区,每个扇区大小仍然是512,因此最大支持128GB的磁盘容量
# LBA48
## LBA48是LBA28的扩展版本,使用48位来表示磁盘的逻辑块地址,它克服了LBA的容量限制,支持更大的磁盘容量,2^48个扇区,最大支持128TB
IO地址端口分配
硬盘寄存器
特殊的寄存器0x1f7
1.如果写这个寄存器,代表向硬盘发命令: 0x20(读)、0x30(写)、0xec(硬盘检测)
2.如果读这个寄存器,读出来的值的含义
0x01:表示发生了错误,错误代码已放置在错误寄存器中
0x02: 表示控制器检测到索引标记(不是很懂)
0x04: 表示控制器必须通过使用ECC字节来纠正数据(纠错码: 扇区末尾的额外字节,允许验证其完整性,有时还可以纠正错误)
0x08:表示控制器正在等待数据(用于写入)或正在发送数据(用于读取)。该位为0时不要访问数据寄存器
0x10: 表示读/写磁头就位(搜索完成)
0x20: 表示控制器检测到写入故障
0x40:表示控制器已准备好接受命令,并且驱动器以正确的速度旋转
0x80:表示控制器正忙于执行命令。设置该位时,不应该访问任何寄存器(数字输出寄存器除外)
特殊的寄存器0x1f7
1.如果写这个寄存器,代表向硬盘发命令: 0x20(读)、0x30(写)、0xec(硬盘检测)
2.如果读这个寄存器,读出来的值的含义
0x01:表示发生了错误,错误代码已放置在错误寄存器中
0x02: 表示控制器检测到索引标记(不是很懂)
0x04: 表示控制器必须通过使用ECC字节来纠正数据(纠错码: 扇区末尾的额外字节,允许验证其完整性,有时还可以纠正错误)
0x08:表示控制器正在等待数据(用于写入)或正在发送数据(用于读取)。该位为0时不要访问数据寄存器
0x10: 表示读/写磁头就位(搜索完成)
0x20: 表示控制器检测到写入故障
0x40:表示控制器已准备好接受命令,并且驱动器以正确的速度旋转
0x80:表示控制器正忙于执行命令。设置该位时,不应该访问任何寄存器(数字输出寄存器除外)
带你玩转CPU段页门
什么是段?就是你经常听到的:代码段、数据段
什么是页?就是你经常听到的:虚拟内存,又叫CPU分页机制
什么是门? 与你经常听到的用户态切内核态有关:
# 四种门:
## 中断门:相应硬件中断或异常(比如定时器、除0)
## 调用门:允许从低特权级调用高特权级函数
## 任务门:进行任务切换(现在几乎不用)
## 陷阱门:相应软件中断(比如int 0x80)
# 快速调用: sysenter/sysexit、(syscall/sysret)
# 门是GDT/LDT(全局/局部描述符表)中的特殊条目
# 当用户程序想进入内核时,会通过门进行跳转,并由CPU自动完成特权级转换(例如从Ring3到Ring0)
# 门记录了目标代码段选择子、偏移量、目标特权级DPL等信息
总结一句话
门时实现操作系统中特权级控制和跳转的底层机制,而快速调用是指一种高效的用户态到内核态的调用方式,它可以通过门实现,也可以绕过门(如使用sysenter)
什么是页?就是你经常听到的:虚拟内存,又叫CPU分页机制
什么是门? 与你经常听到的用户态切内核态有关:
# 四种门:
## 中断门:相应硬件中断或异常(比如定时器、除0)
## 调用门:允许从低特权级调用高特权级函数
## 任务门:进行任务切换(现在几乎不用)
## 陷阱门:相应软件中断(比如int 0x80)
# 快速调用: sysenter/sysexit、(syscall/sysret)
# 门是GDT/LDT(全局/局部描述符表)中的特殊条目
# 当用户程序想进入内核时,会通过门进行跳转,并由CPU自动完成特权级转换(例如从Ring3到Ring0)
# 门记录了目标代码段选择子、偏移量、目标特权级DPL等信息
总结一句话
门时实现操作系统中特权级控制和跳转的底层机制,而快速调用是指一种高效的用户态到内核态的调用方式,它可以通过门实现,也可以绕过门(如使用sysenter)
为什么CPU要引入段机制?
段基址(Segmentation)是一种内存管理技术,它在Intel的8086微处理器中首次引入,该处理器于1978年发布,段机制的引入有几个主要原因:
# 内存保护:通过分割内存到不同的段,每个段可以有自己的访问权限,例如读/写/执行权限。这可以防止程序访问到它不应该访问的内存区域,增加了系统的稳定性和安全性
# 方便模块化编程:在早期的编程实践中,程序往往被分割成不同的模块,例如代码段、数据段、堆栈段等。每个模块可以被加载到内存的任意位置,并且可以独立地增长或缩小,这使得程序设计和内存管理变得更加灵活
# 突破物理内存限制:对于8086这样的16位处理器来说,它的地址线只有20根,最大只能寻址1MB的物理内存。然而,通过段基址,CPU可以使用一个段基址加上一个偏移量的方式来寻址内存,这样就可以突破1MB的物理内存限制,访问更大的虚拟内存空间。虽然段机制在当时解决了一些问题,但页引入了新的问题,例如段间通信的复杂性、内存碎片等问题。后来,随着Intel 80386微处理器的退出,CPU开始引入了更加复杂的内存管理基址,例如分页基址(Pagin),已解决段机制的一些问题。现代的操作系统,如Linux和Windows,主要使用分页基址进行内存管理,而段机制主要用于实现某些特定的功能。例如用户级线程、内存保护等
段基址(Segmentation)是一种内存管理技术,它在Intel的8086微处理器中首次引入,该处理器于1978年发布,段机制的引入有几个主要原因:
# 内存保护:通过分割内存到不同的段,每个段可以有自己的访问权限,例如读/写/执行权限。这可以防止程序访问到它不应该访问的内存区域,增加了系统的稳定性和安全性
# 方便模块化编程:在早期的编程实践中,程序往往被分割成不同的模块,例如代码段、数据段、堆栈段等。每个模块可以被加载到内存的任意位置,并且可以独立地增长或缩小,这使得程序设计和内存管理变得更加灵活
# 突破物理内存限制:对于8086这样的16位处理器来说,它的地址线只有20根,最大只能寻址1MB的物理内存。然而,通过段基址,CPU可以使用一个段基址加上一个偏移量的方式来寻址内存,这样就可以突破1MB的物理内存限制,访问更大的虚拟内存空间。虽然段机制在当时解决了一些问题,但页引入了新的问题,例如段间通信的复杂性、内存碎片等问题。后来,随着Intel 80386微处理器的退出,CPU开始引入了更加复杂的内存管理基址,例如分页基址(Pagin),已解决段机制的一些问题。现代的操作系统,如Linux和Windows,主要使用分页基址进行内存管理,而段机制主要用于实现某些特定的功能。例如用户级线程、内存保护等
为什么CPU要引入页机制?
页机制(Pagin)是一种内存管理技术,主要用于支持虚拟内存系统。它的引入有几个主要原因:
# 简化内存管理:页机制允许将物理内存划分为固定大小的块(称为页或页面),并将这些页映射到虚拟内存的任意位置,这样,操作系统只需要跟踪哪些页被分配和哪些页可用,而无需担心内存碎片等问题
# 支持虚拟内存:页机制可以将部分内存内容存储到硬盘上,从而使得程序可以使用更大的地址空间,超出物理内存的限制,当程序访问到未在物理内存中的数据时,系统会自动将数据从硬盘读取到内存中,这个过程对程序是透明的
# 内存保护:每个页面都有自己的访问权限,例如读/写/执行权限。这可以防止程序访问到它不应该访问的内存区域,提供更强的内存保护
# 支持内存共享和复制:页机制使得实现内存共享和复制更为简单。例如,多个进程可以共享同一个页面,或者通过复制页面来实现进程的复制(如Unix中的fork系统调用)。页机制在Intel的80386微处理器中首次引入,该处理器于1985年发布,80386是Intel第一个支持分页的32位微处理器,它增加了页表和相关的硬件支持
页机制(Pagin)是一种内存管理技术,主要用于支持虚拟内存系统。它的引入有几个主要原因:
# 简化内存管理:页机制允许将物理内存划分为固定大小的块(称为页或页面),并将这些页映射到虚拟内存的任意位置,这样,操作系统只需要跟踪哪些页被分配和哪些页可用,而无需担心内存碎片等问题
# 支持虚拟内存:页机制可以将部分内存内容存储到硬盘上,从而使得程序可以使用更大的地址空间,超出物理内存的限制,当程序访问到未在物理内存中的数据时,系统会自动将数据从硬盘读取到内存中,这个过程对程序是透明的
# 内存保护:每个页面都有自己的访问权限,例如读/写/执行权限。这可以防止程序访问到它不应该访问的内存区域,提供更强的内存保护
# 支持内存共享和复制:页机制使得实现内存共享和复制更为简单。例如,多个进程可以共享同一个页面,或者通过复制页面来实现进程的复制(如Unix中的fork系统调用)。页机制在Intel的80386微处理器中首次引入,该处理器于1985年发布,80386是Intel第一个支持分页的32位微处理器,它增加了页表和相关的硬件支持
CPU运行模式
实模式寻址
如何控制CPU由实模式进入保护模式
1.配置GDT表,至少包含一个代码段一个数据段
2.开A20总线
3.设置控制寄存器CR0
4.设置段寄存器
1.配置GDT表,至少包含一个代码段一个数据段
2.开A20总线
3.设置控制寄存器CR0
4.设置段寄存器
CPU是如何找到数据并读写的
段选择子
段描述符
让你的内核进入保护模式
哪些时机需要关闭中断?
编写操作系统时,可能需要在以下几种情况下关闭中断:
1.临界区: 当CPU正在执行涉及到对共享资源(如全局变量、数据结构等)进行修改的敏感代码段(临界区)时,为了防止数据的不一致性,通常需要关闭中断
2.系统调用:系统调用时用户空间到内核空间的一个切换过程,为了防止系统调用过程中被打断,从而导致系统的不稳定,也需要关闭中断
3.上下文切换:当操作系统需要进行进程或线程的上下文切换时,也需要关闭中断,否则,在保存和恢复上下文的过程中,如果发生中断可能会引发问题
4.内存管理:在进行页面置换等操作时,可能需要关闭中断,以防止在操作下过程中被中断打断,导致数据的不一致性。
然而,需要指出的是,长时间关闭中断会导致系统的响应性降低,因此在实际操作中,我们应该尽量减少关闭中断的时间,并使用其他同步机制(如互斥锁、信号量等)来保证数据的一致性,此外,现代多核处理器中的多线程环境也使得关闭中断并不能解决所有的同步问题,因此更多的是倾向于使用更为复杂的并发控制机制
编写操作系统时,可能需要在以下几种情况下关闭中断:
1.临界区: 当CPU正在执行涉及到对共享资源(如全局变量、数据结构等)进行修改的敏感代码段(临界区)时,为了防止数据的不一致性,通常需要关闭中断
2.系统调用:系统调用时用户空间到内核空间的一个切换过程,为了防止系统调用过程中被打断,从而导致系统的不稳定,也需要关闭中断
3.上下文切换:当操作系统需要进行进程或线程的上下文切换时,也需要关闭中断,否则,在保存和恢复上下文的过程中,如果发生中断可能会引发问题
4.内存管理:在进行页面置换等操作时,可能需要关闭中断,以防止在操作下过程中被中断打断,导致数据的不一致性。
然而,需要指出的是,长时间关闭中断会导致系统的响应性降低,因此在实际操作中,我们应该尽量减少关闭中断的时间,并使用其他同步机制(如互斥锁、信号量等)来保证数据的一致性,此外,现代多核处理器中的多线程环境也使得关闭中断并不能解决所有的同步问题,因此更多的是倾向于使用更为复杂的并发控制机制
CPU从实模式切换到保护模式的步骤:
1.禁用中断:
在开始切换之前,你需要禁用中断来防止切换过程中发生中断,这可能会造成不可预知的结果
cli ; Clear the interrupt flag
2.启用A20地址线
由于历史原因,早期的PC用一个名为A20的地址线来模拟8086的环境,在进入保护模式前需要启用这个地址线,用以访问高于1MB的内存
3.加载全局描述符表(GDT)
创建一个包含所需内存段描述符的GDT,至少需要定义一个代码段和一个数据段
使用lgdt指令加载GDT的地址
4.打开保护模式
通过设置控制寄存器CR0的保护模式使能(PE)位来打开保护模式
5.跳转到保护模式的代码段
进行长跳转(far jump)到新的代码段,这通常会涉及一个选择子(selector),它指向GDT中的一个代码段描述符,这个跳转会刷新处理器的流水线,并使得PE位的设置生效
6.更新段寄存器
一旦CPU开始运行在保护模式下,就必须更新所有的段寄存器(CS, DS, ES, FS, GS,SS)以使用新的段选择子
7.初始化分页(如果需要)
如果你打算使用分页,则需要设置和启用分页。这涉及到初始化页目录和页表,并设置CR0寄存器的分页(PG)位
8.重新加载其他寄存器:
根据需要重新加载其他处理器状态寄存器,如堆栈指针和基指针寄存器
1.禁用中断:
在开始切换之前,你需要禁用中断来防止切换过程中发生中断,这可能会造成不可预知的结果
cli ; Clear the interrupt flag
2.启用A20地址线
由于历史原因,早期的PC用一个名为A20的地址线来模拟8086的环境,在进入保护模式前需要启用这个地址线,用以访问高于1MB的内存
3.加载全局描述符表(GDT)
创建一个包含所需内存段描述符的GDT,至少需要定义一个代码段和一个数据段
使用lgdt指令加载GDT的地址
4.打开保护模式
通过设置控制寄存器CR0的保护模式使能(PE)位来打开保护模式
5.跳转到保护模式的代码段
进行长跳转(far jump)到新的代码段,这通常会涉及一个选择子(selector),它指向GDT中的一个代码段描述符,这个跳转会刷新处理器的流水线,并使得PE位的设置生效
6.更新段寄存器
一旦CPU开始运行在保护模式下,就必须更新所有的段寄存器(CS, DS, ES, FS, GS,SS)以使用新的段选择子
7.初始化分页(如果需要)
如果你打算使用分页,则需要设置和启用分页。这涉及到初始化页目录和页表,并设置CR0寄存器的分页(PG)位
8.重新加载其他寄存器:
根据需要重新加载其他处理器状态寄存器,如堆栈指针和基指针寄存器
x86 gdt表为什么不是从0开始
在x86架构中,全局描述符表(Global Descriptor Table, GDT)是用来定义不同段(segments)的属性的一个数据结构。这些段可以是代码段、数据段或者系统段等。GDT中的每个条目称为一个段描述符(segment descriptor)。GDT不是从0开始的,主要有以下几个原因:
1.空描述符(Null Descriptor): 在GDT的第一个位置(即0偏移)通常包含一个空描述符。这是一个特别的描述符,所有的位都被设置为0,处理器期望GDT的第一个条目是一个空描述符,这是一个有效性检查的手段,如果处理器尝试加载一个段选择子(selector)指向这个空描述符,会产生一个异常,这样可以帮助捕获编程错误,比如一个未初始化的段寄存器。
2.历史和向后兼容性:在x86架构的早期版本中,处理器设计者决定将第一个描述符设置为非法描述符,以便能够通过触发异常来捕捉到软件错误。随着架构的发展,这种涉及决定被保留了下来,以保持与老代码的兼容性
3.处理器的异常处理:如果某个程序错误地将其段寄存器设置为0,处理器会尝试使用GDT的第0个描述符,但因为这是一个空描述符,它会产生一个异常,如果GDT从0开始且不含空描述符,处理器可能会认为这是一个有效的段,从而导致更加难以调试的错误
4.访问控制:段选择子包含一个用于访问GDT的索引,当索引为0时,处理器认为这是一个空描述符,从而不允许访问。者提供了一种简单的方法来保证系统级别的段不能被不恰当地引用或使用
所以GDT中地第一项被预留为一个空描述符是出于安全和错误检测地目的,这是x86架构设计的一部分
在x86架构中,全局描述符表(Global Descriptor Table, GDT)是用来定义不同段(segments)的属性的一个数据结构。这些段可以是代码段、数据段或者系统段等。GDT中的每个条目称为一个段描述符(segment descriptor)。GDT不是从0开始的,主要有以下几个原因:
1.空描述符(Null Descriptor): 在GDT的第一个位置(即0偏移)通常包含一个空描述符。这是一个特别的描述符,所有的位都被设置为0,处理器期望GDT的第一个条目是一个空描述符,这是一个有效性检查的手段,如果处理器尝试加载一个段选择子(selector)指向这个空描述符,会产生一个异常,这样可以帮助捕获编程错误,比如一个未初始化的段寄存器。
2.历史和向后兼容性:在x86架构的早期版本中,处理器设计者决定将第一个描述符设置为非法描述符,以便能够通过触发异常来捕捉到软件错误。随着架构的发展,这种涉及决定被保留了下来,以保持与老代码的兼容性
3.处理器的异常处理:如果某个程序错误地将其段寄存器设置为0,处理器会尝试使用GDT的第0个描述符,但因为这是一个空描述符,它会产生一个异常,如果GDT从0开始且不含空描述符,处理器可能会认为这是一个有效的段,从而导致更加难以调试的错误
4.访问控制:段选择子包含一个用于访问GDT的索引,当索引为0时,处理器认为这是一个空描述符,从而不允许访问。者提供了一种简单的方法来保证系统级别的段不能被不恰当地引用或使用
所以GDT中地第一项被预留为一个空描述符是出于安全和错误检测地目的,这是x86架构设计的一部分
CR0控制寄存器的各个状态标识位
C语言调用汇编
1.汇编层面的函数为什么要声明为global
2.C语言层面通过函数原型去调用(extern 可以不写,但是为了代码可读性,建议写)
1.汇编层面的函数为什么要声明为global
2.C语言层面通过函数原型去调用(extern 可以不写,但是为了代码可读性,建议写)
汇编调用C语言
1.C语言层面的函数必须是全局函数,即不能有static修饰
2.汇编层面通过extern引入
1.C语言层面的函数必须是全局函数,即不能有static修饰
2.汇编层面通过extern引入
单步调试内核之生成内核
1.生成内核时,要指定内核的起始地址(必须)
2.内核依赖的所有.o文件,需要带调试符号
1.生成内核时,要指定内核的起始地址(必须)
2.内核依赖的所有.o文件,需要带调试符号
让CPU进入64位长模式
如何让CPU进入64位模式
1.启用PAE(物理地址扩展)通过设置CR4寄存器的PAE位
2.初始化和启用IA32_EFER寄存器的LME(长模式使能)位,以启用长模式
3.加载并激活PML4(页映射四级表),以支持64位的虚拟地址
4.设置CS(代码段)寄存器,以指向一个64位的代码段,这样CPU就会进入64位模式
1.启用PAE(物理地址扩展)通过设置CR4寄存器的PAE位
2.初始化和启用IA32_EFER寄存器的LME(长模式使能)位,以启用长模式
3.加载并激活PML4(页映射四级表),以支持64位的虚拟地址
4.设置CS(代码段)寄存器,以指向一个64位的代码段,这样CPU就会进入64位模式
64位寄存器变化(例如状态寄存器)
gdtr、idtr
在64位模式下段机制的大幅简化:
# 段基址(Base)全部设为0(除了FS和GS)
# 段限长(Limit)被忽略
# 段访问权限也基本不用,只通过页表实现隔离和保护
# 地址计算全部采用64位线性地址,段基址不参与
所以,在64位模式下,段基址几乎被废弃,只保留最小形式以兼容旧逻辑
在64位模式下段机制的大幅简化:
# 段基址(Base)全部设为0(除了FS和GS)
# 段限长(Limit)被忽略
# 段访问权限也基本不用,只通过页表实现隔离和保护
# 地址计算全部采用64位线性地址,段基址不参与
所以,在64位模式下,段基址几乎被废弃,只保留最小形式以兼容旧逻辑
64位模式下的段描述符
32位、64位段描述符的区别
在Intel x86和x86-64计算机架构中,32位和64位段描述符的区别主要在于它们能够定义的地址和操作模式范围
1.基地址(Base Address):段的起始内存地址,在32位和64位描述符中都是32位长
2.段限制(Segment Limit):定义最后可访问数据的地址,长度为20位
3.D/B(Default operand size/Big): 字段
# 在32位描述符中,如果设置了D/B位,表示为32位代码段
# 在64位描述符中,D/B位必须清零,而L(Long)位设置表示为64位代码段,并且D/B位必须位0.
其他字段,如G(Granularity)、P(Present)、DPL(Descriptor Privilege Level)、S(Ssystem Segment)、Type、C(Conforming)、E(Expand-Down)、R(Readable)、W(Writable)和A(Accessed).在两种段描述符中都村子啊,并有相同的含义。因此,64位段描述符纵向比32位描述符,主要增加了对64位操作模式的支持,这是通过L位来实现的
32位、64位段描述符的区别
在Intel x86和x86-64计算机架构中,32位和64位段描述符的区别主要在于它们能够定义的地址和操作模式范围
1.基地址(Base Address):段的起始内存地址,在32位和64位描述符中都是32位长
2.段限制(Segment Limit):定义最后可访问数据的地址,长度为20位
3.D/B(Default operand size/Big): 字段
# 在32位描述符中,如果设置了D/B位,表示为32位代码段
# 在64位描述符中,D/B位必须清零,而L(Long)位设置表示为64位代码段,并且D/B位必须位0.
其他字段,如G(Granularity)、P(Present)、DPL(Descriptor Privilege Level)、S(Ssystem Segment)、Type、C(Conforming)、E(Expand-Down)、R(Readable)、W(Writable)和A(Accessed).在两种段描述符中都村子啊,并有相同的含义。因此,64位段描述符纵向比32位描述符,主要增加了对64位操作模式的支持,这是通过L位来实现的
如何检测CPU是否支持x64模式?
在子实现的操作系统中检测CPU是否支持x64模式,可以通过以下步骤:
1.检查CPUID指令:首先,你需要确认CPU支持CPUID指令,因为这是获取CPU支持功能信息的基础
2.执行CPUID指令:使用CPUID指令来获取扩展处理器信息和特性。你可以通过将EAX寄存器设置为1,然后执行CPUID指令来完成这个操作
3.检查EDX寄存器:执行CPUID指令后,检查EDX寄存器的第29位(从0开始计数),如果这一位被设置,CPU支持x64moshi
4.检查扩展功能:为了进一步确认,你可以将EAX设置位0x80000000并执行CPUID,这将返回支持的最大扩展功能号,如果返回值大于或等于0x80000001,那么你可以继续将EAX设置为0x80000001并执行CPUID来获取更多多的信息
5.检查扩展特性:最后,再次检查EDX寄存器的第29位,如果这一位被设置,那么CPU支持64位模式。
确保在执行这些检查之前,你已经正确地进入了保护模式,因为在实模式下无法执行这些检查。在编写汇编代码进行这些检查时,你需要了解CPUID指令的具体使用方法一级如何读取寄存器值
在子实现的操作系统中检测CPU是否支持x64模式,可以通过以下步骤:
1.检查CPUID指令:首先,你需要确认CPU支持CPUID指令,因为这是获取CPU支持功能信息的基础
2.执行CPUID指令:使用CPUID指令来获取扩展处理器信息和特性。你可以通过将EAX寄存器设置为1,然后执行CPUID指令来完成这个操作
3.检查EDX寄存器:执行CPUID指令后,检查EDX寄存器的第29位(从0开始计数),如果这一位被设置,CPU支持x64moshi
4.检查扩展功能:为了进一步确认,你可以将EAX设置位0x80000000并执行CPUID,这将返回支持的最大扩展功能号,如果返回值大于或等于0x80000001,那么你可以继续将EAX设置为0x80000001并执行CPUID来获取更多多的信息
5.检查扩展特性:最后,再次检查EDX寄存器的第29位,如果这一位被设置,那么CPU支持64位模式。
确保在执行这些检查之前,你已经正确地进入了保护模式,因为在实模式下无法执行这些检查。在编写汇编代码进行这些检查时,你需要了解CPUID指令的具体使用方法一级如何读取寄存器值
实现物理内存管理模块
分页机制.
在现代操作系统中,包括Linux,都使用了一种被称为"分页"的内存管理技术,分页的目的是为了将物理内存划分成固定大小的块(称为页或页面),并允许程序在它自己的虚拟地址空间内进行运行,这种机制使得每个进程都认为它拥有全部的内存资源,简化了内存管理,并提供了对内存的保护。
在分页系统中,每个进程都有自己的页表,页表用于存储虚拟页到物理页的映射。当进程访问一个虚拟地址时,硬件会将虚拟地址分成两部分:一个部分用于索引页表以找到相应的页表条目,另一部分是在物理页内的偏移,页表条目包含了对应的物理页的地址。
页机制的一个关键组成部分是内存管理单元(Memory Management Unit, MMU)。MMU是处理器的一部分,负责处理虚拟地址到物理地址的转换。在分页系统中,MMU的主要任务是在每次内存访问时,通过查找页表来将虚拟地址转换为物理地址。
分页系统还有一个重要的特性是支持“需求分页(Demand Paging)”,在需求分页系统中,一个进程启动时,并不需要将其所有的页面都加载到内存中。相反,只有当进程实际访问一个页面时,该页面才会被加载。如果一个页面不在内存中,就会触发一个"缺页中断"(Page Fault),操作系统会找到页面在磁盘上的位置,将其加载到内存,然后重新开始该指令。此外,为了提高虚拟地址到物理地址转换的效率,硬件通常会包含一个转译后援缓冲器(Translation Lookaside Buffer, TLB)。TLB是一个小的硬件缓存,用于存储最近使用过的页表条目。当查找一个虚拟地址的物理内存时,硬件会首先检查TLB.如果找到了对应的条目(称为TLB命中),则可以直接进行地址转换。如果没有找到(称为TLB未命中),则需要访问页表。这就是CPU页机制的基本概述,当然,实际的实现可能会更复杂,并包括其他特性,如页的置换算法,写回策略,以及支持各种不同的页表结构等等
2级/3级/4级/5级
在现代操作系统中,包括Linux,都使用了一种被称为"分页"的内存管理技术,分页的目的是为了将物理内存划分成固定大小的块(称为页或页面),并允许程序在它自己的虚拟地址空间内进行运行,这种机制使得每个进程都认为它拥有全部的内存资源,简化了内存管理,并提供了对内存的保护。
在分页系统中,每个进程都有自己的页表,页表用于存储虚拟页到物理页的映射。当进程访问一个虚拟地址时,硬件会将虚拟地址分成两部分:一个部分用于索引页表以找到相应的页表条目,另一部分是在物理页内的偏移,页表条目包含了对应的物理页的地址。
页机制的一个关键组成部分是内存管理单元(Memory Management Unit, MMU)。MMU是处理器的一部分,负责处理虚拟地址到物理地址的转换。在分页系统中,MMU的主要任务是在每次内存访问时,通过查找页表来将虚拟地址转换为物理地址。
分页系统还有一个重要的特性是支持“需求分页(Demand Paging)”,在需求分页系统中,一个进程启动时,并不需要将其所有的页面都加载到内存中。相反,只有当进程实际访问一个页面时,该页面才会被加载。如果一个页面不在内存中,就会触发一个"缺页中断"(Page Fault),操作系统会找到页面在磁盘上的位置,将其加载到内存,然后重新开始该指令。此外,为了提高虚拟地址到物理地址转换的效率,硬件通常会包含一个转译后援缓冲器(Translation Lookaside Buffer, TLB)。TLB是一个小的硬件缓存,用于存储最近使用过的页表条目。当查找一个虚拟地址的物理内存时,硬件会首先检查TLB.如果找到了对应的条目(称为TLB命中),则可以直接进行地址转换。如果没有找到(称为TLB未命中),则需要访问页表。这就是CPU页机制的基本概述,当然,实际的实现可能会更复杂,并包括其他特性,如页的置换算法,写回策略,以及支持各种不同的页表结构等等
2级/3级/4级/5级
并非所有的虚拟地址都会被缓存到TLB中,TLB有大小限制,仅花奴才能最近访问过的虚拟地址页表映射;同时,有些地址(或访问方式)故意不经过TLB或不缓存到TLB,比如:
# 特殊类型页(如uncacheable, WC):
# 映射的设备地址
# 指定为全局无效的页
# 使用invlpg/CR3刷新的页
# 通过页表属性标记不缓存的页
# 特殊类型页(如uncacheable, WC):
# 映射的设备地址
# 指定为全局无效的页
# 使用invlpg/CR3刷新的页
# 通过页表属性标记不缓存的页
TLB(Translation Lookaside Buffer, TLB)是一个硬件设备,存在于CPU中,它的主要任务时加速虚拟地址到物理地址的转换过程。在有了TLB之后,当CPU需要访问一个虚拟地址时,它会首先检查TLB,看看所需的物理地址是否已经在那里,如果在,那么这就是一个TLB命中(TLB hit),物理地址可以直接使用,如果不再,那么这就是一个TLB未命中(TLB miss),需要通过访问内存中的页表来获取物理地址。
TLB的大小有限,因此无法保存所有的地址转换信息。当TLB满了,需要加载新的地址转换时,就需要替换掉一个旧的条目。TLB替换策略可以包括最近最少使用(LRU),随机替换等。
在一次TLB未命中时,需要访问页表来获取物理地址。页表是存储在主内存中的,访问它们需要时间,在最糟糕的情况下,可能需要访问两次内存(一次访问页表,一次访问实际的数据)。这就是所谓的二级内存访问,它可能会极大地影响系统性能。TLB的主要目的就是避免这种二级内存访问。通过缓存常用的地址转换信息,使得大部分的内存访问都可以在一次内存访问内完成。
TLB也支持页的访问权限和存在性的检查。每个TLB条目通常包含一个有效位(表示该条目是否有效)和一组权限位(表示谁可以访问这个页,以及以何种方式访问)。TLB是CPU的一部分,是一个硬件缓存,用来加速虚拟地址到物理地址的转换过程
TLB的大小有限,因此无法保存所有的地址转换信息。当TLB满了,需要加载新的地址转换时,就需要替换掉一个旧的条目。TLB替换策略可以包括最近最少使用(LRU),随机替换等。
在一次TLB未命中时,需要访问页表来获取物理地址。页表是存储在主内存中的,访问它们需要时间,在最糟糕的情况下,可能需要访问两次内存(一次访问页表,一次访问实际的数据)。这就是所谓的二级内存访问,它可能会极大地影响系统性能。TLB的主要目的就是避免这种二级内存访问。通过缓存常用的地址转换信息,使得大部分的内存访问都可以在一次内存访问内完成。
TLB也支持页的访问权限和存在性的检查。每个TLB条目通常包含一个有效位(表示该条目是否有效)和一组权限位(表示谁可以访问这个页,以及以何种方式访问)。TLB是CPU的一部分,是一个硬件缓存,用来加速虚拟地址到物理地址的转换过程
段式内存管理
页式内存管理
页部件
即使在开启分页机制的情况下,段部件(Segment Uint)仍然参与权限检查,特别是在x86保护模式下,但在64位长模式中,大部分段机制被废弃,只有FS、GS和CS的权限字段仍然有效
访问流程如下(32位保护模式下):
逻辑地址(段寄存器+偏移)
# 段机制: 段寄存器->GDT/LDT->得到段基址 + 权限
# 线性地址(段基址 + 偏移)
# 分页基址:线性地址->页表查找->物理地址
# 执行内存访问(并再次做权限检查)
在这个过程中,段机制负责前半段的权限和范围校验,分页基址负责后半段的访问控制
即使在开启分页机制的情况下,段部件(Segment Uint)仍然参与权限检查,特别是在x86保护模式下,但在64位长模式中,大部分段机制被废弃,只有FS、GS和CS的权限字段仍然有效
访问流程如下(32位保护模式下):
逻辑地址(段寄存器+偏移)
# 段机制: 段寄存器->GDT/LDT->得到段基址 + 权限
# 线性地址(段基址 + 偏移)
# 分页基址:线性地址->页表查找->物理地址
# 执行内存访问(并再次做权限检查)
在这个过程中,段机制负责前半段的权限和范围校验,分页基址负责后半段的访问控制
mov byte[0x1234], 0x10在实模式、保护模式、兼容模式(32位)、长模式(64位)下的访问流程对比
1.实模式(Real Mode)
# 地址计算:
物理地址= 段寄存器(比如DS) x 16 + 偏移量(0x1234)
## 比如: DS=0x1000,那么[0x1234]实际访问的是0x10000+0x1234=0x11234
## 只有20位地址线,最大寻址空间1MB
# 特点
## 无分页机制
## 无访问权限控制
## 所有程序运行在Ring0
## 无法隔离用户与内核
## 程序随便访问任何物理内存(包括BIOS区、显存等)
# 地址计算:
物理地址= 段寄存器(比如DS) x 16 + 偏移量(0x1234)
## 比如: DS=0x1000,那么[0x1234]实际访问的是0x10000+0x1234=0x11234
## 只有20位地址线,最大寻址空间1MB
# 特点
## 无分页机制
## 无访问权限控制
## 所有程序运行在Ring0
## 无法隔离用户与内核
## 程序随便访问任何物理内存(包括BIOS区、显存等)
2.保护模式(Protected Mode)
# 地址计算流程
逻辑地址=段选择子: 偏移(如DS:0x1234)
->段选择子->GDT/LDT->找段描述符
->线性地址=段基址+偏移
->若分页开启:线性地址->页表->物理地址
# 权限检查:
## 段权限:是否可写、是否存在、是否越界
## DPL/CPL(Descriptor Privilege Level,段的权限等级/ Current Privilege Level,当前代码正在运行的权限等级)检查
## 分页权限(页是否存在、可写、用户/内核)
## 多级页表(通常2级:页目录+页表)
# 地址计算流程
逻辑地址=段选择子: 偏移(如DS:0x1234)
->段选择子->GDT/LDT->找段描述符
->线性地址=段基址+偏移
->若分页开启:线性地址->页表->物理地址
# 权限检查:
## 段权限:是否可写、是否存在、是否越界
## DPL/CPL(Descriptor Privilege Level,段的权限等级/ Current Privilege Level,当前代码正在运行的权限等级)检查
## 分页权限(页是否存在、可写、用户/内核)
## 多级页表(通常2级:页目录+页表)
3.兼容模式(Compatibility Mode)
# 属于64位模式下的一种子模式,用于运行32位程序
# 保留段基址(和保护模式一致)
# 使用分页(支持4级页表)
# 地址宽度是32位,线性地址最多4GB
本质上,地址访问流程=保护模式流程,所以几乎一致
# 属于64位模式下的一种子模式,用于运行32位程序
# 保留段基址(和保护模式一致)
# 使用分页(支持4级页表)
# 地址宽度是32位,线性地址最多4GB
本质上,地址访问流程=保护模式流程,所以几乎一致
4.长模式(Long Mode, 64位模式)
# 地址计算流程
虚拟地址(RIP/偏移值)
->如果使用FS/GS: 加上FS.base/ GS.base
->得到线性地址
->4级页表->最终物理地址
# 特点
## 段基址基本废弃(除了FS/GS)
## CS/DS/SS/ES段基址恒为0,Limit被忽略
## 地址空间扩大为48位虚拟地址
## 使用4级页表(PML4->PDP->PD-PT)
## 所有权限控制靠页表属性位+NX页+CR4控制位+SMEP/SMAP
# 地址计算流程
虚拟地址(RIP/偏移值)
->如果使用FS/GS: 加上FS.base/ GS.base
->得到线性地址
->4级页表->最终物理地址
# 特点
## 段基址基本废弃(除了FS/GS)
## CS/DS/SS/ES段基址恒为0,Limit被忽略
## 地址空间扩大为48位虚拟地址
## 使用4级页表(PML4->PDP->PD-PT)
## 所有权限控制靠页表属性位+NX页+CR4控制位+SMEP/SMAP
段寄存器的种类
CS/DS/SS/ES/FS/GS
CS/DS/SS/ES/FS/GS
逻辑地址、线性地址、物理地址之间的转换关系
# 逻辑地址(Logical Address)= 段寄存器+偏移
# 线性地址(Linear Address) = 段基址 + 偏移(逻辑地址->线性地址)
# 物理地址(Physical Address) = 线性地址经过分页转换后的实际地址
# 逻辑地址(Logical Address)= 段寄存器+偏移
# 线性地址(Linear Address) = 段基址 + 偏移(逻辑地址->线性地址)
# 物理地址(Physical Address) = 线性地址经过分页转换后的实际地址
地址转换流程图(32位保护模式下)
内存结构
物理内存管理
内存检测
检测结果
ARDS结构中的字段大小都是4字节,共5个字段,所以此结构大小为20字节。每次int 0x15之后,BIOS就返回这样一个结构的数据。注意,ARDS结构中用64位宽度的属性来描述这段内存基地址(起始地址)及其长度,所以表中的基地址和长度都分为低32位和高32位两部分。
其中的Type字段用来描述这段内存的类型,这里所谓的类型是说明这段内存的用途,即其是可以被操作系统使用,还是保留起来不能用,如表所示
ARDS结构中的字段大小都是4字节,共5个字段,所以此结构大小为20字节。每次int 0x15之后,BIOS就返回这样一个结构的数据。注意,ARDS结构中用64位宽度的属性来描述这段内存基地址(起始地址)及其长度,所以表中的基地址和长度都分为低32位和高32位两部分。
其中的Type字段用来描述这段内存的类型,这里所谓的类型是说明这段内存的用途,即其是可以被操作系统使用,还是保留起来不能用,如表所示
CPU分页模式
10-10-12
101012分页
101012分页
PDE、PTE
属性含义:
P:有效位。0表示当前表项无效,缺页异常就是借助这个位实现的
R/W: 0表示只读。1表示可读可写
U/S: 0表示3特权级级程序可访问,1表示只能0、1、2特权级可访问
PWT、PCD:忽略
A: 0表示该页未被访问,1表示已被访问
D:脏位,0表示该页未写过,1表示该页被写过
PS:只存在于页目录。0表示这是4KB页,指向一个页表。1表示这是4MB大页,直接指向物理页
PAT:这个不管
G:如果G位为1刷新TLB时将不会刷新PDE/PET的G为1的页,G=1切换进程该PTE仍然有效
有效位:由软件控制的位,此位仅使用于多处理器系统,指令了可读写或只读
属性含义:
P:有效位。0表示当前表项无效,缺页异常就是借助这个位实现的
R/W: 0表示只读。1表示可读可写
U/S: 0表示3特权级级程序可访问,1表示只能0、1、2特权级可访问
PWT、PCD:忽略
A: 0表示该页未被访问,1表示已被访问
D:脏位,0表示该页未写过,1表示该页被写过
PS:只存在于页目录。0表示这是4KB页,指向一个页表。1表示这是4MB大页,直接指向物理页
PAT:这个不管
G:如果G位为1刷新TLB时将不会刷新PDE/PET的G为1的页,G=1切换进程该PTE仍然有效
有效位:由软件控制的位,此位仅使用于多处理器系统,指令了可读写或只读
PWT、PCD、PAT有什么用?
PWT(Page-level Write-Through)、PCD(Page-level Cache Disable)和PAT(Page Attribute Table)是现代计算机体系结构中的内存管理相关的术语,特别是在处理虚拟内存和内存缓存时,它们时处理器中用于控制缓存策略和内存访问行为的标志或机制。
1.PWT(Page-level-Write-Through):这是一种缓存策略标志。当启用时(即PWT标志设置为1),它指示内存写入操作应该同时更新内存和缓存(即写通)。这样,缓存中的数据总是与主内存中的数据一致,这对于需要高度数据一致性的应用很有用,但可能会降低性能,因为每次写操作都需要更新主内存
2.PCD(Page-level Cache Disable):这个标志用于控制特定内存页面的缓存行为。当设置为1时,它会禁用对应内存页面的缓存,即使缓存在其他情况下时可用的。这对于需要直接和频繁访问物理内存的操作(比如,与硬件设备的内存映射输入/输出操作)非常有用,因为缓存可能会引入不必要的延迟或数据不一致
3.PAT(Page Attribute Table):PAT提供了一种更细粒度的方式来控制内存的缓存策略。它允许操作系统为每个内存页面指定特定的缓存模式,例如写回(Write Back)、写通(Write Through)、不缓存(Uncacheable)或写保护(Write Combinning)。PAT通过与PWT和PCD一起工作,提供了更灵活的缓存控制机制,可以根据不同类型的内存访问需求进行优化。
总体而言,PWT、PCD和PAT时现代处理器用来优化内存访问和提高整体系统性能的关键机制。它们使得操作系统能够根据具体的应用场景和需求调整内存缓存的行为
PWT(Page-level Write-Through)、PCD(Page-level Cache Disable)和PAT(Page Attribute Table)是现代计算机体系结构中的内存管理相关的术语,特别是在处理虚拟内存和内存缓存时,它们时处理器中用于控制缓存策略和内存访问行为的标志或机制。
1.PWT(Page-level-Write-Through):这是一种缓存策略标志。当启用时(即PWT标志设置为1),它指示内存写入操作应该同时更新内存和缓存(即写通)。这样,缓存中的数据总是与主内存中的数据一致,这对于需要高度数据一致性的应用很有用,但可能会降低性能,因为每次写操作都需要更新主内存
2.PCD(Page-level Cache Disable):这个标志用于控制特定内存页面的缓存行为。当设置为1时,它会禁用对应内存页面的缓存,即使缓存在其他情况下时可用的。这对于需要直接和频繁访问物理内存的操作(比如,与硬件设备的内存映射输入/输出操作)非常有用,因为缓存可能会引入不必要的延迟或数据不一致
3.PAT(Page Attribute Table):PAT提供了一种更细粒度的方式来控制内存的缓存策略。它允许操作系统为每个内存页面指定特定的缓存模式,例如写回(Write Back)、写通(Write Through)、不缓存(Uncacheable)或写保护(Write Combinning)。PAT通过与PWT和PCD一起工作,提供了更灵活的缓存控制机制,可以根据不同类型的内存访问需求进行优化。
总体而言,PWT、PCD和PAT时现代处理器用来优化内存访问和提高整体系统性能的关键机制。它们使得操作系统能够根据具体的应用场景和需求调整内存缓存的行为
2-9-9-12分页结构
29912分页
29912分页
为什么物理页设计的时候是4K对齐,而不是8K?
主要基于以下几个考虑因素:
1.内存利用率与碎片管理:较小的页大小可以更有效地管理内存,减少内存浪费。当程序需要的内存量小于页大小时,较小的页能够减少内存的浪费。例如,如果一个程序只需要小量内存,使用4K页比8K页浪费更少的内存
2.虚拟内存系统的灵活性:4K的页大小提供了更高的灵活性,允许操作系统更精细地控制内存分配和访问。这对于现代操作系统中的虚拟内存管理非常重要,因为它们需要在物理内存和硬盘之间有效地映射和管理内存
3.硬件和标准的适应性:4K页大小是许多硬件和操作系统标准的共识。在指定这些标准时,会考虑到广泛的兼容性和最优的性能。4K页大小在这些方面提供了良好的平衡
4.缓存和存取效率:较小的页大小可以更有效地利用缓存,因为小页更有可能被完全用于缓存,而不是部分用于缓存而浪费缓存空间。这对于提高存储系统的整体效率非常重要
5.历史和兼容性因素:4K页大小的选择也受到历史因素的影响。随着计算机科学的发展,许多标准和时间已经围绕着4K页大小简历。改变这一标准可能会引发广泛的兼容问题。
综上所述,4K页大小在内存利用率、系统灵活性、硬件和标准的适应性、缓存效率以及历史和兼容性方面提供了一个良好的平衡点。当然,这并不意味着8K或其他大小的页不能工作,只是在现代计算环境中,4K页大小被认为是一种较为合理的折中方案
主要基于以下几个考虑因素:
1.内存利用率与碎片管理:较小的页大小可以更有效地管理内存,减少内存浪费。当程序需要的内存量小于页大小时,较小的页能够减少内存的浪费。例如,如果一个程序只需要小量内存,使用4K页比8K页浪费更少的内存
2.虚拟内存系统的灵活性:4K的页大小提供了更高的灵活性,允许操作系统更精细地控制内存分配和访问。这对于现代操作系统中的虚拟内存管理非常重要,因为它们需要在物理内存和硬盘之间有效地映射和管理内存
3.硬件和标准的适应性:4K页大小是许多硬件和操作系统标准的共识。在指定这些标准时,会考虑到广泛的兼容性和最优的性能。4K页大小在这些方面提供了良好的平衡
4.缓存和存取效率:较小的页大小可以更有效地利用缓存,因为小页更有可能被完全用于缓存,而不是部分用于缓存而浪费缓存空间。这对于提高存储系统的整体效率非常重要
5.历史和兼容性因素:4K页大小的选择也受到历史因素的影响。随着计算机科学的发展,许多标准和时间已经围绕着4K页大小简历。改变这一标准可能会引发广泛的兼容问题。
综上所述,4K页大小在内存利用率、系统灵活性、硬件和标准的适应性、缓存效率以及历史和兼容性方面提供了一个良好的平衡点。当然,这并不意味着8K或其他大小的页不能工作,只是在现代计算环境中,4K页大小被认为是一种较为合理的折中方案
开启分页,实现虚拟内存管理
4-level paging
4级分页
PT:4级头表
PDPT:页目录指针表
PDT:页目录表
PTT:页表
4级分页
PT:4级头表
PDPT:页目录指针表
PDT:页目录表
PTT:页表
2M分页
1G物理页
4级头表项结构
PT
# P(存在位, Present):位0,指示该页表项所指向的页面是否存在于物理内存中,如果该位为0,则页面不存在,访问时会触发页面错误
# RW(读写位,Read/Write):位1,如果置位,则页面可以进行写操作;如果不置位,页面是只读的
# US(用户/超级用户位, User/Supervisor):位2.控制页面的访问权限,如果置位,表示用户模式可以访问页面;如果不置位,则只有超级用户模式(例如,内核)可以访问
# PWT(页写通位,Page-Write-Through):位3.控制是否使用写通缓存策略
# PCD(页缓存禁用位, Page Cache Disable):位4,如果置位,该页面将不会被缓存
# A(访问位, Accessed):位5.表示该页自从上次被清零以来是否被访问过
# D(脏位,Dirty):位6.仅对页表有效,执行该页字上次被清零以来是否被写入过
# XD(执行禁止位, Execute Disable):位63。如果置位,表示该页面上不允许执行代码
PT
# P(存在位, Present):位0,指示该页表项所指向的页面是否存在于物理内存中,如果该位为0,则页面不存在,访问时会触发页面错误
# RW(读写位,Read/Write):位1,如果置位,则页面可以进行写操作;如果不置位,页面是只读的
# US(用户/超级用户位, User/Supervisor):位2.控制页面的访问权限,如果置位,表示用户模式可以访问页面;如果不置位,则只有超级用户模式(例如,内核)可以访问
# PWT(页写通位,Page-Write-Through):位3.控制是否使用写通缓存策略
# PCD(页缓存禁用位, Page Cache Disable):位4,如果置位,该页面将不会被缓存
# A(访问位, Accessed):位5.表示该页自从上次被清零以来是否被访问过
# D(脏位,Dirty):位6.仅对页表有效,执行该页字上次被清零以来是否被写入过
# XD(执行禁止位, Execute Disable):位63。如果置位,表示该页面上不允许执行代码
页目录指针项结构
PDPT
PDPT
页目录表项结构
页表项
PTT
PTT
如何将内核映射到虚拟内存的高端地址?
地址解析过程
# 举例:访问0xFFFFFFFF80000000
1.PML4[256]->指向PDPT
2.PDPT[0]->PD
3.PD[0]->大页标记,物理地址0x00100000
4.虚拟地址偏移+0~ +0x200000映射到物理地址0x00100000 ~ 0x00300000
-----------------------------------------------------
# 目的是为了让内核始终运行在统一的、固定的高地址空间中,隔离用户空间,同时避免地址冲突.
# 操作系统通过构造页表,将内核在物理内存中的地址(如从0x00100000开始)映射到虚拟地址的高端区域
(如从0xC0000000或0xFFFFFFFF80000000开始),这样内核代码在虚拟地址中具有统一、隔离的视图
为什么要映射到高地址?
# 隔离用户空间:用户程序不能访问内核空间
# 简化内核地址逻辑:所有内核模块地址一致(编译时虚拟地址固定)
# 多任务共享页表:所有进程共享啮合部分页表
# 安全&内存保护:用户态无法越界访问内核
地址解析过程
# 举例:访问0xFFFFFFFF80000000
1.PML4[256]->指向PDPT
2.PDPT[0]->PD
3.PD[0]->大页标记,物理地址0x00100000
4.虚拟地址偏移+0~ +0x200000映射到物理地址0x00100000 ~ 0x00300000
-----------------------------------------------------
# 目的是为了让内核始终运行在统一的、固定的高地址空间中,隔离用户空间,同时避免地址冲突.
# 操作系统通过构造页表,将内核在物理内存中的地址(如从0x00100000开始)映射到虚拟地址的高端区域
(如从0xC0000000或0xFFFFFFFF80000000开始),这样内核代码在虚拟地址中具有统一、隔离的视图
为什么要映射到高地址?
# 隔离用户空间:用户程序不能访问内核空间
# 简化内核地址逻辑:所有内核模块地址一致(编译时虚拟地址固定)
# 多任务共享页表:所有进程共享啮合部分页表
# 安全&内存保护:用户态无法越界访问内核
内存池算法
1.空闲列表
2.指针碰撞
3.伙伴算法
1.空闲列表
2.指针碰撞
3.伙伴算法
让我们的OS接管BIOS中断
中断在操作系统中的应用。
中断(Interrupts)在Linux等操作系统中扮演者非常重要的角色,中断时计算机硬件与软件的一种通信方式,允许硬件向处理器发送信号,表示需要注意的事项。以下是在Linux中使用中断的几个主要用途:
1.硬件通信:当外部设备(如鼠标、键盘、打印机、网络适配器等)需要处理器的注意时,它们可以通过发送中断信号来通知处理器。这可能是由于它们已经完成了一项任务,或者需要处理器进行一些操作(比如,处理新的用户输入或发送数据)
2.任务切换:在多任务环境中,操作系统使用中断来切换不同的任务或进程。当一个任务的时间片已经过去或者需要立即处理一个更高优先级的任务时,操作系统会触发一个中断,然后切换到另一个任务
3.系统调用:中断还用于实现系统调用。当用户空间的应用程序需要执行某种可能影响整个系统的操作(比如,读写文件或创建新的进程)时,它们会发起一个系统调用。这实际上就是通过触发一种特殊的中断(通常称为软中断或异常),将控制权交给内核,让内核代表应用程序执行这些操作
4.异常处理:当处理器遇到某种错误或异常条件时,它会通过触发异常中断来通知操作系统。比如,当程序试图除以0或访问无效的内存地址时,处理器会触发一个异常中断
5.定时器和时钟中断:操作系统使用中断来追踪时间和实现定时器功能。这是通过时钟中断实现的,它在固定的时间间隔内反复触发。时钟中断页用于调度和任务切换。
6.功耗管理:在某些情况下,操作系统可以使用中断来管理系统的功耗。例如,当系统处于空闲状态时,操作系统可以将处理器置于低功耗状态。然后,当有新的任务需要处理时,处理器可以通过中断来唤醒
总的来说,中断是操作系统实现并发处理、硬件通信和异常处理等核心功能的重要工具。它们提供了一种高效的方式,让处理器可以在处理其他任务的同时,快速响应外部设备和系统事件的需要
中断(Interrupts)在Linux等操作系统中扮演者非常重要的角色,中断时计算机硬件与软件的一种通信方式,允许硬件向处理器发送信号,表示需要注意的事项。以下是在Linux中使用中断的几个主要用途:
1.硬件通信:当外部设备(如鼠标、键盘、打印机、网络适配器等)需要处理器的注意时,它们可以通过发送中断信号来通知处理器。这可能是由于它们已经完成了一项任务,或者需要处理器进行一些操作(比如,处理新的用户输入或发送数据)
2.任务切换:在多任务环境中,操作系统使用中断来切换不同的任务或进程。当一个任务的时间片已经过去或者需要立即处理一个更高优先级的任务时,操作系统会触发一个中断,然后切换到另一个任务
3.系统调用:中断还用于实现系统调用。当用户空间的应用程序需要执行某种可能影响整个系统的操作(比如,读写文件或创建新的进程)时,它们会发起一个系统调用。这实际上就是通过触发一种特殊的中断(通常称为软中断或异常),将控制权交给内核,让内核代表应用程序执行这些操作
4.异常处理:当处理器遇到某种错误或异常条件时,它会通过触发异常中断来通知操作系统。比如,当程序试图除以0或访问无效的内存地址时,处理器会触发一个异常中断
5.定时器和时钟中断:操作系统使用中断来追踪时间和实现定时器功能。这是通过时钟中断实现的,它在固定的时间间隔内反复触发。时钟中断页用于调度和任务切换。
6.功耗管理:在某些情况下,操作系统可以使用中断来管理系统的功耗。例如,当系统处于空闲状态时,操作系统可以将处理器置于低功耗状态。然后,当有新的任务需要处理时,处理器可以通过中断来唤醒
总的来说,中断是操作系统实现并发处理、硬件通信和异常处理等核心功能的重要工具。它们提供了一种高效的方式,让处理器可以在处理其他任务的同时,快速响应外部设备和系统事件的需要
中断控制芯片有哪些?
中断控制器是负责管理核处理来自系统中各种设备的中断请求的硬件设备。在早期的计算机系统中,处理器只能处理一个固定数量的中断源。但是随着硬件设备的增加,中断控制器的需求变得更为迫切。以下是一些常见的中断控制器
1.【x86单核】可编程中断控制器(Programmable Interrupt Controller, PIC):PIC是早期PC中使用的中断控制器,如Intel 8259A,它可以来处理8个中断源。对于需要更多中断的系统,可以将多个8259A级联在一起
2.【x64多核实现的】高级可编程中断控制器(Advanced Programmable Interrupt Controller, APIC):随着多核处理器的出现,单个PIC无法满足需求,于是出现了APIC,APIC在每个处理器核心中都有一个局部APIC,用于处理来自核心的中断。此外,还有一个IO APIC,用于处理来自IO设备的中断
3.中断控制优先级器(Priority Interrupt Controller, PIC):这是一种可以根据优先级处理中断的控制器,常见于嵌入式系统中
4.可配置中断控制器(Configurable Interrupt Controller, CIC): CIC可以根据系统的需求核硬件的配置进行动态配置
5.分布式动态可共享中断控制器(Distributed Dynamic Shared Interrupt Controller, DDSI):DDSI是一种可以在多个处理器之间动态共享中断负载的控制器
6.中断线路控制器(Interrupt Line Controller, ILC):ILC可以直接管理硬件设备的中断线路,而无需通过软件
中断控制器是负责管理核处理来自系统中各种设备的中断请求的硬件设备。在早期的计算机系统中,处理器只能处理一个固定数量的中断源。但是随着硬件设备的增加,中断控制器的需求变得更为迫切。以下是一些常见的中断控制器
1.【x86单核】可编程中断控制器(Programmable Interrupt Controller, PIC):PIC是早期PC中使用的中断控制器,如Intel 8259A,它可以来处理8个中断源。对于需要更多中断的系统,可以将多个8259A级联在一起
2.【x64多核实现的】高级可编程中断控制器(Advanced Programmable Interrupt Controller, APIC):随着多核处理器的出现,单个PIC无法满足需求,于是出现了APIC,APIC在每个处理器核心中都有一个局部APIC,用于处理来自核心的中断。此外,还有一个IO APIC,用于处理来自IO设备的中断
3.中断控制优先级器(Priority Interrupt Controller, PIC):这是一种可以根据优先级处理中断的控制器,常见于嵌入式系统中
4.可配置中断控制器(Configurable Interrupt Controller, CIC): CIC可以根据系统的需求核硬件的配置进行动态配置
5.分布式动态可共享中断控制器(Distributed Dynamic Shared Interrupt Controller, DDSI):DDSI是一种可以在多个处理器之间动态共享中断负载的控制器
6.中断线路控制器(Interrupt Line Controller, ILC):ILC可以直接管理硬件设备的中断线路,而无需通过软件
CPU响应中断的流程
CPU响应中断的流程是操作系统的基本工作机制之一。当CPU接收到中断信号后,会采取一系列步骤来处理这个中断。以下是一个简化的描述,描绘了典型的中断处理过程:
1.中断发生:中断可以由外部硬件设备、定时器或者软件触发,这会给CPU发送一个信号,表明有某种需要处理的事件
2.中断响应:当CPU接收到中断信号后,会在当前指令执行完毕后立即停止正在进行的任务
3.保存状态:为了能在中断处理完毕后恢复正常的执行流程,CPU会保存当前正在执行的任务的状态,通常,这包括了寄存器的值,程序计数器(PC),以及其他相关的状态信息
4.设置中断向量:中断向量是一个指向中断处理程序的指针,它的位置在中断向量表中,CPU会根据触发的中断类型找到相应的中断向量
5.执行中断服务例程:中断服务例程(ISR)是用来处理特定中断的一段代码,CPU会跳转倒该例程的地址,并开始执行
6.恢复状态:一旦中断服务例程完成,CPU需要恢复倒被中断的任务,它会载入在步骤3保存的状态信息
7.返回到被中断的程序:最后,CPU将返回并继续执行被中断的程序,就好像没有发生中断一样
CPU响应中断的流程是操作系统的基本工作机制之一。当CPU接收到中断信号后,会采取一系列步骤来处理这个中断。以下是一个简化的描述,描绘了典型的中断处理过程:
1.中断发生:中断可以由外部硬件设备、定时器或者软件触发,这会给CPU发送一个信号,表明有某种需要处理的事件
2.中断响应:当CPU接收到中断信号后,会在当前指令执行完毕后立即停止正在进行的任务
3.保存状态:为了能在中断处理完毕后恢复正常的执行流程,CPU会保存当前正在执行的任务的状态,通常,这包括了寄存器的值,程序计数器(PC),以及其他相关的状态信息
4.设置中断向量:中断向量是一个指向中断处理程序的指针,它的位置在中断向量表中,CPU会根据触发的中断类型找到相应的中断向量
5.执行中断服务例程:中断服务例程(ISR)是用来处理特定中断的一段代码,CPU会跳转倒该例程的地址,并开始执行
6.恢复状态:一旦中断服务例程完成,CPU需要恢复倒被中断的任务,它会载入在步骤3保存的状态信息
7.返回到被中断的程序:最后,CPU将返回并继续执行被中断的程序,就好像没有发生中断一样
CPU响应中断的流程(单核)
CPU响应中断的流程(多核)
LINT0(Local Interrupt)是指高级可编程中断控制器(APIC)系统中的一个局部中断信号。在多处理器系统中,每个处理器都有自己的局部APIC,它负责处理针对该处理器的中断。LINT0和LINT1是两个特殊的中断输入线,它们可以被配置为接收不同类型的中断信号。在许多系统中,LINT0通常被配置为接收非屏蔽中断(NMI),而LINT1被配置为接收其他类型的中断。
非屏蔽中断是一种特殊的中断信号,它不能被常规的中断屏蔽操作阻止。这种中断通常用于处理一些严重的硬件错误,比如内存校验错误,需要操作系统立即处理。
在某些系统中,LINT0和LINT1还可以被配置为接收外部中断,或者作为内部中断信号使用,以便在多处理器系统中同步不同的处理器。要注意的是,具体的配置可能会根据系统的需求和设计有所不同
非屏蔽中断是一种特殊的中断信号,它不能被常规的中断屏蔽操作阻止。这种中断通常用于处理一些严重的硬件错误,比如内存校验错误,需要操作系统立即处理。
在某些系统中,LINT0和LINT1还可以被配置为接收外部中断,或者作为内部中断信号使用,以便在多处理器系统中同步不同的处理器。要注意的是,具体的配置可能会根据系统的需求和设计有所不同
异常与中断
中断门描述符
CMOS RAM
CMOS RAM(互补金属氧化物半导体随机存取存储器)是一种小容量的存储器,用于在个人计算机中存储基本的系统设置和时间信息。这种存储器的特点是即使在电源关闭时也能通过电池保持数据,从而保存重要的系统配置和实时时钟(RTC)信息
CMOS RAM(互补金属氧化物半导体随机存取存储器)是一种小容量的存储器,用于在个人计算机中存储基本的系统设置和时间信息。这种存储器的特点是即使在电源关闭时也能通过电池保持数据,从而保存重要的系统配置和实时时钟(RTC)信息
实现任务切换
实现一套完整任务机制的完美节奏
1.想好你想实现怎样的协程机制(非抢占式还是抢占式)
2.创建一个任务,每次从头执行
3.接入时钟中断实现协程调度
4.让任务接着执行
5.引入优先级、时间片
6.实现协程的接着执行(保存、恢复上下文)
7.实现协程的阻塞、唤醒、sleep
8.引入多核调度
1.想好你想实现怎样的协程机制(非抢占式还是抢占式)
2.创建一个任务,每次从头执行
3.接入时钟中断实现协程调度
4.让任务接着执行
5.引入优先级、时间片
6.实现协程的接着执行(保存、恢复上下文)
7.实现协程的阻塞、唤醒、sleep
8.引入多核调度
任务切换堆栈图
带你玩转多核控制器APIC
CPU响应中断的流程(多核)
Local APIC的基地址可以从多个来源获取,其中ACPI是一个常见的来源,但它不是唯一的方式,以下时关于Local APIC地址的一些要点:
1.默认物理地址:在x86架构上,Local APIC的默认物理基地址通常是0xFEE00000.然而,不推荐硬编码这个地址,因为它是可以被重新配置的
2.从MSR中获取:在x86架构上,你可以从模型特定寄存器(MSR)获取Local APIC的基地址。特定的MSR是IA32_APIC_BASE.其MSR编号为0x1B.这个MSR的高端位包含Local APIC的基地址
3.从ACPI中获取:Local APIC地址也可以从ACPI的MADT(Multiple APIC Description Table)中获取。MADT包含了关于APIC的多种信息,包括Local APIC的地址。如果你已经设置了ACPI并解析了它的表格,这是一个非常可靠的方法来获取Local APIC地址
4.从BIOS配置空间获取:某些BIOS/UEFI固件允许程序查询或设置Local APIC的地址。这通常涉及到使用特定的BIOS调用或访问UEFI配置空间
考虑到上述个点,虽然Local APIC有一个默认地址,但最好的做法是从系统配置(例如ACPI或MSR)中动态地获取它,以确保最大的兼容性和正确性。在设计自己的操作系统或低级硬件抽象时,考虑多种方法来获取此信息通常是一个好注意
1.默认物理地址:在x86架构上,Local APIC的默认物理基地址通常是0xFEE00000.然而,不推荐硬编码这个地址,因为它是可以被重新配置的
2.从MSR中获取:在x86架构上,你可以从模型特定寄存器(MSR)获取Local APIC的基地址。特定的MSR是IA32_APIC_BASE.其MSR编号为0x1B.这个MSR的高端位包含Local APIC的基地址
3.从ACPI中获取:Local APIC地址也可以从ACPI的MADT(Multiple APIC Description Table)中获取。MADT包含了关于APIC的多种信息,包括Local APIC的地址。如果你已经设置了ACPI并解析了它的表格,这是一个非常可靠的方法来获取Local APIC地址
4.从BIOS配置空间获取:某些BIOS/UEFI固件允许程序查询或设置Local APIC的地址。这通常涉及到使用特定的BIOS调用或访问UEFI配置空间
考虑到上述个点,虽然Local APIC有一个默认地址,但最好的做法是从系统配置(例如ACPI或MSR)中动态地获取它,以确保最大的兼容性和正确性。在设计自己的操作系统或低级硬件抽象时,考虑多种方法来获取此信息通常是一个好注意
在自己实现的操作系统中,获取I/O APIC(输入/输出高级可编程中断控制器)的信息通常涉及以下几种方法:
1.通过ACPI表:
# 解析ACPI表是最常用且可靠的方法。特别是,MADT(Multiple APIC Description Table)提供了关于系统中所有APIC,包括IO APIC的信息
# MADT中会列出每个IO APIC的ID、地址和全局系统中断基数,这些信息对于操作系统管理中断至关重要
2.使用MP配置表(仅限于旧系统)
# 在ACPI之前,多核处理器(MP)规范定义了如何在系统中识别和配置多处理器一个键,包括IO APIC
# MP配置表可以在系统基础内存中的特定地址或者BIOS中找到,其中包含IO APIC的信息
3.硬件默认地址
# 某些系统的IO APIC可能有一个硬件默认地址,通常是0xFEC00000,但是,硬件地址可能会变化,因此最好是通过ACPI或MP表来动态获取
4.操作系统提供的接口
# 类似于获取本地APIC的信息,某些操作系统可能提供了内核API或服务来检索IO APIC信息
5.阅读硬件文档和手册
# 对于特定的硬件平台,参考技术文档或硬件手册通常会提供最准确的信息
建议使用ACPI表来获取I/O APIC信息,因为它提供了最为标准和兼容的方式来进行硬件抽象和配置。在你的操作系统中,你需要实现ACPI表的解析功能,以便在系统启动时手机所有必要的硬件信息
1.通过ACPI表:
# 解析ACPI表是最常用且可靠的方法。特别是,MADT(Multiple APIC Description Table)提供了关于系统中所有APIC,包括IO APIC的信息
# MADT中会列出每个IO APIC的ID、地址和全局系统中断基数,这些信息对于操作系统管理中断至关重要
2.使用MP配置表(仅限于旧系统)
# 在ACPI之前,多核处理器(MP)规范定义了如何在系统中识别和配置多处理器一个键,包括IO APIC
# MP配置表可以在系统基础内存中的特定地址或者BIOS中找到,其中包含IO APIC的信息
3.硬件默认地址
# 某些系统的IO APIC可能有一个硬件默认地址,通常是0xFEC00000,但是,硬件地址可能会变化,因此最好是通过ACPI或MP表来动态获取
4.操作系统提供的接口
# 类似于获取本地APIC的信息,某些操作系统可能提供了内核API或服务来检索IO APIC信息
5.阅读硬件文档和手册
# 对于特定的硬件平台,参考技术文档或硬件手册通常会提供最准确的信息
建议使用ACPI表来获取I/O APIC信息,因为它提供了最为标准和兼容的方式来进行硬件抽象和配置。在你的操作系统中,你需要实现ACPI表的解析功能,以便在系统启动时手机所有必要的硬件信息
Local APIC中哪些偏移比较常用?
本地APIC(Advanced Programmable Interrupt Controller)是现代多核处理器系统中用于管理中断的关键部件。它提供了一系列的寄存器,通过内存映射的方式可以被操作系统访问。以下是一些在本地APIC中常用的偏移及其用途的详细介绍:
1.Local APIC ID Register(APIC ID 寄存器)
# 偏移: 0x020
# 用途: 存储本地APIC的唯一标识符。在多核系统中,每个核心的APIC ID是不同的,用于区分各个核心
2.Local APIC Version Register(APIC 版本寄存器)
# 偏移: 0x030
# 用途: 提供有关本地APIC版本的信息,有助于确定APIC的功能和兼容性
3.Task Priority Register(任务优先级寄存器)
# 偏移: 0x080
# 用途: 控制中断的优先级。操作系统可以通过修改这个寄存器来屏蔽或允许不同优先级的中断
4.EOI Register(结束中断寄存器)
# 偏移: 0x0B0
# 用途: 向APIC发送一个结束中断EOI信号,表明当前处理的中断已经完成处理
5.Spurious Interrupt Vector Regsiter(虚假中断向量寄存器)
# 偏移: 0x0F0
# 用途: 用于配置虚假中断向量和控制APIC的软件使能/禁用
本地APIC(Advanced Programmable Interrupt Controller)是现代多核处理器系统中用于管理中断的关键部件。它提供了一系列的寄存器,通过内存映射的方式可以被操作系统访问。以下是一些在本地APIC中常用的偏移及其用途的详细介绍:
1.Local APIC ID Register(APIC ID 寄存器)
# 偏移: 0x020
# 用途: 存储本地APIC的唯一标识符。在多核系统中,每个核心的APIC ID是不同的,用于区分各个核心
2.Local APIC Version Register(APIC 版本寄存器)
# 偏移: 0x030
# 用途: 提供有关本地APIC版本的信息,有助于确定APIC的功能和兼容性
3.Task Priority Register(任务优先级寄存器)
# 偏移: 0x080
# 用途: 控制中断的优先级。操作系统可以通过修改这个寄存器来屏蔽或允许不同优先级的中断
4.EOI Register(结束中断寄存器)
# 偏移: 0x0B0
# 用途: 向APIC发送一个结束中断EOI信号,表明当前处理的中断已经完成处理
5.Spurious Interrupt Vector Regsiter(虚假中断向量寄存器)
# 偏移: 0x0F0
# 用途: 用于配置虚假中断向量和控制APIC的软件使能/禁用
6.Interrupt Command Register(ICR)(中断命令寄存器)
# 偏移: 0x300(低32位)和0x310(高32位)
# 用途: 用于发送IPI(Inter-Processor Interrupts)给其他处理器,这是实现处理器间通信的关键机制
7.LVT Timer Register(本地向量表定时器寄存器)
# 偏移: 0x320
# 用途: 配置本地APIC定时器的行为,如定时器和定时器中断向量
8.LVT Thermal Sensor Register(热传感寄存器)
# 偏移: 0x330
# 用途: 配置于处理器温度相关的中断
9.LVT Performance Monitoring Counters Register(性能监控计数器寄存器)
# 偏移: 0x340
# 用途: 用于配置性能监控相关的中断
10.LVT LINT0 and LINT1 Register(本地中断线寄存器)
# 偏移: 0x350(LINT0)和0x360(LINT1)
# 用途: 配置本地中断线,这些线通常用于将传统的外部中断(如键盘和鼠标中断)映射到本地APIC
11.LVT Error Register(错误寄存器)
# 偏移: 0x370
# 用途: 配置与APIC错误相关的中断
12. Timer Divide Configuration Register(定时器分频配置寄存器)
# 偏移: 0x3E0
# 用途: 设置本地APIC定时器的分频比率,影响定时器的计数速率
# 偏移: 0x300(低32位)和0x310(高32位)
# 用途: 用于发送IPI(Inter-Processor Interrupts)给其他处理器,这是实现处理器间通信的关键机制
7.LVT Timer Register(本地向量表定时器寄存器)
# 偏移: 0x320
# 用途: 配置本地APIC定时器的行为,如定时器和定时器中断向量
8.LVT Thermal Sensor Register(热传感寄存器)
# 偏移: 0x330
# 用途: 配置于处理器温度相关的中断
9.LVT Performance Monitoring Counters Register(性能监控计数器寄存器)
# 偏移: 0x340
# 用途: 用于配置性能监控相关的中断
10.LVT LINT0 and LINT1 Register(本地中断线寄存器)
# 偏移: 0x350(LINT0)和0x360(LINT1)
# 用途: 配置本地中断线,这些线通常用于将传统的外部中断(如键盘和鼠标中断)映射到本地APIC
11.LVT Error Register(错误寄存器)
# 偏移: 0x370
# 用途: 配置与APIC错误相关的中断
12. Timer Divide Configuration Register(定时器分频配置寄存器)
# 偏移: 0x3E0
# 用途: 设置本地APIC定时器的分频比率,影响定时器的计数速率
注意:
# 这些寄存器是通过内存映射IO(MMIO)访问的,需要操作系统在初始化时设置正确的映射
# 对本地APIC的操作通常涉及底层系统编程和对中断处理的深入理解
# 这些寄存器是通过内存映射IO(MMIO)访问的,需要操作系统在初始化时设置正确的映射
# 对本地APIC的操作通常涉及底层系统编程和对中断处理的深入理解
什么是ACPI?
ACPI(高级配置和电源接口)是一个开放标准,用于操作系统与硬件之间的电源管理和配置通信。它是由英特尔、微软和东芝等公司于1996年共同开发的,现在是个人电脑、服务器以及其他硬件设备广泛使用的标准。
ACPI的主要功能包括:
1.电源管理: ACPI允许操作系统控制电源分配给计算机硬件的方式。这包括休眠模式、待机模式、以及完全关闭电源等状态
2.设备枚举: 在启动时,ACPI帮助操作系统识别和配置硬件设备,如CPU、内存、磁盘驱动器和外设
3.热管理: ACPI可以监控系统温度,并在需要时调整风扇速度或采取其他措施来冷却硬件
4.即插即用(PnP):ACPI支持即插即用功能,允许操作系统自动检测和配置新连接的设备
5.处理器性能状态: ACPI可以调整处理器的性能状态(如频率和电压),以优化性能和能耗
6.电池状态监控: 在便携式设备上,ACPI可以监控电池电量和健康状态,向用户提供准确的电量信息
通过这些功能,ACPI在现代计算机中扮演者关键角色,特别是在提高能源效率和动态硬件配置方面,几乎所有现代操作系统,如Windows、Linux和macOS,都支持ACPI
ACPI(高级配置和电源接口)是一个开放标准,用于操作系统与硬件之间的电源管理和配置通信。它是由英特尔、微软和东芝等公司于1996年共同开发的,现在是个人电脑、服务器以及其他硬件设备广泛使用的标准。
ACPI的主要功能包括:
1.电源管理: ACPI允许操作系统控制电源分配给计算机硬件的方式。这包括休眠模式、待机模式、以及完全关闭电源等状态
2.设备枚举: 在启动时,ACPI帮助操作系统识别和配置硬件设备,如CPU、内存、磁盘驱动器和外设
3.热管理: ACPI可以监控系统温度,并在需要时调整风扇速度或采取其他措施来冷却硬件
4.即插即用(PnP):ACPI支持即插即用功能,允许操作系统自动检测和配置新连接的设备
5.处理器性能状态: ACPI可以调整处理器的性能状态(如频率和电压),以优化性能和能耗
6.电池状态监控: 在便携式设备上,ACPI可以监控电池电量和健康状态,向用户提供准确的电量信息
通过这些功能,ACPI在现代计算机中扮演者关键角色,特别是在提高能源效率和动态硬件配置方面,几乎所有现代操作系统,如Windows、Linux和macOS,都支持ACPI
如何通过ACPI获取apic地址?
通过ACPI(高级配置和电源接口)获取APIC(高级可编程中断控制器)地址的过程涉及解析ACPI表,特别是解析名为"MADT"
(Multiple APIC Description Table)的表。MADT表包含有关系统中所有APIC的信息,包括它们的物理地址,以下是获取APIC地址的一般步骤:
1.定位RSDP(Root System Description Pointer):RSDP是一个小的数据结构,作为ACPI表入口点。在早期的BIOS系统中,RSDP通常在系统基本输入输出系统(BIOS)的内存区域中找到。在UEFI系统中,RSDP的位置由UEFI固件提供。
2.读取RSDT或XSDT(Root System Descirption Table/Extended System Description Table):RSDP指向RSDT或XSDT,这些表包含了指向其他ACPI表的指针
3.查找MADT: 在RSDT或XSDT中搜索MADT的入口。MADT表的头部包含了有关APIC的信息
4.解析MADT: MADT包含了不同类型的条目,包括本地APIC地址、I/O APIC地址以及可能的中断源重映射信息。通过解析这些条目,可以找到APIC的物理地址
5.获取APIC地址: 从MADT条目中读取APIC的物理地址
这个过程通常由操作系统在启动时自动完成,以便正确配置和管理硬件中断。如果你需要手动访问这些信息,你可能需要使用专门的软件工具或编写代码来解析ACPI表。
通过ACPI(高级配置和电源接口)获取APIC(高级可编程中断控制器)地址的过程涉及解析ACPI表,特别是解析名为"MADT"
(Multiple APIC Description Table)的表。MADT表包含有关系统中所有APIC的信息,包括它们的物理地址,以下是获取APIC地址的一般步骤:
1.定位RSDP(Root System Description Pointer):RSDP是一个小的数据结构,作为ACPI表入口点。在早期的BIOS系统中,RSDP通常在系统基本输入输出系统(BIOS)的内存区域中找到。在UEFI系统中,RSDP的位置由UEFI固件提供。
2.读取RSDT或XSDT(Root System Descirption Table/Extended System Description Table):RSDP指向RSDT或XSDT,这些表包含了指向其他ACPI表的指针
3.查找MADT: 在RSDT或XSDT中搜索MADT的入口。MADT表的头部包含了有关APIC的信息
4.解析MADT: MADT包含了不同类型的条目,包括本地APIC地址、I/O APIC地址以及可能的中断源重映射信息。通过解析这些条目,可以找到APIC的物理地址
5.获取APIC地址: 从MADT条目中读取APIC的物理地址
这个过程通常由操作系统在启动时自动完成,以便正确配置和管理硬件中断。如果你需要手动访问这些信息,你可能需要使用专门的软件工具或编写代码来解析ACPI表。
如何定位到RSDP?
定位到ACPI的RSDP(Root System Description Pointer)通常涉及在特定的内存区域内搜索特定的签名。RSDP是用于发现ACPI表的起点,它包含了指向RSDT(Root System Description Table)或XSDT(Extended System Description Table)的指针。以下是在不同类型的系统上定位RSDP的方法:
传统BIOS系统
1.BIOS提供的内存区域:在传统的BIOS系统中,RSDP通常位于主内存的0xE0000到0xFFFFF范围内,这个区域包含了系统的BIOS ROM
2.搜索特定签名:RSDP有一个特定的签名,即"RSD PTR"。你可以在上述内存范围内搜索这个签名来定位RSDP
3.校验和验证: 一旦找到看起来像RSDP的结构,还需要验证其校验和以确保数据的有效性
定位到ACPI的RSDP(Root System Description Pointer)通常涉及在特定的内存区域内搜索特定的签名。RSDP是用于发现ACPI表的起点,它包含了指向RSDT(Root System Description Table)或XSDT(Extended System Description Table)的指针。以下是在不同类型的系统上定位RSDP的方法:
传统BIOS系统
1.BIOS提供的内存区域:在传统的BIOS系统中,RSDP通常位于主内存的0xE0000到0xFFFFF范围内,这个区域包含了系统的BIOS ROM
2.搜索特定签名:RSDP有一个特定的签名,即"RSD PTR"。你可以在上述内存范围内搜索这个签名来定位RSDP
3.校验和验证: 一旦找到看起来像RSDP的结构,还需要验证其校验和以确保数据的有效性
RSDP的结构。
RSDP有两个版本,ACPI1.0版本和ACPI2.0及以后的版本
ACPI1.0版本的RSPD
1.签名(Signature):8字节,固定为"RSD PTR"(不包括引号)
2.校验和(Checksum): 1字节,使得RSDP的前20个字节之和为0
3.OEM ID(OEM Identifier): 6字节,用于识别OEM
4.修订(Revision): 1字节,对于ACPI 1.0,该值为0
5.RSDT地址(RsdtAddress): 4字节,指向RSDT(Root System Description Table)的物理内存地址
ACPI2.0及以后版本的RSDP
ACPI2.0在ACPI1.0的基础上扩展了RSDP,包括了以下额外字段:
1.长度(Length): 1字节,表示整个RSDP结构的长度
2.XSDT(XsdtAddress): 8字节,指向XSDT(extended System Description Table)的64位物理内存地址
3.扩展校验和(Extended Checksum): 1字节,覆盖整个结构
4.保留(Reserved): 3字节,保留供将来使用
RSDP有两个版本,ACPI1.0版本和ACPI2.0及以后的版本
ACPI1.0版本的RSPD
1.签名(Signature):8字节,固定为"RSD PTR"(不包括引号)
2.校验和(Checksum): 1字节,使得RSDP的前20个字节之和为0
3.OEM ID(OEM Identifier): 6字节,用于识别OEM
4.修订(Revision): 1字节,对于ACPI 1.0,该值为0
5.RSDT地址(RsdtAddress): 4字节,指向RSDT(Root System Description Table)的物理内存地址
ACPI2.0及以后版本的RSDP
ACPI2.0在ACPI1.0的基础上扩展了RSDP,包括了以下额外字段:
1.长度(Length): 1字节,表示整个RSDP结构的长度
2.XSDT(XsdtAddress): 8字节,指向XSDT(extended System Description Table)的64位物理内存地址
3.扩展校验和(Extended Checksum): 1字节,覆盖整个结构
4.保留(Reserved): 3字节,保留供将来使用
RSDT结构
在ACPI(高级配置和电源接口)规范中,RSDT(根系统描述表)是一个关键的数据结构,用于定位系统中所有其他的ACPI表,RSDT本身是由ACPI的根系统描述指针(RSDP)指向的。RSDT结构主要包含以下部分:
1.表头(Header):
这是一个标准的ACPI描述表头,包括了诸如签名(总是为"RSDT")、长度、修订版本号、校验和、OEM信息等字段
2.b表项(Entry)
# RSDT的主体部分包含了一个或多个32位的物理地址指针,每个指针都指向系统中的其他ACPI表(如FADT、MADT等)
# 这些表包含了有关硬件配置和电源管理功能的详细信息
RSDT与XSDT(扩展系统描述表)的主要区别在于指针的大小。在RSDT中,每个表项是32位,这意味着它只能指向4GB地址物理空间内的表。而在XSDT中,表项是64位的,允许访问更大的物理地址空间。ACPI2.0及以后的版本通常使用XSDT来支持64位系统。
在实现自己的操作系统时,正确解析RSDT是确保ACPI功能正常工作的关键。通过RSDT,你可以找到系统中所有其他重要的ACPI表,并据此来实现电源管理、硬件配置等功能
在ACPI(高级配置和电源接口)规范中,RSDT(根系统描述表)是一个关键的数据结构,用于定位系统中所有其他的ACPI表,RSDT本身是由ACPI的根系统描述指针(RSDP)指向的。RSDT结构主要包含以下部分:
1.表头(Header):
这是一个标准的ACPI描述表头,包括了诸如签名(总是为"RSDT")、长度、修订版本号、校验和、OEM信息等字段
2.b表项(Entry)
# RSDT的主体部分包含了一个或多个32位的物理地址指针,每个指针都指向系统中的其他ACPI表(如FADT、MADT等)
# 这些表包含了有关硬件配置和电源管理功能的详细信息
RSDT与XSDT(扩展系统描述表)的主要区别在于指针的大小。在RSDT中,每个表项是32位,这意味着它只能指向4GB地址物理空间内的表。而在XSDT中,表项是64位的,允许访问更大的物理地址空间。ACPI2.0及以后的版本通常使用XSDT来支持64位系统。
在实现自己的操作系统时,正确解析RSDT是确保ACPI功能正常工作的关键。通过RSDT,你可以找到系统中所有其他重要的ACPI表,并据此来实现电源管理、硬件配置等功能
XSDT结构
MADT结构。
MADT表的结构大致如下:
1.表头
类似于其他ACPI表,MADT以一个标准的ACPI描述表开始,其中包含了签名(‘APIC’),长度,修订版本号,校验和,OEM ID等信息
2.本地APIC地址
表头之后是一个32位的物理地址,指向本地APIC的内存映射开始地址,这通常是0xfee00000
3.标志
一个32位字段,指出系统是否使用了双重8259 PIC模式
4.APIC结构条目:
# 在这个地址和标志字段之后,表的其余部分由一个或多个变量长度的结构组成,这些结构描述了系统中的各种APIC信息
# 每个结构条目的开始是一个类型字节,指明了条目的种类,如本地APIC、IO APIC、中断源覆盖等
# 紧随类型字节的是一个长度字节,指明了整个结构的长度
这些条目的类型包括
# 类型0: 本地APIC。包含了APIC ID和对应的处理器ID
# 类型1: I/O APIC。包含I/O APIC ID, I/O APIC的地址以及全局系统中断基
# 类型2: 中断源覆盖。描述了某个特定IRQ信号如何映射到全局系统中断上
# 类型3: NMI源。指定了哪个输入信号被配置为非屏蔽中断
# 类型4: 本地APIC NMI.描述了针对特定处理器的NMI配置
# 类型5: 本地APIC地址覆盖。提供了本地APIC的替代物理地址
MADT表的结构大致如下:
1.表头
类似于其他ACPI表,MADT以一个标准的ACPI描述表开始,其中包含了签名(‘APIC’),长度,修订版本号,校验和,OEM ID等信息
2.本地APIC地址
表头之后是一个32位的物理地址,指向本地APIC的内存映射开始地址,这通常是0xfee00000
3.标志
一个32位字段,指出系统是否使用了双重8259 PIC模式
4.APIC结构条目:
# 在这个地址和标志字段之后,表的其余部分由一个或多个变量长度的结构组成,这些结构描述了系统中的各种APIC信息
# 每个结构条目的开始是一个类型字节,指明了条目的种类,如本地APIC、IO APIC、中断源覆盖等
# 紧随类型字节的是一个长度字节,指明了整个结构的长度
这些条目的类型包括
# 类型0: 本地APIC。包含了APIC ID和对应的处理器ID
# 类型1: I/O APIC。包含I/O APIC ID, I/O APIC的地址以及全局系统中断基
# 类型2: 中断源覆盖。描述了某个特定IRQ信号如何映射到全局系统中断上
# 类型3: NMI源。指定了哪个输入信号被配置为非屏蔽中断
# 类型4: 本地APIC NMI.描述了针对特定处理器的NMI配置
# 类型5: 本地APIC地址覆盖。提供了本地APIC的替代物理地址
Local APIC结构
I/O APIC结构
多处理器系统的初始化流程:
1.基本输入输出系统(BIOS)启动
系统加电后,BIOS是第一个运行的软件。它检查硬件的基本完整性,并初始化硬件设备,如内存、处理器、磁盘、显示设备等
2.处理器唤醒
在多处理器系统中,通常有一个主处理器(被称为引导处理器,BSP)负责初始化系统。BSP首先启动,并运行BIOS和其他启动代码。其他处理器(称为应用处理器,APs)在这个阶段处于休眠状态
3.内存检测和初始化
BSP检测和初始化系统内存,包括RAM
4.硬件和外围设备初始化
包括诸如网络接口、存储控制器、USB接口等设备的初始化
5.操作系统加载
BIOS通过从硬盘或其他存储介质加载操作系统的引导加载程序来启动操作系统
6.操作系统接管硬件初始化
一旦操作系统开始加载,它将接管硬件的进一步初始化。它加载所需的设备驱动程序,配置硬件资源等
7.多处理器同步和管理
操作系统启动后,它将唤醒其他休眠的处理器,并在它们之间分配任务和管理资源。这通常涉及启动应用处理器,然后将它们集成到操作系统的调度和管理中
8.系统服务和应用程序启动
随着系统进入正常操作模式,操作系统启动各种系统服务和应用程序
每个步骤的具体细节取决于系统的具体架构和所用的操作系统。在一些高级系统中,还可能包括额外的步骤,如固件和设备固件的更新、安全检查、虚拟化环境的初始化等
1.基本输入输出系统(BIOS)启动
系统加电后,BIOS是第一个运行的软件。它检查硬件的基本完整性,并初始化硬件设备,如内存、处理器、磁盘、显示设备等
2.处理器唤醒
在多处理器系统中,通常有一个主处理器(被称为引导处理器,BSP)负责初始化系统。BSP首先启动,并运行BIOS和其他启动代码。其他处理器(称为应用处理器,APs)在这个阶段处于休眠状态
3.内存检测和初始化
BSP检测和初始化系统内存,包括RAM
4.硬件和外围设备初始化
包括诸如网络接口、存储控制器、USB接口等设备的初始化
5.操作系统加载
BIOS通过从硬盘或其他存储介质加载操作系统的引导加载程序来启动操作系统
6.操作系统接管硬件初始化
一旦操作系统开始加载,它将接管硬件的进一步初始化。它加载所需的设备驱动程序,配置硬件资源等
7.多处理器同步和管理
操作系统启动后,它将唤醒其他休眠的处理器,并在它们之间分配任务和管理资源。这通常涉及启动应用处理器,然后将它们集成到操作系统的调度和管理中
8.系统服务和应用程序启动
随着系统进入正常操作模式,操作系统启动各种系统服务和应用程序
每个步骤的具体细节取决于系统的具体架构和所用的操作系统。在一些高级系统中,还可能包括额外的步骤,如固件和设备固件的更新、安全检查、虚拟化环境的初始化等
自实现OS,如何激活所有的ap核
1.检测并识别AP核
# 使用CPUID指令或其他机制来识别系统中的处理器数量核特性
# 解析ACPI表(特别是MADT表),以获取APIC ID和其他相关信息
2.初始化本地APIC(Local APIC)
# 对于引导处理器(BSP),在系统启动时初始化其本地APIC
# 配置Local APIC以接收和发送中断
3.发送初始化(INIT)信号给AP核
# 向每个AP核发送INTI中断(通常是通过编程本地APIC或I/O APIC来实现)
# 这个信号会让AP核进入一种等待启动(Startup)信号的状态
4.发送启动(Startup)信号
# 发送启动(Startup)信号到AP核。这通常涉及指定一个启动地址,AP核将从这个地址开始执行代码
# 可能需要发送多次Startup信号以确保AP核能够正确响应
5.提供启动代码
# 在指定的启动地址处提供一段小的启动代码。这段代码通常负责将AP核从实模式切换到保护模式,并跳转到操作系统的主代码
# 这段代码还应该设置必要的数据结构,如栈、页表等
6.同步AP核
# 在AP核开始执行操作系统代码之后,需要进行同步。这可能涉及到设置和检查某些同步变量,确保所有的核心都已准备好
7.集成AP核到操作系统中
# 一旦AP核处于可运行状态,将它们集成到操作系统的调度器中,使它们能够开始执行任务
8.错误处理核超时检测
# 在整个激活过程总,添加错误处理核超时检测机制,以处理任何可能出现的问题
1.检测并识别AP核
# 使用CPUID指令或其他机制来识别系统中的处理器数量核特性
# 解析ACPI表(特别是MADT表),以获取APIC ID和其他相关信息
2.初始化本地APIC(Local APIC)
# 对于引导处理器(BSP),在系统启动时初始化其本地APIC
# 配置Local APIC以接收和发送中断
3.发送初始化(INIT)信号给AP核
# 向每个AP核发送INTI中断(通常是通过编程本地APIC或I/O APIC来实现)
# 这个信号会让AP核进入一种等待启动(Startup)信号的状态
4.发送启动(Startup)信号
# 发送启动(Startup)信号到AP核。这通常涉及指定一个启动地址,AP核将从这个地址开始执行代码
# 可能需要发送多次Startup信号以确保AP核能够正确响应
5.提供启动代码
# 在指定的启动地址处提供一段小的启动代码。这段代码通常负责将AP核从实模式切换到保护模式,并跳转到操作系统的主代码
# 这段代码还应该设置必要的数据结构,如栈、页表等
6.同步AP核
# 在AP核开始执行操作系统代码之后,需要进行同步。这可能涉及到设置和检查某些同步变量,确保所有的核心都已准备好
7.集成AP核到操作系统中
# 一旦AP核处于可运行状态,将它们集成到操作系统的调度器中,使它们能够开始执行任务
8.错误处理核超时检测
# 在整个激活过程总,添加错误处理核超时检测机制,以处理任何可能出现的问题
自实现OS,如何给AP核发送INIT信号
在自行实现的操作系统中,给应用处理器(AP核)发送INIT信号是一个关键步骤,用于在多核处理器初始化过程中重置AP核.这通常通过编程高级可编程中断控制器(APIC)来完成。以下是发送INTI信号的基本步骤:
1.定位本地APIC(Local APIC):
# 你需要知道Local APIC的基地址。这通常可以从ACPI表(如MADT)中获得
# Local APIC基地址通常映射到某个固定的物理地址
2.确定目标AP核的APIC ID:
# 每个处理器(包括BSP和APs)都有一个唯一的APIC ID
# 这些信息可以从ACPI表或使用CPUID指令获取
3.编程Local APIC发送INIT信号
# 使用Local APIC的寄存器来发送INTI信号。这通常涉及到向Local APIC的中断命令寄存器(ICR)写入特定的值
# ICR寄存器的高32位用于指定目标AP核的APIC ID,低32位用于配置中断类型和其他属性(如中断向量、传送模式等)
4.等待信号发送完成
在发送下一个信号之前,需要检查Local APIC的状态,确保INTI信号已经成功发送
5.遵循适当的时间间隔
# 根据Intel的文档,发送INIT信号后,可能需要等待一定的时间(例如,10ms)以确保处理器有足够的时间来响应
6.错误检查和处理
在发送过程中应检查错误,并相应地处理,以确保系统的稳定和可靠
在自行实现的操作系统中,给应用处理器(AP核)发送INIT信号是一个关键步骤,用于在多核处理器初始化过程中重置AP核.这通常通过编程高级可编程中断控制器(APIC)来完成。以下是发送INTI信号的基本步骤:
1.定位本地APIC(Local APIC):
# 你需要知道Local APIC的基地址。这通常可以从ACPI表(如MADT)中获得
# Local APIC基地址通常映射到某个固定的物理地址
2.确定目标AP核的APIC ID:
# 每个处理器(包括BSP和APs)都有一个唯一的APIC ID
# 这些信息可以从ACPI表或使用CPUID指令获取
3.编程Local APIC发送INIT信号
# 使用Local APIC的寄存器来发送INTI信号。这通常涉及到向Local APIC的中断命令寄存器(ICR)写入特定的值
# ICR寄存器的高32位用于指定目标AP核的APIC ID,低32位用于配置中断类型和其他属性(如中断向量、传送模式等)
4.等待信号发送完成
在发送下一个信号之前,需要检查Local APIC的状态,确保INTI信号已经成功发送
5.遵循适当的时间间隔
# 根据Intel的文档,发送INIT信号后,可能需要等待一定的时间(例如,10ms)以确保处理器有足够的时间来响应
6.错误检查和处理
在发送过程中应检查错误,并相应地处理,以确保系统的稳定和可靠
中断命令寄存器ICR
在多处理器系统中,中断命令寄存器(ICR)是本地高级可编程中断控制器(Local APIC)的一部分,用于控制对其他处理器的中断请求。ICR通常是64位宽,分为高32位和低32位.下面是各个属性位的解析
低32位
1.中断向量(位0-7)
指定中断向量号,用于确定响应中断时要执行的中断服务例程
2.传送模式(位8-10)
指定中断传送的模式,常见的模式包括固定(Fixed)、最低优先级(Lowest Priority)、SMI(System Management Interrupt)等
3.目标处理器集(位11-13)
指定中断目标处理器的集合。可以是所有处理器(All Including Self)、所有其他处理器(All Excluding Self)或单个处理器
4.中断命令(位14-15)
指定要执行的中断命令、如INIT、启动(Startup)或普通中断
5.传送状态(位12, 16-19)
表示中断传送的状态,例如是否已发送或正在发送
6.目标模式(位18-19)
指定目标处理器的模式,可以是逻辑目标模式或物理目标模式
7.远程读(位20)
用于远程读操作,通产在普通操作中不使用
8.级别(位21)
指定中断的触发级别,可以是去触发(Deassert)或者触发(Assert)
9.触发模式(位22)
指定中断的触发模式,可以是边缘触发或者电平触发
10.保留位(位23-31)
这些保留,通常设置为0
在多处理器系统中,中断命令寄存器(ICR)是本地高级可编程中断控制器(Local APIC)的一部分,用于控制对其他处理器的中断请求。ICR通常是64位宽,分为高32位和低32位.下面是各个属性位的解析
低32位
1.中断向量(位0-7)
指定中断向量号,用于确定响应中断时要执行的中断服务例程
2.传送模式(位8-10)
指定中断传送的模式,常见的模式包括固定(Fixed)、最低优先级(Lowest Priority)、SMI(System Management Interrupt)等
3.目标处理器集(位11-13)
指定中断目标处理器的集合。可以是所有处理器(All Including Self)、所有其他处理器(All Excluding Self)或单个处理器
4.中断命令(位14-15)
指定要执行的中断命令、如INIT、启动(Startup)或普通中断
5.传送状态(位12, 16-19)
表示中断传送的状态,例如是否已发送或正在发送
6.目标模式(位18-19)
指定目标处理器的模式,可以是逻辑目标模式或物理目标模式
7.远程读(位20)
用于远程读操作,通产在普通操作中不使用
8.级别(位21)
指定中断的触发级别,可以是去触发(Deassert)或者触发(Assert)
9.触发模式(位22)
指定中断的触发模式,可以是边缘触发或者电平触发
10.保留位(位23-31)
这些保留,通常设置为0
高32位
# 目标APIC ID(位56-63)
指定接收中断的目标处理器的APIC ID.仅在物理目标模式下使用
# 保留位(位32-55)
这些位保留,通常设置为0
# 目标APIC ID(位56-63)
指定接收中断的目标处理器的APIC ID.仅在物理目标模式下使用
# 保留位(位32-55)
这些位保留,通常设置为0
给AP核发送INIT信号后,为什么需要发送两次Startup信号?
在多核处理器系统中,给应用处理器(AP核)发送两次启动(Startup)信号是根据Intel多处理器规范中的建议执行的一个过程。这样做的原因主要包括以下几点
1.确保可靠的启动
在某些硬件和固件配置下,单次发送Startup信号可能无法保证所有AP核都能够可靠地接收并响应该信号。发送两次信号可以提高启动的可靠性
2.处理不同的系统状态
AP核可能处于不同的状态,比如睡眠,等待中断等。两次Startup信号有助于确保无论AP核当前处于什么状态,它都有机会被正确唤醒并开始执行代码
3.兼容性考虑
不同的硬件和BIOS实现可能对Startup信号的处理方式有所不同,发送两次信号是一种兼容性错误,以适应不同的系统实现
4.减少启动延迟
在发送第一次Startup信号后,AP核可能需要一段时间来完成初始化。第二次确保在第一次信号后又足够的时间让AP核准备就绪,从而减少启动延迟
5.遵循规范建议
Intel的文档核多处理器规范建议发送两次Startup信号,这是基于它们对广泛硬件配置的测试和经验总结
6.应对启动信号丢失
在某些情况下,第一次发送的Startup信号可能会因为各种原因(如电气干扰)而丢失。第二次发送作为一种冗余机制,确保信号能够到达并被处理
在多核处理器系统中,给应用处理器(AP核)发送两次启动(Startup)信号是根据Intel多处理器规范中的建议执行的一个过程。这样做的原因主要包括以下几点
1.确保可靠的启动
在某些硬件和固件配置下,单次发送Startup信号可能无法保证所有AP核都能够可靠地接收并响应该信号。发送两次信号可以提高启动的可靠性
2.处理不同的系统状态
AP核可能处于不同的状态,比如睡眠,等待中断等。两次Startup信号有助于确保无论AP核当前处于什么状态,它都有机会被正确唤醒并开始执行代码
3.兼容性考虑
不同的硬件和BIOS实现可能对Startup信号的处理方式有所不同,发送两次信号是一种兼容性错误,以适应不同的系统实现
4.减少启动延迟
在发送第一次Startup信号后,AP核可能需要一段时间来完成初始化。第二次确保在第一次信号后又足够的时间让AP核准备就绪,从而减少启动延迟
5.遵循规范建议
Intel的文档核多处理器规范建议发送两次Startup信号,这是基于它们对广泛硬件配置的测试和经验总结
6.应对启动信号丢失
在某些情况下,第一次发送的Startup信号可能会因为各种原因(如电气干扰)而丢失。第二次发送作为一种冗余机制,确保信号能够到达并被处理
实现多核任务切换
IA32_KERNEL_GS_BASE的作用
在64位的Linux内核中,IA32_KERNEL_GS_BASE寄存器被用于以下目的:
1.存储内核态的基址:该寄存器通常用于存储指向当前运行的内核贤臣的特定数据结构的基址.这些数据结构可能包括任务状态段(Task State Segment, TSS)和内核栈。
2.快速切换上下文: 使用IA32_KERNEL_GS_BASE,操作系统可以快速切换到内核上下文,特别是在系统调用和中断处理时,这提高了上下文切换的效率
3.优化性能: 在多核处理器上,每个核心可能需要快速访问其自己的内核数据结构。通过将这些数据结构的基址存储在IA32_KERNEL_GS_BASE中,每个核心可以快速且直接地访问它们,从而优化性能
4.用户态与内核态之间的区分: 64位操作系统使用IA32_KERNEL_GS_BASE来帮助区分用户态和内核态。这对于保持操作系统的安全性和稳定性至关重要
技术实现:
在实际使用中,操作系统内核会在执行系统调用或处理中断时设置IA32_KERNEL_GS_BASE寄存器。它使得内核代码能够快速定位到当前进程或线程的内核级数据结构,如内核栈或其他特定于线程的数据
总之,IA32_KERNEL_GS_BASE在现代操作系统中起着重要的作用,尤其是在处理器架构和操作系统内核交互方面,它是优化64位内核性能的关键工具,使得上下文切换更加高效,同时维护了系统的安全和稳定
在64位的Linux内核中,IA32_KERNEL_GS_BASE寄存器被用于以下目的:
1.存储内核态的基址:该寄存器通常用于存储指向当前运行的内核贤臣的特定数据结构的基址.这些数据结构可能包括任务状态段(Task State Segment, TSS)和内核栈。
2.快速切换上下文: 使用IA32_KERNEL_GS_BASE,操作系统可以快速切换到内核上下文,特别是在系统调用和中断处理时,这提高了上下文切换的效率
3.优化性能: 在多核处理器上,每个核心可能需要快速访问其自己的内核数据结构。通过将这些数据结构的基址存储在IA32_KERNEL_GS_BASE中,每个核心可以快速且直接地访问它们,从而优化性能
4.用户态与内核态之间的区分: 64位操作系统使用IA32_KERNEL_GS_BASE来帮助区分用户态和内核态。这对于保持操作系统的安全性和稳定性至关重要
技术实现:
在实际使用中,操作系统内核会在执行系统调用或处理中断时设置IA32_KERNEL_GS_BASE寄存器。它使得内核代码能够快速定位到当前进程或线程的内核级数据结构,如内核栈或其他特定于线程的数据
总之,IA32_KERNEL_GS_BASE在现代操作系统中起着重要的作用,尤其是在处理器架构和操作系统内核交互方面,它是优化64位内核性能的关键工具,使得上下文切换更加高效,同时维护了系统的安全和稳定
如何发送IPI broadcast消息
1.理解IPI和APIC
# IPI(Inter-Processor Interrupt):IPI时一种在多核处理器系统中用于核心间通信的基址,它允许一个核心发送中断到另一个或多个核心
# APIC(Advanced Programmable Interrupt Controller):现代多核处理器使用APIC来处理中断,每个核心有一个本地APIC来管理它的中断。还有一个IO APIC用于处理来自外部设备的中断
2.初始化APIC
# 在操作系统启动时,需要初始化系统中的所有APIC,包括本地APIC和IO APIC
# 检测和配置APIC,包括其寄存器和可能的映射到内存的空间
3.发送IPI
# 确定目标处理器,在广播的情况下,目标时系统中的所有处理器
# 设置IPI类型,IPI可以用于多种目的,例如唤醒休眠的核心、执行特定的任务或同步操作
# 配置本地APIC发送IPI,这通常涉及到向特定的APIC寄存器写入值,以指示IPI的类型和目标
4.使用ICR(Interrupt Command Register)
# ICR是本地APIC的一部分,用于控制发送到其他处理器的中断
# 对于广播消息,你需要设置ICR以指示中断应该发送到所有其他核心
# 写入ICR时,需要指定中断类型、目标处理器(在这种情况下时所有处理器)和其他相关的控制位
5.考虑并发和同步问题
# 在多核系统中,发送IPI并响应它们需要仔细处理并发和同步问题
# 确保IPI的处理不会导致死锁或资源竞争
1.理解IPI和APIC
# IPI(Inter-Processor Interrupt):IPI时一种在多核处理器系统中用于核心间通信的基址,它允许一个核心发送中断到另一个或多个核心
# APIC(Advanced Programmable Interrupt Controller):现代多核处理器使用APIC来处理中断,每个核心有一个本地APIC来管理它的中断。还有一个IO APIC用于处理来自外部设备的中断
2.初始化APIC
# 在操作系统启动时,需要初始化系统中的所有APIC,包括本地APIC和IO APIC
# 检测和配置APIC,包括其寄存器和可能的映射到内存的空间
3.发送IPI
# 确定目标处理器,在广播的情况下,目标时系统中的所有处理器
# 设置IPI类型,IPI可以用于多种目的,例如唤醒休眠的核心、执行特定的任务或同步操作
# 配置本地APIC发送IPI,这通常涉及到向特定的APIC寄存器写入值,以指示IPI的类型和目标
4.使用ICR(Interrupt Command Register)
# ICR是本地APIC的一部分,用于控制发送到其他处理器的中断
# 对于广播消息,你需要设置ICR以指示中断应该发送到所有其他核心
# 写入ICR时,需要指定中断类型、目标处理器(在这种情况下时所有处理器)和其他相关的控制位
5.考虑并发和同步问题
# 在多核系统中,发送IPI并响应它们需要仔细处理并发和同步问题
# 确保IPI的处理不会导致死锁或资源竞争
APIC中断优先级
APIC(高级可编程中断控制器)是现代计算机系统中用于处理中断的硬件组件。它提供了比传统的PIC(可编程中断控制器)更高级的共嗯,特别是在中断优先级和处理方面。
在APIC系统中,每个中断都有一个优先级,这决定了中断处理的顺序。这些优先级通常是可配置的,允许操作系统或其他系统软件根据需要调整它们。这种灵活性允许更有效地处理多任务和并发操作,尤其是在高性能或实时系统中。
在多处理器系统中,APIC还支持中断地定向传送,这意味着可以将特定地中断定向到特定的处理器。这进一步提高了处理效率和系统的整体性能。
APIC使用了两种主要类型的中断:边沿触发和电平触发。边沿触发的中断是基于信号边沿的变化(从低到高或从高到低)来触发的,而电平触发的中断则是基于信号电平的持续状态(高或低)来触发的。
在APIC模型中,中断优先级通常是通过优先级寄存器来设置的,操作系统可以根据需要在运行时修改这些寄存器。这种灵活性允许系统更好地响应不同类型的硬件和软件需求,从而提高整体性能和响应性
APIC(高级可编程中断控制器)是现代计算机系统中用于处理中断的硬件组件。它提供了比传统的PIC(可编程中断控制器)更高级的共嗯,特别是在中断优先级和处理方面。
在APIC系统中,每个中断都有一个优先级,这决定了中断处理的顺序。这些优先级通常是可配置的,允许操作系统或其他系统软件根据需要调整它们。这种灵活性允许更有效地处理多任务和并发操作,尤其是在高性能或实时系统中。
在多处理器系统中,APIC还支持中断地定向传送,这意味着可以将特定地中断定向到特定的处理器。这进一步提高了处理效率和系统的整体性能。
APIC使用了两种主要类型的中断:边沿触发和电平触发。边沿触发的中断是基于信号边沿的变化(从低到高或从高到低)来触发的,而电平触发的中断则是基于信号电平的持续状态(高或低)来触发的。
在APIC模型中,中断优先级通常是通过优先级寄存器来设置的,操作系统可以根据需要在运行时修改这些寄存器。这种灵活性允许系统更好地响应不同类型的硬件和软件需求,从而提高整体性能和响应性
发生了多个中断,每个中断的优先级是由什么决定的?
在现代计算机系统中,当发生多个中断时,每个中断的优先级通常由以下因素决定:
1.中断向量号:在很多系统中,中断的优先级是由中断向量号决定的。中断向量号是一个唯一的数字,用于标识特定的中断源。通常,较低的中断向量号拥有较高的优先级。例如,在x86体系结构中,非屏蔽中断NMI有一个较低的向量号,因此具有较高的优先级
2.APIC配置:在使用高级可编程中断控制器(APIC)的系统中,APIC允许对中断优先级进行更细粒度的控制。操作系统可以通过配置APIC中的相关寄存器来设置特定中断的优先级
3.操作系统设置: 操作系统内核通常有能力控制或调整中断的优先级。内核可以根据系统的需要或特定的策略来配置或更改中断优先级
4.硬件特性:在某些系统中,硬件本身可能会对中断优先级有一定的默认设置。例如,某些硬件中断(如时钟中断、电源管理中断)可能被硬件赋予固定的高优先级
5.中断类型: 不同类型的中断(例如, IO中断、时钟中断、软件中断)可能根据其重要性和对系统稳定性的影响而被分配不同的优先级
在现代计算机系统中,当发生多个中断时,每个中断的优先级通常由以下因素决定:
1.中断向量号:在很多系统中,中断的优先级是由中断向量号决定的。中断向量号是一个唯一的数字,用于标识特定的中断源。通常,较低的中断向量号拥有较高的优先级。例如,在x86体系结构中,非屏蔽中断NMI有一个较低的向量号,因此具有较高的优先级
2.APIC配置:在使用高级可编程中断控制器(APIC)的系统中,APIC允许对中断优先级进行更细粒度的控制。操作系统可以通过配置APIC中的相关寄存器来设置特定中断的优先级
3.操作系统设置: 操作系统内核通常有能力控制或调整中断的优先级。内核可以根据系统的需要或特定的策略来配置或更改中断优先级
4.硬件特性:在某些系统中,硬件本身可能会对中断优先级有一定的默认设置。例如,某些硬件中断(如时钟中断、电源管理中断)可能被硬件赋予固定的高优先级
5.中断类型: 不同类型的中断(例如, IO中断、时钟中断、软件中断)可能根据其重要性和对系统稳定性的影响而被分配不同的优先级
与APIC中断优先级有关的寄存器有哪些?
与APIC(高级可编程中断控制器)中断优先级有关的寄存器主要集中在本地APIC(LAPIC)部分。这些寄存器用于管理和配置处理器对中断的响应优先级。以下是与中断优先级直接相关的主要寄存器
1.任务优先级寄存器(TPR):这是最直接影响中断优先级的寄存器。TPR用于设置当前任务的优先级,它阻止优先级低于TPR设置的中断打扰处理器,确保只有高优先级的中断能够触发
2.处理器优先级寄存器(PPR):PPR反应了当前执行任务的优先级,它基于TPR和当前服务中断的优先级计算得出。PPR用于确定是否可以接收新的中断请求,即只有当新的中断请求优先级高于PPR的值时,该中断才会被处理器接收
3.中断服务寄存器(ISR): 虽然ISR不是用于设置优先级,但它显示了当前正在处理的中断。它对理解当前执行的中断和它们的优先级有帮助
4.中断请求寄存器(IRR):同样,IRR并非用于设置优先级,但它显示了等待处理的中断,这些中断已经被APIC接受,但还没有被处理器处理
5.逻辑目标寄存器:这个急促请你虽然不直接决定中断优先级,但它影响中断信号的发送和接收,间接影响中断处理的优先级
6.LVT(本地向量表)寄存器:特定的LVT条目,如LVT计时器和LVT错误,可能包含与特定中断源相关的优先级信息
在配置和管理中断时,这些寄存器协同工作,确保中断按照预定的优先级顺序得到正确处理,操作系统通常负责设置和管理这些寄存器的值,以实现期望的中断处理i行为
与APIC(高级可编程中断控制器)中断优先级有关的寄存器主要集中在本地APIC(LAPIC)部分。这些寄存器用于管理和配置处理器对中断的响应优先级。以下是与中断优先级直接相关的主要寄存器
1.任务优先级寄存器(TPR):这是最直接影响中断优先级的寄存器。TPR用于设置当前任务的优先级,它阻止优先级低于TPR设置的中断打扰处理器,确保只有高优先级的中断能够触发
2.处理器优先级寄存器(PPR):PPR反应了当前执行任务的优先级,它基于TPR和当前服务中断的优先级计算得出。PPR用于确定是否可以接收新的中断请求,即只有当新的中断请求优先级高于PPR的值时,该中断才会被处理器接收
3.中断服务寄存器(ISR): 虽然ISR不是用于设置优先级,但它显示了当前正在处理的中断。它对理解当前执行的中断和它们的优先级有帮助
4.中断请求寄存器(IRR):同样,IRR并非用于设置优先级,但它显示了等待处理的中断,这些中断已经被APIC接受,但还没有被处理器处理
5.逻辑目标寄存器:这个急促请你虽然不直接决定中断优先级,但它影响中断信号的发送和接收,间接影响中断处理的优先级
6.LVT(本地向量表)寄存器:特定的LVT条目,如LVT计时器和LVT错误,可能包含与特定中断源相关的优先级信息
在配置和管理中断时,这些寄存器协同工作,确保中断按照预定的优先级顺序得到正确处理,操作系统通常负责设置和管理这些寄存器的值,以实现期望的中断处理i行为
如何获取Local APIC定时器的时钟频率?
获取Local APIC定时器的时钟频率通常涉及到几个步骤,因为这个频率通常不是直接公开的,你需要通过测量来间接确定这个皮女郎。下面是一个常见的方法:
1.获取CPU的基准时钟频率
# 首先,你需要知道CPU的基准时钟频率,这通常可以通过CPU的文档或者使用特定的系统调用来获得
2.配置和使用Local APIC定时器进行测量
# 将Local APIC定时器设置位一次性模式,并设置一个初始值,比如一个较大的数,这样他就会开始倒数
# 同时,使用一个已知频率的计时器(如高精度事件定时器(HPET)或其他可用的系统定时器)来测量Local APIC定时器技术为零所需的事件
# 在Local APIC定时器计数到零时,记录下高精度事件定时器的值
3.计算Local APIC定时器的频率
# 使用已知的高精度事件定时器的频率和记录的事件,可以计算出Local APIC定时器的频率,基本上,你将使用HPET或类似定时器的频率和测量的事件来推算APIC定时器的时钟速度
获取Local APIC定时器的时钟频率通常涉及到几个步骤,因为这个频率通常不是直接公开的,你需要通过测量来间接确定这个皮女郎。下面是一个常见的方法:
1.获取CPU的基准时钟频率
# 首先,你需要知道CPU的基准时钟频率,这通常可以通过CPU的文档或者使用特定的系统调用来获得
2.配置和使用Local APIC定时器进行测量
# 将Local APIC定时器设置位一次性模式,并设置一个初始值,比如一个较大的数,这样他就会开始倒数
# 同时,使用一个已知频率的计时器(如高精度事件定时器(HPET)或其他可用的系统定时器)来测量Local APIC定时器技术为零所需的事件
# 在Local APIC定时器计数到零时,记录下高精度事件定时器的值
3.计算Local APIC定时器的频率
# 使用已知的高精度事件定时器的频率和记录的事件,可以计算出Local APIC定时器的频率,基本上,你将使用HPET或类似定时器的频率和测量的事件来推算APIC定时器的时钟速度
KPCR(Kernel Processor Control Region,内核处理器控制区).
KPCR是每个CPU的内核私有控制块,保存当前处理器状态、当前线程、当前进程、TSS、GDT、IDT等重要内核信息
KPCR在系统中的位置:
x86: 通常挂载在FS段寄存器
x64: 通常挂载在GS段寄存器
KPCR是一个结构体,他报含指向其他关键结构的指针核状态信息,包括但不局限于:
# CurrentThread
当前正在该CPU上运行的线程
# CurrentPrcb
当前CPU的PRCB(处理器控制块)
# GDTBase
当前处理器的全局描述符表地址
# IDTBase
中断描述符表地址
# TSSBase
当前TSS(任务状态段)地址
# Self/KPCRBase
指向自身(结构自引用)
# Irql
当前处理器的中断请求级别
# ExceptionList
异常链表头指针(类似SEH)
KPCR是每个CPU的内核私有控制块,保存当前处理器状态、当前线程、当前进程、TSS、GDT、IDT等重要内核信息
KPCR在系统中的位置:
x86: 通常挂载在FS段寄存器
x64: 通常挂载在GS段寄存器
KPCR是一个结构体,他报含指向其他关键结构的指针核状态信息,包括但不局限于:
# CurrentThread
当前正在该CPU上运行的线程
# CurrentPrcb
当前CPU的PRCB(处理器控制块)
# GDTBase
当前处理器的全局描述符表地址
# IDTBase
中断描述符表地址
# TSSBase
当前TSS(任务状态段)地址
# Self/KPCRBase
指向自身(结构自引用)
# Irql
当前处理器的中断请求级别
# ExceptionList
异常链表头指针(类似SEH)
多核任务调度流程
进入用户态,实现系统调用
实现节奏
1.由内核态切用户态
2.会出现虚拟机崩溃,引出TSS
3.构建TSS描述符,写入CPU tr寄存器
4.实现0x80号中断门
5.实现系统调用框架,实现内核态切用户态
6.实现系统调用
7.实现syscall、sysret
1.由内核态切用户态
2.会出现虚拟机崩溃,引出TSS
3.构建TSS描述符,写入CPU tr寄存器
4.实现0x80号中断门
5.实现系统调用框架,实现内核态切用户态
6.实现系统调用
7.实现syscall、sysret
用户态进入内核态的方式
在x86架构中,从用户态(通常是特权级3)切换到内核态(特权级0)有几种方法,这些切换通常发生在一些特定的事件或操作中,以便CPU可以执行需要更高特权的操作。以下是用户态进入内核态的主要方式:
1.中断(Interrupt):当外部设备(例如键盘、鼠标或网络卡)需要CPU的注意时,它会发送一个中断信号,这会导致CPU暂停当前的执行流程,跳转到预定义的中断服务例程(ISR)地址,并在特权级0下执行该ISR
2.异常(Exception):当发生某些特定的错误或异常条件(例如除以零或页面错误)时,CPU会触发异常,和中断一样,这会导致CPU跳转到预定义的异常处理例程并在特权级0下执行
3.系统调用(System Call):应用程序通常需要请求操作系统服务,如文件IO、网络访问或内存分配。为了实现这些请求,应用程序执行一个系统调用。x86架构为此提供了几种基址,如int 0x80(在早期Linux中使用)或syscall/sysret(在x86-64)和sysenter/sysexit(在现代32位和64位x86 CPU中使用)
4.任务切换:尽管现代操作系统很少使用硬件任务切换,但x86架构确实提供了支持.通过这种方式,CPU可以从一个任务切换到另一个任务,涉及从一个TSS(Task State Segment)切换到另一个TSS.
为了确保安全性,从用户态切换到内核态的所有这些基址都需要特定的硬件和软件支持。例如,IDT(中断描述符表)保存中断和异常的地址,而系统调用则由操作系统内核提供相应的入口点。
当操作完成后,内核需要返回到用户态,这通常是通过一些与上面对应的指令或机制来实现的,例如iret(从中断或异常返回)或sysret/sysexit(从系统调用返回)
在x86架构中,从用户态(通常是特权级3)切换到内核态(特权级0)有几种方法,这些切换通常发生在一些特定的事件或操作中,以便CPU可以执行需要更高特权的操作。以下是用户态进入内核态的主要方式:
1.中断(Interrupt):当外部设备(例如键盘、鼠标或网络卡)需要CPU的注意时,它会发送一个中断信号,这会导致CPU暂停当前的执行流程,跳转到预定义的中断服务例程(ISR)地址,并在特权级0下执行该ISR
2.异常(Exception):当发生某些特定的错误或异常条件(例如除以零或页面错误)时,CPU会触发异常,和中断一样,这会导致CPU跳转到预定义的异常处理例程并在特权级0下执行
3.系统调用(System Call):应用程序通常需要请求操作系统服务,如文件IO、网络访问或内存分配。为了实现这些请求,应用程序执行一个系统调用。x86架构为此提供了几种基址,如int 0x80(在早期Linux中使用)或syscall/sysret(在x86-64)和sysenter/sysexit(在现代32位和64位x86 CPU中使用)
4.任务切换:尽管现代操作系统很少使用硬件任务切换,但x86架构确实提供了支持.通过这种方式,CPU可以从一个任务切换到另一个任务,涉及从一个TSS(Task State Segment)切换到另一个TSS.
为了确保安全性,从用户态切换到内核态的所有这些基址都需要特定的硬件和软件支持。例如,IDT(中断描述符表)保存中断和异常的地址,而系统调用则由操作系统内核提供相应的入口点。
当操作完成后,内核需要返回到用户态,这通常是通过一些与上面对应的指令或机制来实现的,例如iret(从中断或异常返回)或sysret/sysexit(从系统调用返回)
IDT中断门描述符
TSS(Task State Segment)
它是x86架构中用于支持硬件任务切换的一个数据结构。硬件任务切换是在x86保护模式下,CPU提供的一种机制,可以用来快速保存和恢复一个任务的状态
1.作用
# TSS主要用于存储与任务相关的状态信息。当发生任务切换时,CPU会自动保存当前任务的状态到当前任务的TSS,并从即将开始的任务的TSS中恢复其状态
# TSS中保存的状态信息包括: 通用寄存器、段选择子、EFLAGS、控制急促请你、以及其他的系统信息
2.结构
TSS的具体结构依赖于CPU是在32位还是64位模式下操作,但它通常包括以下字段
# 通用寄存器的值: EAX、ECX、EDX、EBX、ESP、ESI和EDI
# 段选择子: 如CS、DS、ES、FS、GS、SS
# EFLAGS寄存器的值
# 控制寄存器的值:如CR3(页目录基址)
# 一些其他的系统信息和标志,例如IO位图的地址、任务的优先级等
3. 用途:
在早期的x86系统设计中,硬件任务切换被认为是一个非常有用的功能,因为它可以在硬件级别提供快速任务切换,但升职记上,由于其开销和复杂性,许多现代操作系统(如Linux和Windows)选择使用软件进行任务切换,而不是使用硬件任务切换
4.在64位的x86-64(或AMD64)架构中,硬件任务切换不再被支持,但TSS仍然存在并被使用,主要是为了存储特定的数据,例如内核栈的地址
5.与其他模型的关系
在x86架构的其他模型中,如实模式和虚拟8086模式,TSS和硬件任务切换并不使用。这些模型有其自己的任务管理和状态保存基址。
总的来说,TSS是x86架构中与任务相关的状态保存和恢复基址的一部分,尽管现代操作系统通常不使用硬件任务切换。
它是x86架构中用于支持硬件任务切换的一个数据结构。硬件任务切换是在x86保护模式下,CPU提供的一种机制,可以用来快速保存和恢复一个任务的状态
1.作用
# TSS主要用于存储与任务相关的状态信息。当发生任务切换时,CPU会自动保存当前任务的状态到当前任务的TSS,并从即将开始的任务的TSS中恢复其状态
# TSS中保存的状态信息包括: 通用寄存器、段选择子、EFLAGS、控制急促请你、以及其他的系统信息
2.结构
TSS的具体结构依赖于CPU是在32位还是64位模式下操作,但它通常包括以下字段
# 通用寄存器的值: EAX、ECX、EDX、EBX、ESP、ESI和EDI
# 段选择子: 如CS、DS、ES、FS、GS、SS
# EFLAGS寄存器的值
# 控制寄存器的值:如CR3(页目录基址)
# 一些其他的系统信息和标志,例如IO位图的地址、任务的优先级等
3. 用途:
在早期的x86系统设计中,硬件任务切换被认为是一个非常有用的功能,因为它可以在硬件级别提供快速任务切换,但升职记上,由于其开销和复杂性,许多现代操作系统(如Linux和Windows)选择使用软件进行任务切换,而不是使用硬件任务切换
4.在64位的x86-64(或AMD64)架构中,硬件任务切换不再被支持,但TSS仍然存在并被使用,主要是为了存储特定的数据,例如内核栈的地址
5.与其他模型的关系
在x86架构的其他模型中,如实模式和虚拟8086模式,TSS和硬件任务切换并不使用。这些模型有其自己的任务管理和状态保存基址。
总的来说,TSS是x86架构中与任务相关的状态保存和恢复基址的一部分,尽管现代操作系统通常不使用硬件任务切换。
32位模式下的TSS结构
64位模式下的TSS结构
快速系统调用 VS中断门
快速系统调用(Fast System Call)和中断门(Interrupt Gate) 是计算机系统中用于处理中断和系统调用的两种不同机制
1.快速系统调用(Fast System Call/Sysenter/Sysexit)
# 它是一种更快的系统调用机制。用于现代操作系统和处理器
# 快速调用减少了传统调用(如使用中断指令)的开销
# 它通过专用指令(如Inte的sysenter/sysexit)直接转换到内核模式。跳过了一些常规的中断处理步骤
# 这种方法提供了更快的执行速度,因为它减少了状态保存和恢复的需要,以及中断处理的复杂性
2.中断门(Interrupt Gate)
# 中断门是传统的处理中断和系统调用的方式
# 当发生中断时,处理器通过查找中断描述符表(IDT)来确定相应的处理程序
# 使用中断门的系统调用通常涉及执行一个中断指令(如INT),这回导致处理器切换到内核模式并调用相应的中断服务例程
# 这种方法虽然在处理器层面上较为简单,但由于涉及更多的状态切换和检查,因此在性能上不及快速系统调用。
在选择使用快速系统调用还是中断门时,需要考虑系统调用的频率和对性能的要求,快速系统调用在现代操作系统中更为普遍,特别时是需要高性能的环境中
快速系统调用(Fast System Call)和中断门(Interrupt Gate) 是计算机系统中用于处理中断和系统调用的两种不同机制
1.快速系统调用(Fast System Call/Sysenter/Sysexit)
# 它是一种更快的系统调用机制。用于现代操作系统和处理器
# 快速调用减少了传统调用(如使用中断指令)的开销
# 它通过专用指令(如Inte的sysenter/sysexit)直接转换到内核模式。跳过了一些常规的中断处理步骤
# 这种方法提供了更快的执行速度,因为它减少了状态保存和恢复的需要,以及中断处理的复杂性
2.中断门(Interrupt Gate)
# 中断门是传统的处理中断和系统调用的方式
# 当发生中断时,处理器通过查找中断描述符表(IDT)来确定相应的处理程序
# 使用中断门的系统调用通常涉及执行一个中断指令(如INT),这回导致处理器切换到内核模式并调用相应的中断服务例程
# 这种方法虽然在处理器层面上较为简单,但由于涉及更多的状态切换和检查,因此在性能上不及快速系统调用。
在选择使用快速系统调用还是中断门时,需要考虑系统调用的频率和对性能的要求,快速系统调用在现代操作系统中更为普遍,特别时是需要高性能的环境中
IA32_STAR结构
IA32_STAR是一个64位的模型特定寄存器(Mode-Specific Register, MSR)在x86-64架构中用于控制系统调用(syscall)和系统返回(sysret)指令的行为。这个寄存器的结构如下:
# 位63-48(高16位):这些位用于设置SYSRET指令。它们包含用于返回到64位模式下用户空间的代码段(CS)和堆栈段(SS)选择器。这些值通常是用户空间代码段和堆栈选择器的值,左移了16位
# 位47-32(次高16位):这部分用于设置syscall指令,它包含了用于64位模式下的内核空间代码段(CS)选择器,这通常是内核空间代码段选择器的值,左移了16位。这个值用于在执行syscall时将处理器从用户模式切换到内核模式
# 位31-0(低32位):这些位在IA32_STAR寄存器中并不适用,通常被设置为0.
在实践中,IA32_STAR寄存器的设置对于操作系统的内核非常重要,因为它控制了用户模式与内核模式之间的转换。设置这个寄存器需要特权级别的代码执行,并且错误的设置可能导致系统不稳定或崩溃。这是一种非常底层的配置。通常只有操作系统卡覅这和系统程序员会涉及到这方面的设置
IA32_STAR是一个64位的模型特定寄存器(Mode-Specific Register, MSR)在x86-64架构中用于控制系统调用(syscall)和系统返回(sysret)指令的行为。这个寄存器的结构如下:
# 位63-48(高16位):这些位用于设置SYSRET指令。它们包含用于返回到64位模式下用户空间的代码段(CS)和堆栈段(SS)选择器。这些值通常是用户空间代码段和堆栈选择器的值,左移了16位
# 位47-32(次高16位):这部分用于设置syscall指令,它包含了用于64位模式下的内核空间代码段(CS)选择器,这通常是内核空间代码段选择器的值,左移了16位。这个值用于在执行syscall时将处理器从用户模式切换到内核模式
# 位31-0(低32位):这些位在IA32_STAR寄存器中并不适用,通常被设置为0.
在实践中,IA32_STAR寄存器的设置对于操作系统的内核非常重要,因为它控制了用户模式与内核模式之间的转换。设置这个寄存器需要特权级别的代码执行,并且错误的设置可能导致系统不稳定或崩溃。这是一种非常底层的配置。通常只有操作系统卡覅这和系统程序员会涉及到这方面的设置
0 条评论
下一页