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 <bitmacros.h> 15#include <kernel.h> 16#include <dispatch.h> 17#include <paging_kernel_arch.h> 18 19/** 20 * \brief Switch context to 'dcb'. 21 * 22 * Switch to the dispatcher pointed to by 'dcb'. Sets 'dcb_current'. 23 * 24 * \param dcb Pointer to dispatcher to which to switch context. 25 */ 26void 27context_switch(struct dcb *dcb) { 28 struct dispatcher_shared_generic *disp = 29 get_dispatcher_shared_generic(dcb->disp); 30 31 assert(dcb != NULL); 32 assert(dcb->vspace != 0); 33 34 // VM guests do not have a user space dispatcher 35 if (!dcb->is_vm_guest) { 36 assert(dcb->disp != 0); 37 } 38 39 paging_context_switch(dcb->vspace); 40 context_switch_counter++; 41 42 /* Write the CONTEXTID register, so that the debugger can tell dispatchers 43 * apart. We use the physical address of the dispatcher control block. 44 * Note that the low 10 bits of dcb are zero, and the lower 8 bits of the 45 * register hold the ASID, which we're not yet using. */ 46 cp15_write_contextidr(((uint32_t)dcb) & ~MASK(8)); 47 48 if (!dcb->is_vm_guest) { 49 assert(dcb->disp_cte.cap.type == ObjType_Frame); 50 51 /* 52 * The name of the function is somewhat misleading. we need an unused 53 * user register that always stores the pointer to the current 54 * dispatcher. most ABIs define a register for thread-local storage, 55 * and we have been abusing that on x64 for the dispatcher pointer 56 * --arch_set_thread_ register sets this pointer. Obviously this 57 * needs to change to support thread-local storage using a standard 58 * ABI, so we will have to figure out how to get to the dispatcher 59 * from something like a thread-local variable. The reason that this 60 * is in the switch path and not in resume/execute is that on x86_64 61 * loading the thread register (fs) is stupidly expensive, so we avoid 62 * doing it unless we switch contexts -- presumably that could be a 63 * local optimisation in the x86_64 dispatch paths rather than the 64 * generic context_switch path/ 65 */ 66 arch_set_thread_register(disp->udisp); 67 } 68} 69