1

This code is the code given for context switching in xv6. Although I am able to understand that the overall code saves the registers from the old context on to the PCB, I am just not able to wrap my head around how each line works.

void swtch(struct context **old, struct context *new);
#
# Save current register context in old
# and then load register context from new.
.globl swtch
swtch:
# Save old registers
movl 4(%esp), %eax # put old ptr into eax
popl 0(%eax) # save the old IP
movl %esp, 4(%eax) # and stack
movl %ebx, 8(%eax) # and other registers
movl %ecx, 12(%eax)
movl %edx, 16(%eax)
movl %esi, 20(%eax)
movl %edi, 24(%eax)
movl %ebp, 28(%eax)

# Load new registers
movl 4(%esp), %eax #put new ptr into eax
movl 28(%eax), %ebp #restore other registers
movl 24(%eax), %edi
movl 20(%eax), %esi
movl 16(%eax), %edx
movl 12(%eax), %ecx
movl 8(%eax), %ebx
movl 4(%eax), %esp #stack is switched here
pushl 0(%eax) #return addr put in place
ret #finally return into new ctxt

Can someone help me out with how the CPU registers are saved onto the PCB?

Jester
  • 56,577
  • 4
  • 81
  • 125
Ajayv
  • 374
  • 2
  • 13
  • 2
    Ask a more specific question, which part is unclear? It's just a bunch of moves... – Jester Aug 29 '17 at 00:53
  • 1
    When the function starts the _CALL_ instruction has palced the return address on the stack at 0(ESP). The first parameter at 4(ESP) (old context) and 8(ESP) new context. `movl 4(%esp), %eax` get the old context pointer into EAX. The `popl` gets the return instruction pointer pushed by the call and saves it (this add 4 to ESP in the process). All the current registers are saved into the old context via the _EAX_ pointer. because the POP added 4 to _ESP_ when we load the new registers the old context pointer is now on top of stack at 0(ESP) and new context pointer at 4(ESP). – Michael Petch Aug 29 '17 at 01:08
  • The pointer at 4(ESP) (the new context) is then used to load all the registers with the new context. The `pushl 0(%eax)` places the new instruction pointer onto the stack so that the `ret` will return to it. – Michael Petch Aug 29 '17 at 01:11
  • 1
    I looked at this more closely and I am thinking this code has a bug in it. Where did you get this specific code? I noticed `swtch` passes a pointer to a pointer to an old context. There seems to be a missing dereference in this code. After `movl 4(%esp), %eax` I'd expect to see something like `movl (%eax), %eax` – Michael Petch Aug 29 '17 at 02:36
  • 1
    Yeah I just realised that the first line is buggy. It is supposed to be *old, not **old. I got it from the OS: Three easy pieces textbook. – Ajayv Aug 29 '17 at 03:06
  • 1
    I am reading OSTEP and find the same problem. I spend about half an hour figuring it out. Thanks for asking this question to let me confirm there is a bug. – huangjl Feb 23 '21 at 13:54
  • Here is the [xv6 source of swtch.S](https://github.com/mit-pdos/xv6-public/blob/c95bde8163eca7a19c95f3b05156e0ad33312589/swtch.S), which seems to be the version referred in OSTEP. And we can confirm that the current code in OSTEP has a bug and it should be changed to `struct context *old`. I made [a pull request to ostep-typos which includes this fix](https://github.com/remzi-arpacidusseau/ostep-typos/pull/62/commits/c5dda8323d90ca8e8971f6889afd94839b33d69e). – Gorisanson Oct 30 '22 at 01:37

0 Answers0