プロテクトモードに移行し、各セレクタを32bit化することは
できました。しかし、
BIOSが提供する割り込みハンドラはリアルモード用です。
プロテクトモードの割り込みはプロテクトモードで実行されます。
この状態で割り込みを許可するとハングアップします。
割り込みが起きたとき、
CPU は IDTR が指すベースアドレスをベースとした
配列にアクセスします。
割り込みハンドラを用意するには、
IDTRとこの配列を設定すれば良いことになります。
この配列の各エントリには、
リアルモードでは4バイトのfarポインタ、
プロテクトモードでは8バイトのdescriptorを与えます。
起動時に
割り込みハンドラとして
0000h:0000hからの400バイトが使われるのは、
IDTRのベースアドレスには0、
リミットには3FFhが設定されているためです。
割り込み用のdescriptorは次の構造体です。
| オフセット | サイズ | 機能 |
| +00h | 2-byte | ハンドラのオフセットの下位16bitです。 |
| +02h | 2-byte | ハンドラのセレクタです。 |
| +04h | 1-byte | 予約(0) |
| +05h | 1-byte | descriptorの種類です。
GDTと同じものですが、
bit 4-0には次のいずれかの値を設定します。 |
| +06h | 2-byte | ハンドラのオフセットの上位16bitです。 |
#define P32_SEGDESC_DESCTYPE_INTGATE32 0x0e
#define P32_SEGDESC_DESCTYPE_TRAPGATE32 0x0f
struct P32_GATEDESC
{
unsigned short m_offset_L;
unsigned short m_selector;
unsigned char m_reserved;
unsigned char m_desctype;
unsigned short m_offset_H;
};
struct P32_IDTR
{
unsigned short m_limit;
unsigned long m_base;
};
P32_GATEDESC g_interrupt_desc[256];
P32_IDTR idtr; idtr.m_limit = (256 * 8) - 1; idtr.m_base = (exact32u_t)(void*)(&g_interrupt_desc); __asm__ __volatile__ ( "lidt (%0)" // ASM : // OUT : "r"(&idtr) // IN );
extern "C" void p32_init_pic(void); __asm__( ".text\n" ".globl p32_init_pic\n" ".globl _p32_init_pic\n" "p32_init_pic:\n" "_p32_init_pic:\n" "inb $0x21,%al\n" // IMR (master) "mov %al,%dl\n" "inb $0xa1,%al\n" // IMR (slave) "mov %al,%dh\n" "mov $0x11,%al\n" "outb %al,$0x20\n" // ICW1 (master) "outb %al,$0xa0\n" // ICW1 (slave) "mov $0x20,%al\n" "outb %al,$0x21\n" // ICW2 (master) "mov $0x28,%al\n" "outb %al,$0xa1\n" // ICW2 (slave) "mov $0x04,%al\n" "outb %al,$0x21\n" // ICW3 (master) "mov $0x02,%al\n" "outb %al,$0xa1\n" // ICW3 (slave) "mov $0x01,%al\n" "outb %al,$0x21\n" // ICW4 (master) "mov $0x01,%al\n" "outb %al,$0xa1\n" // ICW4 (slave) "mov %dl,%al\n" "outb %al,$0x21\n" // IMR (master) "mov %dh,%al\n" "outb %al,$0xa1\n" // IMR (slave) "ret\n" );
extern "C" void p32_enable_nmi_and_irq(void); __asm__( ".text\n" ".globl p32_enable_nmi_and_irq\n" ".globl _p32_enable_nmi_and_irq\n" "p32_enable_nmi_and_irq:\n" "_p32_enable_nmi_and_irq:\n" "mov $0x8D,%al\n" "outb %al,$0x70\n" // enable NMI "inb $0x80,%al\n" // I/O wait "inb $0x71,%al\n" // read port 70h "sti\n" "ret\n" );