Page 1 of 1
Bochs: LTR: doesn't point to an available TSS descriptor!
Posted: Fri Feb 01, 2008 8:20 am
by AlfaOmega08
When loading my Task Register, bochs exit with:
LTR: doesn't point to an available TSS descriptor!
I've read the Bochs Source Code:
Code: Select all
if (descriptor.valid==0 || descriptor.segment ||
(descriptor.type!=BX_SYS_SEGMENT_AVAIL_286_TSS &&
descriptor.type!=BX_SYS_SEGMENT_AVAIL_386_TSS))
{
BX_ERROR(("LTR: doesn't point to an available TSS descriptor!"));
exception(BX_GP_EXCEPTION, raw_selector & 0xfffc, 0);
}
my descriptor.type is equal to 0x9 in the GDT
I've tried to see where is defined descriptor.segment and .valid.
In the function parse_descriptor in cpu/segment_ctrl_pro.cc is checked if the descriptor is a segment (if the bit4 in the access byte is set). If not it starts to see wath the descriptor is. In this checks is included also the 386 TSS descriptor, and descriptor.valid is set to 1. So why does bochs give me this error?[/code]
Posted: Fri Feb 01, 2008 8:58 am
by alkot
You can set breakpoint (int 3 maybe) in Bochs and see real descriptors loaded into gdt with command "info gdt" to check that Bochs realy loaded what you assume to load.
You need a Bochs compiled with --enable-debugger
Posted: Fri Feb 01, 2008 11:46 am
by AlfaOmega08
I need not the INT 3. When bochs give me that message, a General Protection Fault is fired, and my kernel enter in an infinite loop. So I press CTRL+C to enter the debugger and my gdt contains:
Code: Select all
Global Descriptor Table (base=0x00016c80, limit=39):
GDT[0x00]=??? descriptor hi=0x00000000, lo=0x00000000
GDT[0x01]=Code segment, linearaddr=00000000, limit=fffff * 4Kbytes, Execute/Read, 32-bit
GDT[0x02]=Data segment, linearaddr=00000000, limit=fffff * 4Kbytes, Read/Write, Accessed
GDT[0x03]=32-Bit TSS (Busy) at 0x000274c0, length 0x00068
GDT[0x04]=32-Bit TSS (Available) at 0x00027528, length 0x00068
Posted: Fri Feb 01, 2008 12:17 pm
by alkot
What selector do you pass to the LTR command? What is the error code of GP exception in bochs log?
Can you show a part of your code?
Posted: Fri Feb 01, 2008 12:41 pm
by AlfaOmega08
Sure I can. I've a gdt::setDesc function:
Code: Select all
int gdt::setDesc(int index, unsigned long base, unsigned long limit, unsigned char dpl, types type, char update) {
if (index == 0) {
gdtDescs[0].lowBase = 0;
gdtDescs[0].middleBase = 0;
gdtDescs[0].highBase = 0;
gdtDescs[0].lowLimit = 0;
gdtDescs[0].granularity = 0;
gdtDescs[0].access = 0;
return 0;
}
gdtDescs[index].lowBase = (base & 0xFFFF);
gdtDescs[index].middleBase = (base >> 16) & 0xFF;
gdtDescs[index].highBase = (base >> 24) & 0xFF;
gdtDescs[index].lowLimit = (limit & 0xFFFF);
gdtDescs[index].granularity = (0xC << 4) ^ ((limit >> 16) & 0x0F);
switch (type) {
case DataUp: //0x0
case DataUpWriteable: //0x2
case CodeUp: //0x8
case CodeUpReadable: //0xA
gdtDescs[index].access = (1 << 7) ^ ((dpl & 0x3) << 5) ^ (1 << 4) ^ (type & 0x0F);
break;
default:
gdtDescs[index].access = (1 << 7) ^ ((dpl & 0x3) << 5) ^ (0 << 4) ^ (type & 0x0F);
break;
}
// printf("Dword1: %X\nDword2: %X\n", ((limit & 0xFFFF) << 16) ^ (base & 0xFFFF), (base & 0xFF) ^ (gdtDescs[index].access << 16) ^ (gdtDescs[index].granularity << 8) ^ ((base >> 24) & 0xFF));
GDTr.limit = (sizeof(struct GDTentry) * getNumberOfDescs()) - 1;
if (update)
updGDT();
return index * 8;
}
where gdtDescs is an array of 8192 elements defined as gdt::GDTEntry that is a structure like this:
Code: Select all
struct GDTentry {
unsigned short lowLimit;
unsigned short lowBase;
unsigned char middleBase;
unsigned char access;
unsigned char granularity;
unsigned char highBase;
}
The Handler of my GP Faults report an Error Code = 24 (3 * 8 ), so it should be right
Posted: Fri Feb 01, 2008 1:42 pm
by alkot
According to GP error code (raw_selector & 0xfffc) you are trying to switch to BUSY TSS (index 3) --
/* #GP(selector) if object is not a TSS or is already busy */
Posted: Fri Feb 01, 2008 1:48 pm
by AlfaOmega08
I've tryed to load the 4th segment with the tr = 32. Now info gdt tells that the 4th segment is Busy. So them became busy when I load the TR
Posted: Fri Feb 01, 2008 1:58 pm
by alkot
TSS marks busy when it successfully loaded.
the end of BX_CPU_C::LTR_Ew
Code: Select all
/* mark as busy */
if (!(dword2 & 0x0200)) {
dword2 |= 0x0200; /* set busy bit */
access_linear(BX_CPU_THIS_PTR gdtr.base + selector.index*8 + 4, 4, 0,
BX_WRITE, &dword2);
}
Maybe you are trying to switch to it twice?
Posted: Fri Feb 01, 2008 2:07 pm
by AlfaOmega08
Yes!!!
I've two TSSs. When the PIT fires, I've to load the new TR. If I make an infinite loop after the first LTR is loaded... there isn't any GP fault!!! Now the problem is to understand why it tryes to loads the same TR again...
Thanks a lot