How to write a TSS (in assembly)
How to write a TSS (in assembly)
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.
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".
I make stupid mistakes and my vision is terrible. Not a good combination.
NOTE: Never respond to my posts with "it's too hard".
-
- Member
- Posts: 5568
- Joined: Mon Mar 25, 2013 7:01 pm
Re: How to write a TSS (in assembly)
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:How do I write a TSS?
Which part don't you like, and why?rizxt wrote:Also, it's written in C and generated at runtime. I'm not a fan of that.
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.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?
Re: How to write a TSS (in assembly)
Written in C. I prefer writing data structures in assembly.Octocontrabass wrote:Which part don't you like, and why?rizxt wrote:Also, it's written in C and generated at runtime. I'm not a fan of that.
OF course! I forgot!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.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?
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".
I make stupid mistakes and my vision is terrible. Not a good combination.
NOTE: Never respond to my posts with "it's too hard".
-
- Member
- Posts: 5568
- Joined: Mon Mar 25, 2013 7:01 pm
Re: How to write a TSS (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.rizxt wrote:Written in C. I prefer writing data structures in assembly.
Re: How to write a TSS (in assembly)
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".
I make stupid mistakes and my vision is terrible. Not a good combination.
NOTE: Never respond to my posts with "it's too hard".
-
- Member
- Posts: 5568
- Joined: Mon Mar 25, 2013 7:01 pm
Re: How to write a TSS (in assembly)
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.
It should look familiar since you've already set up other descriptors in your GDT.
Re: How to write a TSS (in assembly)
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".
I make stupid mistakes and my vision is terrible. Not a good combination.
NOTE: Never respond to my posts with "it's too hard".
-
- Member
- Posts: 5568
- Joined: Mon Mar 25, 2013 7:01 pm
Re: How to write a TSS (in assembly)
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.
Re: How to write a TSS (in assembly)
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".
I make stupid mistakes and my vision is terrible. Not a good combination.
NOTE: Never respond to my posts with "it's too hard".
-
- Member
- Posts: 5568
- Joined: Mon Mar 25, 2013 7:01 pm
Re: How to write a TSS (in assembly)
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.
Re: How to write a TSS (in assembly)
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.Also, it's written in C and generated at runtime. I'm not a fan of that.
Re: How to write a TSS (in assembly)
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):
Definition of the TSS structure (long mode):
Finally don't forget to initialize the TSS before using it:
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).
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;
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));
Code: Select all
void InitTss()
{
memset(tss, 0, sizeof(*tss);
tss->iomap = 0xdfff; // For now, point beyond the TSS limit (no iomap)
}
Re: How to write a TSS (in assembly)
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.rizxt wrote:Also, it's written in C and generated at runtime. I'm not a fan of that.
Re: How to write a TSS (in assembly)
Then don't do it. You can easily generate the TSS from Assembly as well, it's just bytes in the memory after all.rizxt wrote:Also, it's written in C and generated at runtime. I'm not a fan of that.
Code: Select all
tss_seg:
.long 0 // reserved
.quad 0 // rsp0
.quad 0 // rsp1
.quad 0 // rsp2
.long 0 // reserved
...etc.
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:
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.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.
Cheers,
bzt
-
- Member
- Posts: 426
- Joined: Tue Apr 03, 2018 2:44 am
Re: How to write a TSS (in assembly)
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?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));
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.