0

サンプル IDT を作成し、それを適切なレジスタにロードするために、このコードを作成しました。Intel System のプログラミング ガイドで適切な構造を確認しましたが、割り込みが機能しません。Bochs でカーネル コードを実行し、割り込みをトリガーして__asm__ ("int $32");いるときに (使用すると、次のようなログが表示されます。

00135687199e[CPU0  ] interrupt(): gate not present
00135687199e[CPU0  ] interrupt(): gate descriptor is not valid sys seg (vector=0x0b)
00135687199e[CPU0  ] interrupt(): gate descriptor is not valid sys seg (vector=0x08)

もちろん、割り込みが処理されないため、これにより CPU がリセットされます。IDT をロードするには、次を使用します。

extern void _lidt(_IDT_PTR* idtPtr); //C code side
//Assembly
.global _lidt
_lidt:
push %ebp
mov %esp,%ebp
mov 8(%esp), %eax
lidt (%eax)
leave
ret

これは次のように呼び出されます。

static struct __InteruptDescriptorTableEntry InteruptDescriptorTable[NUM_IDT_ENTRIES];


void zeroIDT()
{   
    unsigned i;
    for(i=0;i<NUM_IDT_ENTRIES-1;++i)
    {
        IDTEntry nullIDTEntry = fillIDTEntry(0,0,0);
        registerInterupt(nullIDTEntry, i);
    }
}

void registerInterupt(const IDTEntry entry, const unsigned intNo)
{
    if(intNo < NUM_IDT_ENTRIES)
        InteruptDescriptorTable[intNo] = entry;
    else
    {
        __asm__("mov $0xDEADC0DE, %eax");
        __asm__("hlt");
    }
}

#define LOW_FUN_ADDR(fun) ( (uint32_t)fun & 0xFFFF )
#define UP_FUN_ADDR(fun) ( (uint32_t)fun >> 16) & 0xFFFF

IDTEntry fillIDTEntry(uint32_t intHandler,
                      uint16_t selector,   
                      uint8_t type_attr)

{   IDTEntry newEntry;
    newEntry.offset_low = LOW_FUN_ADDR(intHandler); 
    newEntry.selector = selector; 
    newEntry.zero = 0;     
    newEntry.type_attr = type_attr;
    newEntry.offset_up = UP_FUN_ADDR(intHandler);
    return newEntry;
}

extern void _lidt(_IDT_PTR* idtPtr);
void loadIDT()
{
    zeroIDT();
    _IDT_PTR idtPtr;
    idtPtr.idtSize = sizeof(struct __InteruptDescriptorTableEntry)*256 - 1;
    idtPtr.idtBaseAddr = (uint32_t) &InteruptDescriptorTable;

    IDTEntry printOnScreenInt = fillIDTEntry((uint32_t)interupt_pritnOnScreen, 0x18, 0xe);
    registerInterupt(printOnScreenInt, 32);
    _lidt(&idtPtr);
}

データ構造:

struct __InteruptDescriptorTableEntry
{
   uint16_t offset_low;
   uint16_t selector; 
   uint8_t zero;      
   uint8_t type_attr; 
   uint16_t offset_up; 
} __attribute__((packed));
typedef struct __InteruptDescriptorTableEntry IDTEntry;

struct _ITD_PTR
{
    uint16_t idtSize;
    uint32_t idtBaseAddr;
} __attribute__((packed));
typedef struct _ITD_PTR _IDT_PTR;

サンプル割り込みルーチン:

.global interupt_pritnOnScreen
interupt_pritnOnScreen:
   mov $0xf00ff00f, %eax
   hlt
iret

quemu で IDT レジスタに IDT への ptr がロードされているかどうかを確認しましたが、そうです。GRUB で起動した直後に IDT をロードしています (保護モードが設定され、GDT セレクターが RAM 全体にまたがっています)。割り込みルーチンを間違って登録していると思いますが、コードの間違いを指摘できます。

4

1 に答える 1

2

ログには明確に記載されていますnot present。IDT エントリに現在のビットを設定するのを忘れました。を使用する必要がtype_attrあり0x8Eます。

于 2015-05-24T01:15:55.283 に答える