Page 2 of 4

Re: Problems with Ring3 (Problems with GDT and TSS structure

Posted: Fri Aug 23, 2013 1:38 am
by zhiayang
After some twiddling, I realised my error.
The LFB in QEMU is 0xFD000000... the one in Bochs is 0xC0000000.
And *that*, ladies and gentlemen, was the cause of the page-fault.

But there's still a little problem... Returning to ring0.
(For this I've just set up a page-fault to happen on purpose)
The page fault by right should cause me to return to ring0, which it does... sorta.
CS at this point is 0x0B... instead of 0x8.

Highly suspicious.


Next, the TSS doesn't seem to work properly.
This is the TSS code, placing it at 5MB: (don't worry 0-8MB is all identity mapped)

Code: Select all

	GDTTSS:
		.word 0x0068		// Limit (low)
		.word 0x0000		// Base (Addr of TSS)
		.byte 0x50			// middle
		.byte 0xE9
		.byte 0x80
		.byte 0x00
		.long 0x00
		.long 0x00
And this are the fields I set:

Code: Select all


	Memory::Set32((void*)0x500004, 0x00300000, 1);
	Memory::Set32((void*)0x500024, 0x00600000, 1);
	asm volatile("mov $0x2B, %ax; ltr %ax");
Supposedly, it will change RSP to 0x00300000 on returning to ring0.
And it should set RSP to 0x00600000 on an exception... configured as such.

The 8-bit field containing the IST, if == 0x01, would be IST1 on AMD's manual (2012) figure 12-8... Right?
Unless it needs to be 0x0... which doesn't make sense since that is the default value and the lack of a TSS would probably kill everything.


Setting it to 1 for selector < 32 (All the CPU exceptions basically) gives a stack fault when I get an exception (when I push the error-code and the exception number).

At this point %rsp is still the user-mode stack at 0x3FFFF0.
If the TSS works, I'd be seeing a value of 0x600000, right?!
So it probably doesn't work.


Any pointers?

Re: Problems with Ring3 (Problems with GDT and TSS structure

Posted: Fri Aug 23, 2013 9:31 pm
by zhiayang
Bump?

A bit more debugging went through. And I'm pretty sure when the interrupt (I'm just using a divide-by-zero interrupt now, int $0x0) happens, the CPU is still in Ring3.

Because when I try and modify %ds or access %cr2, I get another GPF (which presumably was caused by the int $0x0 in the first place).
And then I get an infinite loop of faultiness.

While i'm here, a quick question:
1. The CPU *is* supposed to switch back to ring0 on an exception.... right?!
2. Can you not force CPU exceptions (like "int $13" or "int $0") in user mode?
3. You *can* execute IRQs (int $0x80) in ring3... right? else I don't see how the linux thing works.

Re: Problems with Ring3 (Problems with GDT and TSS structure

Posted: Sat Aug 24, 2013 3:14 am
by bluemoon
requimrar wrote:A bit more debugging went through. And I'm pretty sure when the interrupt (I'm just using a divide-by-zero interrupt now, int $0x0) happens, the CPU is still in Ring3.
Check your interrupt descriptors CS field.
requimrar wrote:1. The CPU *is* supposed to switch back to ring0 on an exception.... right?!
The CPU switch to whatever set on IDT (ie. CS field), you usually set this to ring0 code
requimrar wrote:2. Can you not force CPU exceptions (like "int $13" or "int $0") in user mode?
You may manually invoke interrupt for exception (there is check for DPL), however, some exception push error code that is a bit tricky to simulate.
requimrar wrote:3. You *can* execute IRQs (int $0x80) in ring3... right? else I don't see how the linux thing works.
Yes, and there is check in DPL field of the IDT entry.

Re: Problems with Ring3 (Problems with GDT and TSS structure

Posted: Sat Aug 24, 2013 7:20 am
by zhiayang
Right. My GDT is basically the same as it was before. (The latest one)
But for reference, here's the 64-bit ring0 CS.

Code: Select all

GDTCode:
	.word 0xFFFF		// Limit (low)
	.word 0			// Base (low)
	.byte 0			// Base (middle)
	.byte 0x9E		// Access
	.byte 0xAF		// Granularity / Limit (high)
	.byte 0			// Base (high)

Should be set to ring0 and such-and-such.
My IDT code is basically from the well-known bkerndev.
The IDT selector is set to 0x8.

Code: Select all

void SetGate(uint8_t num, uint64_t base, uint16_t sel, uint8_t flags)
{
	// The interrupt routine's base address
	idt[num].base_lo = (base & 0xFFFF);
	idt[num].base_mid = (base >> 16) & 0xFFFF;
	idt[num].base_hi = (base >> 32) & 0xFFFFFFFF;

	// The segment or 'selector' that this IDT entry will use
	// is set here, along with any access flags

	idt[num].sel = sel;
	idt[num].always0_ist = 0x0;

	idt[num].always0_1 = 0;
	idt[num].flags = flags;
}
This should send the CPU to ring0, CS=0x08 on an interrupt... but it doesn't.
Called with this:

Code: Select all

SetGate(0, (uint64_t)isr0, 0x08, 0x8E);
Thanks again bluemoon!

Re: Problems with Ring3 (Problems with GDT and TSS structure

Posted: Sun Aug 25, 2013 8:30 pm
by zhiayang
After some more debugging, I still can't seem to solve the problem.
This is the IDT as it stands:

Code: Select all

Interrupt Descriptor Table (base=0x0000000000216080, limit=4095):
IDT[0x00]=64-Bit Interrupt Gate target=0x0008:0000000000204714, DPL=3
IDT[0x01]=64-Bit Interrupt Gate target=0x0008:000000000020471d, DPL=3
IDT[0x02]=64-Bit Interrupt Gate target=0x0008:0000000000204726, DPL=3
IDT[0x03]=64-Bit Interrupt Gate target=0x0008:000000000020472f, DPL=3
IDT[0x04]=64-Bit Interrupt Gate target=0x0008:0000000000204738, DPL=3
IDT[0x05]=64-Bit Interrupt Gate target=0x0008:0000000000204741, DPL=3
IDT[0x06]=64-Bit Interrupt Gate target=0x0008:000000000020474a, DPL=3
IDT[0x07]=64-Bit Interrupt Gate target=0x0008:0000000000204753, DPL=3
IDT[0x08]=64-Bit Interrupt Gate target=0x0008:000000000020475c, DPL=0
IDT[0x09]=64-Bit Interrupt Gate target=0x0008:0000000000204763, DPL=3
IDT[0x0a]=64-Bit Interrupt Gate target=0x0008:000000000020476c, DPL=3
IDT[0x0b]=64-Bit Interrupt Gate target=0x0008:0000000000204773, DPL=3
IDT[0x0c]=64-Bit Interrupt Gate target=0x0008:000000000020477a, DPL=3
IDT[0x0d]=64-Bit Interrupt Gate target=0x0008:0000000000204781, DPL=3
IDT[0x0e]=64-Bit Interrupt Gate target=0x0008:0000000000204788, DPL=3
IDT[0x0f]=64-Bit Interrupt Gate target=0x0008:000000000020478f, DPL=3
I've changed the flags (that includes Present, Type, DPL etc) to 0xEE from 0x8E, setting DPL=3. Probably not supposed to do that, but I'm just trying everything at this stage.

Bochs still reports CS=0xB, not 0x8 as expected, when in the ISR handler.
(Note how the IDT dump above says the target=0x08)...

Any help? Thanks!



EDIT:
Basically what happens is this:
I can get to Ring3 just fine: CS=0x1B.

The code runs and all.
Next I deliberately cause an interrupt (any interrupt, although a #PF is what I usually use) to see if I can at least get back into Ring0.
Problem is, when I try to modify %DS or %CR2, I get a #GPF because presumably I'm still in Ring3... (CS=0xB now)... And because the ISR handler gets CR2 and changes DS=0x10... I interrupt loop forever.

So I think the problem is, the CPU isn't going back to Ring0...

Final GDT/IDT dump:

GDT:

Code: Select all




// 64-bit GDT
GDT64:
	GDTNull:
		.word 0				// Limit (low)
		.word 0				// Base (low)
		.byte 0				// Base (middle)
		.byte 0				// Access
		.byte 0				// Granularity / Limit (high)
		.byte 0				// Base (high)
	GDTCode:
		.word 0xFFFF		// Limit (low)
		.word 0				// Base (low)
		.byte 0				// Base (middle)
		.byte 0x9E			// Access
		.byte 0xAF			// Granularity / Limit (high)
		.byte 0				// Base (high)
	GDTData:
		.word 0xFFFF		// Limit (low)
		.word 0				// Base (low)
		.byte 0				// Base (middle)
		.byte 0x92			// Access
		.byte 0xAF			// Granularity / Limit (high)
		.byte 0				// Base (high)
	GDTCodeR3:
		.word 0xFFFF		// Limit (low)
		.word 0				// Base (low)
		.byte 0				// Base (middle)
		.byte 0xFC			// Access
		.byte 0x2F			// Granulariry / Limit (high)
		.byte 0				// Base (high)
	GDTDataR3:
		.word 0xFFFF		// Limit (low)
		.word 0				// Base (low)
		.byte 0				// Base (middle)
		.byte 0xF2			// Access
		.byte 0xAF			// Granulariry / Limit (high)
		.byte 0				// Base (high)
	GDTTSS:
		.word 0x0068		// Limit (low)
		.word 0x0000		// Base (Addr of TSS)
		.byte 0x50			// middle
		.byte 0xE9
		.byte 0x80
		.byte 0x00
		.long 0x00
		.long 0x00



		// Pointer
	GDT64Pointer:
		.word GDT64Pointer - GDT64 - 1	// Limit
		.quad GDT64						// Base

IDT:

Code: Select all

struct __attribute__((packed)) IDTEntry
	{
		uint16_t base_lo;
		uint16_t sel;
		uint8_t always0_ist;
		uint8_t flags;
		uint16_t base_mid;
		uint32_t base_hi;
		uint32_t always0_1;
	};

	struct __attribute__((packed)) IDTPointer
	{
		uint16_t limit;
		uint64_t base;
	};








	static IDTEntry idt[256];
	static IDTPointer idtp;

	// Use this function to set an entry in the IDT. Alot simpler
	// than twiddling with the GDT ;)
	void SetGate(uint8_t num, uint64_t base, uint16_t sel, uint8_t flags)
	{
		// The interrupt routine's base address
		idt[num].base_lo = (base & 0xFFFF);
		idt[num].base_mid = (base >> 16) & 0xFFFF;
		idt[num].base_hi = (base >> 32) & 0xFFFFFFFF;

		// The segment or 'selector' that this IDT entry will use
		// is set here, along with any access flags

		idt[num].sel = sel;
		// if(num < 32)
		// 	idt[num].always0_ist = 0x1;

		// else
			idt[num].always0_ist = 0x0;

		idt[num].always0_1 = 0;
		idt[num].flags = flags;
	}

	// Installs the IDT
	void Initialise()
	{

		// Sets the special IDT pointer up, just like in 'gdt.c'
		idtp.limit = (sizeof(IDTEntry) * 256) - 1;
		idtp.base = (uintptr_t)&idt;

		// Clear out the entire IDT, initializing it to zeros
		Memory::Set(&idt, 0, sizeof(IDTEntry) * 256);

		// Add any new ISRs to the IDT here using idt_set_gate

		InstallDefaultHandlers();


		// Points the processor's internal register to the new IDT
		HAL_AsmLoadIDT((uint64_t)&idtp);
	}

	void InstallDefaultHandlers()
	{
		SetGate(0, (uint64_t)isr0, 0x08, 0xEE);
		SetGate(1, (uint64_t)isr1, 0x08, 0xEE);
		SetGate(2, (uint64_t)isr2, 0x08, 0xEE);
		SetGate(3, (uint64_t)isr3, 0x08, 0xEE);
		SetGate(4, (uint64_t)isr4, 0x08, 0xEE);
		SetGate(5, (uint64_t)isr5, 0x08, 0xEE);
		SetGate(6, (uint64_t)isr6, 0x08, 0xEE);
		SetGate(7, (uint64_t)isr7, 0x08, 0xEE);

		SetGate(8, (uint64_t)isr8, 0x08, 0x8E);
		SetGate(9, (uint64_t)isr9, 0x08, 0xEE);
		SetGate(10, (uint64_t)isr10, 0x08, 0xEE);
		SetGate(11, (uint64_t)isr11, 0x08, 0xEE);
		SetGate(12, (uint64_t)isr12, 0x08, 0xEE);
		SetGate(13, (uint64_t)isr13, 0x08, 0xEE);
		SetGate(14, (uint64_t)isr14, 0x08, 0xEE);
		SetGate(15, (uint64_t)isr15, 0x08, 0xEE);

		SetGate(16, (uint64_t)isr16, 0x08, 0x8E);
		SetGate(17, (uint64_t)isr17, 0x08, 0x8E);
		SetGate(18, (uint64_t)isr18, 0x08, 0x8E);
		SetGate(19, (uint64_t)isr19, 0x08, 0x8E);
		SetGate(20, (uint64_t)isr20, 0x08, 0x8E);
		SetGate(21, (uint64_t)isr21, 0x08, 0x8E);
		SetGate(22, (uint64_t)isr22, 0x08, 0x8E);
		SetGate(23, (uint64_t)isr23, 0x08, 0x8E);

		SetGate(24, (uint64_t)isr24, 0x08, 0x8E);
		SetGate(25, (uint64_t)isr25, 0x08, 0x8E);
		SetGate(26, (uint64_t)isr26, 0x08, 0x8E);
		SetGate(27, (uint64_t)isr27, 0x08, 0x8E);
		SetGate(28, (uint64_t)isr28, 0x08, 0x8E);
		SetGate(29, (uint64_t)isr29, 0x08, 0x8E);
		SetGate(30, (uint64_t)isr30, 0x08, 0x8E);
		SetGate(31, (uint64_t)isr31, 0x08, 0x8E);


		// Remap the IRQs from 0 - 7 -> 8 - 15 to 32-47
		outb(0x20, 0x11);
		outb(0xA0, 0x11);
		outb(0x21, 0x20);
		outb(0xA1, 0x28);
		outb(0x21, 0x04);
		outb(0xA1, 0x02);
		outb(0x21, 0x01);
		outb(0xA1, 0x01);
		outb(0x21, 0x0);
		outb(0xA1, 0x0);

		SetGate(32, (uint64_t)irq0, 0x08, 0x8E);
		SetGate(33, (uint64_t)irq1, 0x08, 0x8E);
		SetGate(34, (uint64_t)irq2, 0x08, 0x8E);
		SetGate(35, (uint64_t)irq3, 0x08, 0x8E);
		SetGate(36, (uint64_t)irq4, 0x08, 0x8E);
		SetGate(37, (uint64_t)irq5, 0x08, 0x8E);
		SetGate(38, (uint64_t)irq6, 0x08, 0x8E);
		SetGate(39, (uint64_t)irq7, 0x08, 0x8E);
		SetGate(40, (uint64_t)irq8, 0x08, 0x8E);
		SetGate(41, (uint64_t)irq9, 0x08, 0x8E);
		SetGate(42, (uint64_t)irq10, 0x08, 0x8E);
		SetGate(43, (uint64_t)irq11, 0x08, 0x8E);
		SetGate(44, (uint64_t)irq12, 0x08, 0x8E);
		SetGate(45, (uint64_t)irq13, 0x08, 0x8E);
		SetGate(46, (uint64_t)irq14, 0x08, 0x8E);
		SetGate(47, (uint64_t)irq15, 0x08, 0x8E);
	}

Sorry for the code dump... but I'm kinda desperate here.
Thanks!

Re: CPU still in Ring3 on Interrupt

Posted: Sun Aug 25, 2013 11:05 pm
by bluemoon
I think there are too many guess works here.

I suggest to step-by-step re-confirm your guess, there should be something missed, the CPU won't do magics.

1. verify you actually invoked the exception and the right handler, try putting CLI-HLT or put a character on screen/serial port, you may set the vga text buffer to world writable for such test. You may also try different exception, divide by zero is good one.

2. break the emulator right after entered ring3 and dump all machines states including IDT, GDT, TSS, and register states.

3. review seemingly irreverent matters, for example, if you have multiple process, do page tables properly synchronized? Basically all OS developers went thought those nasty bugs, and those bugs produce non-sense symptoms.

Re: CPU still in Ring3 on Interrupt

Posted: Mon Aug 26, 2013 12:54 am
by zhiayang
bluemoon wrote:I think there are too many guess works here.

I suggest to step-by-step re-confirm your guess, there should be something missed, the CPU won't do magics.

1. verify you actually invoked the exception and the right handler, try putting CLI-HLT or put a character on screen/serial port, you may set the vga text buffer to world writable for such test. You may also try different exception, divide by zero is good one.

2. break the emulator right after entered ring3 and dump all machines states including IDT, GDT, TSS, and register states.

3. review seemingly irreverent matters, for example, if you have multiple process, do page tables properly synchronized? Basically all OS developers went thought those nasty bugs, and those bugs produce non-sense symptoms.



1. I'm 100% sure the right exception handler is being invoked... kinda.
asm volatile("int $0x00"); actually gives a #GPF, not a #DIV0 as I would expect.
Hence the question: is "int $0x00" actually legal in Ring3?

Meanwhile, a page fault (not present, for instance. All my pages are mapped 0x07 for now) actually execute the #PF handler.
(I see 0x0E being pushed, as expected)



2. The IDT and GDT all look sane.

Code: Select all

GDT[0x01]=Code segment, base=0x00000000, limit=0xffffffff, Execute/Read, Conforming, Accessed, 64-bit
GDT[0x02]=Data segment, base=0x00000000, limit=0xffffffff, Read/Write, Accessed
GDT[0x03]=Code segment, base=0x00000000, limit=0xffffffff, Execute/Read, Conforming, Accessed, 64-bit
GDT[0x04]=Data segment, base=0x00000000, limit=0xffffffff, Read/Write, Accessed
GDT[0x05]=32-Bit TSS (Busy) at 0x00500000, length 0x00068
Don't know why the TSS is 64-bit, or why it's busy... but the address and length look sane.
EDIT: looks like Bochs thinks the TSS is 32-bit since it's redefined as the 64-bit one.
Still don't know why it's busy.

It's kind of difficult to debug the TSS properly given that Bochs insists on using 32-bit definitions... I can't build Bochs with the 64-bit option... something about gtk/gtk.h.

Either way.



3. Currently I do a "cli" before trying to execute the Ring3 code so my context-switcher doesn't run.
Stepping through the code I'm positive it doesn't.


EDIT: I also realised that I forgot to set the 'gran' bit in the GDT, the limit is fixed now. All entries are flat, 4GB segments.

These are the IDT entries:

Code: Select all

IDT[0x00]=64-Bit Interrupt Gate target=0x0008:0000000000204724, DPL=0
IDT[0x01]=64-Bit Interrupt Gate target=0x0008:000000000020472d, DPL=0
IDT[0x02]=64-Bit Interrupt Gate target=0x0008:0000000000204736, DPL=0
IDT[0x03]=64-Bit Interrupt Gate target=0x0008:000000000020473f, DPL=0
IDT[0x04]=64-Bit Interrupt Gate target=0x0008:0000000000204748, DPL=0
etc...
As mentioned previously, they're all for Ring0, DPL=0 and CS=0x8....

I'm really stuck here, so most of what I can do is guesswork.


EDIT: I've checked, homebrew installs bochs 2.6.1 with --enable-x86-64, so I have *no idea* why it insists on using 32-bit things for the TSS. Especially since 1, the CPU is in long mode and 2, it's compiled to understand 64-bit stuff....

Re: CPU still in Ring3 on Interrupt

Posted: Mon Aug 26, 2013 1:15 am
by bluemoon
requimrar wrote:1. I'm 100% sure the right exception handler is being invoked... kinda.
asm volatile("int $0x00"); actually gives a #GPF, not a #DIV0 as I would expect.
Hence the question: is "int $0x00" actually legal in Ring3?

...

As mentioned previously, they're all for Ring0, DPL=0 and CS=0x8....
If you want to call INT in ring3, the descriptor should set to DPL=3.
When debugging, don't set assumption, you don't 100% sure anything.
requimrar wrote:I'm really stuck here, so most of what I can do is guesswork.
Re-read the manuals or books may help.

Re: CPU still in Ring3 on Interrupt

Posted: Wed Aug 28, 2013 6:09 am
by zhiayang
bluemoon wrote:
requimrar wrote:1. I'm 100% sure the right exception handler is being invoked... kinda.
asm volatile("int $0x00"); actually gives a #GPF, not a #DIV0 as I would expect.
Hence the question: is "int $0x00" actually legal in Ring3?

...

As mentioned previously, they're all for Ring0, DPL=0 and CS=0x8....
If you want to call INT in ring3, the descriptor should set to DPL=3.
When debugging, don't set assumption, you don't 100% sure anything.
requimrar wrote:I'm really stuck here, so most of what I can do is guesswork.
Re-read the manuals or books may help.




1. Right, I totally forgot about that. If I set the DPL to 3, then the correct interrupt handler is called. Problem is, when I try to fetch %cr2 or modify %ds (or in other words do something useful), it generates a #GPF because it's still in ring3.

2. I've read that thing (the relevant sections anyway) quite a number of times now. I could be blind, but I'm not seeing what's wrong here. Honestly.


If someone is willing to spend some time to look at my issue, the relevant code files are

Code: Select all

src/loader/boot.s   --> GDT/TSS
src/loader/bootstrap.s      --> Code to enter ring3
src/kernel/hal/interrupts/interrupts.cpp     --> IDT stuff
src/kernel/main.cpp                                    --> Code to load ring3

Mostly this:
asm volatile("cli");
Memory::Set32((void*)0x500004, 0x00300000, 1);
Memory::Set32((void*)0x500024, 0x00600000, 1);
asm volatile("mov $0x2B, %ax; ltr %ax");

asm volatile("xchg %bx, %bx");
DoUsermode();


Thanks!

Re: CPU still in Ring3 on Interrupt

Posted: Thu Aug 29, 2013 12:20 am
by zhiayang
Alright... I'm pretty sure I've gone through these things too many times.

Bochs says my IDT is as such:

Code: Select all

IDT[0x00]=64-Bit Interrupt Gate target=0x0008:0000000000204724, DPL=3
So the IDT entry looks correct: target 0x8, DPL=3 (to execute from Ring3)
I don't really think the GDT is involved in this, since the CPU should automatically change CS to the value in the IDT's selector.
And the TSS shouldn't matter here as well, since it's just supposed to change %sp (which doesn't really matter at this point).

I really, really have no idea why CS=0xB. The IDT clearly sets the target selector to 0x8.
Is it something to do with interrupts to a different privilege level? The manual has me jumping around from page to page and I cannot discern the problem...

Re: CPU still in Ring3 on Interrupt

Posted: Fri Aug 30, 2013 12:19 am
by bluemoon
requimrar wrote:And the TSS shouldn't matter here as well, since it's just supposed to change %sp (which doesn't really matter at this point).
It does matter, if rsp is point to wrong place, it can get all sort of funny things.
requimrar wrote:I really, really have no idea why CS=0xB. The IDT clearly sets the target selector to 0x8.
Is it something to do with interrupts to a different privilege level? The manual has me jumping around from page to page and I cannot discern the problem...
I suspect you either jump to wrong interrupt with bad descriptor, or successfully get into the handler itself but then doing funny things, have you tried CLI/HLT right at the interrupt handler and break there?

Re: CPU still in Ring3 on Interrupt

Posted: Fri Aug 30, 2013 1:15 am
by zhiayang
bluemoon wrote:
requimrar wrote:And the TSS shouldn't matter here as well, since it's just supposed to change %sp (which doesn't really matter at this point).
It does matter, if rsp is point to wrong place, it can get all sort of funny things.
requimrar wrote:I really, really have no idea why CS=0xB. The IDT clearly sets the target selector to 0x8.
Is it something to do with interrupts to a different privilege level? The manual has me jumping around from page to page and I cannot discern the problem...
I suspect you either jump to wrong interrupt with bad descriptor, or successfully get into the handler itself but then doing funny things, have you tried CLI/HLT right at the interrupt handler and break there?


1. Right. I'm currently not doing anything with the TSS now (I don't do the LTR). It shouldn't matter as long as both stacks are valid, right?

The kernel's stack is at 0x8000, the user-prorgam's stack is at 0x00400000. Since an exception is supposed to push some values on the stack, I obviously can't just change %sp on entering the handler.

The stack should be valid, at least as valid as a mostly-empty stack containing only %rbp.


2. I'm not doing anything funny. Obviously I can't do a cli; hlt, since, as I mention before, the CPU thinks I'm in Ring3 and I can't do any of those privileged instructions, one of which is modifying %ds to 0x10 and getting the value of %cr2.


It's jumping to the right interrupt handler, after I set the flags to 0xEE (allowing Ring3 to call the interrupt). Thing is, the CPU insists on setting the bottom 2 bits of my CS selector making it 0xB instead of 0x8, which I'm 99% sure is the cause of the problem.

Re: CPU still in Ring3 on Interrupt

Posted: Fri Aug 30, 2013 1:23 am
by bluemoon
requimrar wrote:1. Right. I'm currently not doing anything with the TSS now (I don't do the LTR). It shouldn't matter as long as both stacks are valid, right?
You can't get back to ring0 without a proper TSS, the stack switch will fail.
requimrar wrote:2. I'm not doing anything funny. Obviously I can't do a cli; hlt, since, as I mention before, the CPU thinks I'm in Ring3 and I can't do any of those privileged instructions, one of which is modifying %ds to 0x10 and getting the value of %cr2.
You can still setup breakpoint there with the debugger, then investigate the machine state right at the interrupt handler. In theory you should be in ring0 right at the interrupt entrance if you setup everything correctly.

Re: CPU still in Ring3 on Interrupt

Posted: Fri Aug 30, 2013 3:16 am
by zhiayang
Well. I did fix the TSS, as follows:

Code: Select all

GDTTSS:
	.word 0x0068		// Limit (low)
	.word 0x0000		// Base (Addr of TSS)
	.byte 0x50			// middle
	.byte 0xE9
	.byte 0x80
	.byte 0x00
	.long 0x00
	.long 0x00
And this:

Code: Select all

Memory::Set((void*)0x500000, 0, 0x68);
Memory::Set32((void*)0x500004, 0x00008000, 1);
Memory::Set32((void*)0x500008, 0, 1);
Memory::Set32((void*)0x500024, 0x00009000, 1);
Memory::Set32((void*)0x500028, 0, 1);
asm volatile("mov $0x2B, %ax; ltr %ax");

The TSS is supposed to switch to 0x8000 on ring-0 and all CPU exceptions.
Problem again: works on qemu, not on bochs.
In QEMU I can do all the things: set %ds, get %cr2 etc. (means I'm in ring3, CS verifies this)


QEMU somehow successfully changes CS=0x8 on interrupts... but not bochs.
(I set a loop on the interrupt handler (before it does anything privileged), and checked CS on both bochs and QEMU; the former is 0xB, the latter is 0x8)

Any ideas? The TSS's IST works, it changes %sp to 0x9000 on interrupt.
CS though... CS...

Re: CPU still in Ring3 on Interrupt

Posted: Fri Aug 30, 2013 3:44 am
by bluemoon
How about "mov $0x28, %ax; ltr %ax"? This is the only thing differ with how I do in my kernel.

Without a serious debugging session, what I can help is limited to educated guess.