1 /**
2  * @file
3  * @brief Intel x86 GCC specific floating point register macros
4  */
5 
6 /*
7  * Copyright (c) 2015, Wind River Systems, Inc.
8  *
9  * SPDX-License-Identifier: Apache-2.0
10  */
11 
12 #ifndef _FLOAT_REGS_X86_GCC_H
13 #define _FLOAT_REGS_X86_GCC_H
14 
15 #if !defined(__GNUC__) || !defined(CONFIG_X86)
16 #error __FILE__ goes only with x86 GCC
17 #endif
18 
19 #include <zephyr/toolchain.h>
20 #include "float_context.h"
21 
22 /**
23  *
24  * @brief Load all floating point registers
25  *
26  * This function loads ALL floating point registers pointed to by @a regs.
27  * It is expected that a subsequent call to _store_all_float_registers()
28  * will be issued to dump the floating point registers to memory.
29  *
30  * The format/organization of 'struct fp_register_set'; the generic C test
31  * code (main.c) merely treat the register set as an array of bytes.
32  *
33  * The only requirement is that the arch specific implementations of
34  * _load_all_float_registers(), _store_all_float_registers() and
35  * _load_then_store_all_float_registers() agree on the format.
36  *
37  */
38 
_load_all_float_registers(struct fp_register_set * regs)39 static inline void _load_all_float_registers(struct fp_register_set *regs)
40 {
41 	__asm__ volatile (
42 		"movdqu  0(%0), %%xmm0\n\t;"
43 		"movdqu 16(%0), %%xmm1\n\t;"
44 		"movdqu 32(%0), %%xmm2\n\t;"
45 		"movdqu 48(%0), %%xmm3\n\t;"
46 		"movdqu 64(%0), %%xmm4\n\t;"
47 		"movdqu 80(%0), %%xmm5\n\t;"
48 		"movdqu 96(%0), %%xmm6\n\t;"
49 		"movdqu 112(%0), %%xmm7\n\t;"
50 
51 		"fldt   128(%0)\n\t;"
52 		"fldt   138(%0)\n\t;"
53 		"fldt   148(%0)\n\t;"
54 		"fldt   158(%0)\n\t;"
55 		"fldt   168(%0)\n\t;"
56 		"fldt   178(%0)\n\t;"
57 		"fldt   188(%0)\n\t;"
58 		"fldt   198(%0)\n\t;"
59 
60 		: : "r" (regs)
61 		);
62 }
63 
64 
65 /**
66  *
67  * @brief Load then dump all float registers to memory
68  *
69  * This function loads ALL floating point registers from the memory buffer
70  * specified by @a regs, and then stores them back to that buffer.
71  *
72  * This routine is called by a high priority thread prior to calling a primitive
73  * that pends and triggers a co-operative context switch to a low priority
74  * thread. Because the kernel doesn't save floating point context for
75  * co-operative context switches, the x87 FPU register stack must be put back
76  * in an empty state before the switch occurs in case the next task to perform
77  * floating point operations was also co-operatively switched out and simply
78  * inherits the existing x87 FPU state (expecting the stack to be empty).
79  *
80  */
81 
82 static inline void
_load_then_store_all_float_registers(struct fp_register_set * regs)83 _load_then_store_all_float_registers(struct fp_register_set *regs)
84 {
85 	__asm__ volatile (
86 		"movdqu  0(%0), %%xmm0\n\t;"
87 		"movdqu 16(%0), %%xmm1\n\t;"
88 		"movdqu 32(%0), %%xmm2\n\t;"
89 		"movdqu 48(%0), %%xmm3\n\t;"
90 		"movdqu 64(%0), %%xmm4\n\t;"
91 		"movdqu 80(%0), %%xmm5\n\t;"
92 		"movdqu 96(%0), %%xmm6\n\t;"
93 		"movdqu 112(%0), %%xmm7\n\t;"
94 
95 		"fldt   128(%0)\n\t;"
96 		"fldt   138(%0)\n\t;"
97 		"fldt   148(%0)\n\t;"
98 		"fldt   158(%0)\n\t;"
99 		"fldt   168(%0)\n\t;"
100 		"fldt   178(%0)\n\t;"
101 		"fldt   188(%0)\n\t;"
102 		"fldt   198(%0)\n\t;"
103 
104 		/* pop the x87 FPU registers back to memory */
105 
106 		"fstpt  198(%0)\n\t;"
107 		"fstpt  188(%0)\n\t;"
108 		"fstpt  178(%0)\n\t;"
109 		"fstpt  168(%0)\n\t;"
110 		"fstpt  158(%0)\n\t;"
111 		"fstpt  148(%0)\n\t;"
112 		"fstpt  138(%0)\n\t;"
113 		"fstpt  128(%0)\n\t;"
114 
115 		: : "r" (regs)
116 		);
117 }
118 
119 
120 /**
121  *
122  * @brief Dump all floating point registers to memory
123  *
124  * This function stores ALL floating point registers to the memory buffer
125  * specified by @a regs. It is expected that a previous invocation of
126  * _load_all_float_registers() occurred to load all the floating point
127  * registers from a memory buffer.
128  *
129  */
130 
_store_all_float_registers(struct fp_register_set * regs)131 static inline void _store_all_float_registers(struct fp_register_set *regs)
132 {
133 	__asm__ volatile (
134 		"movdqu %%xmm0, 0(%0)\n\t;"
135 		"movdqu %%xmm1, 16(%0)\n\t;"
136 		"movdqu %%xmm2, 32(%0)\n\t;"
137 		"movdqu %%xmm3, 48(%0)\n\t;"
138 		"movdqu %%xmm4, 64(%0)\n\t;"
139 		"movdqu %%xmm5, 80(%0)\n\t;"
140 		"movdqu %%xmm6, 96(%0)\n\t;"
141 		"movdqu %%xmm7, 112(%0)\n\t;"
142 
143 		"fstpt  198(%0)\n\t;"
144 		"fstpt  188(%0)\n\t;"
145 		"fstpt  178(%0)\n\t;"
146 		"fstpt  168(%0)\n\t;"
147 		"fstpt  158(%0)\n\t;"
148 		"fstpt  148(%0)\n\t;"
149 		"fstpt  138(%0)\n\t;"
150 		"fstpt  128(%0)\n\t;"
151 
152 		: : "r" (regs) : "memory"
153 		);
154 }
155 #endif /* _FLOAT_REGS_X86_GCC_H */
156