- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
为什么我无法访问此 C 代码中的 Tss 变量 Qnd 如何解决此问题?以及为什么在尝试从 C 代码写入 Tss 变量时出现 Page Fault 异常?
在保护模式下,我在 boot32.S 中声明了 gdt64 和 Tss:
.align 16
gdt64:
.quad 0x0000000000000000 // 0x00 NULL
.quad 0x0020980000000000 // 0x08 KCODE64
.quad 0x0020f80000000000
.quad 0x0000f20000000000
TssDesc:
.word TssLen-1
.word 0
.byte 0
.byte 0x89
.byte 0
.byte 0
.quad 0
gdt64_end:
.align 16
.global init_gdt64_ptr_baseaddr
.global init_gdt64_ptr
init_gdt64_ptr:
.word gdt64_end - gdt64 - 1
init_gdt64_ptr_baseaddr:
.quad gdt64 # Change to QUAD from LONG
.global Tss
.global TssDesc
Tss:
.long 0
.quad 0xffff800000190000
.fill 88
.long TssLen
.equ TssLen, . - Tss
boot64.S:
.extern Tss
.extern TssDesc
...
SetTss:
lea Tss, %rax
lea TssDesc, %rbx
mov %ax, 2(%rbx)
shr $16,%rax
mov %al,4(%rbx)
shr $8,%rax
mov %al,7(%rbx)
shr $8,%rax
mov %eax,8(%rbx)
mov $0x20,%ax
ltr %ax
ret
...
.global _start64h
_start64h:
mov $KERNEL_VMA, %rax
add %rax, init_gdt64_ptr_baseaddr
lgdt init_gdt64_ptr(%rax)
add %rax, %rsp
call SetTss
但后来在长模式和 proc.c 中的 C 代码中:
extern struct TSS Tss;
static void set_tss(struct Process *proc)
{
Tss.rsp0 = proc->stack + STACK_SIZE;
}
当写入 Tss.rsp0 时,我在这一行得到页面错误 (14) 异常。
Cannot access memory at address 0x20103a
Qemu 输出:
printk("[Error %d at ring %d] %d:%x %x", tf->trapno, (tf->cs & 3), tf->errorcode, read_cr2(), tf->rip);
输出这个:
[Error 14 at ring 0] 2:20103EH FFFF800000209AC8H
github 上此项目的链接:
https://github.com/JustVic/kernel_multitasking
最佳答案
Qemu 的 printk("[Error %d at ring %d] %d:%x %x", tf->trapno, (tf->cs & 3), tf->errorcode, read_cr2(), tf->rip);
显示的信息表明地址 FFFF800000209AC8H 处的指令试图写入地址 20103EH 处的“不存在”页面。
这导致了 3 个可能的观察结果:
a) 代码在虚拟地址空间的上半部分(“内核空间”)中运行,并试图访问虚拟地址空间(“用户空间”)下半部分不存在的内容。这可能意味着链接器正在为物理内存(在内核设置分页之前使用)生成地址,这在设置分页后没有意义。
b) 数据应该位于比代码更低的地址 (0xFFF800000020103E)(位于 0xFFFF800000209AC8)。这是不寻常的(通常 .data
部分位于比 code/.text
部分更高的地址)。我们可以从您的源代码中看到,您在创建 TSS 数据时没有更改部分,因此很可能(除非它是“剪切和粘贴遗漏”)您实际上已经在 code/.text
部分中获得了数据。这是相对糟糕的,因为 CPU 的工作方式(例如,如果您在高速缓存线的一部分中有代码而在同一高速缓存线的另一部分中有数据,则写入数据看起来像 CPU 的自修改代码,而现代CPU可以同时“运行”数百条指令,真的不喜欢自我修改代码)。
c) 内核代码就在“非规范漏洞”之上。这也是不寻常的。原因是“64 位”80x86 大多不支持指令中的 64 位立即数操作数(mov
的一种特殊变体,如 mov rax, 0x0123456789ABCDEF
,可以处理 64 位立即数,仅此而已)。这意味着当“编译时已知的地址”可以被压缩到 32 位时,代码会更有效,并且可以使用零扩展或符号扩展到 64 位。扩展到 64 位的(负)32 位数字符号最终在 0xFFFFFFFF80000000 到 0xFFFFFFFFFFFFFFFF 范围内,因此该地址范围比从 0xFFFF800000000000 开始的范围(对于“编译时已知的地址”)更有效(可以'不能以 32 位表示)。
查看源代码中的“kernel/kernel.ld”,看起来您已经创建了特殊部分来解决第一个问题(例如,在设置分页之前运行的代码的 .boottext
部分和用于数据的 .bootdata
部分)在设置分页之前使用)。但是,第二个问题(“代码节中的数据”)暗示您没有正确使用节,因此推断第一个问题也是由于未正确使用节引起的,这是合理的。
换句话说,可以合理地假设(在您的 SetTss
例程中)lea Tss, %rax
和 lea TssDesc, %rbx
正在使用物理地址(因为这些标签是在错误的部分创建的 - 即在 .boottext
部分而不是 .data
部分),导致下一个指令( mov %ax, 2(%rbx)
)写入错误的地址(物理地址,而不是虚拟地址)。
然而;检查您的代码(主要在 kernel/boot64.S
中)表明我的假设在某处是不正确的。 call SetTss
在物理内存的前 1 GiB 仍然身份映射到虚拟地址空间时发生,因此这应该“偶然工作”(直到稍后 CPU 尝试使用已经消失的 TSS 时);然后在 movq $0x0, p4_table
完成后不久(通过 invlpg 0
和 call SetTss
)删除物理内存映射。这意味着在其他地方还有额外的“使用错误的部分”错误。
关于c - 为什么我不能从这个 C 代码访问在汇编中声明的 Tss 变量?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68212845/
#include using namespace std; class C{ private: int value; public: C(){ value = 0;
这个问题已经有答案了: What is the difference between char a[] = ?string?; and char *p = ?string?;? (8 个回答) 已关闭
关闭。此题需要details or clarity 。目前不接受答案。 想要改进这个问题吗?通过 editing this post 添加详细信息并澄清问题. 已关闭 7 年前。 此帖子已于 8 个月
除了调试之外,是否有任何针对 c、c++ 或 c# 的测试工具,其工作原理类似于将独立函数复制粘贴到某个文本框,然后在其他文本框中输入参数? 最佳答案 也许您会考虑单元测试。我推荐你谷歌测试和谷歌模拟
我想在第二台显示器中移动一个窗口 (HWND)。问题是我尝试了很多方法,例如将分辨率加倍或输入负值,但它永远无法将窗口放在我的第二台显示器上。 关于如何在 C/C++/c# 中执行此操作的任何线索 最
我正在寻找 C/C++/C## 中不同类型 DES 的现有实现。我的运行平台是Windows XP/Vista/7。 我正在尝试编写一个 C# 程序,它将使用 DES 算法进行加密和解密。我需要一些实
很难说出这里要问什么。这个问题模棱两可、含糊不清、不完整、过于宽泛或夸夸其谈,无法以目前的形式得到合理的回答。如需帮助澄清此问题以便重新打开,visit the help center . 关闭 1
有没有办法强制将另一个 窗口置于顶部? 不是应用程序的窗口,而是另一个已经在系统上运行的窗口。 (Windows, C/C++/C#) 最佳答案 SetWindowPos(that_window_ha
假设您可以在 C/C++ 或 Csharp 之间做出选择,并且您打算在 Windows 和 Linux 服务器上运行同一服务器的多个实例,那么构建套接字服务器应用程序的最明智选择是什么? 最佳答案 如
你们能告诉我它们之间的区别吗? 顺便问一下,有什么叫C++库或C库的吗? 最佳答案 C++ 标准库 和 C 标准库 是 C++ 和 C 标准定义的库,提供给 C++ 和 C 程序使用。那是那些词的共同
下面的测试代码,我将输出信息放在注释中。我使用的是 gcc 4.8.5 和 Centos 7.2。 #include #include class C { public:
很难说出这里问的是什么。这个问题是含糊的、模糊的、不完整的、过于宽泛的或修辞性的,无法以目前的形式得到合理的回答。如需帮助澄清此问题以便重新打开它,visit the help center 。 已关
我的客户将使用名为 annoucement 的结构/类与客户通信。我想我会用 C++ 编写服务器。会有很多不同的类继承annoucement。我的问题是通过网络将这些类发送给客户端 我想也许我应该使用
我在 C# 中有以下函数: public Matrix ConcatDescriptors(IList> descriptors) { int cols = descriptors[0].Co
我有一个项目要编写一个函数来对某些数据执行某些操作。我可以用 C/C++ 编写代码,但我不想与雇主共享该函数的代码。相反,我只想让他有权在他自己的代码中调用该函数。是否可以?我想到了这两种方法 - 在
我使用的是编写糟糕的第 3 方 (C/C++) Api。我从托管代码(C++/CLI)中使用它。有时会出现“访问冲突错误”。这使整个应用程序崩溃。我知道我无法处理这些错误[如果指针访问非法内存位置等,
关闭。这个问题不符合Stack Overflow guidelines .它目前不接受答案。 我们不允许提问寻求书籍、工具、软件库等的推荐。您可以编辑问题,以便用事实和引用来回答。 关闭 7 年前。
已关闭。此问题不符合Stack Overflow guidelines 。目前不接受答案。 要求我们推荐或查找工具、库或最喜欢的场外资源的问题对于 Stack Overflow 来说是偏离主题的,因为
我有一些 C 代码,将使用 P/Invoke 从 C# 调用。我正在尝试为这个 C 函数定义一个 C# 等效项。 SomeData* DoSomething(); struct SomeData {
这个问题已经有答案了: Why are these constructs using pre and post-increment undefined behavior? (14 个回答) 已关闭 6
我是一名优秀的程序员,十分优秀!