Loading the TR register causes the system to crash

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.
Post Reply
User avatar
mrjbom
Member
Member
Posts: 317
Joined: Sun Jul 21, 2019 7:34 am

Loading the TR register causes the system to crash

Post by mrjbom »

Hi.
I am trying to embed user space in my core, however I am having problems when trying to load Task Register.
In the init_gdt() function, I add entries to GDT, and write TSS and TR using the write_tss() function, then using the tss_flush() function, I try to load TR, but at this point it causes the system to crash.

What am I doing wrong?

(I apologize for the comments that are not in English, it makes it easier for me to understand the code.)
nexos
Member
Member
Posts: 1081
Joined: Tue Feb 18, 2020 3:29 pm
Libera.chat IRC: nexos

Re: Loading the TR register causes the system to crash

Post by nexos »

You forgot to adjust the limit to account for the TSS. You need to multiply by 6.
"How did you do this?"
"It's very simple — you read the protocol and write the code." - Bill Joy
Projects: NexNix | libnex | nnpkg
User avatar
mrjbom
Member
Member
Posts: 317
Joined: Sun Jul 21, 2019 7:34 am

Re: Loading the TR register causes the system to crash

Post by mrjbom »

nexos wrote:You forgot to adjust the limit to account for the TSS. You need to multiply by 6.
Yes, you're right, I didn't follow it.
I changed the number 3 to the number 6 in this line, however this did not solve the problem.
nexos
Member
Member
Posts: 1081
Joined: Tue Feb 18, 2020 3:29 pm
Libera.chat IRC: nexos

Re: Loading the TR register causes the system to crash

Post by nexos »

You also need to add in write_tss

Code: Select all

gdt_set_gate (0x28, base, base + sizeof (tss-entry), 0xE9, 0x00) 
. My TSS code is at https://github.com/nexos-dev/NexNix/blo ... i686/tss.c.
"How did you do this?"
"It's very simple — you read the protocol and write the code." - Bill Joy
Projects: NexNix | libnex | nnpkg
sj95126
Member
Member
Posts: 151
Joined: Tue Aug 11, 2020 12:14 pm

Re: Loading the TR register causes the system to crash

Post by sj95126 »

It's not necessarily going to help diagnose the problem, but I'd suggest waiting to load TR until after your IDT is set up. That way, you'll get an Invalid TSS exception instead of a triple fault. The error code passed to the handler will indicate the segment selector (the TSS, or a segment referenced by the TSS) that caused the fault.
User avatar
mrjbom
Member
Member
Posts: 317
Joined: Sun Jul 21, 2019 7:34 am

Re: Loading the TR register causes the system to crash

Post by mrjbom »

sj95126 wrote:It's not necessarily going to help diagnose the problem, but I'd suggest waiting to load TR until after your IDT is set up. That way, you'll get an Invalid TSS exception instead of a triple fault. The error code passed to the handler will indicate the segment selector (the TSS, or a segment referenced by the TSS) that caused the fault.
I moved the call to the tss_flush() function after gdt_init() and idt_init(), now this triggers the General Protection Fault exception.
User avatar
mrjbom
Member
Member
Posts: 317
Joined: Sun Jul 21, 2019 7:34 am

Re: Loading the TR register causes the system to crash

Post by mrjbom »

nexos wrote:You also need to add in write_tss

Code: Select all

gdt_set_gate (0x28, base, base + sizeof (tss-entry), 0xE9, 0x00) 
. My TSS code is at https://github.com/nexos-dev/NexNix/blo ... i686/tss.c.
I tried to do what you recommend when initializing gdt.
Just as tss_flush() is called after idt_init(), now an exception #GP occurs when trying to ltr.

Code: Select all

void init_gdt(void)
{
  gdt_ptr.limit = (sizeof(gdt_entry_t) * 6) - 1;
  gdt_ptr.base = (uint32_t)&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_set_gate(0x28, (uint32_t)&tss, (uint32_t)&tss + sizeof (tss_entry_t), 0xE9, 0x00);
  
  write_tss(5, 0x10, (uint32_t)kernel_stack_top);
 
  gdt_flush( (uint32_t) &gdt_ptr);
}
nexos
Member
Member
Posts: 1081
Joined: Tue Feb 18, 2020 3:29 pm
Libera.chat IRC: nexos

Re: Loading the TR register causes the system to crash

Post by nexos »

lgdt needs to be called before ltr.
"How did you do this?"
"It's very simple — you read the protocol and write the code." - Bill Joy
Projects: NexNix | libnex | nnpkg
User avatar
mrjbom
Member
Member
Posts: 317
Joined: Sun Jul 21, 2019 7:34 am

Re: Loading the TR register causes the system to crash

Post by mrjbom »

nexos wrote:lgdt needs to be called before ltr.
At the moment, I first call gdt_flush(), then idt_flush() , and last tss_flush()
mkfree
Member
Member
Posts: 55
Joined: Thu Apr 30, 2020 6:03 am
Libera.chat IRC: mkfree

Re: Loading the TR register causes the system to crash

Post by mkfree »

If the system locks up only when you change the TR, then check the following
if the descriptors of CS, DS, SS work correctly when you load them then the problem
it's in the TSS descriptor. Keep in mind that if you define the table you must take into account the
size.


I give you an example of my code, which works correctly with several CPUs, it is just a summary of the code:

Code: Select all

// Some definitions

struct SgdtDescriptor {
u16 limit0_15;
u16 base0_15;
u8 base16_23;
u8 dacces;
u8 limit16_19: 4;
u8 option: 4;
u8 base24_31;
} __ attribute__ ((packed));


struct Sgdtr {
        u16 limit;
       u32 base;
} __attribute__ ((packed));

struct Stss {
u16 ret_task, ret_task_unused;
u32 esp0;
u16 ss0, ss0_unused;
u32 esp1;
u16 ss1, ss1_unused;
u32 esp2;
u16 ss2, ss2_unused;
u32 cr3;
u32 eip, eflags, eax, ecx, edx, ebx, esp, ebp, esi, edi;
u16 is, is_unused;
u16 cs, cs_unused;
u16 ss, ss_unused;
u16 ds, ds_unused;
u16 fs, fs_unused;
u16 gs, gs_unused;
u16 ldt_selector, ldt_sel_unused;
u16 debug_flag, io_map;
} __ attribute__ ((packed));


struct Scpus {
    Stss tss;
    SgdtDescriptor kgdt [8]; // Only eight 0's, KCS, KDS, KES, UCS, UDS, USS, UTSS
    Sgdtr gdtr;
    u32 kstack;
 } __attribute __ ((packed));

 
// Code snippet

void CmodeProtected :: initGdtDescriptor (u32 abase, u32 alimit, u8 adacces, u8 aoption, struct SgdtDescriptor * adescriptor) {
    adescriptor-> limit0_15 = (alimit & 0xffff);
    adescriptor-> base0_15 = (abase & 0xffff);
    adescriptor-> base16_23 = (abase & 0xff0000) >> 16;
    adescriptor-> dacces = adacces;
    adescriptor-> limit16_19 = (alimit & 0xf0000) >> 16;
    adescriptor-> option = (aoption & 0xf);
    adescriptor-> base24_31 = (abase & 0xff000000) >> 24;
}


void CmodeProtected :: initGdt (Scpus * cpu) {
    cpu-> tss.debug_flag = 0x00;
    cpu-> tss.io_map = 0x00;
    cpu-> tss.esp0 = cpu-> kstack; // Address for the kernel stack on ring 0
    cpu-> tss.ss0 = 0x18; // Kernel stack segment descriptor


    initGdtDescriptor (0x0, 0x0, 0x0, 0x0, & cpu-> kgdt [0]); // Null descriptor always Index 0
initGdtDescriptor (0x0, 0xFFFFF, 0x9B, 0x0D, & cpu-> kgdt [1]); // Index 1 0x8 KCS
initGdtDescriptor (0x0, 0xFFFFF, 0x93, 0x0D, & cpu-> kgdt [2]); // Index 2 0x10 KDS
    initGdtDescriptor (0x0, 0x00000, 0x97, 0x0D, & cpu-> kgdt [3]); // Index 3 0x18 KSS
initGdtDescriptor (0x0, 0xFFFFF, 0xFF, 0x0D, & cpu-> kgdt [4]); // index 4 0x20 Task CS
initGdtDescriptor (0x0, 0xFFFFF, 0xF3, 0x0D, & cpu-> kgdt [5]); // index 5 0x28 Task DS
initGdtDescriptor (0x0, 0x0, 0xF7, 0x0D, & cpu-> kgdt [6]); // index 6 0x30 Task SS
initGdtDescriptor ((u32) & cpu-> tss, 0x67, 0xE9, 0x00, & cpu-> kgdt [7]); // index 7 0x38 TSS

cpu-> gdtr.limit = 8 * 8;
    cpu-> gdtr.base = (u32) cpu-> kgdt;
    Sgdtr * ptr = & cpu-> gdtr;

    asm volatile ("lgdtl (% 0)": "= r" (ptr));
    asm volatile ("movw $ 0x10,% ax \ n \
    movw% ax,% ds \ n \
    movw% ax,% is \ n \
    movw% ax,% fs \ n \
    movw% ax,% gs \ n \
    ljmp $ 0x08, $ change \ n \
    change: nop \ n ");
    asm volatile ("movw $ 0x18,% ax \ n \
    movw% ax,% ss \ n \
    ");


}

int start () {
  initGdt (& cpus [0]);
  ................
  ................
  asm ("movw $ 0x38,% ax; ltr% ax"); // Load the Task Log and Jump to the Kernel
  kernel ();
 }
User avatar
mrjbom
Member
Member
Posts: 317
Joined: Sun Jul 21, 2019 7:34 am

Re: Loading the TR register causes the system to crash

Post by mrjbom »

mkfree wrote:If the system locks up only when you change the TR, then check the following
if the descriptors of CS, DS, SS work correctly when you load them then the problem
it's in the TSS descriptor. Keep in mind that if you define the table you must take into account the
size.


I give you an example of my code, which works correctly with several CPUs, it is just a summary of the code:

Code: Select all

// Some definitions

struct SgdtDescriptor {
u16 limit0_15;
u16 base0_15;
u8 base16_23;
u8 dacces;
u8 limit16_19: 4;
u8 option: 4;
u8 base24_31;
} __ attribute__ ((packed));


struct Sgdtr {
        u16 limit;
       u32 base;
} __attribute__ ((packed));

struct Stss {
u16 ret_task, ret_task_unused;
u32 esp0;
u16 ss0, ss0_unused;
u32 esp1;
u16 ss1, ss1_unused;
u32 esp2;
u16 ss2, ss2_unused;
u32 cr3;
u32 eip, eflags, eax, ecx, edx, ebx, esp, ebp, esi, edi;
u16 is, is_unused;
u16 cs, cs_unused;
u16 ss, ss_unused;
u16 ds, ds_unused;
u16 fs, fs_unused;
u16 gs, gs_unused;
u16 ldt_selector, ldt_sel_unused;
u16 debug_flag, io_map;
} __ attribute__ ((packed));


struct Scpus {
    Stss tss;
    SgdtDescriptor kgdt [8]; // Only eight 0's, KCS, KDS, KES, UCS, UDS, USS, UTSS
    Sgdtr gdtr;
    u32 kstack;
 } __attribute __ ((packed));

 
// Code snippet

void CmodeProtected :: initGdtDescriptor (u32 abase, u32 alimit, u8 adacces, u8 aoption, struct SgdtDescriptor * adescriptor) {
    adescriptor-> limit0_15 = (alimit & 0xffff);
    adescriptor-> base0_15 = (abase & 0xffff);
    adescriptor-> base16_23 = (abase & 0xff0000) >> 16;
    adescriptor-> dacces = adacces;
    adescriptor-> limit16_19 = (alimit & 0xf0000) >> 16;
    adescriptor-> option = (aoption & 0xf);
    adescriptor-> base24_31 = (abase & 0xff000000) >> 24;
}


void CmodeProtected :: initGdt (Scpus * cpu) {
    cpu-> tss.debug_flag = 0x00;
    cpu-> tss.io_map = 0x00;
    cpu-> tss.esp0 = cpu-> kstack; // Address for the kernel stack on ring 0
    cpu-> tss.ss0 = 0x18; // Kernel stack segment descriptor


    initGdtDescriptor (0x0, 0x0, 0x0, 0x0, & cpu-> kgdt [0]); // Null descriptor always Index 0
initGdtDescriptor (0x0, 0xFFFFF, 0x9B, 0x0D, & cpu-> kgdt [1]); // Index 1 0x8 KCS
initGdtDescriptor (0x0, 0xFFFFF, 0x93, 0x0D, & cpu-> kgdt [2]); // Index 2 0x10 KDS
    initGdtDescriptor (0x0, 0x00000, 0x97, 0x0D, & cpu-> kgdt [3]); // Index 3 0x18 KSS
initGdtDescriptor (0x0, 0xFFFFF, 0xFF, 0x0D, & cpu-> kgdt [4]); // index 4 0x20 Task CS
initGdtDescriptor (0x0, 0xFFFFF, 0xF3, 0x0D, & cpu-> kgdt [5]); // index 5 0x28 Task DS
initGdtDescriptor (0x0, 0x0, 0xF7, 0x0D, & cpu-> kgdt [6]); // index 6 0x30 Task SS
initGdtDescriptor ((u32) & cpu-> tss, 0x67, 0xE9, 0x00, & cpu-> kgdt [7]); // index 7 0x38 TSS

cpu-> gdtr.limit = 8 * 8;
    cpu-> gdtr.base = (u32) cpu-> kgdt;
    Sgdtr * ptr = & cpu-> gdtr;

    asm volatile ("lgdtl (% 0)": "= r" (ptr));
    asm volatile ("movw $ 0x10,% ax \ n \
    movw% ax,% ds \ n \
    movw% ax,% is \ n \
    movw% ax,% fs \ n \
    movw% ax,% gs \ n \
    ljmp $ 0x08, $ change \ n \
    change: nop \ n ");
    asm volatile ("movw $ 0x18,% ax \ n \
    movw% ax,% ss \ n \
    ");


}

int start () {
  initGdt (& cpus [0]);
  ................
  ................
  asm ("movw $ 0x38,% ax; ltr% ax"); // Load the Task Log and Jump to the Kernel
  kernel ();
 }
Hmm, I have roughly figured out what I should do, but it still doesn't solve the problem with ltr.
User avatar
mrjbom
Member
Member
Posts: 317
Joined: Sun Jul 21, 2019 7:34 am

Re: Loading the TR register causes the system to crash

Post by mrjbom »

I tried to figure out the error code.
This is the error code I get: 0xd440.
He tells us:
1101010001000000b
bit 0(External) = 0
bits 1-2(IDT/GDT/LDT table) = 00 -> The Selector Index references a descriptor in the GDT.
bits 3-13(index) = 1101010001000 = 6792
It turns out that the problem in GDT is in the record with the index 6792, and there is no such thing in GDT. I only have 6 entries.
What does that mean?
Post Reply