Triple fault on GDT install

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
User avatar
casnix
Member
Member
Posts: 67
Joined: Fri Jan 14, 2011 7:24 pm

Triple fault on GDT install

Post by casnix »

Hello,

My machine triple faults on my installation of the GDT, and, does it before the routines that should happen first happen (order:
parse command line
print messages
check boot loader info
install gdt
install idt

Instead it's doing it in this order:
install gdt
parse command line
print half the messages
crash

I had no problems before adding the gdt.

Anyway, I've read several posts about this, but nothing seems to fix my problem. And bochs won't compile for me :evil: So I'm limited on information about what happens when.

Code: Select all

gdt.c
#include <gdt.h>
#include <link.h>

extern void gdt_flush(unsigned int);

void __install_gdt();
static void gdt_set_gate(int,unsigned int,unsigned int,unsigned char,unsigned char);

gdt_entry_t gdt_entries[5];
gdt_ptr_t   gdt_ptr;

void __install_gdt()
{
   gdt_ptr.limit = (sizeof(gdt_entry_t) * 5) - 1;
   gdt_ptr.base  = (unsigned int)&gdt_entries;

   gdt_set_gate(0, 0, 0, 0, 0);                // Null segment
   gdt_set_gate(1, 0, 0xFFFFFFFF, 0x9A, 0xCF); // Code segment
   gdt_set_gate(2, 0, 0xFFFFFFFF, 0x92, 0xCF); // Data segment
   gdt_set_gate(3, 0, 0xFFFFFFFF, 0xFA, 0xCF); // User mode code segment
   gdt_set_gate(4, 0, 0xFFFFFFFF, 0xF2, 0xCF); // User mode data segment

   gdt_flush((unsigned int)&gdt_ptr);
}

// Set the value of one GDT entry.
static void gdt_set_gate(int num, unsigned int base, unsigned int limit, unsigned char access, unsigned char gran)
{
   gdt_entries[num].base_low    = (base & 0xFFFF);
   gdt_entries[num].base_middle = (base >> 16) & 0xFF;
   gdt_entries[num].base_high   = (base >> 24) & 0xFF;

   gdt_entries[num].limit_low   = (limit & 0xFFFF);
   gdt_entries[num].granularity = (limit >> 16) & 0x0F;

   gdt_entries[num].granularity |= gran & 0xF0;
   gdt_entries[num].access      = access;
}

Code: Select all

gdt.h

#ifndef __GDT_H
#define __GDT_H

struct gdt_entry_struct
{
   unsigned short limit_low;           // The lower 16 bits of the limit.
   unsigned short base_low;            // The lower 16 bits of the base.
   unsigned char  base_middle;         // The next 8 bits of the base.
   unsigned char  access;              // Access flags, determine what ring this segment can be used in.
   unsigned char  granularity;
   unsigned char  base_high;           // The last 8 bits of the base.
} __attribute__((packed));
typedef struct gdt_entry_struct gdt_entry_t;

struct gdt_ptr_struct
{
   unsigned short limit;               // The upper 16 bits of all selector limits.
   unsigned int base;                // The address of the first gdt_entry_t struct.
}
 __attribute__((packed));
typedef struct gdt_ptr_struct gdt_ptr_t;

#endif

Code: Select all

;gdt.asm


[GLOBAL gdt_flush]    ; Allows the C code to call gdt_flush().

gdt_flush:
   mov eax, [esp+4]  ; Get the pointer to the GDT, passed as a parameter.
   lgdt [eax]        ; Load the new GDT pointer

   mov ax, 0x10      ; 0x10 is the offset in the GDT to our data segment
   mov ds, ax        ; Load all data segment selectors
   mov es, ax
   mov fs, ax
   mov gs, ax
   mov ss, ax
   jmp 0x08:.flush   ; 0x08 is the offset to our code segment: Far jump!
.flush:
   ret
I know it's better to do the lgdt after the far jump, but I don't know if I would have to move 0x10 into ax and ax into the segments afterwards too (I assume so because I think I would have to load the new GDT ptr first). I wanna ask "please help?!?!?" but as that's not really gonna appease the computer demons............(shifty look)

Is there anything wrong with my code (I hope it's that)?
You are a computer.
~ MCS ~
User avatar
DavidCooper
Member
Member
Posts: 1150
Joined: Wed Oct 27, 2010 4:53 pm
Location: Scotland

Re: Triple fault on GDT install

Post by DavidCooper »

Is it a good idea to call a routine to switch to protected mode and then ret? The call happens in real mode and the ret in protected mode...

Edit: I can't follow your GDT at all so I can't check it - I've never seen something so simple made so complicated.
Help the people of Laos by liking - https://www.facebook.com/TheSBInitiative/?ref=py_c

MSB-OS: http://www.magicschoolbook.com/computing/os-project - direct machine code programming
User avatar
casnix
Member
Member
Posts: 67
Joined: Fri Jan 14, 2011 7:24 pm

Re: Triple fault on GDT install

Post by casnix »

Sorry, probably should have mentioned: I'm already in Pmode.
You are a computer.
~ MCS ~
User avatar
DavidCooper
Member
Member
Posts: 1150
Joined: Wed Oct 27, 2010 4:53 pm
Location: Scotland

Re: Triple fault on GDT install

Post by DavidCooper »

Can you explain what the previous GDT looks like and what the new one is supposed to look like (in terms of the actual bytes you want to end up in it). I'd also like to understand why you're replacing the old GDT. Are you calling this code in 32-bit mode and retting in 32-bit mode?
Help the people of Laos by liking - https://www.facebook.com/TheSBInitiative/?ref=py_c

MSB-OS: http://www.magicschoolbook.com/computing/os-project - direct machine code programming
User avatar
casnix
Member
Member
Posts: 67
Joined: Fri Jan 14, 2011 7:24 pm

Re: Triple fault on GDT install

Post by casnix »

I am calling in 32 bit and retting in 32 bit, and don't leave 32bit in between.

gdt_set_gate(0, 0, 0, 0, 0); // Null segment
gdt_set_gate(1, 0, 0xFFFFFFFF, 0x9A, 0xCF); // Code segment
gdt_set_gate(2, 0, 0xFFFFFFFF, 0x92, 0xCF); // Data segment
gdt_set_gate(3, 0, 0xFFFFFFFF, 0xFA, 0xCF); // User mode code segment
gdt_set_gate(4, 0, 0xFFFFFFFF, 0xF2, 0xCF); // User mode data segment

I'm not giving any bytes yet, I assume....hold on, let me check sommat...
You are a computer.
~ MCS ~
User avatar
casnix
Member
Member
Posts: 67
Joined: Fri Jan 14, 2011 7:24 pm

Re: Triple fault on GDT install

Post by casnix »

Okay, the GDT is not causing the triple fault...maybe it's my IDT. Be right back..

[EDIT]: Okay, the IDT doesn't finish initializing...
You are a computer.
~ MCS ~
User avatar
DavidCooper
Member
Member
Posts: 1150
Joined: Wed Oct 27, 2010 4:53 pm
Location: Scotland

Re: Triple fault on GDT install

Post by DavidCooper »

casnix wrote:I had no problems before adding the gdt.
Or maybe they just didn't show up before that. You can't really have a cause causing an effect before it's been triggered.

Edit: I'm thinking in terms of events happening in the wrong order and the last item being blamed for this.
Help the people of Laos by liking - https://www.facebook.com/TheSBInitiative/?ref=py_c

MSB-OS: http://www.magicschoolbook.com/computing/os-project - direct machine code programming
User avatar
casnix
Member
Member
Posts: 67
Joined: Fri Jan 14, 2011 7:24 pm

Re: Triple fault on GDT install

Post by casnix »

...am I supposed to sti before setting up the IDT? 'Cause the GDT installs and the IDT stops.

I've only gotten to the ISRs, not IRQs, if it matters.
You are a computer.
~ MCS ~
User avatar
DavidCooper
Member
Member
Posts: 1150
Joined: Wed Oct 27, 2010 4:53 pm
Location: Scotland

Re: Triple fault on GDT install

Post by DavidCooper »

What do you mean by "the IDT stops"?

Edit: And why would you want to set the interrupt flag before you've got everything in place to handle the interrupts?

Perhaps someone else can take this up - I'm going offline for 24 hours.
Help the people of Laos by liking - https://www.facebook.com/TheSBInitiative/?ref=py_c

MSB-OS: http://www.magicschoolbook.com/computing/os-project - direct machine code programming
User avatar
casnix
Member
Member
Posts: 67
Joined: Fri Jan 14, 2011 7:24 pm

Re: Triple fault on GDT install

Post by casnix »

I mean the computer hangs when installing the IDT.

Code: Select all

__install_idt();
__asm__ __volatile__ ("int $0x3");

// Above causes the triple fault.  But, if I do this:

__install_idt();
puts("Done with the IDT.\n");
// Nothing happens. The message doesn't print.

// And this triple faults:
__install_idt();
__asm__ __volatile("sti
                             int $0x3");
Should I post my IDT code?
You are a computer.
~ MCS ~
User avatar
DavidCooper
Member
Member
Posts: 1150
Joined: Wed Oct 27, 2010 4:53 pm
Location: Scotland

Re: Triple fault on GDT install

Post by DavidCooper »

casnix wrote:I mean the computer hangs when installing the IDT.
So the problem could well be there.
Should I post my IDT code?
I think so, but I doubt I'll understand it. I've got to go, but I'm sure someone will look at it.
Help the people of Laos by liking - https://www.facebook.com/TheSBInitiative/?ref=py_c

MSB-OS: http://www.magicschoolbook.com/computing/os-project - direct machine code programming
User avatar
casnix
Member
Member
Posts: 67
Joined: Fri Jan 14, 2011 7:24 pm

Re: Triple fault on GDT install

Post by casnix »

DavidCooper wrote:
casnix wrote:I mean the computer hangs when installing the IDT.
So the problem could well be there.
Should I post my IDT code?
I think so, but I doubt I'll understand it. I've got to go, but I'm sure someone will look at it.
Okay.

idt.h

Code: Select all

// idt.h -- From James Molloys kernel tutorial
//	-- http://www.jamesmolloy.co.uk

// A struct describing an interrupt gate.

#ifndef __IDT_H
#define __IDT_H
struct idt_entry_struct
{
   unsigned short base_lo;             // The lower 16 bits of the address to jump to when this interrupt fires.
   unsigned short sel;                 // Kernel segment selector.
   unsigned char  always0;             // This must always be zero.
   unsigned char  flags;               // More flags. See documentation.
   unsigned short base_hi;             // The upper 16 bits of the address to jump to.
} __attribute__((packed));
typedef struct idt_entry_struct idt_entry_t;

// A struct describing a pointer to an array of interrupt handlers.
// This is in a format suitable for giving to 'lidt'.
struct idt_ptr_struct
{
   unsigned short limit;
   unsigned int base;                // The address of the first element in our idt_entry_t array.
} __attribute__((packed));
typedef struct idt_ptr_struct idt_ptr_t;

// These extern directives let us access the addresses of our ASM ISR handlers.
extern void isr0 ();
extern void isr1 ();
extern void isr2 ();
extern void isr3 ();
extern void isr4 ();
extern void isr5 ();
extern void isr6 ();
extern void isr7 ();
extern void isr8 ();
extern void isr9 ();
extern void isr10();
extern void isr11();
extern void isr12();
extern void isr13();
extern void isr14();
extern void isr15();
extern void isr16();
extern void isr17();
extern void isr18();
extern void isr19();
extern void isr20();
extern void isr21();
extern void isr22();
extern void isr23();
extern void isr24();
extern void isr25();
extern void isr26();
extern void isr27();
extern void isr28();
extern void isr29();
extern void isr30();
extern void isr31();

#endif
That's from JamesM's tutorial. I wanna get something working before I change it too much.

idt.c

Code: Select all

// idt.c -- From James Molloys kernel tutorial
//	-- http://www.jamesmolloy.co.uk

#include <idt.h>
#include <link.h>

extern void idt_flush(unsigned int);
idt_entry_t idt_entries[256];
idt_ptr_t	idt_ptr;
void __install_idt();

static void idt_set_gate(unsigned char, unsigned int, unsigned short, unsigned char);

void __install_idt()
{
	idt_ptr.limit = sizeof(idt_entry_t) * 256 -1;
   idt_ptr.base  = (unsigned int)&idt_entries;

   memset(&idt_entries, 0, (unsigned int)sizeof(idt_entry_t)*256);

   idt_set_gate( 0, (unsigned int)isr0 , 0x08, 0x8E);
   idt_set_gate( 1, (unsigned int)isr1 , 0x08, 0x8E);
   idt_set_gate( 2, (unsigned int)isr2 , 0x08, 0x8E);
    idt_set_gate( 3, (unsigned int)isr3 , 0x08, 0x8E);
    idt_set_gate( 4, (unsigned int)isr4 , 0x08, 0x8E);
    idt_set_gate( 5, (unsigned int)isr5 , 0x08, 0x8E);
    idt_set_gate( 6, (unsigned int)isr6 , 0x08, 0x8E);
    idt_set_gate( 7, (unsigned int)isr7 , 0x08, 0x8E);
    idt_set_gate( 8, (unsigned int)isr8 , 0x08, 0x8E);
    idt_set_gate( 9, (unsigned int)isr9 , 0x08, 0x8E);
    idt_set_gate(10, (unsigned int)isr10, 0x08, 0x8E);
    idt_set_gate(11, (unsigned int)isr11, 0x08, 0x8E);
    idt_set_gate(12, (unsigned int)isr12, 0x08, 0x8E);
    idt_set_gate(13, (unsigned int)isr13, 0x08, 0x8E);
    idt_set_gate(14, (unsigned int)isr14, 0x08, 0x8E);
    idt_set_gate(15, (unsigned int)isr15, 0x08, 0x8E);
    idt_set_gate(16, (unsigned int)isr16, 0x08, 0x8E);
    idt_set_gate(17, (unsigned int)isr17, 0x08, 0x8E);
    idt_set_gate(18, (unsigned int)isr18, 0x08, 0x8E);
    idt_set_gate(19, (unsigned int)isr19, 0x08, 0x8E);
    idt_set_gate(20, (unsigned int)isr20, 0x08, 0x8E);
    idt_set_gate(21, (unsigned int)isr21, 0x08, 0x8E);
    idt_set_gate(22, (unsigned int)isr22, 0x08, 0x8E);
    idt_set_gate(23, (unsigned int)isr23, 0x08, 0x8E);
    idt_set_gate(24, (unsigned int)isr24, 0x08, 0x8E);
    idt_set_gate(25, (unsigned int)isr25, 0x08, 0x8E);
    idt_set_gate(26, (unsigned int)isr26, 0x08, 0x8E);
    idt_set_gate(27, (unsigned int)isr27, 0x08, 0x8E);
    idt_set_gate(28, (unsigned int)isr28, 0x08, 0x8E);
    idt_set_gate(29, (unsigned int)isr29, 0x08, 0x8E);
    idt_set_gate(30, (unsigned int)isr30, 0x08, 0x8E);
   idt_set_gate(31, (unsigned int)isr31, 0x08, 0x8E);

   idt_flush((unsigned int)&idt_ptr);
}

static void idt_set_gate(unsigned char num, unsigned int base, unsigned short sel, unsigned char flags)
{
   idt_entries[num].base_lo = base & 0xFFFF;
   idt_entries[num].base_hi = (base >> 16) & 0xFFFF;

   idt_entries[num].sel     = sel;
   idt_entries[num].always0 = 0;
   // We must uncomment the OR below when we get to using user-mode.
   // It sets the interrupt gate's privilege level to 3.
   idt_entries[num].flags   = flags /* | 0x60 */;
}
idt.asm

Code: Select all


; idt.asm -- From James Molloys kernel tutorials
;	-- http://www.jamesmolloy.co.uk

[GLOBAL idt_flush]    ; Allows the C code to call idt_flush().

idt_flush:
   mov eax, [esp+4]  ; Get the pointer to the IDT, passed as a parameter. 
   lidt [eax]        ; Load the IDT pointer.
   ret
   
%macro ISR_NOERRCODE 1  ; define a macro, taking one parameter
  [GLOBAL isr%1]        ; %1 accesses the first parameter.
  isr%1:
    cli
    push byte 0
    push byte %1
    jmp isr_common_stub
%endmacro

%macro ISR_ERRCODE 1
  [GLOBAL isr%1]
  isr%1:
    cli
    push byte %1
    jmp isr_common_stub
%endmacro

      
ISR_NOERRCODE 0
ISR_NOERRCODE 1
ISR_NOERRCODE 2
ISR_NOERRCODE 3
ISR_NOERRCODE 4
ISR_NOERRCODE 5
ISR_NOERRCODE 6
ISR_NOERRCODE 7
ISR_ERRCODE   8
ISR_NOERRCODE 9
ISR_ERRCODE   10
ISR_ERRCODE   11
ISR_ERRCODE   12
ISR_ERRCODE   13
ISR_ERRCODE   14
ISR_NOERRCODE 15
ISR_NOERRCODE 16
ISR_NOERRCODE 17
ISR_NOERRCODE 18
ISR_NOERRCODE 19
ISR_NOERRCODE 20
ISR_NOERRCODE 21
ISR_NOERRCODE 22
ISR_NOERRCODE 23
ISR_NOERRCODE 24
ISR_NOERRCODE 25
ISR_NOERRCODE 26
ISR_NOERRCODE 27
ISR_NOERRCODE 28
ISR_NOERRCODE 29
ISR_NOERRCODE 30
ISR_NOERRCODE 31

; In isr.c
[EXTERN isr_handler]

; This is our common ISR stub. It saves the processor state, sets
; up for kernel mode segments, calls the C-level fault handler,
; and finally restores the stack frame.
isr_common_stub:
   pusha                    ; Pushes edi,esi,ebp,esp,ebx,edx,ecx,eax

   mov ax, ds               ; Lower 16-bits of eax = ds.
   push eax                 ; save the data segment descriptor

   mov ax, 0x10  ; load the kernel data segment descriptor
   mov ds, ax
   mov es, ax
   mov fs, ax
   mov gs, ax

   call isr_handler

   pop eax        ; reload the original data segment descriptor
   mov ds, ax
   mov es, ax
   mov fs, ax
   mov gs, ax

   popa                     ; Pops edi,esi,ebp...
   add esp, 8     ; Cleans up the pushed error code and pushed ISR number
   sti
   iret           ; pops 5 things at once: CS, EIP, EFLAGS, SS, and ESP
isr.h

Code: Select all

//
// isr.h -- Interface and structures for high level interrupt service routines.
// Part of this code is modified from Bran's kernel development tutorials.
// Rewritten for JamesM's kernel development tutorials.
//

#ifndef __ISR_H
#define __ISR_H
typedef struct registers
{
   unsigned int ds;                  // Data segment selector
   unsigned int edi, esi, ebp, esp, ebx, edx, ecx, eax; // Pushed by pusha.
   unsigned int int_no, err_code;    // Interrupt number and error code (if applicable)
   unsigned int eip, cs, eflags, useresp, ss; // Pushed by the processor automatically.
} registers_t;

#endif
isr.c

Code: Select all


////
// isr.c -- High level interrupt service routines and interrupt request handlers.
// Part of this code is modified from Bran's kernel development tutorials.
// Rewritten for JamesM's kernel development tutorials.
//

#include <link.h>
#include <isr.h>

// This gets called from our ASM interrupt handler stub.
void isr_handler(registers_t regs)
{
	puts("Recieved interrupt: ");
	putnum(regs.int_no);
   	putc('\n');
}
So, yeah. Basically the code from JamesM's tutorial, 'cause (like I said before) I wanna get something working before I meddle with it and completely destroy something...
You are a computer.
~ MCS ~
User avatar
DavidCooper
Member
Member
Posts: 1150
Joined: Wed Oct 27, 2010 4:53 pm
Location: Scotland

Re: Triple fault on GDT install

Post by DavidCooper »

Surely that's the wrong approach. You shouldn't be trying to install tutorial code into your OS, but rather you should be using it to learn a little about how things can be done before building your own code from scratch. To take all that code and try to evolve it in small steps into something of your own design is going to be horribly messy. Tutorial code isn't guaranteed to work properly in any case.
Help the people of Laos by liking - https://www.facebook.com/TheSBInitiative/?ref=py_c

MSB-OS: http://www.magicschoolbook.com/computing/os-project - direct machine code programming
User avatar
casnix
Member
Member
Posts: 67
Joined: Fri Jan 14, 2011 7:24 pm

Re: Triple fault on GDT install

Post by casnix »

Well, it does compile. Anyhow, I just realized that messing with the descriptor tables has messed up the video memory. Which worries me. How, how is that possible?
You are a computer.
~ MCS ~
User avatar
DavidCooper
Member
Member
Posts: 1150
Joined: Wed Oct 27, 2010 4:53 pm
Location: Scotland

Re: Triple fault on GDT install

Post by DavidCooper »

casnix wrote:Well, it does compile. Anyhow, I just realized that messing with the descriptor tables has messed up the video memory. Which worries me. How, how is that possible?
What worries me is that you can't see how adding code to install descriptor tables has made earlier sections of your code run in the wrong order and messed up the video memory. You also seem to be making wild guesses as to the cause. Stick some proper progress markers into your code (and some delay loops if necessary so that you can space out the events through time at a rate that you can keep up with) - then you might have a chance of finding out where it begins to go wrong.
Help the people of Laos by liking - https://www.facebook.com/TheSBInitiative/?ref=py_c

MSB-OS: http://www.magicschoolbook.com/computing/os-project - direct machine code programming
Post Reply