xref: /optee_os/core/arch/arm/kernel/vfp.c (revision abe38974ad2d4cbb72940f322210364fb3a9a490)
1 /*
2  * Copyright (c) 2015, Linaro Limited
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright notice,
9  * this list of conditions and the following disclaimer.
10  *
11  * 2. Redistributions in binary form must reproduce the above copyright notice,
12  * this list of conditions and the following disclaimer in the documentation
13  * and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
19  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25  * POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 #include <arm.h>
29 #include <kernel/vfp.h>
30 #include "vfp_private.h"
31 #include <assert.h>
32 
33 bool vfp_is_enabled(void)
34 {
35 	return !!(vfp_read_fpexc() & FPEXC_EN);
36 }
37 
38 static bool instr_match_cp10_cp11(uint32_t instr, uint32_t mask)
39 {
40 	if ((instr & mask) == mask) {
41 		uint32_t coprocessor = instr & 0xf0;
42 
43 		if (coprocessor == 10 || coprocessor == 11)
44 			return true;
45 	}
46 	return false;
47 }
48 
49 bool vfp_is_vpfinstr(uint32_t instr, uint32_t spsr)
50 {
51 
52 
53 	if (spsr & CPSR_T) {
54 		/* Thumb mode */
55 		return instr_match_cp10_cp11(instr, 0xec000000) ||
56 		       ((instr & 0xef000000) == 0xef000000) ||
57 		       ((instr & 0xff100000) == 0xf9000000);
58 	} else {
59 		/* ARM mode */
60 		return instr_match_cp10_cp11(instr, 0x0c000000) ||
61 		       ((instr & 0xfe000000) == 0xf2000000) ||
62 		       ((instr & 0xff100000) == 0xf4000000);
63 	}
64 }
65 
66 void vfp_enable(void)
67 {
68 	vfp_write_fpexc(vfp_read_fpexc() | FPEXC_EN);
69 }
70 
71 void vfp_disable(void)
72 {
73 	vfp_write_fpexc(vfp_read_fpexc() & ~FPEXC_EN);
74 }
75 
76 void vfp_lazy_save_state_init(struct vfp_state *state)
77 {
78 	uint32_t fpexc = vfp_read_fpexc();
79 
80 	state->fpexc = fpexc;
81 	vfp_write_fpexc(fpexc & ~FPEXC_EN);
82 }
83 
84 void vfp_lazy_save_state_final(struct vfp_state *state)
85 {
86 	if (state->fpexc & FPEXC_EN) {
87 		uint32_t fpexc = vfp_read_fpexc();
88 
89 		assert(!(fpexc & FPEXC_EN));
90 		vfp_write_fpexc(fpexc | FPEXC_EN);
91 		state->fpscr = vfp_read_fpscr();
92 		vfp_save_extension_regs(state->reg);
93 		vfp_write_fpexc(fpexc);
94 	}
95 }
96 
97 void vfp_lazy_restore_state(struct vfp_state *state, bool full_state)
98 {
99 
100 	if (full_state) {
101 		/*
102 		 * Only restore VFP registers if they been touched as they
103 		 * otherwise are intact.
104 		 */
105 
106 		/* FPEXC is restored to what's in state->fpexc below */
107 		vfp_write_fpexc(vfp_read_fpexc() | FPEXC_EN);
108 
109 		vfp_write_fpscr(state->fpscr);
110 		vfp_restore_extension_regs(state->reg);
111 	}
112 	vfp_write_fpexc(state->fpexc);
113 }
114