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