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