1/*
2 * Copyright 2014, General Dynamics C4 Systems
3 *
4 * This software may be distributed and modified according to the terms of
5 * the GNU General Public License version 2. Note that NO WARRANTY is provided.
6 * See "LICENSE_GPLv2.txt" for details.
7 *
8 * @TAG(GD_GPL)
9 */
10#ifndef __ARMV_CONTEXT_SWITCH_H__
11#define __ARMV_CONTEXT_SWITCH_H__
12
13#include <config.h>
14#include <arch/object/structures.h>
15#include <arch/api/types.h>
16#include <mode/model/statedata.h>
17
18static inline void setHardwareASID(hw_asid_t hw_asid)
19{
20#if defined(CONFIG_ARM_ERRATA_430973)
21    flushBTAC();
22#endif
23    writeContextID(hw_asid);
24}
25
26static inline void armv_contextSwitch_HWASID(pde_t *cap_pd, hw_asid_t hw_asid)
27{
28#ifdef CONFIG_ARM_HYPERVISOR_SUPPORT
29    writeContextIDAndPD(hw_asid, addrFromPPtr(cap_pd));
30#else
31    /*
32     * On ARMv7, speculative refills that complete between switching
33     * ASID and PD can cause TLB entries to be Tagged with the wrong
34     * ASID. The correct method to avoid this problem is to
35     * either cycle the context switch through a reserved ASID or
36     * through a page directory that has only global mappings.
37     * The reserved Page directory method has shown to perform better
38     * than the reserved ASID method.
39     *
40     * We do not call setCurrentPD here as we want to perform a
41     * minimal number of DSB and ISBs and the second PD switch we
42     * do does not need a DSB
43     */
44    dsb();
45    writeTTBR0Ptr(addrFromPPtr(armKSGlobalPD));
46    isb();
47    setHardwareASID(hw_asid);
48    writeTTBR0Ptr(addrFromPPtr(cap_pd));
49    isb();
50#endif
51}
52
53static inline void armv_contextSwitch(pde_t* cap_pd, asid_t asid)
54{
55    armv_contextSwitch_HWASID(cap_pd, getHWASID(asid));
56}
57
58#endif /* __ARMV_CONTEXT_SWITCH_H__ */
59