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

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