2 * AcessOS Microkernel Version
6 #include <threads_int.h>
11 #define DEBUG_TO_SERIAL 1
12 #define SERIAL_PORT 0x3F8
13 #define GDB_SERIAL_PORT 0x2F8
17 extern struct sShortSpinlock glDebug_Lock;
19 extern int GetCPUNum(void);
22 Uint64 __udivdi3(Uint64 Num, Uint64 Den);
23 Uint64 __umoddi3(Uint64 Num, Uint64 Den);
26 int gbDebug_SerialSetup = 0;
27 int gbGDB_SerialSetup = 0;
31 * \brief Determine if a short spinlock is locked
32 * \param Lock Lock pointer
34 int IS_LOCKED(struct sShortSpinlock *Lock)
40 * \brief Check if the current CPU has the lock
41 * \param Lock Lock pointer
43 int CPU_HAS_LOCK(struct sShortSpinlock *Lock)
45 #if STACKED_LOCKS == 1
46 return Lock->Lock == GetCPUNum() + 1;
47 #elif STACKED_LOCKS == 2
48 return Lock->Lock == Proc_GetCurThread();
55 * \brief Acquire a Short Spinlock
56 * \param Lock Lock pointer
58 * This type of mutex should only be used for very short sections of code,
59 * or in places where a Mutex_* would be overkill, such as appending
60 * an element to linked list (usually two assignement lines in C)
62 * \note This type of lock halts interrupts, so ensure that no timing
63 * functions are called while it is held. As a matter of fact, spend as
64 * little time as possible with this lock held
65 * \note If \a STACKED_LOCKS is set, this type of spinlock can be nested
67 void SHORTLOCK(struct sShortSpinlock *Lock)
73 #if STACKED_LOCKS == 1
74 int cpu = GetCPUNum() + 1;
75 #elif STACKED_LOCKS == 2
76 void *thread = Proc_GetCurThread();
80 // Save interrupt state
81 __ASM__ ("pushf;\n\tpop %0" : "=r"(IF));
82 IF &= 0x200; // AND out all but the interrupt flag
85 #if STACKED_LOCKS == 1
86 if( Lock->Lock == cpu ) {
90 #elif STACKED_LOCKS == 2
91 if( Lock->Lock == thread ) {
97 // Wait for another CPU to release
100 // If r/m32 == EAX, set ZF and set r/m32 = r32
101 // Else, clear ZF and set EAX = r/m32
102 #if STACKED_LOCKS == 1
103 __ASM__("lock cmpxchgl %2, (%3)"
105 : "a"(0), "r"(cpu), "r"(&Lock->Lock)
107 #elif STACKED_LOCKS == 2
108 __ASM__("lock cmpxchgl %2, (%3)"
110 : "a"(0), "r"(thread), "r"(&Lock->Lock)
113 __ASM__("xchgl %%eax, (%%edi)":"=a"(v):"a"(1),"D"(&Lock->Lock));
116 #if LOCK_DISABLE_INTS
117 if( v ) __ASM__("sti"); // Re-enable interrupts
121 #if LOCK_DISABLE_INTS
127 if( Lock != &glDebug_Lock )
129 //Log_Log("LOCK", "%p locked by %p", Lock, __builtin_return_address(0));
130 LogF("Lock %p locked by %p\n", Lock, __builtin_return_address(0));
135 * \brief Release a short lock
136 * \param Lock Lock pointer
138 void SHORTREL(struct sShortSpinlock *Lock)
148 if( Lock != &glDebug_Lock )
150 //Log_Log("LOCK", "%p released by %p", Lock, __builtin_return_address(0));
151 LogF("Lock %p released by %p\n", Lock, __builtin_return_address(0));
155 #if LOCK_DISABLE_INTS
156 // Lock->IF can change anytime once Lock->Lock is zeroed
171 int putDebugChar(char ch)
173 if(!gbGDB_SerialSetup) {
174 outb(GDB_SERIAL_PORT + 1, 0x00); // Disable all interrupts
175 outb(GDB_SERIAL_PORT + 3, 0x80); // Enable DLAB (set baud rate divisor)
176 outb(GDB_SERIAL_PORT + 0, 0x0C); // Set divisor to 12 (lo byte) 9600 baud
177 outb(GDB_SERIAL_PORT + 1, 0x00); // (base is (hi byte)
178 outb(GDB_SERIAL_PORT + 3, 0x03); // 8 bits, no parity, one stop bit (8N1)
179 outb(GDB_SERIAL_PORT + 2, 0xC7); // Enable FIFO with 14-byte threshold and clear it
180 outb(GDB_SERIAL_PORT + 4, 0x0B); // IRQs enabled, RTS/DSR set
181 gbDebug_SerialSetup = 1;
183 while( (inb(GDB_SERIAL_PORT + 5) & 0x20) == 0 );
184 outb(GDB_SERIAL_PORT, ch);
187 int getDebugChar(void)
189 if(!gbGDB_SerialSetup) {
190 outb(GDB_SERIAL_PORT + 1, 0x00); // Disable all interrupts
191 outb(GDB_SERIAL_PORT + 3, 0x80); // Enable DLAB (set baud rate divisor)
192 outb(GDB_SERIAL_PORT + 0, 0x0C); // Set divisor to 12 (lo byte) 9600 baud
193 outb(GDB_SERIAL_PORT + 1, 0x00); // (hi byte)
194 outb(GDB_SERIAL_PORT + 3, 0x03); // 8 bits, no parity, one stop bit
195 outb(GDB_SERIAL_PORT + 2, 0xC7); // Enable FIFO with 14-byte threshold and clear it
196 outb(GDB_SERIAL_PORT + 4, 0x0B); // IRQs enabled, RTS/DSR set
197 gbDebug_SerialSetup = 1;
199 while( (inb(GDB_SERIAL_PORT + 5) & 1) == 0) ;
200 return inb(GDB_SERIAL_PORT);
202 #endif /* USE_GDB_STUB */
204 void Debug_PutCharDebug(char ch)
207 __asm__ __volatile__ ( "outb %%al, $0xe9" :: "a"(((Uint8)ch)) );
211 if(!gbDebug_SerialSetup) {
212 outb(SERIAL_PORT + 1, 0x00); // Disable all interrupts
213 outb(SERIAL_PORT + 3, 0x80); // Enable DLAB (set baud rate divisor)
214 outb(SERIAL_PORT + 0, 0x0C); // Set divisor to 12 (lo byte) 9600 baud
215 outb(SERIAL_PORT + 1, 0x00); // (hi byte)
216 outb(SERIAL_PORT + 3, 0x03); // 8 bits, no parity, one stop bit
217 outb(SERIAL_PORT + 2, 0xC7); // Enable FIFO with 14-byte threshold and clear it
218 outb(SERIAL_PORT + 4, 0x0B); // IRQs enabled, RTS/DSR set
219 gbDebug_SerialSetup = 1;
221 while( (inb(SERIAL_PORT + 5) & 0x20) == 0 );
222 outb(SERIAL_PORT, ch);
226 void Debug_PutStringDebug(const char *String)
229 Debug_PutCharDebug(*String++);
232 // === IO Commands ===
233 void outb(Uint16 Port, Uint8 Data)
235 __asm__ __volatile__ ("outb %%al, %%dx"::"d"(Port),"a"(Data));
237 void outw(Uint16 Port, Uint16 Data)
239 __asm__ __volatile__ ("outw %%ax, %%dx"::"d"(Port),"a"(Data));
241 void outd(Uint16 Port, Uint32 Data)
243 __asm__ __volatile__ ("outl %%eax, %%dx"::"d"(Port),"a"(Data));
245 Uint8 inb(Uint16 Port)
248 __asm__ __volatile__ ("inb %%dx, %%al":"=a"(ret):"d"(Port));
251 Uint16 inw(Uint16 Port)
254 __asm__ __volatile__ ("inw %%dx, %%ax":"=a"(ret):"d"(Port));
257 Uint32 ind(Uint16 Port)
260 __asm__ __volatile__ ("inl %%dx, %%eax":"=a"(ret):"d"(Port));
265 * \fn void *memset(void *Dest, int Val, size_t Num)
266 * \brief Do a byte granuality set of Dest
268 void *memset(void *Dest, int Val, size_t Num)
270 Uint32 val = Val&0xFF;
273 __asm__ __volatile__ (
277 :: "D" (Dest), "a" (val), "c" (Num/4), "r" (Num&3));
281 * \brief Set double words
283 void *memsetd(void *Dest, Uint32 Val, size_t Num)
285 __asm__ __volatile__ ("rep stosl" :: "D" (Dest), "a" (Val), "c" (Num));
290 * \fn int memcmp(const void *m1, const void *m2, size_t Num)
291 * \brief Compare two pieces of memory
293 int memcmp(const void *m1, const void *m2, size_t Num)
295 const Uint8 *d1 = m1;
296 const Uint8 *d2 = m2;
297 if( Num == 0 ) return 0; // No bytes are always identical
310 * \fn void *memcpy(void *Dest, const void *Src, size_t Num)
311 * \brief Copy \a Num bytes from \a Src to \a Dest
313 void *memcpy(void *Dest, const void *Src, size_t Num)
315 if( ((Uint)Dest & 3) || ((Uint)Src & 3) )
316 __asm__ __volatile__ ("rep movsb" :: "D" (Dest), "S" (Src), "c" (Num));
318 __asm__ __volatile__ (
322 :: "D" (Dest), "S" (Src), "c" (Num/4), "r" (Num&3));
327 * \fn void *memcpyd(void *Dest, const void *Src, size_t Num)
328 * \brief Copy \a Num DWORDs from \a Src to \a Dest
330 void *memcpyd(void *Dest, const void *Src, size_t Num)
332 __asm__ __volatile__ ("rep movsl" :: "D" (Dest), "S" (Src), "c" (Num));
337 * \fn Uint64 __udivdi3(Uint64 Num, Uint64 Den)
338 * \brief Divide two 64-bit integers
340 Uint64 __udivdi3(Uint64 Num, Uint64 Den)
346 if(Den == 0) __asm__ __volatile__ ("int $0x0");
348 if(Num <= 0xFFFFFFFF && Den <= 0xFFFFFFFF)
349 return (Uint32)Num / (Uint32)Den;
350 if(Den == 1) return Num;
351 if(Den == 2) return Num >> 1; // Speed Hacks
352 if(Den == 4) return Num >> 2; // Speed Hacks
353 if(Den == 8) return Num >> 3; // Speed Hacks
354 if(Den == 16) return Num >> 4; // Speed Hacks
355 if(Den == 32) return Num >> 5; // Speed Hacks
356 if(Den == 1024) return Num >> 10; // Speed Hacks
357 if(Den == 2048) return Num >> 11; // Speed Hacks
358 if(Den == 4096) return Num >> 12;
359 if(Num < Den) return 0;
360 if(Num < Den*2) return 1;
361 if(Num == Den*2) return 2;
367 __asm__ __volatile__ (
368 "fildq %2\n\t" // Num
369 "fildq %1\n\t" // Den
373 : "m" (P[0]), "m" (P[1])
376 //Log("%llx / %llx = %llx\n", Num, Den, q);
378 // Restoring division, from wikipedia
379 // http://en.wikipedia.org/wiki/Division_(digital)
380 P[0] = Num; P[1] = 0;
384 P[1] = (P[1] << 1) | (P[0] >> 63);
391 if( !(P[1] & (1ULL<<63)) ) {
392 q |= (Uint64)1 << (63-i);
405 * \fn Uint64 __umoddi3(Uint64 Num, Uint64 Den)
406 * \brief Get the modulus of two 64-bit integers
408 Uint64 __umoddi3(Uint64 Num, Uint64 Den)
410 if(Den == 0) __asm__ __volatile__ ("int $0x0"); // Call Div by Zero Error
411 if(Den == 1) return 0; // Speed Hacks
412 if(Den == 2) return Num & 1; // Speed Hacks
413 if(Den == 4) return Num & 3; // Speed Hacks
414 if(Den == 8) return Num & 7; // Speed Hacks
415 if(Den == 16) return Num & 15; // Speed Hacks
416 if(Den == 32) return Num & 31; // Speed Hacks
417 if(Den == 1024) return Num & 1023; // Speed Hacks
418 if(Den == 2048) return Num & 2047; // Speed Hacks
419 if(Den == 4096) return Num & 4095; // Speed Hacks
421 if(Num >> 32 == 0 && Den >> 32 == 0)
422 return (Uint32)Num % (Uint32)Den;
424 return Num - __udivdi3(Num, Den) * Den;
429 EXPORT(memcpy); EXPORT(memset);
431 //EXPORT(memcpyw); EXPORT(memsetw);
432 EXPORT(memcpyd); EXPORT(memsetd);
433 EXPORT(inb); EXPORT(inw); EXPORT(ind);
434 EXPORT(outb); EXPORT(outw); EXPORT(outd);
435 EXPORT(__udivdi3); EXPORT(__umoddi3);