这个汇编函数有什么问题来制作 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)。