sve.c 2.89 KB
Newer Older
David Cunado's avatar
David Cunado committed
1
/*
2
 * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
David Cunado's avatar
David Cunado committed
3
4
5
6
7
8
9
10
11
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */

#include <arch.h>
#include <arch_helpers.h>
#include <pubsub.h>
#include <sve.h>

12
int sve_supported(void)
David Cunado's avatar
David Cunado committed
13
14
15
16
{
	uint64_t features;

	features = read_id_aa64pfr0_el1() >> ID_AA64PFR0_SVE_SHIFT;
17
18
	return (features & ID_AA64PFR0_SVE_MASK) == 1;
}
David Cunado's avatar
David Cunado committed
19

20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
static void *disable_sve_hook(const void *arg)
{
	uint64_t cptr;

	if (!sve_supported())
		return (void *)-1;

	/*
	 * Disable SVE, SIMD and FP access for the Secure world.
	 * As the SIMD/FP registers are part of the SVE Z-registers, any
	 * use of SIMD/FP functionality will corrupt the SVE registers.
	 * Therefore it is necessary to prevent use of SIMD/FP support
	 * in the Secure world as well as SVE functionality.
	 */
	cptr = read_cptr_el3();
	cptr = (cptr | TFP_BIT) & ~(CPTR_EZ_BIT);
	write_cptr_el3(cptr);

	/*
	 * No explicit ISB required here as ERET to switch to Secure
	 * world covers it
	 */
David Cunado's avatar
David Cunado committed
42
43
44
45
46
	return 0;
}

static void *enable_sve_hook(const void *arg)
{
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
	uint64_t cptr;

	if (!sve_supported())
		return (void *)-1;

	/*
	 * Enable SVE, SIMD and FP access for the Non-secure world.
	 */
	cptr = read_cptr_el3();
	cptr = (cptr | CPTR_EZ_BIT) & ~(TFP_BIT);
	write_cptr_el3(cptr);

	/*
	 * No explicit ISB required here as ERET to switch to Non-secure
	 * world covers it
	 */
David Cunado's avatar
David Cunado committed
63
64
65
66
67
	return 0;
}

void sve_enable(int el2_unused)
{
68
69
70
71
	uint64_t cptr;

	if (!sve_supported())
		return;
David Cunado's avatar
David Cunado committed
72
73

#if CTX_INCLUDE_FPREGS
74
75
76
77
	/*
	 * CTX_INCLUDE_FPREGS is not supported on SVE enabled systems.
	 */
	assert(0);
David Cunado's avatar
David Cunado committed
78
#endif
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
	/*
	 * Update CPTR_EL3 to enable access to SVE functionality for the
	 * Non-secure world.
	 * NOTE - assumed that CPTR_EL3.TFP is set to allow access to
	 * the SIMD, floating-point and SVE support.
	 *
	 * CPTR_EL3.EZ: Set to 1 to enable access to SVE  functionality
	 *  in the Non-secure world.
	 */
	cptr = read_cptr_el3();
	cptr |= CPTR_EZ_BIT;
	write_cptr_el3(cptr);

	/*
	 * Need explicit ISB here to guarantee that update to ZCR_ELx
	 * and CPTR_EL2.TZ do not result in trap to EL3.
	 */
	isb();

	/*
	 * Ensure lower ELs have access to full vector length.
	 */
	write_zcr_el3(ZCR_EL3_LEN_MASK);

	if (el2_unused) {
David Cunado's avatar
David Cunado committed
104
		/*
105
106
107
108
		 * Update CPTR_EL2 to enable access to SVE functionality
		 * for Non-secure world, EL2 and Non-secure EL1 and EL0.
		 * NOTE - assumed that CPTR_EL2.TFP is set to allow
		 * access to the SIMD, floating-point and SVE support.
David Cunado's avatar
David Cunado committed
109
		 *
110
111
		 * CPTR_EL2.TZ: Set to 0 to enable access to SVE support
		 *  for EL2 and Non-secure EL1 and EL0.
David Cunado's avatar
David Cunado committed
112
		 */
113
114
115
		cptr = read_cptr_el2();
		cptr &= ~(CPTR_EL2_TZ_BIT);
		write_cptr_el2(cptr);
David Cunado's avatar
David Cunado committed
116
117
118
119

		/*
		 * Ensure lower ELs have access to full vector length.
		 */
120
		write_zcr_el2(ZCR_EL2_LEN_MASK);
David Cunado's avatar
David Cunado committed
121
	}
122
123
124
125
	/*
	 * No explicit ISB required here as ERET to switch to
	 * Non-secure world covers it.
	 */
David Cunado's avatar
David Cunado committed
126
127
128
129
}

SUBSCRIBE_TO_EVENT(cm_exited_normal_world, disable_sve_hook);
SUBSCRIBE_TO_EVENT(cm_entering_normal_world, enable_sve_hook);