1/* 2 * Architecture-specific context switch 3 */ 4 5/* 6 * Copyright (c) 2015, ETH Zurich. 7 * All rights reserved. 8 * 9 * This file is distributed under the terms in the attached LICENSE file. 10 * If you do not find this file, copies can be found by writing to: 11 * ETH Zurich D-INFK, Universitaetstr. 6, CH-8092 Zurich. Attn: Systems Group. 12 */ 13 14#include <kernel.h> 15#include <dispatch.h> 16#include <paging_kernel_arch.h> 17 18/** 19 * \brief Switch context to 'dcb'. 20 * 21 * Switch to the dispatcher pointed to by 'dcb'. Sets 'dcb_current'. 22 * 23 * \param dcb Pointer to dispatcher to which to switch context. 24 */ 25void 26context_switch(struct dcb *dcb) { 27 struct dispatcher_shared_generic *disp = 28 get_dispatcher_shared_generic(dcb->disp); 29 30 assert(dcb != NULL); 31 assert(dcb->vspace != 0); 32 33 // VM guests do not have a user space dispatcher 34 if (!dcb->is_vm_guest) { 35 assert(dcb->disp != 0); 36 } 37 38 fpu_lazy_top(dcb); 39 40 paging_context_switch(dcb->vspace); 41 context_switch_counter++; 42 43 if (!dcb->is_vm_guest) { 44 assert(dcb->disp_cte.cap.type == ObjType_Frame); 45 46 fpu_lazy_bottom(dcb); 47 48 /* 49 * The name of the function is somewhat misleading. we need an unused 50 * user register that always stores the pointer to the current 51 * dispatcher. most ABIs define a register for thread-local storage, 52 * and we have been abusing that on x64 for the dispatcher pointer 53 * --arch_set_thread_ register sets this pointer. Obviously this 54 * needs to change to support thread-local storage using a standard 55 * ABI, so we will have to figure out how to get to the dispatcher 56 * from something like a thread-local variable. The reason that this 57 * is in the switch path and not in resume/execute is that on x86_64 58 * loading the thread register (fs) is stupidly expensive, so we avoid 59 * doing it unless we switch contexts -- presumably that could be a 60 * local optimisation in the x86_64 dispatch paths rather than the 61 * generic context_switch path/ 62 */ 63 arch_set_thread_register(disp->udisp); 64 } 65} 66