OSDev.org

The Place to Start for Operating System Developers
It is currently Tue Nov 12, 2019 12:42 pm

All times are UTC - 6 hours




Post new topic Reply to topic  [ 7 posts ] 
Author Message
 Post subject: Triple fault when attempting to load the task register
PostPosted: Sat Jun 22, 2019 9:00 am 
Offline

Joined: Mon Sep 26, 2016 8:25 am
Posts: 18
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
Code:
ltr %ax


The code I am using to install the TSS is similar to Jame's Molly's:
Code:
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;

   asm(
      "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:
Code:
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 */
   install_gdt();
}


I added the flag
Code:
-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
Code:
ltr
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
Code:
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


Top
 Profile  
 
 Post subject: Re: Triple fault when attempting to load the task register
PostPosted: Sun Jun 23, 2019 6:05 am 
Offline

Joined: Thu Apr 19, 2018 5:31 am
Posts: 18
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:
Code:
gdt_set_descriptor(i, 0x00, 0xFFFFFFFF, 0x89, 0x00);

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

Hopefully it will then work :D

_________________
Currently working on https://github.com/Remco123/CactusOS


Top
 Profile  
 
 Post subject: Re: Triple fault when attempting to load the task register
PostPosted: Sun Jun 23, 2019 10:51 am 
Offline

Joined: Mon Sep 26, 2016 8:25 am
Posts: 18
Thanks so much for the reply @GhelloWorld, but unfortunately that doesn't seem to work :(


Top
 Profile  
 
 Post subject: Re: Triple fault when attempting to load the task register
PostPosted: Sun Jun 23, 2019 12:55 pm 
Offline
Member
Member

Joined: Fri Aug 26, 2016 1:41 pm
Posts: 492
Why don't you update your repository with the code that doesn't work?


Top
 Profile  
 
 Post subject: Re: Triple fault when attempting to load the task register
PostPosted: Tue Jun 25, 2019 9:14 am 
Offline

Joined: Mon Sep 26, 2016 8:25 am
Posts: 18
@MichaelPetch thanks. I have pushed the code to the "user-mode" branch


Top
 Profile  
 
 Post subject: Re: Triple fault when attempting to load the task register
PostPosted: Tue Jun 25, 2019 11:29 am 
Offline
Member
Member

Joined: Fri Aug 26, 2016 1:41 pm
Posts: 492
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:
Code:
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:
Code:
    asm (
        "ltr %0" :: "r"((uint16_t)0x2b)
    );


Top
 Profile  
 
 Post subject: Re: Triple fault when attempting to load the task register
PostPosted: Thu Jun 27, 2019 6:25 am 
Offline

Joined: Mon Sep 26, 2016 8:25 am
Posts: 18
@MichaelPetch thank you SO much! I don't know how I made such a dumb mistake - face palm!
This solved my problem :D :D


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 7 posts ] 

All times are UTC - 6 hours


Who is online

Users browsing this forum: Google [Bot], MSN [Bot] and 11 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group