[resolved] TSS and system segments in Long Mode.
[resolved] TSS and system segments in Long Mode.
Hi,
To create my OS, I need to manage the TSS, with descriptors systems in the GDT.
The problem is that I can't create them in C, and I get a TripleFault.
Can you tell me how can I easily create system descriptors, in Long Mode ?
Cheers.
(sorry for my English, I'm french)
To create my OS, I need to manage the TSS, with descriptors systems in the GDT.
The problem is that I can't create them in C, and I get a TripleFault.
Can you tell me how can I easily create system descriptors, in Long Mode ?
Cheers.
(sorry for my English, I'm french)
Last edited by deste on Thu Jun 05, 2008 9:23 am, edited 1 time in total.
You absolutely can create a GDT in C, but you will need a way of separating your code compiled for 32 and 64 bit. I prefer to go to long mode in my boot loader, so the kernel is pure 64 bit. The kernel can always manage the GDT later. If you prefer to do it another way, you will need to link 64 and 32 bit code in to the same executable - something which is probably easy, but I have never tried.
I suggest you run your code in Bochs, which will often give you some nice debug information. When playing with the GDT, a single bit out of place can give you an immediate triple fault. Really verify that the GDT entries are exactly correct, read the Intel Manuals (available for download or in hard copy) and if all else still fails, post the Bochs debug dump here and we will try to help further.
Cheers,
Adam
I suggest you run your code in Bochs, which will often give you some nice debug information. When playing with the GDT, a single bit out of place can give you an immediate triple fault. Really verify that the GDT entries are exactly correct, read the Intel Manuals (available for download or in hard copy) and if all else still fails, post the Bochs debug dump here and we will try to help further.
Cheers,
Adam
Hi,
The GDT is created in C, and I believe that his recordings are good. The kernel is 100% in Long Mode.
I test my OS in Qemu, which gives me a dump of registers on a TripleFault.
Here is the code (inline assembly) which generates my GDT's entries :
EDIT: I forgot the exit code of Qemu, here it is:
Cheers.
The GDT is created in C, and I believe that his recordings are good. The kernel is 100% in Long Mode.
I test my OS in Qemu, which gives me a dump of registers on a TripleFault.
Here is the code (inline assembly) which generates my GDT's entries :
Code: Select all
void CreateSysSegment(int index, int64 baseAddress, int16 limit, int16 flags) {
int64 addr = 0;
addr = ((int64)(index))*8; //entries measures 8 bytes.
addr += 0x30000; //The base address of GDT is 0x30000.
//inline assembly in GCC.
asm volatile (
"mov %0, %%rbx\n"
"mov %1, %%ax\n"
"mov %%ax, (%%rbx)\n"
"mov %2, %%rax\n"
"mov %%eax, 2(%%rbx)\n"
"mov %3, %%ax\n"
"mov %%ax, 5(%%rbx)\n"
"mov %2, %%rax\n"
"shl $24, %%rax\n"
"mov %%rax, 7(%%rbx)\n"
"mov $0x0, %%eax\n"
"mov %%eax, 12(%%rbx)\n"
:
: "m" (addr), "m" (limit), "m" (baseAddress), "m" (flags)
: "rbx", "rax"
);
}
Code: Select all
IN:
0x00000000008007c4: push %rbp
0x00000000008007c5: mov %rsp,%rbp
0x00000000008007c8: mov %di,0xfffffffffffffffc(%rbp)
0x00000000008007cc: shlw $0x3,0xfffffffffffffffc(%rbp)
0x00000000008007d1: movzwl 0xfffffffffffffffc(%rbp),%eax
0x00000000008007d5: ltr %ax
0x00000000008007d8: leaveq
0x00000000008007d9: retq
qemu: fatal: triple fault
RAX=0000000000000020 RBX=0000000000000000 RCX=000000000000808b RDX=0000000000000100
RSI=0000000000801580 RDI=0000000000000004 RBP=000000000000ff60 RSP=000000000000ff60
R8 =0000000000000000 R9 =0000000000000000 R10=0000000000000000 R11=0000000000000000
R12=0000000000000000 R13=0000000000000000 R14=0000000000000000 R15=0000000000000000
RIP=00000000008007d5 RFL=00000002 [-------] CPL=0 II=0 A20=1 SMM=0 HLT=0
ES =ffff 00000000000ffff0 0000ffff 00009300
CS =0010 0000000000000000 0fffffff 00a09a00
SS =0018 0000000000000000 0fffffff 00809300
DS =0018 0000000000000000 00000fff 00809300
FS =0000 0000000000000000 0000ffff 00009300
GS =0000 0000000000000000 0000ffff 00009300
LDT=0000 0000000000000000 0000ffff 00008000
TR =0000 0000000000000000 0000ffff 00008000
GDT= 0000000000030000 0000ffff
IDT= 0000000000000000 00000200
CR0=80000011 CR2=0000000000000080 CR3=0000000000050000 CR4=00000020
CCS=0000000000000010 CCD=0000000000000020 CCO=SHLW
FCW=037f FSW=0000 [ST=0] FTW=00 MXCSR=00001f80
Hi,
I'm not going to try to debug that assembly - someone else will be better at that, but I can tell you what the problem is. You seem to be getting a page fault exception at 0x0000000000000080, which strikes me as what happes if someone uses an array based on a null pointer.
You are triple-faulting rather than handling the page fault gracefully which means that either you have no 64 bit IDT or you are trying to load RIP or RSP with an unpaged area. I wonder if that 'iret' statement could be trying to load invalid data or the stack has become misaligned?
Cheers,
Adam
I'm not going to try to debug that assembly - someone else will be better at that, but I can tell you what the problem is. You seem to be getting a page fault exception at 0x0000000000000080, which strikes me as what happes if someone uses an array based on a null pointer.
You are triple-faulting rather than handling the page fault gracefully which means that either you have no 64 bit IDT or you are trying to load RIP or RSP with an unpaged area. I wonder if that 'iret' statement could be trying to load invalid data or the stack has become misaligned?
Cheers,
Adam
Hi,
CR2 actually contains the linear address of the page fault, not the page number. This means something is trying to access linear address 0x80, not 0x800000.
Also, you can load the IDT before you have a TSS and it will work as it should do (I handle exceptions and IRQ's and I have no TSS yet). You only need a TSS once you start multitasking. Note also that long mode does not use the 'task switch in interrupt' mechanism like PMode. Instead, you can switch stack using the IST mechanism.
Cheers,
Adam
CR2 actually contains the linear address of the page fault, not the page number. This means something is trying to access linear address 0x80, not 0x800000.
Also, you can load the IDT before you have a TSS and it will work as it should do (I handle exceptions and IRQ's and I have no TSS yet). You only need a TSS once you start multitasking. Note also that long mode does not use the 'task switch in interrupt' mechanism like PMode. Instead, you can switch stack using the IST mechanism.
Cheers,
Adam
Hi,
In Long Mode, interruptions in the IDT require IST, which must be in the TSS.
I recoded function, using structures. They are:
Cheers.
In Long Mode, interruptions in the IDT require IST, which must be in the TSS.
I recoded function, using structures. They are:
Code: Select all
typedef struct {
int16 limit;
int16 base0_15;
int8 base16_23;
int16 flags;
int8 base24_31;
} __attribute__ ((packed)) gdtenrg;
typedef struct {
int16 limit;
int16 base0_15;
int8 base16_23;
int16 flags;
int8 base24_31;
int32 base32_63;
int32 zeros;
} __attribute__ ((packed)) gdtsysenrg;
void CreateSegment(int index, int16 flags) {
gdtenrg *enrg;
enrg = (gdtenrg *) 0x30000;
enrg[index].limit = 0;
enrg[index].base0_15 = 0;
enrg[index].base16_23 = 0;
enrg[index].flags = flags;
enrg[index].base24_31 = 0;
}
void CreateSysSegment(int index, int64 baseAddress, int16 limit, int16 flags) {
gdtsysenrg *enrg;
int64 mindex = (int64) index;
enrg = (gdtsysenrg *)(0x30000+(mindex*8));
enrg->limit = limit;
enrg->base0_15 = (int16)baseAddress;
enrg->base16_23 = (int8)(baseAddress>>16);
enrg->flags = flags;
enrg->base24_31 = (int8)(baseAddress>>24);
enrg->base32_63 = (int32)(baseAddress>>32);
enrg->zeros = 0;
}
No. Note that the IST's are numbered 1-7 (not 0-7). Specifying a zero IST means that the CPU keeps the current stack if you are running in ring 0 (you do not need a TSS), or loads RSP0 if you are running in ring 3 (for which you do need a TSS).In Long Mode, interruptions in the IDT require IST, which must be in the TSS.
Cheers,
Adam
Last edited by AJ on Thu Jun 05, 2008 8:24 am, edited 1 time in total.
-
- Posts: 20
- Joined: Fri Nov 24, 2006 10:55 pm
- Location: C eh, N eh, D eh
Re: TSS and system segments in Long Mode.
I wouldn't say that this is resolved. I have been unsuccessful at this as well. I'll ignore it for now, because:
It would be really nice if someone would post a working example here or on the wiki.AJ wrote:you do not need a TSS
*WARNING* -- Automatic logout enabled. Save drafts frequently or risk data loss! -- *WARNING*
Re: [resolved] TSS and system segments in Long Mode.
What of? Interrupts in Long Mode? A Long Mode TSS? If you just want to set up a long mode TSS, see sandpile.org for the complete layout or the Intel Manuals for a full explanation.Mr.Confuzed wrote:It would be really nice if someone would post a working example here or on the wiki.
Sorry if I misunderstood and you want an example of something different.
Cheers,
Adam
-
- Posts: 20
- Joined: Fri Nov 24, 2006 10:55 pm
- Location: C eh, N eh, D eh
Re: [resolved] TSS and system segments in Long Mode.
Hm, sandpile.org looks useful. I'll have to remember that. Unfortunately, it didn't help today.
Yes, I was looking for an example of how to build a long mode TSS. I have been using the AMD64 manuals extensively. Let's see if you can help. My code produces a GP fault at the ltr and works perfectly when it is commented out. Bochs says, "LTR: loading with NULL selector!" I fail to see why.
Thanks in advance!
Yes, I was looking for an example of how to build a long mode TSS. I have been using the AMD64 manuals extensively. Let's see if you can help. My code produces a GP fault at the ltr and works perfectly when it is commented out. Bochs says, "LTR: loading with NULL selector!" I fail to see why.
Code: Select all
;Global Descriptor Table
gdt:
dq 0x0000000000000000
.code equ $ - gdt
dq 0x00af98000000ffff
.data equ $ - gdt
dq 0x008f90000000ffff
.TSS equ $ - gdt
dq 0x000089000000006a
dq 0x0000000000000000
.pointer:
dw $-gdt-1
dq gdt
Code: Select all
startLongMode:
lidt [idt.pointer]
sti
xor rcx,rcx
xor rdi,rdi
mov rax,0x000003b800000000
mov cl,13
rep stosq
mov ax,0x0068
mov [0x66],ax
mov eax,0xffffffff
mov [0x68],eax
ltr [gdt.TSS]
*WARNING* -- Automatic logout enabled. Save drafts frequently or risk data loss! -- *WARNING*
Re: [resolved] TSS and system segments in Long Mode.
Ok,
I'm normally doing this stuff using C functions which nicely split the access / granularity etc... bytes of the GDT entires, but think I can see what's going on
I can't see that the "Base" of your TSS descriptor actually points to a valid TSS. It seems to be pointing to NULL.
Am I right in thinking that this should be:
? Again - I could be wrong. I'm just going to have a look through my archives and see how my test kernel did this (if I can find it!).
Cheers,
Adam
I'm normally doing this stuff using C functions which nicely split the access / granularity etc... bytes of the GDT entires, but think I can see what's going on
I can't see that the "Base" of your TSS descriptor actually points to a valid TSS. It seems to be pointing to NULL.
Code: Select all
ltr [gdt.TSS]
Code: Select all
ltr gdt.TSS
Cheers,
Adam
-
- Posts: 20
- Joined: Fri Nov 24, 2006 10:55 pm
- Location: C eh, N eh, D eh
Re: [resolved] TSS and system segments in Long Mode.
Argh! How could I be so stupid! Well, it turns out you're wrong. I had tried that, but in doing so, caused NASM to yell, "error: invalid combination of opcode and operands", regardless of the fact that it would seem to work in protected mode. It turns out that you have to do this...
... and this ...
... to make it work, despite that being the silliest way of doing things that I know of.
I guess my weekend wasn't wasted after all! Thank you for "passing" my brain fart, as it were.
Code: Select all
ltr [tss.pointer]
Code: Select all
tss.pointer:
dw gdt.TSS
I guess my weekend wasn't wasted after all! Thank you for "passing" my brain fart, as it were.
*WARNING* -- Automatic logout enabled. Save drafts frequently or risk data loss! -- *WARNING*