Page 1 of 1

Syscall/Sysret works the first time, causes #IO next.

Posted: Sat Oct 05, 2013 9:49 am
by zhiayang
Hello.

I've recently got Ring3 threads working in my scheduler, but right now I'm using iret and there is a noticeable lag/stutter/what have you.

So I'm looking into replacing that with Syscall/Sysret... and I believe i've gotten most of the thing figured out... except this.

As you can tell from the title, I can successfully perform a syscall and sysret... however, it fails with an Invalid Opcode exception subsequent times.

Here is the code:

Ring3 program:

Code: Select all

while(true)
{
	asm volatile("syscall");
}
quite simple. Here is the MSR setup:

Code: Select all

        // setup MSRs for syscall/sysret

	// modify STAR
	mov $0xC0000081, %ecx
	rdmsr
	// msr is edx:eax

	// simultaneously setup sysret CS and syscall CS
	mov $0x001B0008, %edx
	xor %eax, %eax
	wrmsr


	// now we modify LSTAR to hold the address of HandleSyscall
	xor %edx, %edx

	// TODO: Write handler for SYSCALL instruction instead of interrupt
	// keep both options available.
	// fill in address when ready/
	mov $HandleSyscallInstruction, %eax
	mov $0xC0000082, %ecx
	wrmsr


	// set SFMASK to 0.
	mov $0xC0000084, %ecx
	xor %eax, %eax
	wrmsr








	// Call our kernel.
	call kmain

And here is the actual code that gets called:

Code: Select all

xchg %bx, %bx
push %rcx

pop %rcx
sysret


Anyone got any clues? All the register values look normal at the time -- the exception occurs on the 'syscall' instruction, the second time. Works 100% as far as i can tell for the first time.

Thanks!

Re: Syscall/Sysret works the first time, causes #IO next.

Posted: Sat Oct 05, 2013 12:48 pm
by bluemoon
requimrar wrote: // TODO: Write handler for SYSCALL instruction instead of interrupt
// keep both options available.
// fill in address when ready/
xor %edx, %edx
mov $HandleSyscallInstruction, %eax
mov $0xC0000082, %ecx
wrmsr
EDX:EAX should point to the handler, you probably should do this instead:

Code: Select all

    mov     ecx, 0xC0000082     ; IA32_LSTAR
    mov     rax, qword _syscall_stub
    mov     rdx, rax
    shr     rdx, 32
requimrar wrote: // set SFMASK to 0.
mov $0xC0000084, %ecx
xor %eax, %eax
wrmsr
I suggest to set FMASK to IF, so you could safely setup things like valid stack after the CPU gets into ring0.

By the way, I assume you have set IA32_EFER.SCE.

Re: Syscall/Sysret works the first time, causes #IO next.

Posted: Sun Oct 06, 2013 4:38 am
by zhiayang
bluemoon wrote:
requimrar wrote: // TODO: Write handler for SYSCALL instruction instead of interrupt
// keep both options available.
// fill in address when ready/
xor %edx, %edx
mov $HandleSyscallInstruction, %eax
mov $0xC0000082, %ecx
wrmsr
EDX:EAX should point to the handler, you probably should do this instead:

Code: Select all

    mov     ecx, 0xC0000082     ; IA32_LSTAR
    mov     rax, qword _syscall_stub
    mov     rdx, rax
    shr     rdx, 32
requimrar wrote: // set SFMASK to 0.
mov $0xC0000084, %ecx
xor %eax, %eax
wrmsr
I suggest to set FMASK to IF, so you could safely setup things like valid stack after the CPU gets into ring0.

By the way, I assume you have set IA32_EFER.SCE.

I know for a fact that the sys call handler is below 4GB so I can omit the %edx part of the MSR. (notice i xor it).
And yes, SCE is set.
I get the feeling it's the IST messing the stack up (I encountered a similar problem this morning while working with my iret model)...

Re: Syscall/Sysret works the first time, causes #IO next.

Posted: Sun Oct 06, 2013 5:07 am
by iansjack
I get the feeling it's the IST messing the stack up
Easily tested with a debugger. Facts are better than feelings in OS design.