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