How to write a TSS (in assembly)

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
austanss
Member
Member
Posts: 377
Joined: Sun Oct 11, 2020 9:46 pm
Location: United States

How to write a TSS (in assembly)

Post by austanss »

How do I write a TSS?

I've seen the article on the OSDev wiki, but it doesn't go into enough detail for me.

I've also seen some code from someone else, but it is hard to understand for me. Also, it's written in C and generated at runtime. I'm not a fan of that.

I also don't understand the meaning behind the values in the TSS. What are the RSP values, and why are there multiple. What is an IST, and why is there so damn many of them?

Thank you in advance for any insight.
Skylight: https://github.com/austanss/skylight

I make stupid mistakes and my vision is terrible. Not a good combination.

NOTE: Never respond to my posts with "it's too hard".
Octocontrabass
Member
Member
Posts: 5568
Joined: Mon Mar 25, 2013 7:01 pm

Re: How to write a TSS (in assembly)

Post by Octocontrabass »

rizxt wrote:How do I write a TSS?
You put the TSS values in memory according to the TSS structure, set up a TSS descriptor, and load the TSS descriptor into the task register.
rizxt wrote:Also, it's written in C and generated at runtime. I'm not a fan of that.
Which part don't you like, and why?
rizxt wrote:I also don't understand the meaning behind the values in the TSS. What are the RSP values, and why are there multiple. What is an IST, and why is there so damn many of them?
Have you checked the Intel SDM or AMD APM yet? Make sure you're looking at the 64-bit TSS, it's very different from the others.
User avatar
austanss
Member
Member
Posts: 377
Joined: Sun Oct 11, 2020 9:46 pm
Location: United States

Re: How to write a TSS (in assembly)

Post by austanss »

Octocontrabass wrote:
rizxt wrote:Also, it's written in C and generated at runtime. I'm not a fan of that.
Which part don't you like, and why?
Written in C. I prefer writing data structures in assembly.
rizxt wrote:I also don't understand the meaning behind the values in the TSS. What are the RSP values, and why are there multiple. What is an IST, and why is there so damn many of them?
Have you checked the Intel SDM or AMD APM yet? Make sure you're looking at the 64-bit TSS, it's very different from the others.
OF course! I forgot!
Skylight: https://github.com/austanss/skylight

I make stupid mistakes and my vision is terrible. Not a good combination.

NOTE: Never respond to my posts with "it's too hard".
Octocontrabass
Member
Member
Posts: 5568
Joined: Mon Mar 25, 2013 7:01 pm

Re: How to write a TSS (in assembly)

Post by Octocontrabass »

rizxt wrote:Written in C. I prefer writing data structures in assembly.
Hmm... It's true that a lot of x86-specific data structures are difficult to represent in C, but I still think it's easier to manipulate those structures in C.
User avatar
austanss
Member
Member
Posts: 377
Joined: Sun Oct 11, 2020 9:46 pm
Location: United States

Re: How to write a TSS (in assembly)

Post by austanss »

How do I write the GDT segment descriptor for the TSS? I can't find much info in the Intel/AMD manuals.
Skylight: https://github.com/austanss/skylight

I make stupid mistakes and my vision is terrible. Not a good combination.

NOTE: Never respond to my posts with "it's too hard".
Octocontrabass
Member
Member
Posts: 5568
Joined: Mon Mar 25, 2013 7:01 pm

Re: How to write a TSS (in assembly)

Post by Octocontrabass »

Intel describes it in Volume 3A, section 7.2.3 "TSS Descriptor in 64-bit mode". AMD describes it in Volume 2, section 4.8.3 "System Descriptors". Both have diagrams showing the layout of individual bits.

It should look familiar since you've already set up other descriptors in your GDT.
User avatar
austanss
Member
Member
Posts: 377
Joined: Sun Oct 11, 2020 9:46 pm
Location: United States

Re: How to write a TSS (in assembly)

Post by austanss »

I don't quite understand the diagram.
Skylight: https://github.com/austanss/skylight

I make stupid mistakes and my vision is terrible. Not a good combination.

NOTE: Never respond to my posts with "it's too hard".
Octocontrabass
Member
Member
Posts: 5568
Joined: Mon Mar 25, 2013 7:01 pm

Re: How to write a TSS (in assembly)

Post by Octocontrabass »

Very strange, aren't they? You basically have to read them backwards, since bit 0 is in the bottom right corner. Each row is four bytes.
User avatar
austanss
Member
Member
Posts: 377
Joined: Sun Oct 11, 2020 9:46 pm
Location: United States

Re: How to write a TSS (in assembly)

Post by austanss »

I don't understand how with my current GDT/TSS (link in signature), how I can configure that segment. That's what I am lost on.
Skylight: https://github.com/austanss/skylight

I make stupid mistakes and my vision is terrible. Not a good combination.

NOTE: Never respond to my posts with "it's too hard".
Octocontrabass
Member
Member
Posts: 5568
Joined: Mon Mar 25, 2013 7:01 pm

Re: How to write a TSS (in assembly)

Post by Octocontrabass »

You add the descriptor to your GDT? I'm not sure how you wrote your GDT in the first place without understanding how to add a descriptor to it.
xeyes
Member
Member
Posts: 212
Joined: Mon Dec 07, 2020 8:09 am

Re: How to write a TSS (in assembly)

Post by xeyes »

Also, it's written in C and generated at runtime. I'm not a fan of that.
The easiest way is to solve this particular problem would be to hand translate that C code to assembly or use gcc -S and copy paste as needed.
kzinti
Member
Member
Posts: 898
Joined: Mon Feb 02, 2015 7:11 pm

Re: How to write a TSS (in assembly)

Post by kzinti »

If you have decided to write your OS using only assembly and you aren't sure how to convert a small snippet of code from C to ASM that simply adds new entries to what you already have... You might want to take a pause and question why you are making your life so hard.

Doing it in C is rather simple... Maybe this will help you (you do need two entries in long mode):

Code: Select all

    const uintptr_t tss_base = (uintptr_t)tss;
    const uintptr_t tss_limit = sizeof(*tss) - 1;

    // TSS - low
    gdt[5].limit    = tss_limit;                                      // Limit (15:0)
    gdt[5].base     = (uint16_t)tss_base;                             // Base (15:0)
    gdt[5].flags1   = (uint16_t)(0xE900 + ((tss_base >> 16) & 0xFF)); // P + DPL 3 + TSS + base (23:16)
    gdt[5].flags2   = (uint16_t)((tss_base >> 16) & 0xFF00);          // Base (31:24)

    // TSS - high
    gdt[6].limit    = (uint16_t)(tss_base >> 32);                     // Base (47:32)
    gdt[6].base     = (uint16_t)(tss_base >> 48);                     // Base (63:32)
    gdt[6].flags1   = 0x0000;
    gdt[6].flags2   = 0x0000;
Definition of the TSS structure (long mode):

Code: Select all

struct Tss64
{
    uint32_t reserved0;
    uint64_t rsp0;      // rsp when entering ring 0
    uint64_t rsp1;      // rsp when entering ring 1
    uint64_t rsp2;      // rsp when entering ring 2
    uint64_t reserved1;
    // The next 7 entries are the "Interrupt stack Table"
    // Here we can define stack pointers to use when handling interrupts.
    // Which one to use is defined in the Interrupt Descriptor Table.
    uint64_t ist1;
    uint64_t ist2;
    uint64_t ist3;
    uint64_t ist4;
    uint64_t ist5;
    uint64_t ist6;
    uint64_t ist7;
    uint64_t reserved2;
    uint16_t reserved3;
    uint16_t iomap;

} __attribute__((packed));
Finally don't forget to initialize the TSS before using it:

Code: Select all

void InitTss()
{
    memset(tss, 0, sizeof(*tss);
    tss->iomap = 0xdfff; // For now, point beyond the TSS limit (no iomap)
}
You will also want to set "rsp0" in the TSS before returning to user mode. This way the CPU will now where to store the kernel stack when the user program makes system calls (or interrupts occur).
nexos
Member
Member
Posts: 1081
Joined: Tue Feb 18, 2020 3:29 pm
Libera.chat IRC: nexos

Re: How to write a TSS (in assembly)

Post by nexos »

rizxt wrote:Also, it's written in C and generated at runtime. I'm not a fan of that.
Generating a GDT at runtime is your only option. Doing it in C is another good thing as well. The problem with a static GDT comes in at SMP time. You always need one CPU per TSS at least. If you did it statically, you would limit yourself to a fixed number of CPUs, which, isn't optimal at all.
"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
bzt
Member
Member
Posts: 1584
Joined: Thu Oct 13, 2016 4:55 pm
Contact:

Re: How to write a TSS (in assembly)

Post by bzt »

rizxt wrote:Also, it's written in C and generated at runtime. I'm not a fan of that.
Then don't do it. You can easily generate the TSS from Assembly as well, it's just bytes in the memory after all.

Code: Select all

tss_seg:
.long 0 // reserved
.quad 0 // rsp0
.quad 0 // rsp1
.quad 0 // rsp2
.long 0 // reserved
...etc.
And if your linker places that "tss_seg" at a fixed address, you can also generate the GDT statically, for example:

Code: Select all

gdt64:
    .word   gdt64_end - gdt64_start - 1
    .quad   gdt64_start
gdt64_start:
    .quad 0x0000000000000000    /* null descriptor */
    .quad 0x002098000000ffff    /* 08 core CS */
    .quad 0x008092000000ffff    /* 10 core DS */
    .quad 0x0080f2000000ffff    /* 18 user DS */
    .quad 0x0020f8000000ffff    /* 20 user CS */
    .quad 0x8000890000000068    /* 28 tss, you should use your static tss_seg address here */
    .quad 0x00000000ffffffff
gdt64_end:
nexos wrote:You always need one CPU per TSS at least. If you did it statically, you would limit yourself to a fixed number of CPUs, which, isn't optimal at all.
Not necessarily, you could create 255 TSS segments statically (APIC can't have more cores anyway, as APIC ID is a byte and 255 is reserved for broadcast address.) It isn't more complicated than to create 256 IDT entries statically. And with x2APIC dynamically generated or not, the limit of GDT won't be enough, so there you must use the "all cores have different CR3" trick anyway if you want to support all possible cores.

Cheers,
bzt
thewrongchristian
Member
Member
Posts: 426
Joined: Tue Apr 03, 2018 2:44 am

Re: How to write a TSS (in assembly)

Post by thewrongchristian »

kzinti wrote: Definition of the TSS structure (long mode):

Code: Select all

struct Tss64
{
    uint32_t reserved0;
    uint64_t rsp0;      // rsp when entering ring 0
    uint64_t rsp1;      // rsp when entering ring 1
...
} __attribute__((packed));
Oh god, really? I'd have thought the 64-bit pointers would have been 64-bit aligned at least, given that AMD had a free hand to define this. Why would they put a reserved, 32-bit structure at the beginning, and basically force C users to have to pack their structures?

I can sort of perhaps see that it aligns with the 32-bit TSS, and its offsets for ESP[0,1,2], but why did they have to? They literally had no compatibility baggage to worry about.

I think working with anything x86 must rot the brain.
Post Reply