General fixes
[tpg/acess2.git] / Kernel / arch / x86 / lib.c
1 /*
2  * AcessOS Microkernel Version
3  * lib.c
4  */
5 #include <acess.h>
6 #include <threads.h>
7
8 extern int      GetCPUNum(void);
9
10 // === CODE ===
11 /**
12  * \brief Determine if a short spinlock is locked
13  * \param Lock  Lock pointer
14  */
15 int IS_LOCKED(struct sShortSpinlock *Lock)
16 {
17         return !!Lock->Lock;
18 }
19
20 /**
21  * \brief Check if the current CPU has the lock
22  * \param Lock  Lock pointer
23  */
24 int CPU_HAS_LOCK(struct sShortSpinlock *Lock)
25 {
26         #if STACKED_LOCKS == 1
27         return Lock->Lock == GetCPUNum() + 1;
28         #elif STACKED_LOCKS == 2
29         return Lock->Lock == Proc_GetCurThread();
30         #else
31         return 0;
32         #endif
33 }
34
35 /**
36  * \brief Acquire a Short Spinlock
37  * \param Lock  Lock pointer
38  * 
39  * This type of mutex should only be used for very short sections of code,
40  * or in places where a Mutex_* would be overkill, such as appending
41  * an element to linked list (usually two assignement lines in C)
42  * 
43  * \note This type of lock halts interrupts, so ensure that no timing
44  * functions are called while it is held. As a matter of fact, spend as
45  * little time as possible with this lock held
46  * \note If \a STACKED_LOCKS is set, this type of spinlock can be nested
47  */
48 void SHORTLOCK(struct sShortSpinlock *Lock)
49 {
50          int    v = 1;
51         #if LOCK_DISABLE_INTS
52          int    IF;
53         #endif
54         #if STACKED_LOCKS == 1
55          int    cpu = GetCPUNum() + 1;
56         #elif STACKED_LOCKS == 2
57         void    *thread = Proc_GetCurThread();
58         #endif
59         
60         #if LOCK_DISABLE_INTS
61         // Save interrupt state and clear interrupts
62         __ASM__ ("pushf;\n\tpop %%eax\n\tcli" : "=a"(IF));
63         IF &= 0x200;    // AND out all but the interrupt flag
64         #endif
65         
66         #if STACKED_LOCKS == 1
67         if( Lock->Lock == cpu ) {
68                 Lock->Depth ++;
69                 return ;
70         }
71         #elif STACKED_LOCKS == 2
72         if( Lock->Lock == thread ) {
73                 Lock->Depth ++;
74                 return ;
75         }
76         #endif
77         
78         // Wait for another CPU to release
79         while(v) {
80                 // CMPXCHG:
81                 //  If r/m32 == EAX, set ZF and set r/m32 = r32
82                 //  Else, clear ZF and set EAX = r/m32
83                 #if STACKED_LOCKS == 1
84                 __ASM__("lock cmpxchgl %2, (%3)"
85                         : "=a"(v)
86                         : "a"(0), "r"(cpu), "r"(&Lock->Lock)
87                         );
88                 #elif STACKED_LOCKS == 2
89                 __ASM__("lock cmpxchgl %2, (%3)"
90                         : "=a"(v)
91                         : "a"(0), "r"(thread), "r"(&Lock->Lock)
92                         );
93                 #else
94                 __ASM__("xchgl %%eax, (%%edi)":"=a"(v):"a"(1),"D"(&Lock->Lock));
95                 #endif
96         }
97         
98         #if LOCK_DISABLE_INTS
99         Lock->IF = IF;
100         #endif
101 }
102 /**
103  * \brief Release a short lock
104  * \param Lock  Lock pointer
105  */
106 void SHORTREL(struct sShortSpinlock *Lock)
107 {
108         #if STACKED_LOCKS
109         if( Lock->Depth ) {
110                 Lock->Depth --;
111                 return ;
112         }
113         #endif
114         
115         #if LOCK_DISABLE_INTS
116         // Lock->IF can change anytime once Lock->Lock is zeroed
117         if(Lock->IF) {
118                 Lock->Lock = 0;
119                 __ASM__ ("sti");
120         }
121         else {
122                 Lock->Lock = 0;
123         }
124         #else
125         Lock->Lock = 0;
126         #endif
127 }
128
129 // === IO Commands ===
130 void outb(Uint16 Port, Uint8 Data)
131 {
132         __asm__ __volatile__ ("outb %%al, %%dx"::"d"(Port),"a"(Data));
133 }
134 void outw(Uint16 Port, Uint16 Data)
135 {
136         __asm__ __volatile__ ("outw %%ax, %%dx"::"d"(Port),"a"(Data));
137 }
138 void outd(Uint16 Port, Uint32 Data)
139 {
140         __asm__ __volatile__ ("outl %%eax, %%dx"::"d"(Port),"a"(Data));
141 }
142 Uint8 inb(Uint16 Port)
143 {
144         Uint8   ret;
145         __asm__ __volatile__ ("inb %%dx, %%al":"=a"(ret):"d"(Port));
146         return ret;
147 }
148 Uint16 inw(Uint16 Port)
149 {
150         Uint16  ret;
151         __asm__ __volatile__ ("inw %%dx, %%ax":"=a"(ret):"d"(Port));
152         return ret;
153 }
154 Uint32 ind(Uint16 Port)
155 {
156         Uint32  ret;
157         __asm__ __volatile__ ("inl %%dx, %%eax":"=a"(ret):"d"(Port));
158         return ret;
159 }
160
161 /**
162  * \fn void *memset(void *Dest, int Val, size_t Num)
163  * \brief Do a byte granuality set of Dest
164  */
165 void *memset(void *Dest, int Val, size_t Num)
166 {
167         Uint32  val = Val&0xFF;
168         val |= val << 8;
169         val |= val << 16;
170         __asm__ __volatile__ (
171                 "rep stosl;\n\t"
172                 "mov %3, %%ecx;\n\t"
173                 "rep stosb"
174                 :: "D" (Dest), "a" (val), "c" (Num/4), "r" (Num&3));
175         return Dest;
176 }
177 /**
178  * \brief Set double words
179  */
180 void *memsetd(void *Dest, Uint32 Val, size_t Num)
181 {
182         __asm__ __volatile__ ("rep stosl" :: "D" (Dest), "a" (Val), "c" (Num));
183         return Dest;
184 }
185
186 /**
187  * \fn int memcmp(const void *m1, const void *m2, size_t Num)
188  * \brief Compare two pieces of memory
189  */
190 int memcmp(const void *m1, const void *m2, size_t Num)
191 {
192         if( Num == 0 )  return 1;       // No bytes are always identical
193         
194         while(Num--)
195         {
196                 if(*(Uint8*)m1 != *(Uint8*)m2)  break;
197                 m1 ++;
198                 m2 ++;
199         }
200         return *(Uint8*)m1 - *(Uint8*)m2;
201 }
202
203 /**
204  * \fn void *memcpy(void *Dest, const void *Src, size_t Num)
205  * \brief Copy \a Num bytes from \a Src to \a Dest
206  */
207 void *memcpy(void *Dest, const void *Src, size_t Num)
208 {
209         if( ((Uint)Dest & 3) || ((Uint)Src & 3) )
210                 __asm__ __volatile__ ("rep movsb" :: "D" (Dest), "S" (Src), "c" (Num));
211         else {
212                 __asm__ __volatile__ (
213                         "rep movsl;\n\t"
214                         "mov %3, %%ecx;\n\t"
215                         "rep movsb"
216                         :: "D" (Dest), "S" (Src), "c" (Num/4), "r" (Num&3));
217         }
218         return Dest;
219 }
220 /**
221  * \fn void *memcpyd(void *Dest, const void *Src, size_t Num)
222  * \brief Copy \a Num DWORDs from \a Src to \a Dest
223  */
224 void *memcpyd(void *Dest, const void *Src, size_t Num)
225 {
226         __asm__ __volatile__ ("rep movsl" :: "D" (Dest), "S" (Src), "c" (Num));
227         return Dest;
228 }
229
230 /**
231  * \fn Uint64 __udivdi3(Uint64 Num, Uint64 Den)
232  * \brief Divide two 64-bit integers
233  */
234 Uint64 __udivdi3(Uint64 Num, Uint64 Den)
235 {
236         Uint64  P[2];
237         Uint64  q = 0;
238          int    i;
239         
240         if(Den == 0)    __asm__ __volatile__ ("int $0x0");
241         // Common speedups
242         if(Num <= 0xFFFFFFFF && Den <= 0xFFFFFFFF)
243                 return (Uint32)Num / (Uint32)Den;
244         if(Den == 1)    return Num;
245         if(Den == 2)    return Num >> 1;        // Speed Hacks
246         if(Den == 4)    return Num >> 2;        // Speed Hacks
247         if(Den == 8)    return Num >> 3;        // Speed Hacks
248         if(Den == 16)   return Num >> 4;        // Speed Hacks
249         if(Den == 32)   return Num >> 5;        // Speed Hacks
250         if(Den == 1024) return Num >> 10;       // Speed Hacks
251         if(Den == 2048) return Num >> 11;       // Speed Hacks
252         if(Den == 4096) return Num >> 12;
253         if(Num < Den)   return 0;
254         if(Num < Den*2) return 1;
255         if(Num == Den*2)        return 2;
256         
257         // Restoring division, from wikipedia
258         // http://en.wikipedia.org/wiki/Division_(digital)
259         P[0] = Num;     P[1] = 0;
260         for( i = 64; i--; )
261         {
262                 // P <<= 1;
263                 P[1] = (P[1] << 1) | (P[0] >> 63);
264                 P[0] = P[0] << 1;
265                 
266                 // P -= Den << 64
267                 P[1] -= Den;
268                 
269                 // P >= 0
270                 if( !(P[1] & (1ULL<<63)) ) {
271                         q |= (Uint64)1 << (63-i);
272                 }
273                 else {
274                         //q |= 0 << (63-i);
275                         P[1] += Den;
276                 }
277         }
278         
279         return q;
280 }
281
282 /**
283  * \fn Uint64 __umoddi3(Uint64 Num, Uint64 Den)
284  * \brief Get the modulus of two 64-bit integers
285  */
286 Uint64 __umoddi3(Uint64 Num, Uint64 Den)
287 {
288         if(Den == 0)    __asm__ __volatile__ ("int $0x0");      // Call Div by Zero Error
289         if(Den == 1)    return 0;       // Speed Hacks
290         if(Den == 2)    return Num & 1; // Speed Hacks
291         if(Den == 4)    return Num & 3; // Speed Hacks
292         if(Den == 8)    return Num & 7; // Speed Hacks
293         if(Den == 16)   return Num & 15;        // Speed Hacks
294         if(Den == 32)   return Num & 31;        // Speed Hacks
295         if(Den == 1024) return Num & 1023;      // Speed Hacks
296         if(Den == 2048) return Num & 2047;      // Speed Hacks
297         if(Den == 4096) return Num & 4095;      // Speed Hacks
298         
299         if(Num >> 32 == 0 && Den >> 32 == 0)
300                 return (Uint32)Num % (Uint32)Den;
301         
302         return Num - __udivdi3(Num, Den) * Den;
303 }
304
305 Uint16 LittleEndian16(Uint16 Val)
306 {
307         return Val;
308 }
309 Uint16 BigEndian16(Uint16 Val)
310 {
311         return ((Val&0xFF)<<8) | ((Val>>8)&0xFF);
312 }
313 Uint32 LittleEndian32(Uint32 Val)
314 {
315         return Val;
316 }
317 Uint32 BigEndian32(Uint32 Val)
318 {
319         return ((Val&0xFF)<<24) | ((Val&0xFF00)<<8) | ((Val>>8)&0xFF00) | ((Val>>24)&0xFF);
320 }
321
322 // --- EXPORTS ---
323 EXPORT(memcpy); EXPORT(memset);
324 EXPORT(memcmp);
325 //EXPORT(memcpyw);      EXPORT(memsetw);
326 EXPORT(memcpyd);        EXPORT(memsetd);
327 EXPORT(inb);    EXPORT(inw);    EXPORT(ind);
328 EXPORT(outb);   EXPORT(outw);   EXPORT(outd);
329 EXPORT(__udivdi3);      EXPORT(__umoddi3);
330
331 EXPORT(LittleEndian16); EXPORT(BigEndian16);
332 EXPORT(LittleEndian32); EXPORT(BigEndian32);
333
334 EXPORT(SHORTLOCK);
335 EXPORT(SHORTREL);
336 EXPORT(IS_LOCKED);

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