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