这个汇编函数有什么问题来制作 idt 条目?
what is wrong in this assembly function to make idt entries?
我正在用汇编编写一个简单的引导加载程序并在 qemu 上测试它。
我需要一个 idt 并编写了一个函数来创建条目。我知道这里出了什么问题-请检查-
makeidt:
;privilage level in cl
;index to a gdt entry in ax
;handler function pointer in edx
;put 0x01 in ch to make this interrupt active
;the table entry would be given in eax:edx
mov bx, dx ; the first part
shl ebx, 16
mov bl, cl
shl ax, 3 ; else, bx would be overwriten
or bx, ax ; selector in gdt
mov [answerh], ebx ; high part made
shr edx, 16
mov ebx, 0xe
shl ebx, 3
or bl , cl
shl ebx, 1
or bl, ch
shl ebx, 16
mov bx, dx
mov eax, [answerh]
ret
intcode:
call myfunct
iret
answerh dd 0
idtdesc:
idtlen dw 100h
dd idt
idt:
我这样调用这个函数-
mov edx, intcode
mov ax, 2
mov ch, 1
mov cl, 3
call makeidt
mov [idt], eax
mov [idt+4], edx
lidt [idtdesc]
mov ebx, string
sti
int 0
cli
myfunct 在从其他地方调用时工作正常..但是机器在遇到这个块后一次又一次地重新启动
为什么??顺便说一句,我处于 32 位保护模式。
对于makeidt:
例程;我认为您混淆了“字节顺序”(或字节顺序或字顺序?)。例如。 “最低 16 位偏移量”应该以 edx
的最低 16 位结束(这是它在输入参数中开始的位置),但您将其视为“最高 16 位偏移量”。
你想要的更像是(未经测试,NASM语法):
makeidt:
;Put "offset" in the right places
mov ebx,edx ;Put highest 16 bits of offset into highest 16 bits of ebx
and edx,0x0000FFFF ;Mask lowest 16 bits of offset
and ebx,0xFFFF0000 ;Mask highest 16 bits of offset
;Put "code segment" in the right place (and combine with "low 16 bits of offset")
shl eax,3+16 ;eax = convert "GDT index" into a code segment ("<< 3") then and shift code segment into the right place ("<< 16")
or eax,edx ;eax = first dword of result
;Build "type and attributes"
shl cl,6 ;cl = DPL in highest 2 bits (to bring them next to "present" bit in CH)
shl cx,7 ;cx = DPL in bits 13 to 14, present bit in bit 15
or ch,0x0E ;Set "descriptor type = interrupt gate" (trap gates not supported?)
;Combine "type and attributes" with highest 16 bits of offset
and ecx,0x0000FFFF ;Make sure highest 16 bits of ECX are zeros
lea edx,[ecx+ebx] ;Merge (using addition as "bitwise or" so the result can be moved to a different register for free)
ret
IDT 的限制 (idtlen dw 100h
) 可能是错误的。它应该是“总字节数 - 1”,所以在保护模式下(其中一个条目是 8 个字节)对于 256 个条目你想要 256*8 - 1
或 0x07FF。注意:如果你只想要前 32 个 IDT 条目(为异常保留),那么 0x00FF 的限制是正确的,但大多数人不想要那个(他们想要 space 用于 IRQ 等)。
备注:
让汇编程序完成大部分工作会更快更灵活(例如,调用程序中的 mov ecx,(1 << 15) | (3 << 14)
和 mov eax,(2 << 3) << 16
,因此您不需要在makeidt:
例程);如果你愿意,你可以使用宏来让它更快(没有函数 call/return 开销,更清晰的分离,没有使用它的代码的变化)。
"DPL=3"表示非特权代码可以通过中断使用。 int n
指令。这几乎不是你想要的(除了对内核 API 使用 int 0x80
之类的东西)。异常和 IRQ 应该使用“DPL=0”来禁止非特权代码直接使用(同时仍然允许异常和 IRQ 中断非特权代码——出于保护检查的目的,“中断源”被假定为 CPL=0,当CPU 或硬件正在生成中断,即使被中断的代码是 CPL=3)。
我正在用汇编编写一个简单的引导加载程序并在 qemu 上测试它。 我需要一个 idt 并编写了一个函数来创建条目。我知道这里出了什么问题-请检查-
makeidt:
;privilage level in cl
;index to a gdt entry in ax
;handler function pointer in edx
;put 0x01 in ch to make this interrupt active
;the table entry would be given in eax:edx
mov bx, dx ; the first part
shl ebx, 16
mov bl, cl
shl ax, 3 ; else, bx would be overwriten
or bx, ax ; selector in gdt
mov [answerh], ebx ; high part made
shr edx, 16
mov ebx, 0xe
shl ebx, 3
or bl , cl
shl ebx, 1
or bl, ch
shl ebx, 16
mov bx, dx
mov eax, [answerh]
ret
intcode:
call myfunct
iret
answerh dd 0
idtdesc:
idtlen dw 100h
dd idt
idt:
我这样调用这个函数-
mov edx, intcode
mov ax, 2
mov ch, 1
mov cl, 3
call makeidt
mov [idt], eax
mov [idt+4], edx
lidt [idtdesc]
mov ebx, string
sti
int 0
cli
myfunct 在从其他地方调用时工作正常..但是机器在遇到这个块后一次又一次地重新启动 为什么??顺便说一句,我处于 32 位保护模式。
对于makeidt:
例程;我认为您混淆了“字节顺序”(或字节顺序或字顺序?)。例如。 “最低 16 位偏移量”应该以 edx
的最低 16 位结束(这是它在输入参数中开始的位置),但您将其视为“最高 16 位偏移量”。
你想要的更像是(未经测试,NASM语法):
makeidt:
;Put "offset" in the right places
mov ebx,edx ;Put highest 16 bits of offset into highest 16 bits of ebx
and edx,0x0000FFFF ;Mask lowest 16 bits of offset
and ebx,0xFFFF0000 ;Mask highest 16 bits of offset
;Put "code segment" in the right place (and combine with "low 16 bits of offset")
shl eax,3+16 ;eax = convert "GDT index" into a code segment ("<< 3") then and shift code segment into the right place ("<< 16")
or eax,edx ;eax = first dword of result
;Build "type and attributes"
shl cl,6 ;cl = DPL in highest 2 bits (to bring them next to "present" bit in CH)
shl cx,7 ;cx = DPL in bits 13 to 14, present bit in bit 15
or ch,0x0E ;Set "descriptor type = interrupt gate" (trap gates not supported?)
;Combine "type and attributes" with highest 16 bits of offset
and ecx,0x0000FFFF ;Make sure highest 16 bits of ECX are zeros
lea edx,[ecx+ebx] ;Merge (using addition as "bitwise or" so the result can be moved to a different register for free)
ret
IDT 的限制 (idtlen dw 100h
) 可能是错误的。它应该是“总字节数 - 1”,所以在保护模式下(其中一个条目是 8 个字节)对于 256 个条目你想要 256*8 - 1
或 0x07FF。注意:如果你只想要前 32 个 IDT 条目(为异常保留),那么 0x00FF 的限制是正确的,但大多数人不想要那个(他们想要 space 用于 IRQ 等)。
备注:
让汇编程序完成大部分工作会更快更灵活(例如,调用程序中的
mov ecx,(1 << 15) | (3 << 14)
和mov eax,(2 << 3) << 16
,因此您不需要在makeidt:
例程);如果你愿意,你可以使用宏来让它更快(没有函数 call/return 开销,更清晰的分离,没有使用它的代码的变化)。"DPL=3"表示非特权代码可以通过中断使用。
int n
指令。这几乎不是你想要的(除了对内核 API 使用int 0x80
之类的东西)。异常和 IRQ 应该使用“DPL=0”来禁止非特权代码直接使用(同时仍然允许异常和 IRQ 中断非特权代码——出于保护检查的目的,“中断源”被假定为 CPL=0,当CPU 或硬件正在生成中断,即使被中断的代码是 CPL=3)。