Sorting source tree a bit
[tpg/acess2.git] / KernelLand / Kernel / arch / x86_64 / lib.c
1 /*
2  */
3 #include <acess.h>
4 #include <arch.h>
5
6 #define DEBUG_TO_E9     1
7 #define DEBUG_TO_SERIAL 1
8 #define SERIAL_PORT     0x3F8
9 #define GDB_SERIAL_PORT 0x2F8
10
11
12 // === IMPORTS ===
13 extern int      GetCPUNum(void);
14 extern void     *Proc_GetCurThread(void);
15
16 // === GLOBALS ===
17  int    gbDebug_SerialSetup = 0;
18  int    gbGDB_SerialSetup = 0;
19
20 // === PROTOTYPEs ===
21  int    putDebugChar(char ch);
22
23 // === CODE ===
24 /**
25  * \brief Determine if a short spinlock is locked
26  * \param Lock  Lock pointer
27  */
28 int IS_LOCKED(struct sShortSpinlock *Lock)
29 {
30         return !!Lock->Lock;
31 }
32
33 /**
34  * \brief Check if the current CPU has the lock
35  * \param Lock  Lock pointer
36  */
37 int CPU_HAS_LOCK(struct sShortSpinlock *Lock)
38 {
39         #if STACKED_LOCKS == 1
40         return Lock->Lock == GetCPUNum() + 1;
41         #elif STACKED_LOCKS == 2
42         return Lock->Lock == Proc_GetCurThread();
43         #else
44         return 0;
45         #endif
46 }
47
48 /**
49  * \brief Acquire a Short Spinlock
50  * \param Lock  Lock pointer
51  * 
52  * This type of mutex should only be used for very short sections of code,
53  * or in places where a Mutex_* would be overkill, such as appending
54  * an element to linked list (usually two assignement lines in C)
55  * 
56  * \note This type of lock halts interrupts, so ensure that no timing
57  * functions are called while it is held. As a matter of fact, spend as
58  * little time as possible with this lock held
59  * \note If \a STACKED_LOCKS is set, this type of spinlock can be nested
60  */
61 void SHORTLOCK(struct sShortSpinlock *Lock)
62 {
63          int    v = 1;
64         #if LOCK_DISABLE_INTS
65          int    IF;
66         #endif
67         #if STACKED_LOCKS == 1
68          int    cpu = GetCPUNum() + 1;
69         #elif STACKED_LOCKS == 2
70         void    *thread = Proc_GetCurThread();
71         #endif
72         
73         #if LOCK_DISABLE_INTS
74         // Save interrupt state and clear interrupts
75         __ASM__ ("pushf;\n\tpop %0" : "=r"(IF));
76         IF &= 0x200;    // AND out all but the interrupt flag
77         #endif
78         
79         #if STACKED_LOCKS == 1
80         if( Lock->Lock == cpu ) {
81                 Lock->Depth ++;
82                 return ;
83         }
84         #elif STACKED_LOCKS == 2
85         if( Lock->Lock == thread ) {
86                 Lock->Depth ++;
87                 return ;
88         }
89         #endif
90         
91         // Wait for another CPU to release
92         while(v) {
93                 // CMPXCHG:
94                 //  If r/m32 == EAX, set ZF and set r/m32 = r32
95                 //  Else, clear ZF and set EAX = r/m32
96                 #if STACKED_LOCKS == 1
97                 __ASM__("lock cmpxchgl %2, (%3)"
98                         : "=a"(v)
99                         : "a"(0), "r"(cpu), "r"(&Lock->Lock)
100                         );
101                 #elif STACKED_LOCKS == 2
102                 __ASM__("lock cmpxchgq %2, (%3)"
103                         : "=a"(v)
104                         : "a"(0), "r"(thread), "r"(&Lock->Lock)
105                         );
106                 #else
107                 __ASM__("xchgl %0, (%2)":"=a"(v):"a"(1),"D"(&Lock->Lock));
108                 #endif
109                 
110                 #if LOCK_DISABLE_INTS
111                 if( v ) __ASM__("sti"); // Re-enable interrupts
112                 #endif
113         }
114         
115         #if LOCK_DISABLE_INTS
116         __ASM__("cli");
117         Lock->IF = IF;
118         #endif
119 }
120 /**
121  * \brief Release a short lock
122  * \param Lock  Lock pointer
123  */
124 void SHORTREL(struct sShortSpinlock *Lock)
125 {
126         #if STACKED_LOCKS
127         if( Lock->Depth ) {
128                 Lock->Depth --;
129                 return ;
130         }
131         #endif
132         
133         #if LOCK_DISABLE_INTS
134         // Lock->IF can change anytime once Lock->Lock is zeroed
135         if(Lock->IF) {
136                 Lock->Lock = 0;
137                 __ASM__ ("sti");
138         }
139         else {
140                 Lock->Lock = 0;
141         }
142         #else
143         Lock->Lock = 0;
144         #endif
145 }
146
147 // === DEBUG IO ===
148 #if USE_GDB_STUB
149 int putDebugChar(char ch)
150 {
151         if(!gbGDB_SerialSetup) {
152                 outb(GDB_SERIAL_PORT + 1, 0x00);    // Disable all interrupts
153                 outb(GDB_SERIAL_PORT + 3, 0x80);    // Enable DLAB (set baud rate divisor)
154                 outb(GDB_SERIAL_PORT + 0, 0x0C);    // Set divisor to 12 (lo byte) 9600 baud
155                 outb(GDB_SERIAL_PORT + 1, 0x00);    //  (base is         (hi byte)
156                 outb(GDB_SERIAL_PORT + 3, 0x03);    // 8 bits, no parity, one stop bit (8N1)
157                 outb(GDB_SERIAL_PORT + 2, 0xC7);    // Enable FIFO with 14-byte threshold and clear it
158                 outb(GDB_SERIAL_PORT + 4, 0x0B);    // IRQs enabled, RTS/DSR set
159                 gbDebug_SerialSetup = 1;
160         }
161         while( (inb(GDB_SERIAL_PORT + 5) & 0x20) == 0 );
162         outb(GDB_SERIAL_PORT, ch);
163         return 0;
164 }
165 int getDebugChar(void)
166 {
167         if(!gbGDB_SerialSetup) {
168                 outb(GDB_SERIAL_PORT + 1, 0x00);    // Disable all interrupts
169                 outb(GDB_SERIAL_PORT + 3, 0x80);    // Enable DLAB (set baud rate divisor)
170                 outb(GDB_SERIAL_PORT + 0, 0x0C);    // Set divisor to 12 (lo byte) 9600 baud
171                 outb(GDB_SERIAL_PORT + 1, 0x00);    //                   (hi byte)
172                 outb(GDB_SERIAL_PORT + 3, 0x03);    // 8 bits, no parity, one stop bit
173                 outb(GDB_SERIAL_PORT + 2, 0xC7);    // Enable FIFO with 14-byte threshold and clear it
174                 outb(GDB_SERIAL_PORT + 4, 0x0B);    // IRQs enabled, RTS/DSR set
175                 gbDebug_SerialSetup = 1;
176         }
177         while( (inb(GDB_SERIAL_PORT + 5) & 1) == 0)     ;
178         return inb(GDB_SERIAL_PORT);
179 }
180 #endif
181
182 void Debug_PutCharDebug(char ch)
183 {
184         #if DEBUG_TO_E9
185         __asm__ __volatile__ ( "outb %%al, $0xe9" :: "a"(((Uint8)ch)) );
186         #endif
187         
188         #if DEBUG_TO_SERIAL
189         if(!gbDebug_SerialSetup) {
190                 outb(SERIAL_PORT + 1, 0x00);    // Disable all interrupts
191                 outb(SERIAL_PORT + 3, 0x80);    // Enable DLAB (set baud rate divisor)
192                 outb(SERIAL_PORT + 0, 0x0C);    // Set divisor to 12 (lo byte) 9600 baud
193                 outb(SERIAL_PORT + 1, 0x00);    //                   (hi byte)
194                 outb(SERIAL_PORT + 3, 0x03);    // 8 bits, no parity, one stop bit
195                 outb(SERIAL_PORT + 2, 0xC7);    // Enable FIFO with 14-byte threshold and clear it
196                 outb(SERIAL_PORT + 4, 0x0B);    // IRQs enabled, RTS/DSR set
197                 gbDebug_SerialSetup = 1;
198         }
199         while( (inb(SERIAL_PORT + 5) & 0x20) == 0 );
200         outb(SERIAL_PORT, ch);
201         #endif
202 }
203
204 void Debug_PutStringDebug(const char *String)
205 {
206         while(*String)
207                 Debug_PutCharDebug(*String++);
208 }
209
210 // === PORT IO ===
211 void outb(Uint16 Port, Uint8 Data)
212 {
213         __asm__ __volatile__ ("outb %%al, %%dx"::"d"(Port),"a"(Data));
214 }
215 void outw(Uint16 Port, Uint16 Data)
216 {
217         __asm__ __volatile__ ("outw %%ax, %%dx"::"d"(Port),"a"(Data));
218 }
219 void outd(Uint16 Port, Uint32 Data)
220 {
221         __asm__ __volatile__ ("outl %%eax, %%dx"::"d"(Port),"a"(Data));
222 }
223 Uint8 inb(Uint16 Port)
224 {
225         Uint8   ret;
226         __asm__ __volatile__ ("inb %%dx, %%al":"=a"(ret):"d"(Port));
227         return ret;
228 }
229 Uint16 inw(Uint16 Port)
230 {
231         Uint16  ret;
232         __asm__ __volatile__ ("inw %%dx, %%ax":"=a"(ret):"d"(Port));
233         return ret;
234 }
235 Uint32 ind(Uint16 Port)
236 {
237         Uint32  ret;
238         __asm__ __volatile__ ("inl %%dx, %%eax":"=a"(ret):"d"(Port));
239         return ret;
240 }
241
242 // === Endianness ===
243 /*
244 Uint32 BigEndian32(Uint32 Value)
245 {
246         Uint32  ret;
247         ret = (Value >> 24);
248         ret |= ((Value >> 16) & 0xFF) << 8;
249         ret |= ((Value >>  8) & 0xFF) << 16;
250         ret |= ((Value >>  0) & 0xFF) << 24;
251         return ret;
252 }
253
254 Uint16 BigEndian16(Uint16 Value)
255 {
256         return  (Value>>8)|(Value<<8);
257 }
258 */
259
260 // === Memory Manipulation ===
261 int memcmp(const void *__dest, const void *__src, size_t __count)
262 {
263         if( ((tVAddr)__dest & 7) != ((tVAddr)__src & 7) ) {
264                 const Uint8     *src = __src, *dst = __dest;
265                 while(__count)
266                 {
267                         if( *src != *dst )
268                                 return *dst - *src;
269                         src ++; dst ++; __count --;
270                 }
271                 return 0;
272         }
273         else {
274                 const Uint8     *src = __src;
275                 const Uint8     *dst = __dest;
276                 const Uint64    *src64, *dst64;
277                 
278                 while( (tVAddr)src & 7 && __count ) {
279                         if( *src != *dst )
280                                 return *dst - *src;
281                         dst ++; src ++; __count --;
282                 }
283
284                 src64 = (void*)src;
285                 dst64 = (void*)dst;
286
287                 while( __count >= 8 )
288                 {
289                         if( *src64 != *dst64 )
290                         {
291                                 src = (void*)src64;
292                                 dst = (void*)dst64;
293                                 if(src[0] != dst[0])    return dst[0]-src[0];
294                                 if(src[1] != dst[1])    return dst[1]-src[1];
295                                 if(src[2] != dst[2])    return dst[2]-src[2];
296                                 if(src[3] != dst[3])    return dst[3]-src[3];
297                                 if(src[4] != dst[4])    return dst[4]-src[4];
298                                 if(src[5] != dst[5])    return dst[5]-src[5];
299                                 if(src[6] != dst[6])    return dst[6]-src[6];
300                                 if(src[7] != dst[7])    return dst[7]-src[7];
301                                 return -1;      // This should never happen
302                         }
303                         __count -= 8;
304                         src64 ++;
305                         dst64 ++;
306                 }
307
308                 src = (void*)src64;
309                 dst = (void*)dst64;
310                 while( __count-- )
311                 {
312                         if(*dst != *src)        return *dst - *src;
313                         dst ++;
314                         src ++;
315                 }
316         }
317         return 0;
318 }
319
320 void *memcpy(void *__dest, const void *__src, size_t __count)
321 {
322         tVAddr  dst = (tVAddr)__dest, src = (tVAddr)__src;
323         if( (dst & 7) != (src & 7) )
324         {
325                 __asm__ __volatile__ ("rep movsb" : : "D"(dst),"S"(src),"c"(__count));
326         }
327         else
328         {
329                 while( (src & 7) && __count ) {
330                         *(char*)dst++ = *(char*)src++;
331                         __count --;
332                 }
333
334                 __asm__ __volatile__ ("rep movsq" : "=D"(dst),"=S"(src) : "0"(dst),"1"(src),"c"(__count/8));
335                 __count = __count & 7;
336                 while( __count-- )
337                         *(char*)dst++ = *(char*)src++;
338         }
339         return __dest;
340 }
341
342 void *memset(void *__dest, int __val, size_t __count)
343 {
344         if( __val != 0 || ((tVAddr)__dest & 7) != 0 )
345                 __asm__ __volatile__ ("rep stosb" : : "D"(__dest),"a"(__val),"c"(__count));
346         else {
347                 Uint8   *dst = __dest;
348
349                 __asm__ __volatile__ ("rep stosq" : : "D"(dst),"a"(0),"c"(__count/8));
350                 dst += __count & ~7;
351                 __count = __count & 7;
352                 while( __count-- )
353                         *dst++ = 0;
354         }
355         return __dest;
356 }
357
358 void *memsetd(void *__dest, Uint32 __val, size_t __count)
359 {
360         __asm__ __volatile__ ("rep stosl" : : "D"(__dest),"a"(__val),"c"(__count));
361         return __dest;
362 }
363
364 Uint64 DivMod64U(Uint64 Num, Uint64 Den, Uint64 *Rem)
365 {
366         Uint64  ret, rem;
367         __asm__ __volatile__(
368                 "div %4"
369                 : "=a" (ret), "=d" (rem)
370                 : "a" ( Num ), "d" (0), "r" (Den)
371                 );
372         if(Rem) *Rem = rem;
373         return ret;
374 }
375

UCC git Repository :: git.ucc.asn.au