I'm developing small OS. It is correctly working in emulators (qemu, bochs and virtualbox). I have tried to run it on two baremetal old machines (old because it doesn't have uefi). On friend's desktop everything works fine. But on my netbook OS gives GPF exception.
Netbook is Samsung NC110P.
I tried to localize the problem. Minimal steps to repeat the exception:
1. init memory, enable paging.
2. init gdt
3. init idt (besides standard exception, also create handler for 32 exception vector. All other entries in IDT are zero)
4. init pic, remap irqs (shift is 32)
5. init pit, unmask only IRQ0
6. enable interrupt (sti)
7. fall into forever loop.
After interrupts are enabled PIT generate an exception, which is passed to handler, handler prints values, which look ok. I handler I don't do EOI, so PIT interrupt will not repeat.
If I put forever loop before iret (in exception handler), then system correctlry freeze. If not, then after iret, I get GPF exception with error code 0x13b.
Error code 0x13b is segment error in IDT, segment selector is 39. But 39th entry in IDT is zero.
I don't understand why it happens, and why only on on machine. Do you have any idea?
Code that may be usefull
"main" code
Code: Select all
...
asm("sti");
while(1) {
}
Code: Select all
idt_entry_t pok_idt[IDT_SIZE];
void ja_idt_init (void)
{
sysdesc_t sysdesc;
/* Clear table */
memset(pok_idt, 0, sizeof (idt_entry_t) * IDT_SIZE);
/* Load IDT */
sysdesc.limit = sizeof (pok_idt);
sysdesc.base = (uint32_t)pok_idt;
asm ("lidt %0"
:
: "m" (sysdesc));
}
void pok_idt_set_gate (uint8_t index,
void (*entry)(void),
e_idte_type t)
{
uint32_t offset = (uint32_t)entry;
pok_idt[index].offset_low = (offset) & 0xFFFF;
pok_idt[index].offset_high = (offset >> 16) & 0xFFFF;
pok_idt[index].segsel = GDT_CORE_CODE_SEGMENT << 3;
pok_idt[index].dpl = 3;
pok_idt[index].type = t;
pok_idt[index].d = 1;
pok_idt[index].res0 = 0; /* reserved */
pok_idt[index].res1 = 0; /* reserved */
pok_idt[index].present = 1;
}
const struct exception_descriptor exception_list[] =
{
{EXCEPTION_DIVIDE_ERROR, exception_DIVIDE_ERROR},
{EXCEPTION_DEBUG, exception_DEBUG},
{EXCEPTION_NMI, exception_NMI},
{EXCEPTION_BREAKPOINT, exception_BREAKPOINT},
{EXCEPTION_OVERFLOW, exception_OVERFLOW},
{EXCEPTION_INVALIDOPCODE, exception_INVALIDOPCODE},
{EXCEPTION_NOMATH_COPROC, exception_NOMATH_COPROC},
{EXCEPTION_DOUBLEFAULT, exception_DOUBLEFAULT},
{EXCEPTION_COPSEG_OVERRUN, exception_COPSEG_OVERRUN},
{EXCEPTION_INVALID_TSS, exception_INVALID_TSS},
{EXCEPTION_SEGMENT_NOT_PRESENT, exception_SEGMENT_NOT_PRESENT},
{EXCEPTION_STACKSEG_FAULT, exception_STACKSEG_FAULT},
{EXCEPTION_GENERAL_PROTECTION, exception_GENERAL_PROTECTION},
{EXCEPTION_PAGEFAULT, exception_PAGEFAULT},
{EXCEPTION_FPU_FAULT, exception_FPU_FAULT},
{EXCEPTION_ALIGNEMENT_CHECK, exception_ALIGNEMENT_CHECK},
{EXCEPTION_MACHINE_CHECK, exception_MACHINE_CHECK},
{EXCEPTION_SIMD_FAULT, exception_SIMD_FAULT},
{EXCEPTION_TIMER, exception_TIMER}, //32
{0, NULL}
};
void ja_exception_init(void)
{
int i;
for (i = 0; exception_list[i].handler != NULL; ++i)
{
pok_idt_set_gate (exception_list[i].vector,
exception_list[i].handler,
IDTE_INTERRUPT);
}
}
Code: Select all
.macro INTERRUPT_PROLOGUE_ERROR
pusha
push %ds //push 16 bit value in 32 bit cell
push %es //push 16 bit value in 32 bit cell
mov $0x10, %ax
mov %ax, %ds
mov %ax, %es
mov $0, %ebp // Mark current frame as first
push %esp // Interrupt frame is the only parameter to the followed functions.
.endm
.macro INTERRUPT_PROLOGUE
pushl $0 // error_code
INTERRUPT_PROLOGUE_ERROR // Fallback to the common code
.endm
INTERRUPT_EPILOGUE:
//call update_tss
addl $4, %esp
pop %es
pop %ds
popa
addl $4, %esp
iret
.global exception_TIMER
.type exception_TIMER ,@function
exception_TIMER:
INTERRUPT_PROLOGUE
call exception_TIMER_handler
jmp INTERRUPT_EPILOGUE
Code: Select all
typedef struct
{
uint16_t es;
uint16_t padding1;
uint16_t ds;
uint16_t padding2;
// These registers are ordered for pusha/popa
uint32_t edi;
uint32_t esi;
uint32_t ebp;
uint32_t __esp;
uint32_t ebx;
uint32_t edx;
uint32_t ecx;
uint32_t eax;
/* These are pushed by interrupt */
uint32_t error; /* Error code or padding */
uint32_t eip;
uint16_t cs;
uint16_t padding3;
uint32_t eflags;
/* Only pushed with privilege switch */
/* (Check cs content to have original CPL) */
uint32_t esp;
uint16_t ss;
uint16_t padding4;
} __attribute__((packed)) interrupt_frame;
void exception_TIMER_handler(interrupt_frame* frame)
{
printf ("ES: %x, DS: %x\n", frame->es, frame->ds);
printf ("CS: %x, SS: %x\n", frame->cs, frame->ss);
printf ("EDI: %lx, ESI: %lx\n", frame->edi, frame->esi);
printf ("EBP: %lx, ESP: %lx\n", frame->ebp, frame->esp);
printf ("EAX: %lx, ECX: %lx\n", frame->eax, frame->ecx);
printf ("EDX: %lx, EBX: %lx\n", frame->edx, frame->ebx);
printf ("EIP: %lx, ErrorCode: %lx\n", frame->eip, frame->error);
printf ("EFLAGS: %lx\n\n", frame->eflags);
}