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 */
get_rsp()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 */
verify_area(uint64_t addr_start,uint64_t length)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 */
get_rbp()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 */
get_ds()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 */
get_rax()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 */
get_rbx()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
get_rflags()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
memset(void * dst,unsigned char C,ul size)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
memset_c(void * dst,uint8_t c,size_t count)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 */
memcpy(void * dst,const void * src,long Num)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
io_in8(unsigned short port)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
io_in32(unsigned short port)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到输出端口
io_out8(unsigned short port,unsigned char value)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到输出端口
io_out32(unsigned short port,unsigned int value)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 */
copy_from_user(void * dst,void * src,uint64_t size)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 */
copy_to_user(void * dst,void * src,uint64_t size)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 */
__write8b(uint64_t vaddr,uint64_t value)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 */
__write4b(uint64_t vaddr,uint32_t value)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 */
__read8b(uint64_t vaddr)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 */
__read4b(uint64_t vaddr)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 */
memcmp(const void * s1,const void * s2,size_t len)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