Triple fault when attempting to load the task register
Page 1 of 1

Author:  0xBADC0DE [ Sat Jun 22, 2019 9:00 am ]
Post subject:  Triple fault when attempting to load the task register

I've finished up writing my shell and filesystem for my operating system, and now have decided to move onto user mode and writing system calls. Though the difficulty I've been having in doing that is before actually entering user mode: trying to load a selector from the GDT into the task register, which results in a triple fault and the CPU resetting.

To setup the GDT, IDT, interrupts and exception handling, I followed http://www.osdever.net/bkerndev/Docs/intro.htm (bran's kernel development tutorial). Now for entering user mode, I was following http://jamesmolloy.co.uk/tutorial_html/ ... 0Mode.html (James Molly), but unfortunately couldn't get that to work. Since that wasn't working, I've been looking at other articles on this site about the GDT and exceptions, and the brokenthorne OS dev series to try and help me out. I've found some other questions similar to mine, but none of the answers there have helped me.

The specific instruction that is causing the processor to triple fault is
ltr %ax

The code I am using to install the TSS is similar to Jame's Molly's:
void install_tss(uint32_t i, uint16_t kernel_ss, uint16_t kernel_esp)
   gdt_set_descriptor(i, 0x00, 0xFFFFFFFF, 0x89, 0x00);

   memset(&tss_entry, 0, sizeof(tss_entry));

   tss_entry.ss0 = kernel_ss;
   tss_entry.esp0 = kernel_esp;

   tss_entry.cs = 0x0b;
   tss_entry.ss = 0x13;
   tss_entry.es = 0x13;
   tss_entry.ds = 0x13;
   tss_entry.fs = 0x13;
   tss_entry.gs = 0x13;

      "mov $0x2b, %ax\n"
      "ltr %ax"

I have read the article about the known bugs in that tutorial, and my code doesn't appear to have any of the problems discussed in that article.

This is the function I am using to initialize the GDT:
void init_gdt()
   gdt_ptr.limit = (sizeof(struct gdt_descriptor) * MAX_DESCRIPTORS) - 1;
   gdt_ptr.base  = (uint32_t) &gdt_desc;

   gdt_set_descriptor(0, 0, 0, 0, 0); // Null descriptor
   gdt_set_descriptor(1, 0, 0xFFFFFFFF, 0x9A, 0xCF); // Kernel code descriptor
   gdt_set_descriptor(2, 0, 0xFFFFFFFF, 0x92, 0xCF); // Kernel data descriptor
   gdt_set_descriptor(3, 0, 0xFFFFFFFF, 0xFA, 0xCF); // User code descriptor
   gdt_set_descriptor(4, 0, 0xFFFFFFFF, 0xF2, 0xCF); // User data descriptor

   // Install the TSS to selector 5
   install_tss(5, 0x10, 0x0);

   /* install the GDT */

I added the flag
-d int,cpu_reset
to the qemu command when running my OS, and noticed it ended with a triple fault, with ~2 or 3 general protection faults before that. I tried debugging using gdb, but that didn't help since it still just crashed on the
instruction and doesn't provide any other information.

I also read somewhere that a triple fault (or something of the sort) is the result of fault exception handling code. I'm pretty sure that my exception handling code is catching exceptions, because when I do
asm("int $0")
I get a division by zero exception. The IRQs have been remapped and the timer is firing as expected. Should exceptions always result in the exception handler being called (as in my code should be catching exceptions) or are there occasions (like loading some invalid value into the task register) that won't be caught by the exception handler and immediately result in a triple fault/crash?).

My OS can be found at https://github.com/aaron2212/XOS, though I have not pushed the latest code about entering user mode, or rather, even just setting up the task state segment.

I have tried everything I can think of, and searched all of google with avail, so any help is greatly appreciated :D

Author:  GhelloWorld [ Sun Jun 23, 2019 6:05 am ]
Post subject:  Re: Triple fault when attempting to load the task register

Instead of using 0 and 0xFFFFFFFF as the base for the TSS GDT descriptor you should set the base to the address of the tss and the limit to the same address + size of the tss. This way the CPU can read where the tss is located.
Try changing this line:
gdt_set_descriptor(i, 0x00, 0xFFFFFFFF, 0x89, 0x00);

To something like this:
gdt_set_descriptor(i, &tss_entry, $tss_entry + size of the tss, 0x89, 0x00);

Hopefully it will then work :D

Author:  0xBADC0DE [ Sun Jun 23, 2019 10:51 am ]
Post subject:  Re: Triple fault when attempting to load the task register

Thanks so much for the reply @GhelloWorld, but unfortunately that doesn't seem to work :(

Author:  MichaelPetch [ Sun Jun 23, 2019 12:55 pm ]
Post subject:  Re: Triple fault when attempting to load the task register

Why don't you update your repository with the code that doesn't work?

Author:  0xBADC0DE [ Tue Jun 25, 2019 9:14 am ]
Post subject:  Re: Triple fault when attempting to load the task register

@MichaelPetch thanks. I have pushed the code to the "user-mode" branch

Author:  MichaelPetch [ Tue Jun 25, 2019 11:29 am ]
Post subject:  Re: Triple fault when attempting to load the task register

It seems you are doing the ltr before you have installed the GDT! You'll need to move the inline assembly that does the LTR after you call install_gdt. I think the TSS descriptor should be set up this way:
gdt_set_descriptor(i, base, limit-1, 0x89, 0x00);
The limit is relative to the base (don't add base to limit) and you should be subtracting 1 from the limit in the descriptor entry. You also have a problem in your inline assembly (inline assembly is hard to get right) but you can't modify a register without telling the compiler you did so. You can fix the inline assembly by passing the TSS's selector as a 16-bit value and have the compiler pick a register for you. It could look like:
    asm (
        "ltr %0" :: "r"((uint16_t)0x2b)

Author:  0xBADC0DE [ Thu Jun 27, 2019 6:25 am ]
Post subject:  Re: Triple fault when attempting to load the task register

@MichaelPetch thank you SO much! I don't know how I made such a dumb mistake - face palm!
This solved my problem :D :D

Page 1 of 1 All times are UTC - 6 hours
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group