Page 1 of 1

Can you jmp to a memory operand instead of a register value?

Posted: Wed Sep 16, 2020 1:59 am
by ITchimp
I finally got my syscall_fork to work...
also I got my scheduler to deviate from james molloy's.. it worked after a few trial and error...

here is my code for doing the actual switch...

Code: Select all

asm volatile( "pushl %%edi;"
                "pushl %%esi;"
                "pushl %%ebx;"
                "movl %%esp, %0;"
                "movl $1f, %1;"
                "movl %%ebp, %2;"
                "movl  %6, %%eax;" // load new cr3
                "movl  %%eax, %%cr3;"
                "movl  %5, %%ebp;"
                "movl  %4, %%esp;" // load new esp
                "jmp  *%3;"
                "1: ;"
                "popl %%ebx;"
                "popl %%esi;"
                "popl %%edi;"
                :"=m"(prev->esp),"=m"(prev->eip), "=m"(prev->ebp)
                :"r"(current_task->eip), "m"(current_task->esp),"g"(current_task->ebp),"m"(current_task->page_dir->phy_addr)      
                :
   );
what I noticed that if I put current_task->eip into a memory operand (ie. "m"(current_task->eip)) it won't work... it will only work if I put it a register...

why is that the case? Can't I jump to a eip located in a memory location?

Re: Can you jmp to a memory operand instead of a register va

Posted: Wed Sep 16, 2020 2:58 am
by Octocontrabass
Of course you can jump to a memory operand.

The problem is that you've written your inline assembly according to the System V ABI, but the System V ABI only applies to function calls. For inline assembly, all registers are owned by the "caller" and you cannot modify any of them without using them as outputs or putting them in the clobber list. Since you're switching tasks, that means all registers need to be preserved.

I suggest you put your task switch code in an external function instead of using inline assembly.

Re: Can you jmp to a memory operand instead of a register va

Posted: Wed Sep 16, 2020 3:55 am
by ITchimp
since eax, edx, and ecx are scratch register, there should not be a need to preserve those.. that was what system V abi says...

are you saying I have to do a pusha and popa to make the code work, and jmp *%3, will them work, be it register or memory?

Re: Can you jmp to a memory operand instead of a register va

Posted: Wed Sep 16, 2020 7:29 am
by thewrongchristian
ITchimp wrote:since eax, edx, and ecx are scratch register, there should not be a need to preserve those.. that was what system V abi says...

are you saying I have to do a pusha and popa to make the code work, and jmp *%3, will them work, be it register or memory?

The part of the ABI you're referring to covers register use across function calls.

You're not calling a function. Therefore, all the registers at the point you're doing the inline assembly, belong to the compiler to use at it sees fit.

If it helps, move away from inline assembly, and do context switching in a self contained assembly, in either a single context switch function (which can trash eax, edx, and ecx) or in a pair of save/restore context functions (which can do the same.)

setjmp/longjmp is an example of the latter, as is getcontext/setcontext (but these are for user context, mentioned here for reference.)

https://wiki.osdev.org/Kernel_Multitasking contains an example of the former.

Re: Can you jmp to a memory operand instead of a register va

Posted: Wed Sep 16, 2020 11:32 am
by Schol-R-LEA
As an aside, please used [ CODE ] tags in the future, like so:

Code: Select all

asm volatile( "pushl %%edi;"
                "pushl %%esi;"
                "pushl %%ebx;"
                "movl %%esp, %0;"
                "movl $1f, %1;"
                "movl %%ebp, %2;"
                "movl  %6, %%eax;" // load new cr3
                "movl  %%eax, %%cr3;"
                "movl  %5, %%ebp;"
                "movl  %4, %%esp;" // load new esp
                "jmp  *%3;"
                "1: ;"
                "popl %%ebx;"
                "popl %%esi;"
                "popl %%edi;"
                :"=m"(prev->esp),"=m"(prev->eip), "=m"(prev->ebp)
                :"r"(current_task->eip), "m"(current_task->esp),"g"(current_task->ebp),"m"(current_task->page_dir->phy_addr)      
                :
   );

Re: Can you jmp to a memory operand instead of a register va

Posted: Wed Sep 16, 2020 2:53 pm
by linguofreak
ITchimp wrote:since eax, edx, and ecx are scratch register, there should not be a need to preserve those.. that was what system V abi says...

are you saying I have to do a pusha and popa to make the code work, and jmp *%3, will them work, be it register or memory?
The ABI talks about what happens when one bit of code gives control to another. It tells each bit of code what it can expect from the other bit of code. The designation of registers as scratch registers means that the code giving control must expect the code receiving control to use those registers.

During a task switch, the task being switched out is, in general, not giving control to the kernel. The kernel is *taking* control without asking. The task may not be ready to transfer control (it may currently be using a scratch register, for instance). Therefore, the kernel needs to save the complete state of the task it's taking control from, and restore that state when it next selects the task to run. If it does not do this, it will almost certainly cause the task to crash.