You can see the source code at LEX and the switch_to macro is in include/linux/sched.h.
168#define switch_to(n) {\ 169struct {long a,b;} __tmp; \ 170__asm__("cmpl %%ecx,_current\n\t" \ 171 "je 1f\n\t" \ 172 "xchgl %%ecx,_current\n\t" \ 173 "movw %%dx,%1\n\t" \ 174 "ljmp %0\n\t" \ 175 "cmpl %%ecx,%2\n\t" \ 176 "jne 1f\n\t" \ 177 "clts\n" \ 178 "1:" \ 179 ::"m" (*&__tmp.a),"m" (*&__tmp.b), \ 180 "m" (last_task_used_math),"d" _TSS(n),"c" ((long) task[n])); \This is the switch_to macro at all. It's simple isn't it?
It is called from schedule() like switch_to(next);. next is an index number to next process in the array of task it data type is struct task_struct.
At line 169, temporary structure is defined which need to segment jump. Line 170 is comparing ecx register to current process. btw, in assembly code, "_" prefix is needed. Anyway, why it uses ecx register means at line 180 you can see "c" ((long) task[n]) statement. It means the address of task[n] is copied to ecx register. so, it can use ecx register to comparing.
Then if current process and next process is same, jump to line 178 and finish this macro. If current process != next process, current process is copied to ecx register.
At line 173, edx register's value is copied to __tmp.b. Then do segment jump at line 174. Then process was switched to new process because linux v0.01 uses hardware context switch so that segment jump via TSS segment cause task switching.
Next, at line 175 checks if current is same as last_task_used_math. The last_task_used_math has FPU registers state. If current == last_task_used_math, it call clts instruction to clear TS flag in CR0 register. From intel's ducument, it says The processor sets the TS flag every time a task switch occurs. The flag is used to synchronize the saving of FPU context in
multitasking applications. Then everything is done:-)