I'm trying to enable interrupts in my OS but QEMU keeps crashing.
What I know:
- My IDT is filled in properly:
- My ISRs are getting called.
Here is my code:
idt.cpp (Adapted from a few example from the wiki )
Code: Select all
#include <stddef.h>
#include <stdint.h>
#include "idt.h"
#include "terminal.h"
#define IDT_ENTRY_COUNT 0xFF
IDT_Class IDT;
uint8_t _IDT[IDT_ENTRY_COUNT * 8];
void lidt(void* base, uint16_t size)
{ // This function works in 32 and 64bit mode
struct {
uint16_t length;
void* base;
} __attribute__((packed)) IDTR = { size, base };
asm ( "lidt %0" : : "m"(IDTR) ); // let the compiler choose an addressing mode
}
void encodeIdtEntry(uint8_t *target, uint32_t offset, uint16_t selector, uint8_t type)
{
// Encode the offset
target[0] = offset & 0xFF;
target[1] = (offset >> 8) & 0xFF;
target[6] |= (offset >> 16) & 0xFF;
target[7] |= (offset >> 24) & 0xFF;
// Encode the selector
target[2] = selector & 0xFF;
target[3] = (selector >> 8) & 0xFF;
// Encode the Zero
target[4] = 0x00;
// And... Type
target[5] = type;
}
void IDT_Class::load() {
for (int i = 0; i < 0xFF; i++) {
encodeIdtEntry(&_IDT[i * 8], (uint32_t)&ASM_ISR_0, 8, 0x8E);
}
encodeIdtEntry(&_IDT[33 * 8], (uint32_t)&ASM_ISR_KBD, 8, 0x8E);
lidt(&_IDT, 0xFF);
}
uint8_t IDT_Class::DEBUG(int index) {
return _IDT[index];
}
Code: Select all
.align 4
.global ASM_ISR_0
.global ASM_ISR_KBD
ASM_ISR_0:
pushal;
cld /* C code following the sysV ABI requires DF to be clear on function entry */
call ISR_0
popal;
iret
ASM_ISR_KBD:
pushal;
cld /* C code following the sysV ABI requires DF to be clear on function entry */
call ISR_KBD
popal;
iret
Code: Select all
#include "io.h"
#include "terminal.h"
extern "C"
{
void ISR_0(void) {
outb(0x20,0x20);
//Terminal.println("DEFAULT !");
}
void ISR_KBD(void) {
outb(0x20,0x20);
char b = inb(0x60);
Terminal.println("KEYBOARD !");
}
}
Code: Select all
#include <stddef.h>
#include <stdint.h>
#include "terminal.h"
#include "io.h"
#include "gdt.h"
#include "idt.h"
#include "string.h"
/* reinitialize the PIC controllers, giving them specified vector offsets
rather than 8h and 70h, as configured by default */
#define ICW1_ICW4 0x01 /* ICW4 (not) needed */
#define ICW1_SINGLE 0x02 /* Single (cascade) mode */
#define ICW1_INTERVAL4 0x04 /* Call address interval 4 (8) */
#define ICW1_LEVEL 0x08 /* Level triggered (edge) mode */
#define ICW1_INIT 0x10 /* Initialization - required! */
#define ICW4_8086 0x01 /* 8086/88 (MCS-80/85) mode */
#define ICW4_AUTO 0x02 /* Auto (normal) EOI */
#define ICW4_BUF_SLAVE 0x08 /* Buffered mode/slave */
#define ICW4_BUF_MASTER 0x0C /* Buffered mode/master */
#define ICW4_SFNM 0x10 /* Special fully nested (not) */
#define PIC1 0x20 /* IO base address for master PIC */
#define PIC2 0xA0 /* IO base address for slave PIC */
#define PIC1_COMMAND PIC1
#define PIC1_DATA (PIC1+1)
#define PIC2_COMMAND PIC2
#define PIC2_DATA (PIC2+1)
/*
arguments:
offset1 - vector offset for master PIC
vectors on the master become offset1..offset1+7
offset2 - same for slave PIC: offset2..offset2+7
*/
void PIC_remap(int offset1, int offset2)
{
unsigned char a1, a2;
a1 = inb(PIC1_DATA); // save masks
a2 = inb(PIC2_DATA);
outb(PIC1_COMMAND, ICW1_INIT+ICW1_ICW4); // starts the initialization sequence (in cascade mode)
io_wait();
outb(PIC2_COMMAND, ICW1_INIT+ICW1_ICW4);
io_wait();
outb(PIC1_DATA, offset1); // ICW2: Master PIC vector offset
io_wait();
outb(PIC2_DATA, offset2); // ICW2: Slave PIC vector offset
io_wait();
outb(PIC1_DATA, 4); // ICW3: tell Master PIC that there is a slave PIC at IRQ2 (0000 0100)
io_wait();
outb(PIC2_DATA, 2); // ICW3: tell Slave PIC its cascade identity (0000 0010)
io_wait();
outb(PIC1_DATA, ICW4_8086);
io_wait();
outb(PIC2_DATA, ICW4_8086);
io_wait();
outb(PIC1_DATA, a1); // restore saved masks.
outb(PIC2_DATA, a2);
}
extern "C" // Use C link for kernel_main
void kernel_main(void)
{
Terminal.Init(80, 25);
Terminal.setColor(0x0E);
Terminal.clear();
Terminal.hideCursor();
Terminal.println("Welcome to MemeOS !");
Terminal.setColor(0x07);
Terminal.print("Loading GDT... ");
GDT.load();
Terminal.OK();
Terminal.print("Remapping PIC... ");
PIC_remap(0x20, 0x28);
Terminal.OK();
Terminal.print("Loading IDT... ");
IDT.load();
Terminal.OK();
for (long i = 0; i < 8; i++) {
Terminal.print("IDT[33] at index 0x");
Terminal.print(dumpHexByte(i));
Terminal.print(" = 0x");
Terminal.println(dumpHexByte(IDT.DEBUG((8 * 33) + i)));
}
Terminal.println("Allowing interrupts...");
asm("sti");
Terminal.println("<- DONE ->");
for(;;) {
asm("hlt");
}
}
Symtoms:
- QEMU reboots
- BOCHS says:
Code: Select all
00456186320e[CPU0 ] check_cs(0x0014): conforming code seg descriptor dpl > cpl, dpl=3, cpl=0
<- ^^^ A LOT of times this line, not gonna copy them all ^^^ ->
00456186416e[CPU0 ] check_cs(0x0014): conforming code seg descriptor dpl > cpl, dpl=3, cpl=0
00456186416e[CPU0 ] interrupt(): gate descriptor is not valid sys seg (vector=0x0d)
00456186424e[CPU0 ] check_cs(0x0014): conforming code seg descriptor dpl > cpl, dpl=3, cpl=0
00456186424e[CPU0 ] interrupt(): gate descriptor is not valid sys seg (vector=0x0d)
00456186432e[CPU0 ] check_cs(0x0014): conforming code seg descriptor dpl > cpl, dpl=3, cpl=0
00456186432e[CPU0 ] interrupt(): gate descriptor is not valid sys seg (vector=0x0d)
00456186440e[CPU0 ] check_cs(0x0014): conforming code seg descriptor dpl > cpl, dpl=3, cpl=0
00456186440e[CPU0 ] interrupt(): gate descriptor is not valid sys seg (vector=0x0d)
00456186440e[CPU0 ] interrupt(): gate descriptor is not valid sys seg (vector=0x08)
00456186440i[CPU0 ] CPU is in protected mode (active)
00456186440i[CPU0 ] CS.mode = 32 bit
00456186440i[CPU0 ] SS.mode = 32 bit
00456186440i[CPU0 ] EFER = 0x00000000
00456186440i[CPU0 ] | EAX=0000000e EBX=00000008 ECX=0000041a EDX=000003d5
00456186440i[CPU0 ] | ESP=00103080 EBP=00000000 ESI=00000000 EDI=00000000
00456186440i[CPU0 ] | IOPL=0 ID vip vif ac vm RF nt of df if tf sf zf af pf cf
00456186440i[CPU0 ] | SEG sltr(index|ti|rpl) base limit G D
00456186440i[CPU0 ] | CS:0008( 0001| 0| 0) 00000000 ffffffff 1 1
00456186440i[CPU0 ] | DS:0018( 0003| 0| 0) 00000000 ffffffff 1 1
00456186440i[CPU0 ] | SS:0018( 0003| 0| 0) 00000000 ffffffff 1 1
00456186440i[CPU0 ] | ES:0018( 0003| 0| 0) 00000000 ffffffff 1 1
00456186440i[CPU0 ] | FS:0018( 0003| 0| 0) 00000000 ffffffff 1 1
00456186440i[CPU0 ] | GS:0018( 0003| 0| 0) 00000000 ffffffff 1 1
00456186440i[CPU0 ] | EIP=00100014 (00100014)
00456186440i[CPU0 ] | CR0=0x60000011 CR2=0x00000000
00456186440i[CPU0 ] | CR3=0x00000000 CR4=0x00000000
00456186440i[CPU0 ] 0x0000000000100014>> iret : CF
00456186440e[CPU0 ] exception(): 3rd (13) exception with no resolution, shutdown status is 00h, resetting
00456186440i[SYS ] bx_pc_system_c::Reset(HARDWARE) called
00456186440i[CPU0 ] cpu hardware reset
00456186440i[APIC0 ] allocate APIC id=0 (MMIO enabled) to 0x0000fee00000