From 6749a631452c3c5af68426cdbcfdd011d315c0ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Lov=C3=A9n?= Date: Tue, 27 Mar 2018 14:50:59 +0200 Subject: [PATCH] DOC - CH10 WIP --- doc/10_Threading.md | 92 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) diff --git a/doc/10_Threading.md b/doc/10_Threading.md index e69de29..1c510db 100644 --- a/doc/10_Threading.md +++ b/doc/10_Threading.md @@ -0,0 +1,92 @@ +# Threading + +In this chapter we'll implement context switching and a simple scheduler. + +## Context switching + +Switching from one thread to another is actually really easy. All you need to +do is replace everything in every processor register at the same time, and +you're good to go. Ok... that doesn't sound so simple, but we get some help. + +In the conventions used by our gcc cross compiler (known as [System V +ABI](https://wiki.osdev.org/System_V_ABI)), when calling a function only a few +registers are guaranteed to be preserved. Those are `rbx`, `rsp`, `rbp`, `r12`, +`r13`, `r14` and `r15`. The rest can not be assumed to retain the same value. + +So, if we make our context switch out to look like a function call, we only +need to replace those seven registers. This can easily be done with a small asm +routine: + +`src/kernel/proc/swtch.S` +```asm +.intel_syntax noprefix + +.global switch_stack +switch_stack: + push rbp + mov rbp, rsp + + push r15 + push r14 + push r13 + push r12 + push rbx + push rbp + + mov [rdi], rsp + mov rsp, [rsi] + + pop rbp + pop rbx + pop r12 + pop r13 + pop r14 + pop r15 + + leaveq + ret +``` + +This pushes all registers, writes the stack pointer to the address passed as +the first argument, reads a new stack pointer from the address in the second +argument, and pops all registers. Since the return address is on the stack, the +`ret` instruction will return to the new thread. + +> #### A note on credit +> +> Not everything I present here is my own original ideas. In fact, most of it +> probably isn't. I've been itterating my kernel design from the ground up a +> dozen times or more through the last ten years, and where I picked up methods +> and ideas have gotten lost along the way. +> +> This method of switching threads, though, I know I got from XV6, where it may +> or may not have originated. +> +> I'm sorry I can't always give proper and detailed credit to the giants on +> whose shoulders I stand, but for a list of my most significant sources of +> inspiration through the years, see Chapter 0. + +## Threads + +Ok, so now switching between two threads of execution only requires: + +```c +switch_stack(&old_stack_ptr, &new_stack_ptr); +``` + +So the next step would be to have a structured and reliable way of keeping +track of stacks and stack pointers. The stack pointer is easy enough, and we +might as well store some more thread related stuff at the same place while +we're at it. + +`src/kernel/include/thread.h` +```c +struct thread +{ + uintptr_t stack_ptr; + uint64_t tid; + uint64_t state; +}; +``` + +## Queueing