xref: /DragonOS/kernel/src/arch/x86_64/include/asm/asm.h (revision da152319797436368304cbc3f85a3b9ec049134b)
1 #pragma once
2 
3 #include <DragonOS/stdint.h>
4 #include <stdbool.h>
5 #include <common/stddef.h>
6 
7 
8 
9 #define sti() __asm__ __volatile__("sti\n\t" :: \
10                                        : "memory") // 开启外部中断
11 #define cli() __asm__ __volatile__("cli\n\t" :: \
12                                        : "memory") // 关闭外部中断
13 #define nop() __asm__ __volatile__("nop\n\t")
14 #define hlt() __asm__ __volatile__("hlt\n\t")
15 #define pause() asm volatile("pause\n\t"); // 处理器等待一段时间
16 
17 // 内存屏障
18 #define io_mfence() __asm__ __volatile__("mfence\n\t" :: \
19                                              : "memory") // 在mfence指令前的读写操作必须在mfence指令后的读写操作前完成。
20 #define io_sfence() __asm__ __volatile__("sfence\n\t" :: \
21                                              : "memory") // 在sfence指令前的写操作必须在sfence指令后的写操作前完成
22 #define io_lfence() __asm__ __volatile__("lfence\n\t" :: \
23                                              : "memory") // 在lfence指令前的读操作必须在lfence指令后的读操作前完成。
24 
25 /*
26  * Macros to generate condition code outputs from inline assembly,
27  * The output operand must be type "bool".
28  */
29 // 如果编译器支持输出标志寄存器值到变量的话,则会定义__GCC_ASM_FLAG_OUTPUTS__
30 #ifdef __GCC_ASM_FLAG_OUTPUTS__
31 // CC_SET(c)则是用于设置标志寄存器中的某一位
32 #define CC_SET(c) "\n\t/* output condition code " #c "*/\n"
33 // "=@cccond"的用法是,将标志寄存器中的cond(也就是指令集定义的标准条件)的值输出到变量中
34 #define CC_OUT(c) "=@cc" #c
35 #else
36 #define CC_SET(c) "\n\tset" #c " %[_cc_" #c "]\n"
37 #define CC_OUT(c) [_cc_##c] "=qm"
38 #endif
39 
40 #define rdtsc() ({                                    \
41     uint64_t tmp1 = 0, tmp2 = 0;                      \
42     asm volatile("rdtsc"                              \
43                  : "=d"(tmp1), "=a"(tmp2)::"memory"); \
44     (tmp1 << 32 | tmp2);                              \
45 })
46 
47 /**
48  * @brief 读取rsp寄存器的值(存储了页目录的基地址)
49  *
50  * @return unsigned*  rsp的值的指针
51  */
52 unsigned long *get_rsp()
53 {
54     uint64_t *tmp;
55     __asm__ __volatile__(
56         "movq %%rsp, %0\n\t"
57         : "=r"(tmp)::"memory");
58     return tmp;
59 }
60 
61 /**
62  * @brief 验证地址空间是否为用户地址空间
63  *
64  * @param addr_start 地址起始值
65  * @param length 地址长度
66  * @return true
67  * @return false
68  */
69 bool verify_area(uint64_t addr_start, uint64_t length)
70 {
71     if ((addr_start + length) <= 0x00007fffffffffffUL) // 用户程序可用的的地址空间应<= 0x00007fffffffffffUL
72         return true;
73     else
74         return false;
75 }
76 
77 /**
78  * @brief 读取rbp寄存器的值(存储了页目录的基地址)
79  *
80  * @return unsigned*  rbp的值的指针
81  */
82 unsigned long *get_rbp()
83 {
84     uint64_t *tmp;
85     __asm__ __volatile__(
86         "movq %%rbp, %0\n\t"
87         : "=r"(tmp)::"memory");
88     return tmp;
89 }
90 
91 /**
92  * @brief 读取ds寄存器的值(存储了页目录的基地址)
93  *
94  * @return unsigned*  ds的值的指针
95  */
96 unsigned long *get_ds()
97 {
98     uint64_t *tmp;
99     __asm__ __volatile__(
100         "movq %%ds, %0\n\t"
101         : "=r"(tmp)::"memory");
102     return tmp;
103 }
104 
105 /**
106  * @brief 读取rax寄存器的值(存储了页目录的基地址)
107  *
108  * @return unsigned*  rax的值的指针
109  */
110 unsigned long *get_rax()
111 {
112     uint64_t *tmp;
113     __asm__ __volatile__(
114         "movq %%rax, %0\n\t"
115         : "=r"(tmp)::"memory");
116     return tmp;
117 }
118 /**
119  * @brief 读取rbx寄存器的值(存储了页目录的基地址)
120  *
121  * @return unsigned*  rbx的值的指针
122  */
123 unsigned long *get_rbx()
124 {
125     uint64_t *tmp;
126     __asm__ __volatile__(
127         "movq %%rbx, %0\n\t"
128         : "=r"(tmp)::"memory");
129     return tmp;
130 }
131 
132 uint64_t get_rflags()
133 {
134     unsigned long tmp = 0;
135     __asm__ __volatile__("pushfq	\n\t"
136                          "movq	(%%rsp), %0	\n\t"
137                          "popfq	\n\t"
138                          : "=r"(tmp)::"memory");
139     return tmp;
140 }
141 
142 void *memset(void *dst, unsigned char C, ul size)
143 {
144 
145     int d0, d1;
146     unsigned long tmp = C * 0x0101010101010101UL;
147     __asm__ __volatile__("cld	\n\t"
148                          "rep	\n\t"
149                          "stosq	\n\t"
150                          "testb	$4, %b3	\n\t"
151                          "je	1f	\n\t"
152                          "stosl	\n\t"
153                          "1:\ttestb	$2, %b3	\n\t"
154                          "je	2f\n\t"
155                          "stosw	\n\t"
156                          "2:\ttestb	$1, %b3	\n\t"
157                          "je	3f	\n\t"
158                          "stosb	\n\t"
159                          "3:	\n\t"
160                          : "=&c"(d0), "=&D"(d1)
161                          : "a"(tmp), "q"(size), "0"(size / 8), "1"(dst)
162                          : "memory");
163     return dst;
164 }
165 
166 void *memset_c(void *dst, uint8_t c, size_t count)
167 {
168     uint8_t *xs = (uint8_t *)dst;
169 
170     while (count--)
171         *xs++ = c;
172 
173     return dst;
174 }
175 
176 /**
177  * @brief 内存拷贝函数
178  *
179  * @param dst 目标数组
180  * @param src 源数组
181  * @param Num 字节数
182  * @return void*
183  */
184 static void *memcpy(void *dst, const void *src, long Num)
185 {
186     int d0 = 0, d1 = 0, d2 = 0;
187     __asm__ __volatile__("cld	\n\t"
188                          "rep	\n\t"
189                          "movsq	\n\t"
190                          "testb	$4,%b4	\n\t"
191                          "je	1f	\n\t"
192                          "movsl	\n\t"
193                          "1:\ttestb	$2,%b4	\n\t"
194                          "je	2f	\n\t"
195                          "movsw	\n\t"
196                          "2:\ttestb	$1,%b4	\n\t"
197                          "je	3f	\n\t"
198                          "movsb	\n\t"
199                          "3:	\n\t"
200                          : "=&c"(d0), "=&D"(d1), "=&S"(d2)
201                          : "0"(Num / 8), "q"(Num), "1"(dst), "2"(src)
202                          : "memory");
203     return dst;
204 }
205 
206 // 从io口读入8个bit
207 unsigned char io_in8(unsigned short port)
208 {
209     unsigned char ret = 0;
210     __asm__ __volatile__("inb	%%dx,	%0	\n\t"
211                          "mfence			\n\t"
212                          : "=a"(ret)
213                          : "d"(port)
214                          : "memory");
215     return ret;
216 }
217 
218 // 从io口读入32个bit
219 unsigned int io_in32(unsigned short port)
220 {
221     unsigned int ret = 0;
222     __asm__ __volatile__("inl	%%dx,	%0	\n\t"
223                          "mfence			\n\t"
224                          : "=a"(ret)
225                          : "d"(port)
226                          : "memory");
227     return ret;
228 }
229 
230 // 输出8个bit到输出端口
231 void io_out8(unsigned short port, unsigned char value)
232 {
233     __asm__ __volatile__("outb	%0,	%%dx	\n\t"
234                          "mfence			\n\t"
235                          :
236                          : "a"(value), "d"(port)
237                          : "memory");
238 }
239 
240 // 输出32个bit到输出端口
241 void io_out32(unsigned short port, unsigned int value)
242 {
243     __asm__ __volatile__("outl	%0,	%%dx	\n\t"
244                          "mfence			\n\t"
245                          :
246                          : "a"(value), "d"(port)
247                          : "memory");
248 }
249 
250 /**
251  * @brief 从端口读入n个word到buffer
252  *
253  */
254 #define io_insw(port, buffer, nr)                                                 \
255     __asm__ __volatile__("cld;rep;insw;mfence;" ::"d"(port), "D"(buffer), "c"(nr) \
256                          : "memory")
257 
258 /**
259  * @brief 从输出buffer中的n个word到端口
260  *
261  */
262 #define io_outsw(port, buffer, nr)                                                 \
263     __asm__ __volatile__("cld;rep;outsw;mfence;" ::"d"(port), "S"(buffer), "c"(nr) \
264                          : "memory")
265 
266 /**
267  * @brief 从用户空间搬运数据到内核空间
268  *
269  * @param dst 目的地址
270  * @param src 源地址
271  * @param size 搬运的大小
272  * @return uint64_t
273  */
274 static inline uint64_t copy_from_user(void *dst, void *src, uint64_t size)
275 {
276     uint64_t tmp0, tmp1;
277     if (!verify_area((uint64_t)src, size))
278         return 0;
279 
280     /**
281      * @brief 先每次搬运8 bytes,剩余就直接一个个byte搬运
282      *
283      */
284     asm volatile("rep   \n\t"
285                  "movsq  \n\t"
286                  "movq %3, %0   \n\t"
287                  "rep   \n\t"
288                  "movsb \n\t"
289                  : "=&c"(size), "=&D"(tmp0), "=&S"(tmp1)
290                  : "r"(size & 7), "0"(size >> 3), "1"(dst), "2"(src)
291                  : "memory");
292     return size;
293 }
294 
295 /**
296  * @brief 从内核空间搬运数据到用户空间
297  *
298  * @param dst 目的地址
299  * @param src 源地址
300  * @param size 搬运的大小
301  * @return uint64_t
302  */
303 static inline uint64_t copy_to_user(void *dst, void *src, uint64_t size)
304 {
305     if (verify_area((uint64_t)src, size))
306         return 0;
307 
308     /**
309      * @brief 先每次搬运8 bytes,剩余就直接一个个byte搬运
310      *
311      */
312     // todo:编译有bug
313     // asm volatile("rep   \n\t"
314     //              "movsq  \n\t"
315     //              "movq %3, %0   \n\t"
316     //              "rep   \n\t"
317     //              "movsb \n\t"
318     //              : "=&c"(size), "=&D"(tmp0), "=&S"(tmp1)
319     //              : "r"(size & 7), "0"(size >> 3), "1"(dst), "2"(src)
320     //              : "memory");
321     memcpy(dst, src, size);
322 
323     return size;
324 }
325 
326 /**
327  * @brief 往指定地址写入8字节
328  * 防止由于编译器优化导致不支持的内存访问类型(尤其是在mmio的时候)
329  *
330  * @param vaddr 虚拟地址
331  * @param value 要写入的值
332  */
333 static __always_inline void __write8b(uint64_t vaddr, uint64_t value)
334 {
335     asm volatile("movq %%rdx, 0(%%rax)" ::"a"(vaddr), "d"(value)
336                  : "memory");
337 }
338 
339 /**
340  * @brief 往指定地址写入4字节
341  * 防止由于编译器优化导致不支持的内存访问类型(尤其是在mmio的时候)
342  *
343  * @param vaddr 虚拟地址
344  * @param value 要写入的值
345  */
346 static __always_inline void __write4b(uint64_t vaddr, uint32_t value)
347 {
348     asm volatile("movl %%edx, 0(%%rax)" ::"a"(vaddr), "d"(value)
349                  : "memory");
350 }
351 
352 /**
353  * @brief 从指定地址读取8字节
354  * 防止由于编译器优化导致不支持的内存访问类型(尤其是在mmio的时候)
355  *
356  * @param vaddr 虚拟地址
357  * @return uint64_t 读取到的值
358  */
359 static __always_inline uint64_t __read8b(uint64_t vaddr)
360 {
361     uint64_t retval;
362     asm volatile("movq 0(%%rax), %0"
363                  : "=r"(retval)
364                  : "a"(vaddr)
365                  : "memory");
366     return retval;
367 }
368 
369 /**
370  * @brief 从指定地址读取4字节
371  * 防止由于编译器优化导致不支持的内存访问类型(尤其是在mmio的时候)
372  *
373  * @param vaddr 虚拟地址
374  * @return uint64_t 读取到的值
375  */
376 static __always_inline uint32_t __read4b(uint64_t vaddr)
377 {
378     uint32_t retval;
379     asm volatile("movl 0(%%rax), %0"
380                  : "=d"(retval)
381                  : "a"(vaddr)
382                  : "memory");
383     return retval;
384 }
385 
386 
387 /**
388  * @brief 逐字节比较指定内存区域的值,并返回s1、s2的第一个不相等的字节i处的差值(s1[i]-s2[i])。
389  * 若两块内存区域的内容相同,则返回0
390  *
391  * @param s1 内存区域1
392  * @param s2 内存区域2
393  * @param len 要比较的内存区域长度
394  * @return int s1、s2的第一个不相等的字节i处的差值(s1[i]-s2[i])。若两块内存区域的内容相同,则返回0
395  */
396 static inline int memcmp(const void *s1, const void *s2, size_t len)
397 {
398     int diff;
399 
400     asm("cld \n\t"  // 复位DF,确保s1、s2指针是自增的
401         "repz; cmpsb\n\t" CC_SET(nz)
402         : CC_OUT(nz)(diff), "+D"(s1), "+S"(s2)
403         : "c"(len)
404         : "memory");
405 
406     if (diff)
407         diff = *(const unsigned char *)(s1 - 1) - *(const unsigned char *)(s2 - 1);
408 
409     return diff;
410 }
411