Fixed memcmp error (checks 1 more byte than it should)
[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 0;       // No bytes are always identical
193         
194         while(Num--)
195         {
196                 if(*(Uint8*)m1 != *(Uint8*)m2)
197                         return *(Uint8*)m1 - *(Uint8*)m2;
198                 m1 ++;
199                 m2 ++;
200         }
201         return 0;
202 }
203
204 /**
205  * \fn void *memcpy(void *Dest, const void *Src, size_t Num)
206  * \brief Copy \a Num bytes from \a Src to \a Dest
207  */
208 void *memcpy(void *Dest, const void *Src, size_t Num)
209 {
210         if( ((Uint)Dest & 3) || ((Uint)Src & 3) )
211                 __asm__ __volatile__ ("rep movsb" :: "D" (Dest), "S" (Src), "c" (Num));
212         else {
213                 __asm__ __volatile__ (
214                         "rep movsl;\n\t"
215                         "mov %3, %%ecx;\n\t"
216                         "rep movsb"
217                         :: "D" (Dest), "S" (Src), "c" (Num/4), "r" (Num&3));
218         }
219         return Dest;
220 }
221 /**
222  * \fn void *memcpyd(void *Dest, const void *Src, size_t Num)
223  * \brief Copy \a Num DWORDs from \a Src to \a Dest
224  */
225 void *memcpyd(void *Dest, const void *Src, size_t Num)
226 {
227         __asm__ __volatile__ ("rep movsl" :: "D" (Dest), "S" (Src), "c" (Num));
228         return Dest;
229 }
230
231 /**
232  * \fn Uint64 __udivdi3(Uint64 Num, Uint64 Den)
233  * \brief Divide two 64-bit integers
234  */
235 Uint64 __udivdi3(Uint64 Num, Uint64 Den)
236 {
237         Uint64  P[2];
238         Uint64  q = 0;
239          int    i;
240         
241         if(Den == 0)    __asm__ __volatile__ ("int $0x0");
242         // Common speedups
243         if(Num <= 0xFFFFFFFF && Den <= 0xFFFFFFFF)
244                 return (Uint32)Num / (Uint32)Den;
245         if(Den == 1)    return Num;
246         if(Den == 2)    return Num >> 1;        // Speed Hacks
247         if(Den == 4)    return Num >> 2;        // Speed Hacks
248         if(Den == 8)    return Num >> 3;        // Speed Hacks
249         if(Den == 16)   return Num >> 4;        // Speed Hacks
250         if(Den == 32)   return Num >> 5;        // Speed Hacks
251         if(Den == 1024) return Num >> 10;       // Speed Hacks
252         if(Den == 2048) return Num >> 11;       // Speed Hacks
253         if(Den == 4096) return Num >> 12;
254         if(Num < Den)   return 0;
255         if(Num < Den*2) return 1;
256         if(Num == Den*2)        return 2;
257         
258         // Restoring division, from wikipedia
259         // http://en.wikipedia.org/wiki/Division_(digital)
260         P[0] = Num;     P[1] = 0;
261         for( i = 64; i--; )
262         {
263                 // P <<= 1;
264                 P[1] = (P[1] << 1) | (P[0] >> 63);
265                 P[0] = P[0] << 1;
266                 
267                 // P -= Den << 64
268                 P[1] -= Den;
269                 
270                 // P >= 0
271                 if( !(P[1] & (1ULL<<63)) ) {
272                         q |= (Uint64)1 << (63-i);
273                 }
274                 else {
275                         //q |= 0 << (63-i);
276                         P[1] += Den;
277                 }
278         }
279         
280         return q;
281 }
282
283 /**
284  * \fn Uint64 __umoddi3(Uint64 Num, Uint64 Den)
285  * \brief Get the modulus of two 64-bit integers
286  */
287 Uint64 __umoddi3(Uint64 Num, Uint64 Den)
288 {
289         if(Den == 0)    __asm__ __volatile__ ("int $0x0");      // Call Div by Zero Error
290         if(Den == 1)    return 0;       // Speed Hacks
291         if(Den == 2)    return Num & 1; // Speed Hacks
292         if(Den == 4)    return Num & 3; // Speed Hacks
293         if(Den == 8)    return Num & 7; // Speed Hacks
294         if(Den == 16)   return Num & 15;        // Speed Hacks
295         if(Den == 32)   return Num & 31;        // Speed Hacks
296         if(Den == 1024) return Num & 1023;      // Speed Hacks
297         if(Den == 2048) return Num & 2047;      // Speed Hacks
298         if(Den == 4096) return Num & 4095;      // Speed Hacks
299         
300         if(Num >> 32 == 0 && Den >> 32 == 0)
301                 return (Uint32)Num % (Uint32)Den;
302         
303         return Num - __udivdi3(Num, Den) * Den;
304 }
305
306 Uint16 LittleEndian16(Uint16 Val)
307 {
308         return Val;
309 }
310 Uint16 BigEndian16(Uint16 Val)
311 {
312         return ((Val&0xFF)<<8) | ((Val>>8)&0xFF);
313 }
314 Uint32 LittleEndian32(Uint32 Val)
315 {
316         return Val;
317 }
318 Uint32 BigEndian32(Uint32 Val)
319 {
320         return ((Val&0xFF)<<24) | ((Val&0xFF00)<<8) | ((Val>>8)&0xFF00) | ((Val>>24)&0xFF);
321 }
322
323 // --- EXPORTS ---
324 EXPORT(memcpy); EXPORT(memset);
325 EXPORT(memcmp);
326 //EXPORT(memcpyw);      EXPORT(memsetw);
327 EXPORT(memcpyd);        EXPORT(memsetd);
328 EXPORT(inb);    EXPORT(inw);    EXPORT(ind);
329 EXPORT(outb);   EXPORT(outw);   EXPORT(outd);
330 EXPORT(__udivdi3);      EXPORT(__umoddi3);
331
332 EXPORT(LittleEndian16); EXPORT(BigEndian16);
333 EXPORT(LittleEndian32); EXPORT(BigEndian32);
334
335 EXPORT(SHORTLOCK);
336 EXPORT(SHORTREL);
337 EXPORT(IS_LOCKED);

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