- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
保护模式设置中断的过程是怎样的?
This链接说应该:
- Make space for the interrupt descriptor table
- Tell the CPU where that space is (see GDT Tutorial: lidt works the very same way as lgdt)
- Tell the PIC that you no longer want to use the BIOS defaults (see Programming the PIC chips)
- Write a couple of ISR handlers (see Interrupt Service Routines) for both IRQs and exceptions
- Put the addresses of the ISR handlers in the appropriate descriptors
- Enable all supported interrupts in the IRQ mask (of the PIC)
第三步对我来说毫无意义(我查看了 this 链接,但没有任何关于告诉 PIC 的任何信息)所以我忽略了它并完成了接下来的两个步骤,只是当我再次无能为力时到了最后一步。然而,根据我对中断的理解,我不理解的两个步骤都与 PIC Controller 的硬件中断有关,不应该影响 PIT 在 IRQ 0 上引发的中断。因此我也忽略了这一步。
当我运行我的代码时,它编译得很好,甚至可以在虚拟机中运行,但中断似乎只触发一次。然后我意识到我没有向 PIC 发送 EOI,以防止它引发更多中断。但是,在 iret
指令之前添加 mov al, 0x20
和 out 0x20, al
会使虚拟机崩溃。
这是我的 IDT:
; idt
idt_start :
dw 0x00 ; The interrupt handler is located at absolute address 0x00
dw CODE_SEG ; CODE_SEG points to the GDT entry for code
db 0x0 ; The unused byte
db 0b11101001 ; 1110 Defines a 32 bit Interrupt gate, 0 is mandatory, privilege level = 0 (0b00), the last bit is one so that the CPU knows that the interrupt will be used
dw 0x00 ; The higher part of the offset (0x00) is 0x00
idt_end:
idt_descriptor :
dw idt_end - idt_start - 1 ; Size of our idt, always one less than the actual size
dd idt_start ; Start address of our idt
这是我的中断处理程序(位于内存中的绝对位置 0x00):
ISR_0:
push eax
add [0x300], byte
mov al, 0x20
out 0x20, al
pop eax
iret
times 512-($-$$) db 0
这是我用来进入保护模式并将 GDT 和 IDT 加载到内存中的代码:
[bits 16]
switch_to_pm:
cli
lgdt [gdt_descriptor]
lidt [idt_descriptor]
mov eax, cr0
or eax, 1
mov cr0,eax
jmp CODE_SEG:init_pm
[bits 32]
init_pm :
mov ax, DATA_SEG
mov ds, ax
mov ss, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ebp, 0x90000
mov esp, ebp
sti
call BEGIN_PM
我的主要功能(检查 0x300 的值)如下所示:
void main() {
char iii[15];
int * aa = (int *)0x300;
for (;;)
{
setCursor(0, 0);
print(itoab(*aa, iii));
}
}
顺便说一下,我已经使用内存转储验证了所有内容都加载到正确的地址并且所有内容都在预期的位置。例如,0x300 是内存的空闲部分,仅用于简化我的代码。
最佳答案
让我们看看一些相对较小的内核,即 Linux 0.01做到了!
- Make space for the interrupt descriptor table
这做了两次(好吧,技术上只有一次):首先,引导加载程序(路径是/boot/boot.s
)初始化IDTR,所以CPU在跳转时很高兴进入保护模式。 IDTR内容如下:
idt_48:
.word 0 | idt limit=0
.word 0,0 | idt base=0L
IDTR 是这样加载的:
lidt idt_48 | load idt with 0,0
现在,可以进行跳跃了。
请注意,这里没有 IDT。它只是一个虚拟对象,因此内核中不会出现任何错误。
之后,真正的IDT被初始化(路径为/boot/head.s
)。空间是这样分配的:
_idt: .fill 256,8,0 # idt is uninitialized
- Tell the CPU where that space is (see GDT Tutorial:
lidt
works the very same way aslgdt
)
lidt
需要一个包含 IDTR 内容的线性地址。该内容如下所示:
idt_descr:
.word 256*8-1 # idt contains 256 entries
.long _idt
IDTR初始化如下:
lidt idt_descr
- Tell the PIC that you no longer want to use the BIOS defaults (see Programming the PIC chips)
正如@RossRidge 在对您的问题的评论中提到的,这意味着重新映射 IRQ 中断 vector (IV)。
由于 PIC IV 与 Intel x86 异常地址重叠,我们必须重新映射其中之一。异常地址是硬连线的,因此我们需要重新映射 PIC vector 。
另请参阅 Linus 相应代码上方的评论:
| well, that went ok, I hope. Now we have to reprogram the interrupts :-(
| we put them right after the intel-reserved hardware interrupts, at
| int 0x20-0x2F. There they won't mess up anything. Sadly IBM really
| messed this up with the original PC, and they haven't been able to
| rectify it afterwards. Thus the bios puts interrupts at 0x08-0x0f,
| which is used for the internal hardware interrupts as well. We just
| have to reprogram the 8259's, and it isn't fun.
现在,这是真正的代码。中间的jmp
是为了同步CPU和PIC,所以CPU不会发送PIC还不能接收到的数据。这类似于写入内存时的等待状态:当 CPU 比内存/内存仲裁器快时,它需要等待一段时间才能下次访问内存。
mov al,#0x11 | initialization sequence
out #0x20,al | send it to 8259A-1
.word 0x00eb,0x00eb | jmp $+2, jmp $+2
out #0xA0,al | and to 8259A-2
.word 0x00eb,0x00eb
mov al,#0x20 | start of hardware int's (0x20)
out #0x21,al
.word 0x00eb,0x00eb
mov al,#0x28 | start of hardware int's 2 (0x28)
out #0xA1,al
.word 0x00eb,0x00eb
mov al,#0x04 | 8259-1 is master
out #0x21,al
.word 0x00eb,0x00eb
mov al,#0x02 | 8259-2 is slave
out #0xA1,al
.word 0x00eb,0x00eb
mov al,#0x01 | 8086 mode for both
out #0x21,al
.word 0x00eb,0x00eb
out #0xA1,al
.word 0x00eb,0x00eb
mov al,#0xFF | mask off all interrupts for now
out #0x21,al
.word 0x00eb,0x00eb
out #0xA1,al
- Write a couple of ISR handlers (see Interrupt Service Routines) for both IRQs and exceptions
对于异常,您可以在/kernel/traps.c
和/kernel/asm.s
中找到处理程序代码。
一些异常在跳转到处理程序之前将错误代码压入堆栈,您必须将其弹出,否则 iret
指令将失败。另外,页面错误还会将相应的虚拟地址写入cr2
。
IRQ 处理程序分布在整个系统中。 -.- 例如,定时器和磁盘中断处理程序在 /kernel/system_call.s
中,键盘中断处理程序在 /kernel/keyboard.s
中。
- Put the addresses of the ISR handlers in the appropriate descriptors
异常的初始化在 /kernel/traps.c
中的 trap_init
函数中完成:
void trap_init(void)
{
int i;
set_trap_gate(0,÷_error);
set_trap_gate(1,&debug);
set_trap_gate(2,&nmi);
set_system_gate(3,&int3); /* int3-5 can be called from all */
set_system_gate(4,&overflow);
set_system_gate(5,&bounds);
set_trap_gate(6,&invalid_op);
set_trap_gate(7,&device_not_available);
set_trap_gate(8,&double_fault);
set_trap_gate(9,&coprocessor_segment_overrun);
set_trap_gate(10,&invalid_TSS);
set_trap_gate(11,&segment_not_present);
set_trap_gate(12,&stack_segment);
set_trap_gate(13,&general_protection);
set_trap_gate(14,&page_fault);
set_trap_gate(15,&reserved);
set_trap_gate(16,&coprocessor_error);
for (i=17;i<32;i++)
set_trap_gate(i,&reserved);
/* __asm__("movl $0x3ff000,%%eax\n\t"
"movl %%eax,%%db0\n\t"
"movl $0x000d0303,%%eax\n\t"
"movl %%eax,%%db7"
:::"ax");*/
}
IRQ 处理程序条目初始化再次分布在多个文件中。例如,/kernel/sched.c
中的 sched_init
初始化定时器中断处理程序的地址。
- Enable all supported interrupts in the IRQ mask (of the PIC)
这是在 /init/main.c
中的 main
函数中使用宏 sti
完成的。在/asm/system.h
中定义如下:
#define sti() __asm__ ("sti"::)
关于c - 在保护模式下设置中断 (x86),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34561275/
对此感到疯狂,真的缺少一些东西。 我有webpack 4.6.0,webpack-cli ^ 2.1.2,所以是最新的。 在文档(https://webpack.js.org/concepts/mod
object Host "os.google.com" { import "windows" address = "linux.google.com" groups = ["linux"] } obj
每当我安装我的应用程序时,我都可以将数据库从 Assets 文件夹复制到 /data/data/packagename/databases/ .到此为止,应用程序工作得很好。 但 10 或 15 秒后
我在 cc 模式缓冲区中使用 hideshow.el 来折叠我不查看的文件部分。 如果能够在 XML 文档中做到这一点就好了。我使用 emacs 22.2.1 和内置的 sgml-mode 进行 xm
已结束。此问题不符合 Stack Overflow guidelines .它目前不接受答案。 我们不允许提出有关书籍、工具、软件库等方面的建议的问题。您可以编辑问题,以便用事实和引用来回答它。 关闭
根据java: public Scanner useDelimiter(String pattern) Sets this scanner's delimiting pattern to a patt
我读过一些关于 PRG 模式以及它如何防止用户重新提交表单的文章。比如this post有一张不错的图: 我能理解为什么在收到 2xx 后用户刷新页面时不会发生表单提交。但我仍然想知道: (1) 如果
看看下面的图片,您可能会清楚地看到这一点。 那么如何在带有其他一些 View 的简单屏幕中实现没有任何弹出/对话框/模式的微调器日期选择器? 我在整个网络上进行了谷歌搜索,但没有找到与之相关的任何合适
我不知道该怎么做,我一直遇到问题。 以下是代码: rows = int(input()) for i in range(1,rows): for j in range(1,i+1):
我想为重写创建一个正则表达式。 将所有请求重写为 index.php(不需要匹配),它不是以/api 开头,或者不是以('.html',或'.js'或'.css'或'.png'结束) 我的例子还是这样
MVC模式代表 Model-View-Controller(模型-视图-控制器) 模式 MVC模式用于应用程序的分层开发 Model(模型) - 模型代表一个存取数据的对象或 JAVA PO
我想为组织模式创建一个 RDF 模式世界。您可能知道,组织模式文档基于层次结构大纲,其中标题是主要的分组实体。 * March auxiliary :PROPERTIES: :HLEVEL: 1 :E
我正在编写一个可以从文件中读取 JSON 数据的软件。该文件包含“person”——一个值为对象数组的对象。我打算使用 JSON 模式验证库来验证内容,而不是自己编写代码。符合代表以下数据的 JSON
假设我有 4 张 table 人 公司 团体 和 账单 现在bills/persons和bills/companys和bills/groups之间是多对多的关系。 我看到了 4 种可能的 sql 模式
假设您有这样的文档: doc1: id:1 text: ... references: Journal1, 2013, pag 123 references: Journal2, 2014,
我有这个架构。它检查评论,目前工作正常。 var schema = { id: '', type: 'object', additionalProperties: false, pro
这可能很简单,但有人可以解释为什么以下模式匹配不明智吗?它说其他规则,例如1, 0, _ 永远不会匹配。 let matchTest(n : int) = let ran = new Rand
我有以下选择序列作为 XML 模式的一部分。理想情况下,我想要一个序列: 来自 my:namespace 的元素必须严格解析。 来自任何其他命名空间的元素,不包括 ##targetNamespace和
我希望编写一个 json 模式来涵盖这个(简化的)示例 { "errorMessage": "", "nbRunningQueries": 0, "isError": Fals
首先,我是 f# 的新手,所以也许答案很明显,但我没有看到。所以我有一些带有 id 和值的元组。我知道我正在寻找的 id,我想从我传入的三个元组中选择正确的元组。我打算用两个 match 语句来做到这
我是一名优秀的程序员,十分优秀!