Skip to content

Instantly share code, notes, and snippets.

@danielpyon
Created January 24, 2024 21:47
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save danielpyon/a384919390b3a6288695a0252d66e8ae to your computer and use it in GitHub Desktop.
Save danielpyon/a384919390b3a6288695a0252d66e8ae to your computer and use it in GitHub Desktop.
how traps and context switching works
First, it's important to note the difference between kernel<->userspace switch and kernel process -> another kernel process switch. The kernel<->userspace switch is called traps (syscalls, interrupts, etc), and kernel process -> another kernel process is called context switching.

How kernel<->userspace works
	1. Userspace makes syscall (mov rax, syscall num; syscall)
	2. Syscall instruction finds the interrupt table (in xk: vectors.S), jumps to the correct entry. In the case of a syscall, it's entry 0x40, but for example, timer interrupts will have a different value for this. Additionally,  syscall instruction switches CPU into kernel mode, and saves rip,rsp,eflags onto kernel stack.
	3. The interrupt handler pushes 0 (some systems use this as the error code, ignore this), then the interrupt number (so in the case of syscall, 0x40).
	4. Interrupt handler jumps to alltraps.
	5. Alltraps saves rest of registers onto kernel stack, then jumps to trap(tf) with the trapframe (the set of all saved registers) as an argument.
	6. The trap() function will look at trap frame, interrupt type, and saved RAX (on kernel stack) to determine which syscall handler to call.

	1. When returning from kernel to user, the saved registers are popped, then iretq will restore rip,rsp,eflags to the values they were in usermode.

How does kernel process switch to another kernel process?
image
Basically, there's a global array of process objects. Each process object stores a pointer to trapframe and context (stored on per-process kernel stack).

	- Trapframe stores userspace state (as mentioned earlier).
	- Context stores KERNEL state, and this is used for multiprocessing.

Aside: how sched() function works in xk
	- First argument is address of the P->context field (this will point to the old process's context created in sched())
		○ The context is created by pushing registers onto old process's stack, then setting P->context = rsp.
	- Second argument is the context of the NEW process. Sched() will pop regs from this NEW context to switch into it.

	- So BASICALLY, save old context into old process's struct, then switch to new context.


How kernel->kernel switch works
	1. Userspace program is executing.
	2. Timer interrupt occurs (timeslice for this process is up).
	3. The handler for the interrupt calls yield(), which calls sched(), which does a context switch via swtch into the scheduler() function. The scheduler() function can be thought of as analogous to a process (even though it's not).
	4. Then, the scheduler() function will do ANOTHER context switch via swtch, but this time into another PROCESS in the global process table.

What about when a process is first created?
	- Allocproc sets up trapframe (to be address of main() presumably), trapret (assembly that restores trapframe regs to return to userspace).
	- Process is created via fork. So its initial context actually points to forkret.
	- Look at the diagram. After context switch into new process (and it runs forkret), it'll return to trapret (which will go back to userspace).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment