xref: /DragonOS/kernel/src/arch/x86_64/include/asm/asm.h (revision 4fda81ce81939d83b74c8042d6fb4223deff3685)
166f67c6aSlogin #pragma once
266f67c6aSlogin 
30e0c1874Slogin #include <DragonOS/stdint.h>
446e234aeSLoGin #include <stdbool.h>
546e234aeSLoGin #include <common/stddef.h>
646e234aeSLoGin 
7*4fda81ceSLoGin 
866f67c6aSlogin 
966f67c6aSlogin #define sti() __asm__ __volatile__("sti\n\t" :: \
1066f67c6aSlogin                                        : "memory") // 开启外部中断
1166f67c6aSlogin #define cli() __asm__ __volatile__("cli\n\t" :: \
1266f67c6aSlogin                                        : "memory") // 关闭外部中断
1366f67c6aSlogin #define nop() __asm__ __volatile__("nop\n\t")
1466f67c6aSlogin #define hlt() __asm__ __volatile__("hlt\n\t")
1566f67c6aSlogin #define pause() asm volatile("pause\n\t"); // 处理器等待一段时间
1666f67c6aSlogin 
1766f67c6aSlogin // 内存屏障
1866f67c6aSlogin #define io_mfence() __asm__ __volatile__("mfence\n\t" :: \
1966f67c6aSlogin                                              : "memory") // 在mfence指令前的读写操作必须在mfence指令后的读写操作前完成。
2066f67c6aSlogin #define io_sfence() __asm__ __volatile__("sfence\n\t" :: \
2166f67c6aSlogin                                              : "memory") // 在sfence指令前的写操作必须在sfence指令后的写操作前完成
2266f67c6aSlogin #define io_lfence() __asm__ __volatile__("lfence\n\t" :: \
2366f67c6aSlogin                                              : "memory") // 在lfence指令前的读操作必须在lfence指令后的读操作前完成。
2466f67c6aSlogin 
2566f67c6aSlogin /*
2666f67c6aSlogin  * Macros to generate condition code outputs from inline assembly,
2766f67c6aSlogin  * The output operand must be type "bool".
2866f67c6aSlogin  */
2966f67c6aSlogin // 如果编译器支持输出标志寄存器值到变量的话,则会定义__GCC_ASM_FLAG_OUTPUTS__
3066f67c6aSlogin #ifdef __GCC_ASM_FLAG_OUTPUTS__
3166f67c6aSlogin // CC_SET(c)则是用于设置标志寄存器中的某一位
3266f67c6aSlogin #define CC_SET(c) "\n\t/* output condition code " #c "*/\n"
3366f67c6aSlogin // "=@cccond"的用法是,将标志寄存器中的cond(也就是指令集定义的标准条件)的值输出到变量中
3466f67c6aSlogin #define CC_OUT(c) "=@cc" #c
3566f67c6aSlogin #else
3666f67c6aSlogin #define CC_SET(c) "\n\tset" #c " %[_cc_" #c "]\n"
3766f67c6aSlogin #define CC_OUT(c) [_cc_##c] "=qm"
3866f67c6aSlogin #endif
3966f67c6aSlogin 
4066f67c6aSlogin #define rdtsc() ({                                    \
4166f67c6aSlogin     uint64_t tmp1 = 0, tmp2 = 0;                      \
4266f67c6aSlogin     asm volatile("rdtsc"                              \
4366f67c6aSlogin                  : "=d"(tmp1), "=a"(tmp2)::"memory"); \
4466f67c6aSlogin     (tmp1 << 32 | tmp2);                              \
4566f67c6aSlogin })
4666f67c6aSlogin 
4766f67c6aSlogin /**
4866f67c6aSlogin  * @brief 读取rsp寄存器的值(存储了页目录的基地址)
4966f67c6aSlogin  *
5066f67c6aSlogin  * @return unsigned*  rsp的值的指针
5166f67c6aSlogin  */
get_rsp()5266f67c6aSlogin unsigned long *get_rsp()
5366f67c6aSlogin {
5466f67c6aSlogin     uint64_t *tmp;
5566f67c6aSlogin     __asm__ __volatile__(
5666f67c6aSlogin         "movq %%rsp, %0\n\t"
5766f67c6aSlogin         : "=r"(tmp)::"memory");
5866f67c6aSlogin     return tmp;
5966f67c6aSlogin }
6066f67c6aSlogin 
6166f67c6aSlogin /**
6246e234aeSLoGin  * @brief 验证地址空间是否为用户地址空间
6346e234aeSLoGin  *
6446e234aeSLoGin  * @param addr_start 地址起始值
6546e234aeSLoGin  * @param length 地址长度
6646e234aeSLoGin  * @return true
6746e234aeSLoGin  * @return false
6846e234aeSLoGin  */
verify_area(uint64_t addr_start,uint64_t length)6946e234aeSLoGin bool verify_area(uint64_t addr_start, uint64_t length)
7046e234aeSLoGin {
7146e234aeSLoGin     if ((addr_start + length) <= 0x00007fffffffffffUL) // 用户程序可用的的地址空间应<= 0x00007fffffffffffUL
7246e234aeSLoGin         return true;
7346e234aeSLoGin     else
7446e234aeSLoGin         return false;
7546e234aeSLoGin }
7646e234aeSLoGin 
7746e234aeSLoGin /**
7866f67c6aSlogin  * @brief 读取rbp寄存器的值(存储了页目录的基地址)
7966f67c6aSlogin  *
8066f67c6aSlogin  * @return unsigned*  rbp的值的指针
8166f67c6aSlogin  */
get_rbp()8266f67c6aSlogin unsigned long *get_rbp()
8366f67c6aSlogin {
8466f67c6aSlogin     uint64_t *tmp;
8566f67c6aSlogin     __asm__ __volatile__(
8666f67c6aSlogin         "movq %%rbp, %0\n\t"
8766f67c6aSlogin         : "=r"(tmp)::"memory");
8866f67c6aSlogin     return tmp;
8966f67c6aSlogin }
9066f67c6aSlogin 
9166f67c6aSlogin /**
9266f67c6aSlogin  * @brief 读取ds寄存器的值(存储了页目录的基地址)
9366f67c6aSlogin  *
9466f67c6aSlogin  * @return unsigned*  ds的值的指针
9566f67c6aSlogin  */
get_ds()9666f67c6aSlogin unsigned long *get_ds()
9766f67c6aSlogin {
9866f67c6aSlogin     uint64_t *tmp;
9966f67c6aSlogin     __asm__ __volatile__(
10066f67c6aSlogin         "movq %%ds, %0\n\t"
10166f67c6aSlogin         : "=r"(tmp)::"memory");
10266f67c6aSlogin     return tmp;
10366f67c6aSlogin }
10466f67c6aSlogin 
10566f67c6aSlogin /**
10666f67c6aSlogin  * @brief 读取rax寄存器的值(存储了页目录的基地址)
10766f67c6aSlogin  *
10866f67c6aSlogin  * @return unsigned*  rax的值的指针
10966f67c6aSlogin  */
get_rax()11066f67c6aSlogin unsigned long *get_rax()
11166f67c6aSlogin {
11266f67c6aSlogin     uint64_t *tmp;
11366f67c6aSlogin     __asm__ __volatile__(
11466f67c6aSlogin         "movq %%rax, %0\n\t"
11566f67c6aSlogin         : "=r"(tmp)::"memory");
11666f67c6aSlogin     return tmp;
11766f67c6aSlogin }
11866f67c6aSlogin /**
11966f67c6aSlogin  * @brief 读取rbx寄存器的值(存储了页目录的基地址)
12066f67c6aSlogin  *
12166f67c6aSlogin  * @return unsigned*  rbx的值的指针
12266f67c6aSlogin  */
get_rbx()12366f67c6aSlogin unsigned long *get_rbx()
12466f67c6aSlogin {
12566f67c6aSlogin     uint64_t *tmp;
12666f67c6aSlogin     __asm__ __volatile__(
12766f67c6aSlogin         "movq %%rbx, %0\n\t"
12866f67c6aSlogin         : "=r"(tmp)::"memory");
12966f67c6aSlogin     return tmp;
13066f67c6aSlogin }
13166f67c6aSlogin 
get_rflags()13266f67c6aSlogin uint64_t get_rflags()
13366f67c6aSlogin {
13466f67c6aSlogin     unsigned long tmp = 0;
13566f67c6aSlogin     __asm__ __volatile__("pushfq	\n\t"
13666f67c6aSlogin                          "movq	(%%rsp), %0	\n\t"
13766f67c6aSlogin                          "popfq	\n\t"
13866f67c6aSlogin                          : "=r"(tmp)::"memory");
13966f67c6aSlogin     return tmp;
14066f67c6aSlogin }
14146e234aeSLoGin 
memset(void * dst,unsigned char C,ul size)14246e234aeSLoGin void *memset(void *dst, unsigned char C, ul size)
14346e234aeSLoGin {
14446e234aeSLoGin 
14546e234aeSLoGin     int d0, d1;
14646e234aeSLoGin     unsigned long tmp = C * 0x0101010101010101UL;
14746e234aeSLoGin     __asm__ __volatile__("cld	\n\t"
14846e234aeSLoGin                          "rep	\n\t"
14946e234aeSLoGin                          "stosq	\n\t"
15046e234aeSLoGin                          "testb	$4, %b3	\n\t"
15146e234aeSLoGin                          "je	1f	\n\t"
15246e234aeSLoGin                          "stosl	\n\t"
15346e234aeSLoGin                          "1:\ttestb	$2, %b3	\n\t"
15446e234aeSLoGin                          "je	2f\n\t"
15546e234aeSLoGin                          "stosw	\n\t"
15646e234aeSLoGin                          "2:\ttestb	$1, %b3	\n\t"
15746e234aeSLoGin                          "je	3f	\n\t"
15846e234aeSLoGin                          "stosb	\n\t"
15946e234aeSLoGin                          "3:	\n\t"
16046e234aeSLoGin                          : "=&c"(d0), "=&D"(d1)
16146e234aeSLoGin                          : "a"(tmp), "q"(size), "0"(size / 8), "1"(dst)
16246e234aeSLoGin                          : "memory");
16346e234aeSLoGin     return dst;
16446e234aeSLoGin }
16546e234aeSLoGin 
memset_c(void * dst,uint8_t c,size_t count)16646e234aeSLoGin void *memset_c(void *dst, uint8_t c, size_t count)
16746e234aeSLoGin {
16846e234aeSLoGin     uint8_t *xs = (uint8_t *)dst;
16946e234aeSLoGin 
17046e234aeSLoGin     while (count--)
17146e234aeSLoGin         *xs++ = c;
17246e234aeSLoGin 
17346e234aeSLoGin     return dst;
17446e234aeSLoGin }
17546e234aeSLoGin 
17646e234aeSLoGin /**
17746e234aeSLoGin  * @brief 内存拷贝函数
17846e234aeSLoGin  *
17946e234aeSLoGin  * @param dst 目标数组
18046e234aeSLoGin  * @param src 源数组
18146e234aeSLoGin  * @param Num 字节数
18246e234aeSLoGin  * @return void*
18346e234aeSLoGin  */
memcpy(void * dst,const void * src,long Num)18446e234aeSLoGin static void *memcpy(void *dst, const void *src, long Num)
18546e234aeSLoGin {
18646e234aeSLoGin     int d0 = 0, d1 = 0, d2 = 0;
18746e234aeSLoGin     __asm__ __volatile__("cld	\n\t"
18846e234aeSLoGin                          "rep	\n\t"
18946e234aeSLoGin                          "movsq	\n\t"
19046e234aeSLoGin                          "testb	$4,%b4	\n\t"
19146e234aeSLoGin                          "je	1f	\n\t"
19246e234aeSLoGin                          "movsl	\n\t"
19346e234aeSLoGin                          "1:\ttestb	$2,%b4	\n\t"
19446e234aeSLoGin                          "je	2f	\n\t"
19546e234aeSLoGin                          "movsw	\n\t"
19646e234aeSLoGin                          "2:\ttestb	$1,%b4	\n\t"
19746e234aeSLoGin                          "je	3f	\n\t"
19846e234aeSLoGin                          "movsb	\n\t"
19946e234aeSLoGin                          "3:	\n\t"
20046e234aeSLoGin                          : "=&c"(d0), "=&D"(d1), "=&S"(d2)
20146e234aeSLoGin                          : "0"(Num / 8), "q"(Num), "1"(dst), "2"(src)
20246e234aeSLoGin                          : "memory");
20346e234aeSLoGin     return dst;
20446e234aeSLoGin }
20546e234aeSLoGin 
20646e234aeSLoGin // 从io口读入8个bit
io_in8(unsigned short port)20746e234aeSLoGin unsigned char io_in8(unsigned short port)
20846e234aeSLoGin {
20946e234aeSLoGin     unsigned char ret = 0;
21046e234aeSLoGin     __asm__ __volatile__("inb	%%dx,	%0	\n\t"
21146e234aeSLoGin                          "mfence			\n\t"
21246e234aeSLoGin                          : "=a"(ret)
21346e234aeSLoGin                          : "d"(port)
21446e234aeSLoGin                          : "memory");
21546e234aeSLoGin     return ret;
21646e234aeSLoGin }
21746e234aeSLoGin 
21846e234aeSLoGin // 从io口读入32个bit
io_in32(unsigned short port)21946e234aeSLoGin unsigned int io_in32(unsigned short port)
22046e234aeSLoGin {
22146e234aeSLoGin     unsigned int ret = 0;
22246e234aeSLoGin     __asm__ __volatile__("inl	%%dx,	%0	\n\t"
22346e234aeSLoGin                          "mfence			\n\t"
22446e234aeSLoGin                          : "=a"(ret)
22546e234aeSLoGin                          : "d"(port)
22646e234aeSLoGin                          : "memory");
22746e234aeSLoGin     return ret;
22846e234aeSLoGin }
22946e234aeSLoGin 
23046e234aeSLoGin // 输出8个bit到输出端口
io_out8(unsigned short port,unsigned char value)23146e234aeSLoGin void io_out8(unsigned short port, unsigned char value)
23246e234aeSLoGin {
23346e234aeSLoGin     __asm__ __volatile__("outb	%0,	%%dx	\n\t"
23446e234aeSLoGin                          "mfence			\n\t"
23546e234aeSLoGin                          :
23646e234aeSLoGin                          : "a"(value), "d"(port)
23746e234aeSLoGin                          : "memory");
23846e234aeSLoGin }
23946e234aeSLoGin 
24046e234aeSLoGin // 输出32个bit到输出端口
io_out32(unsigned short port,unsigned int value)24146e234aeSLoGin void io_out32(unsigned short port, unsigned int value)
24246e234aeSLoGin {
24346e234aeSLoGin     __asm__ __volatile__("outl	%0,	%%dx	\n\t"
24446e234aeSLoGin                          "mfence			\n\t"
24546e234aeSLoGin                          :
24646e234aeSLoGin                          : "a"(value), "d"(port)
24746e234aeSLoGin                          : "memory");
24846e234aeSLoGin }
24946e234aeSLoGin 
25046e234aeSLoGin /**
25146e234aeSLoGin  * @brief 从端口读入n个word到buffer
25246e234aeSLoGin  *
25346e234aeSLoGin  */
25446e234aeSLoGin #define io_insw(port, buffer, nr)                                                 \
25546e234aeSLoGin     __asm__ __volatile__("cld;rep;insw;mfence;" ::"d"(port), "D"(buffer), "c"(nr) \
25646e234aeSLoGin                          : "memory")
25746e234aeSLoGin 
25846e234aeSLoGin /**
25946e234aeSLoGin  * @brief 从输出buffer中的n个word到端口
26046e234aeSLoGin  *
26146e234aeSLoGin  */
26246e234aeSLoGin #define io_outsw(port, buffer, nr)                                                 \
26346e234aeSLoGin     __asm__ __volatile__("cld;rep;outsw;mfence;" ::"d"(port), "S"(buffer), "c"(nr) \
26446e234aeSLoGin                          : "memory")
26546e234aeSLoGin 
26646e234aeSLoGin /**
26746e234aeSLoGin  * @brief 从用户空间搬运数据到内核空间
26846e234aeSLoGin  *
26946e234aeSLoGin  * @param dst 目的地址
27046e234aeSLoGin  * @param src 源地址
27146e234aeSLoGin  * @param size 搬运的大小
27246e234aeSLoGin  * @return uint64_t
27346e234aeSLoGin  */
copy_from_user(void * dst,void * src,uint64_t size)27446e234aeSLoGin static inline uint64_t copy_from_user(void *dst, void *src, uint64_t size)
27546e234aeSLoGin {
27646e234aeSLoGin     uint64_t tmp0, tmp1;
27746e234aeSLoGin     if (!verify_area((uint64_t)src, size))
27846e234aeSLoGin         return 0;
27946e234aeSLoGin 
28046e234aeSLoGin     /**
28146e234aeSLoGin      * @brief 先每次搬运8 bytes,剩余就直接一个个byte搬运
28246e234aeSLoGin      *
28346e234aeSLoGin      */
28446e234aeSLoGin     asm volatile("rep   \n\t"
28546e234aeSLoGin                  "movsq  \n\t"
28646e234aeSLoGin                  "movq %3, %0   \n\t"
28746e234aeSLoGin                  "rep   \n\t"
28846e234aeSLoGin                  "movsb \n\t"
28946e234aeSLoGin                  : "=&c"(size), "=&D"(tmp0), "=&S"(tmp1)
29046e234aeSLoGin                  : "r"(size & 7), "0"(size >> 3), "1"(dst), "2"(src)
29146e234aeSLoGin                  : "memory");
29246e234aeSLoGin     return size;
29346e234aeSLoGin }
29446e234aeSLoGin 
29546e234aeSLoGin /**
29646e234aeSLoGin  * @brief 从内核空间搬运数据到用户空间
29746e234aeSLoGin  *
29846e234aeSLoGin  * @param dst 目的地址
29946e234aeSLoGin  * @param src 源地址
30046e234aeSLoGin  * @param size 搬运的大小
30146e234aeSLoGin  * @return uint64_t
30246e234aeSLoGin  */
copy_to_user(void * dst,void * src,uint64_t size)30346e234aeSLoGin static inline uint64_t copy_to_user(void *dst, void *src, uint64_t size)
30446e234aeSLoGin {
30546e234aeSLoGin     if (verify_area((uint64_t)src, size))
30646e234aeSLoGin         return 0;
30746e234aeSLoGin 
30846e234aeSLoGin     /**
30946e234aeSLoGin      * @brief 先每次搬运8 bytes,剩余就直接一个个byte搬运
31046e234aeSLoGin      *
31146e234aeSLoGin      */
31246e234aeSLoGin     // todo:编译有bug
31346e234aeSLoGin     // asm volatile("rep   \n\t"
31446e234aeSLoGin     //              "movsq  \n\t"
31546e234aeSLoGin     //              "movq %3, %0   \n\t"
31646e234aeSLoGin     //              "rep   \n\t"
31746e234aeSLoGin     //              "movsb \n\t"
31846e234aeSLoGin     //              : "=&c"(size), "=&D"(tmp0), "=&S"(tmp1)
31946e234aeSLoGin     //              : "r"(size & 7), "0"(size >> 3), "1"(dst), "2"(src)
32046e234aeSLoGin     //              : "memory");
32146e234aeSLoGin     memcpy(dst, src, size);
32246e234aeSLoGin 
32346e234aeSLoGin     return size;
32446e234aeSLoGin }
32546e234aeSLoGin 
32646e234aeSLoGin /**
32746e234aeSLoGin  * @brief 往指定地址写入8字节
32846e234aeSLoGin  * 防止由于编译器优化导致不支持的内存访问类型(尤其是在mmio的时候)
32946e234aeSLoGin  *
33046e234aeSLoGin  * @param vaddr 虚拟地址
33146e234aeSLoGin  * @param value 要写入的值
33246e234aeSLoGin  */
__write8b(uint64_t vaddr,uint64_t value)33346e234aeSLoGin static __always_inline void __write8b(uint64_t vaddr, uint64_t value)
33446e234aeSLoGin {
33546e234aeSLoGin     asm volatile("movq %%rdx, 0(%%rax)" ::"a"(vaddr), "d"(value)
33646e234aeSLoGin                  : "memory");
33746e234aeSLoGin }
33846e234aeSLoGin 
33946e234aeSLoGin /**
34046e234aeSLoGin  * @brief 往指定地址写入4字节
34146e234aeSLoGin  * 防止由于编译器优化导致不支持的内存访问类型(尤其是在mmio的时候)
34246e234aeSLoGin  *
34346e234aeSLoGin  * @param vaddr 虚拟地址
34446e234aeSLoGin  * @param value 要写入的值
34546e234aeSLoGin  */
__write4b(uint64_t vaddr,uint32_t value)34646e234aeSLoGin static __always_inline void __write4b(uint64_t vaddr, uint32_t value)
34746e234aeSLoGin {
34846e234aeSLoGin     asm volatile("movl %%edx, 0(%%rax)" ::"a"(vaddr), "d"(value)
34946e234aeSLoGin                  : "memory");
35046e234aeSLoGin }
35146e234aeSLoGin 
35246e234aeSLoGin /**
35346e234aeSLoGin  * @brief 从指定地址读取8字节
35446e234aeSLoGin  * 防止由于编译器优化导致不支持的内存访问类型(尤其是在mmio的时候)
35546e234aeSLoGin  *
35646e234aeSLoGin  * @param vaddr 虚拟地址
35746e234aeSLoGin  * @return uint64_t 读取到的值
35846e234aeSLoGin  */
__read8b(uint64_t vaddr)35946e234aeSLoGin static __always_inline uint64_t __read8b(uint64_t vaddr)
36046e234aeSLoGin {
36146e234aeSLoGin     uint64_t retval;
36246e234aeSLoGin     asm volatile("movq 0(%%rax), %0"
36346e234aeSLoGin                  : "=r"(retval)
36446e234aeSLoGin                  : "a"(vaddr)
36546e234aeSLoGin                  : "memory");
36646e234aeSLoGin     return retval;
36746e234aeSLoGin }
36846e234aeSLoGin 
36946e234aeSLoGin /**
37046e234aeSLoGin  * @brief 从指定地址读取4字节
37146e234aeSLoGin  * 防止由于编译器优化导致不支持的内存访问类型(尤其是在mmio的时候)
37246e234aeSLoGin  *
37346e234aeSLoGin  * @param vaddr 虚拟地址
37446e234aeSLoGin  * @return uint64_t 读取到的值
37546e234aeSLoGin  */
__read4b(uint64_t vaddr)37646e234aeSLoGin static __always_inline uint32_t __read4b(uint64_t vaddr)
37746e234aeSLoGin {
37846e234aeSLoGin     uint32_t retval;
37946e234aeSLoGin     asm volatile("movl 0(%%rax), %0"
38046e234aeSLoGin                  : "=d"(retval)
38146e234aeSLoGin                  : "a"(vaddr)
38246e234aeSLoGin                  : "memory");
38346e234aeSLoGin     return retval;
38446e234aeSLoGin }
385*4fda81ceSLoGin 
386*4fda81ceSLoGin 
387*4fda81ceSLoGin /**
388*4fda81ceSLoGin  * @brief 逐字节比较指定内存区域的值,并返回s1、s2的第一个不相等的字节i处的差值(s1[i]-s2[i])。
389*4fda81ceSLoGin  * 若两块内存区域的内容相同,则返回0
390*4fda81ceSLoGin  *
391*4fda81ceSLoGin  * @param s1 内存区域1
392*4fda81ceSLoGin  * @param s2 内存区域2
393*4fda81ceSLoGin  * @param len 要比较的内存区域长度
394*4fda81ceSLoGin  * @return int s1、s2的第一个不相等的字节i处的差值(s1[i]-s2[i])。若两块内存区域的内容相同,则返回0
395*4fda81ceSLoGin  */
memcmp(const void * s1,const void * s2,size_t len)396*4fda81ceSLoGin static inline int memcmp(const void *s1, const void *s2, size_t len)
397*4fda81ceSLoGin {
398*4fda81ceSLoGin     int diff;
399*4fda81ceSLoGin 
400*4fda81ceSLoGin     asm("cld \n\t"  // 复位DF,确保s1、s2指针是自增的
401*4fda81ceSLoGin         "repz; cmpsb\n\t" CC_SET(nz)
402*4fda81ceSLoGin         : CC_OUT(nz)(diff), "+D"(s1), "+S"(s2)
403*4fda81ceSLoGin         : "c"(len)
404*4fda81ceSLoGin         : "memory");
405*4fda81ceSLoGin 
406*4fda81ceSLoGin     if (diff)
407*4fda81ceSLoGin         diff = *(const unsigned char *)(s1 - 1) - *(const unsigned char *)(s2 - 1);
408*4fda81ceSLoGin 
409*4fda81ceSLoGin     return diff;
410*4fda81ceSLoGin }
411