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

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