Page 1 of 1

Triple Fault after STI

Posted: Tue Sep 08, 2020 2:18 pm
by KoizumiChineko
I have problem with setting up an IDT, I read 3 different GDT and IDT tutorials and still I'm unable to set it up correctly, as far as I can investigate code with "HelpMe" function I can tell that CPU do not event jump into "HandleInterrupt" asm section. I'm fighting two days with this and this is probably my lack of knowledge. Here is code:

GDT.h:

Code: Select all

#ifndef __GDT_H
#define __GDT_H

#include <stdint.h>
#include "kernelstdio.h"

struct gdt_entry
{
	uint16_t limit_low;
	uint16_t base_low;
	
	uint8_t base_middle;
	uint8_t access;
	uint8_t granularity;
	uint8_t base_high;
	
}__attribute__((packed));

struct gdt_ptr
{
	uint16_t limit;
	uint32_t base;
	
}__attribute__((packed));

extern struct gdt_entry gdt[3];
extern struct gdt_ptr gp;

extern void gdt_flush();
extern void gdt_set_gate(uint32_t num, uint32_t base, uint32_t limit, uint8_t access, uint8_t gran);
extern void gdt_install();
#endif
GDT.c

Code: Select all

#include "GDT.h"

struct gdt_entry gdt[3];
struct gdt_ptr gp;

void gdt_set_gate(uint32_t num, uint32_t base, uint32_t limit, uint8_t access, uint8_t gran)
{
	/* Setup the descriptor base address */
		gdt[num].base_low 		= (base & 0xFFFF);
		gdt[num].base_middle	= (base >> 16) & 0xFF;
		gdt[num].base_high		= (base >> 24) & 0xFF;
		
	/* Setup the descriptor limits */
		gdt[num].limit_low 		= (limit & 0xFFFF);
		gdt[num].granularity	= ((limit >> 16) & 0x0F);
		
	/* Finally set up the granularity and access flags */
		gdt[num].granularity |= (gran & 0xF0);
		gdt[num].access = access;
}

void gdt_install()
{		
	
		/* NULL descriptor*/
		gdt_set_gate(0, 0, 0, 0, 0);
		
		/* CODE segment 4GB */
		gdt_set_gate(1, 0, 0xFFFFFFFF, 0x9A, 0xCF);

		/* DATA segment 4GB */
		gdt_set_gate(2, 0, 0xFFFFFFFF, 0x92, 0xCF);
		
		/*Flush old GDT and aplly new one*/

		gp.limit = (sizeof(struct gdt_entry) * 3) - 1;
		gp.base = gdt;
	
		gdt_flush();
}
GDTasm.s

Code: Select all

.section .text

.global gdt_flush
.extern gp

gdt_flush:

	lgdt gp
	jmp $0x08, $flush2
	
flush2:
	mov $0x10, %eax
	mov %eax,  %ds
	mov %eax,  %es
	mov %eax,  %fs
	mov %eax,  %gs
	mov %eax,  %ss
	ret
interrupt.h

Code: Select all

#ifndef __INTERRUPT_H
#define __INTERRUPT_H

#include <stdint.h>

#include "GDT.h"
#include "kernelstdio.h"

struct idt_entry
{
	uint16_t handlerAddressLow;
	uint16_t gdt_codeSegmentSelector;
	uint8_t reserved;
	uint8_t access;
	uint16_t handlerAddressHigh; 
	
}__attribute__((packed));

struct idt_ptr
{
	uint16_t limit;
	uint32_t base;
	
}__attribute__((packed));


extern struct idt_entry idt[256];
extern struct idt_ptr ip;


extern void InitInterupts();
extern void ActivateInterrupts();
extern void SetIDTentry(uint8_t INT_number, uint16_t CodeSegmentSelectorOffset, void(*handler)(), uint8_t DescriptorPrivilidgeLevel, uint8_t DescriptorType);


extern uint32_t HandleInterrupt(uint8_t INT_number, uint32_t ESP);

extern void HandleInterruptRequest0x00();
extern void HandleInterruptRequest0x01(); 

extern void IgnoreInterruptRequest();

extern void HelpMe();
extern void idt_install();
#endif
interrupt.c

Code: Select all

#include "interrupt.h"

struct idt_entry idt[256];
struct idt_ptr ip;

void InitInterupts()
{
	const uint8_t IDT_INT_GATE = 0xE;
	
	uint16_t CodeSegment = &gdt[1];
	
	
	for(uint16_t i=0; i<256; ++i)
	{
		SetIDTentry(i, CodeSegment, &IgnoreInterruptRequest, 0, IDT_INT_GATE);
	}
	
	SetIDTentry(0x20, CodeSegment, &HandleInterruptRequest0x00, 0, IDT_INT_GATE);
	SetIDTentry(0x21, CodeSegment, &HandleInterruptRequest0x01, 0, IDT_INT_GATE);
	
	ip.limit = (sizeof(struct idt_entry) * 256) - 1;
	ip.base = idt;
	
	idt_install();
	
}
void ActivateInterrupts()
{
		asm volatile("sti");
}


void SetIDTentry(uint8_t INT_number, uint16_t CodeSegmentSelectorOffset, void(*handler)(), uint8_t DescriptorPrivilidgeLevel, uint8_t DescriptorType)
{
	const uint8_t IDT_DESC_PRESENT = 0x80;
	
	idt[INT_number].handlerAddressLow 		= ((uint32_t)handler) & 0xFFFF;
	idt[INT_number].handlerAddressHigh 		= ((uint32_t)handler >> 16) & 0xFFFF;
	idt[INT_number].gdt_codeSegmentSelector = CodeSegmentSelectorOffset;
	idt[INT_number].access 					= IDT_DESC_PRESENT | DescriptorType | ((DescriptorPrivilidgeLevel & 3) << 5);
	idt[INT_number].reserved 				= 0;
}



uint32_t HandleInterrupt(uint8_t INT_number, uint32_t ESP)
{
	
	printf("INTERRUPT\n");
	return ESP;	
}

void HelpMe()
{
		printf("Help\n");
}
interruptasm.s

Code: Select all

.set IRQ_BASE, 0x20

.section .text

.extern HandleInterrupt
.extern HelpMe
.extern ip

.global idt_install
.global IgnoreInterruptRequest


.macro MyHandleInterruptRequest num
.global HandleInterruptRequest\num\()

HandleInterruptRequest\num\():
	movb $\num + IRQ_BASE, (interruptnumber)
	jmp int_bottom

.endm	

MyHandleInterruptRequest 0x00
MyHandleInterruptRequest 0x01


.macro MyHandleException num
.global HandleException\num\()

HandleException\num\():
	movb $\num, (interruptnumber)
	jmp int_bottom

.endm	


idt_install:
	lidt ip
	ret

int_bottom:
	
	pusha
	pushl %ds
	pushl %es
	pushl %fs
	pushl %gs

	pushl %esp
	push (interruptnumber)
	call HandleInterrupt
	mov %eax, %esp
	
	popl %gs
	popl %fs
	popl %es
	popl %ds
	popa
	
IgnoreInterruptRequest:

	iret 
	
	
.data 
	interruptnumber: .byte 0
I hope someone would help me.

Re: Triple Fault after STI

Posted: Fri Sep 11, 2020 8:55 pm
by Octocontrabass
Are you compiling with extra warnings enabled? At the very least I'd recommend "-Wall" and "-Wextra" but there are probably others you could enable as well.
KoizumiChineko wrote:interrupt.c

Code: Select all

	uint16_t CodeSegment = &gdt[1];
What is the value of CodeSegment here? What value should it be?

Re: Triple Fault after STI

Posted: Fri Sep 11, 2020 10:06 pm
by KoizumiChineko
Octocontrabass wrote:Are you compiling with extra warnings enabled? At the very least I'd recommend "-Wall" and "-Wextra" but there are probably others you could enable as well.
KoizumiChineko wrote:interrupt.c

Code: Select all

	uint16_t CodeSegment = &gdt[1];
What is the value of CodeSegment here? What value should it be?
I replaced that with this code and seems to work for now.

Code: Select all

	uint16_t CodeSegment;
	
	asm volatile("mov %%CS, %0": "=r"(CodeSegment) :);
Thank you for pointing this out, I confused code segment selector loaded to register with descriptor for code segment.

Re: Triple Fault after STI

Posted: Fri Sep 11, 2020 10:18 pm
by Octocontrabass
I guess that works, but wouldn't it be easier to just use the number 8? (Actually 8 times the index into the GDT, but the index is 1 here...)