You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

32位保护模式下Bootloader的IDT条目生成函数异常导致QEMU反复重启问题排查

Troubleshooting Your makeidt Function for 32-bit Protected Mode IDT

Let's break down the issues in your makeidt function step by step—your IDT entries are being constructed incorrectly, which is why your system keeps rebooting when you trigger the interrupt. First, let's recap the structure of a 32-bit interrupt gate descriptor (the type you need here):

A valid 8-byte interrupt gate looks like this:

Bytes 0-1Bytes 2-3Byte 4Byte 5Bytes 6-7
Offset 0-15 (low 16 bits of handler)GDT/LDT Selector0 (reserved for 32-bit gates)AttributesOffset 16-31 (high 16 bits of handler)

The attribute byte (byte 5) has these bits:

  • Bit 7: P (Present) → 1 for valid gates
  • Bits 6-5: DPL (Descriptor Privilege Level) → your cl value
  • Bit 4: S (Storage Segment) → 0 for system gates
  • Bits 3-0: Type → 0xE for 32-bit interrupt gates

Issues in Your makeidt Code

  1. Incorrect field ordering & storage
    Your function returns the IDT entry as eax:edx, then you store eax at [idt] and edx at [idt+4]. This reverses the low and high 32-bit halves of the IDT entry. The low 32 bits (offset low + selector) should go to [idt], and the high 32 bits (attributes + offset high) to [idt+4].

  2. Broken selector construction
    You're mishandling the GDT selector:

    • The selector is a 16-bit value: (index << 3) | RPL. Since you're using a GDT segment, TI (bit 2) stays 0.
    • Your code mixes the selector with the handler's low offset and privilege level incorrectly, corrupting both fields.
  3. Wrong attribute byte calculation
    Your bit-shifting logic for the attribute byte is flawed. You end up with 0xE7 instead of the correct 0xEE (for P=1, DPL=3, Type=0xE). Your shifts and ORs don't align the bits to their correct positions in the attribute byte.

  4. Misplaced handler offset bits
    You're splitting the handler address (edx) into the wrong parts of the IDT entry, swapping low and high offset positions.

Fixed makeidt Function

Here's the corrected version that properly constructs a 32-bit interrupt gate:

makeidt:
; Inputs:
;   cl = DPL (privilege level, 0-3)
;   ax = GDT segment index (for code segment)
;   edx = handler function pointer
;   ch = Present flag (1 = valid, 0 = invalid)
; Output:
;   eax = low 32 bits of IDT entry (offset low + selector)
;   edx = high 32 bits of IDT entry (attributes + offset high)

    ; Build low 32 bits: [offset 0-15][selector]
    mov eax, edx
    and eax, 0x0000FFFF         ; Isolate offset low 16 bits (bytes 0-1)
    mov ebx, eax                ; Save offset low temporarily
    mov ax, [esp+12]            ; Restore original GDT index (since we overwrote ax)
    shl ax, 3                   ; Convert GDT index to selector base (TI=0)
    or al, cl                   ; Add RPL to selector (match DPL for simplicity)
    mov ebx, ebx                ; Restore offset low to ebx
    shl ebx, 16                 ; Move selector to upper 16 bits of ebx
    or eax, ebx                 ; eax now = [offset low][selector] (low 32 bits)

    ; Build high 32 bits: [0][attributes][offset high]
    mov edx, [esp+8]            ; Restore original handler pointer
    shr edx, 16                 ; Isolate offset high 16 bits (bytes 6-7)
    mov ebx, 0
    mov bl, ch
    shl bl, 7                   ; Set Present bit (bit7)
    mov bh, cl
    shr bh, 3
    or bl, bh                   ; Set DPL bits (6-5)
    or bl, 0x0E                 ; Set S=0 and Type=0xE (interrupt gate)
    shl ebx, 16                 ; Move attribute byte to correct position
    or edx, ebx                 ; edx now = [0][attributes][offset high] (high 32 bits)

    ret

answerh dd 0 ; No longer needed with corrected logic

Corrected Call Flow

When storing the IDT entry, make sure you're putting the low 32 bits first, then the high 32 bits:

mov edx, intcode
mov ax, 2          ; GDT index for your code segment
mov ch, 1          ; Mark gate as present
mov cl, 3          ; DPL=3
call makeidt
mov [idt], eax     ; Store low 32 bits of interrupt gate
mov [idt+4], edx   ; Store high 32 bits
lidt [idtdesc]
mov ebx, string
sti
int 0
cli

Additional Notes

  • Double-check that your GDT index 2 points to a valid 32-bit code segment (with appropriate privileges matching your DPL=3 setting if needed).
  • The iret in your intcode handler is correct for 32-bit mode, but ensure myfunct doesn't corrupt any registers that need to be preserved (push/pop them if it does).

内容的提问来源于stack exchange,提问作者Sasidhar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.29 10:32:29