coverity appeasement
[minix.git] / kernel / arch / i386 / klib.S
blobb10595ec17be455bc7599488cb7d31bbba328205
1 /* sections */
4 #include <minix/config.h>
5 #include <minix/const.h>
6 #include <machine/asm.h>
7 #include <machine/interrupt.h>
8 #include <machine/vm.h>
9 #include "archconst.h"
10 #include "kernel/const.h"
11 #include "sconst.h"
12 #include <machine/multiboot.h>
15 /* Easy way to make functions */
17 /* Make a function of the form func(arg) */
19 #define STACKARG 8(%ebp)
21 #define ARG_EAX_ACTION(FUNCTION, ACTION)        ;\
22 ENTRY(FUNCTION)                         ;\
23         push    %ebp                    ;\
24         mov     %esp, %ebp              ;\
25         mov     STACKARG, %eax           ;\
26         ACTION                          ;\
27         pop     %ebp                    ;\
28         ret
30 /* Make a function of the form ret = func() */
31 #define ARG_EAX_RETURN(FUNCTION, EXPR)        ;\
32 ENTRY(FUNCTION)                         ;\
33         push    %ebp                    ;\
34         mov     %esp, %ebp              ;\
35         mov     EXPR, %eax              ;\
36         pop     %ebp                    ;\
37         ret
39 /* Make a function of the form ret = func() */
40 #define ARG_EAX_SET(FUNCTION, DEST)        ;\
41 ENTRY(FUNCTION)                         ;\
42         push    %ebp                    ;\
43         mov     %esp, %ebp              ;\
44         mov     STACKARG, %eax          ;\
45         mov     %eax, DEST              ;\
46         jmp 0f /* a jump is required for some sets */ ;\
47 0:      pop     %ebp                    ;\
48         ret     
50 /* Make a function of the form ret = func() */
51 #define ARG_AX_SET(FUNCTION, DEST)        ;\
52 ENTRY(FUNCTION)                         ;\
53         push    %ebp                    ;\
54         mov     %esp, %ebp              ;\
55         mov     STACKARG, %eax          ;\
56         mov     %ax, DEST               ;\
57         jmp 0f /* a jump is required for some sets */ ;\
58 0:      pop     %ebp                    ;\
59         ret     
62  * This file contains a number of assembly code utility routines needed by the
63  * kernel.
64  */
66 ENTRY(__main)
67         ret
70 /*===========================================================================*/
71 /*                              phys_insw                                    */
72 /*===========================================================================*/
74  * PUBLIC void phys_insw(Port_t port, phys_bytes buf, size_t count); 
75  * Input an array from an I/O port.  Absolute address version of insw(). 
76  */
77 /* transfer data from (disk controller) port to memory */
78 ENTRY(phys_insw)
79         push    %ebp
80         mov     %esp, %ebp
81         cld
82         push    %edi
84         mov     8(%ebp), %edx   /* port to read from */
85         mov     12(%ebp), %edi  /* destination addr */
86         mov     16(%ebp), %ecx  /* byte count */
87         shr     $1, %ecx        /* word count */
88         rep insw        /* input many words */
89         pop     %edi
90         pop     %ebp
91         ret
94 /*===========================================================================*/
95 /*                              phys_insb                                    */
96 /*===========================================================================*/
98  * PUBLIC void phys_insb(Port_t port, phys_bytes buf, size_t count); 
99  * Input an array from an I/O port.  Absolute address version of insb(). 
100  */
101 /* transfer data from (disk controller) port to memory byte by byte */
102 ENTRY(phys_insb)
103         push    %ebp
104         mov     %esp, %ebp
105         cld
106         push    %edi
108         mov     8(%ebp), %edx   /* port to read from */
109         mov     12(%ebp), %edi  /* destination addr */
110         mov     16(%ebp), %ecx  /* byte count */
111         rep insb        /* input many bytes */
112         pop     %edi
113         pop     %ebp
114         ret
117 /*===========================================================================*/
118 /*                              phys_outsw                                   */
119 /*===========================================================================*/
121  * PUBLIC void phys_outsw(Port_t port, phys_bytes buf, size_t count); 
122  * Output an array to an I/O port.  Absolute address version of outsw(). 
123  */
124 /* transfer data from memory to (disk controller) port */
125 ENTRY(phys_outsw)
126         push    %ebp
127         mov     %esp, %ebp
128         cld
129         push    %esi
131         mov     8(%ebp), %edx   /* port to write to */
132         mov     12(%ebp), %esi  /* source addr */
133         mov     16(%ebp), %ecx  /* byte count */
134         shr     $1, %ecx        /* word count */
135         rep outsw       /* output many words */
136         pop     %esi
137         pop     %ebp
138         ret
141 /*===========================================================================*/
142 /*                              phys_outsb                                   */
143 /*===========================================================================*/
144 /* 
145  * PUBLIC void phys_outsb(Port_t port, phys_bytes buf, size_t count);
146  * Output an array to an I/O port.  Absolute address version of outsb().
147  */
148 /* transfer data from memory to (disk controller) port byte by byte */
149 ENTRY(phys_outsb)
150         push    %ebp
151         mov     %esp, %ebp
152         cld
153         push    %esi
155         mov     8(%ebp), %edx   /* port to write to */
156         mov     12(%ebp), %esi  /* source addr */
157         mov     16(%ebp), %ecx  /* byte count */
158         rep outsb       /* output many bytes */
159         pop     %esi
160         pop     %ebp
161         ret
164 /*===========================================================================*/
165 /*                              phys_copy                                    */
166 /*===========================================================================*/
168  * PUBLIC phys_bytes phys_copy(phys_bytes source, phys_bytes destination,
169  *                      phys_bytes bytecount); 
170  * Copy a block of data from anywhere to anywhere in physical memory.
171  */
172 /*              es edi esi eip   src dst len */
173 ENTRY(phys_copy)
174         push    %ebp
175         mov     %esp, %ebp
177         cld
178         push    %esi
179         push    %edi
181         mov     8(%ebp), %esi
182         mov     12(%ebp), %edi
183         mov     16(%ebp), %eax
185         cmp     $10, %eax       /* avoid align overhead for small counts */
186         jb      pc_small
187         mov     %esi, %ecx      /* align source, hope target is too */
188         neg     %ecx
189         and     $3, %ecx        /* count for alignment */
190         sub     %ecx, %eax
192         rep     movsb (%esi), (%edi)
193         mov     %eax, %ecx
194         shr     $2, %ecx        /* count of dwords */
196         rep     movsl (%esi), (%edi)
197         and     $3, %eax
198 pc_small:
199         xchg    %eax, %ecx      /* remainder */
201         rep     movsb (%esi), (%edi)
203         mov     $0, %eax                /* 0 means: no fault */
204 LABEL(phys_copy_fault)          /* kernel can send us here */
205         pop     %edi
206         pop     %esi
207         pop     %ebp
208         ret
210 LABEL(phys_copy_fault_in_kernel)        /* kernel can send us here */
211         pop     %edi
212         pop     %esi
213         pop     %ebp
214         mov     %cr2, %eax
215         ret
218 /*===========================================================================*/
219 /*                              copy_msg_from_user                           */
220 /*===========================================================================*/
222  * int copy_msg_from_user(message * user_mbuf, message * dst);
224  * Copies a message of 36 bytes from user process space to a kernel buffer. This
225  * function assumes that the process address space is installed (cr3 loaded).
227  * This function from the callers point of view either succeeds or returns an
228  * error which gives the caller a chance to respond accordingly. In fact it
229  * either succeeds or if it generates a pagefault, general protection or other
230  * exception, the trap handler has to redirect the execution to
231  * __user_copy_msg_pointer_failure where the error is reported to the caller
232  * without resolving the pagefault. It is not kernel's problem to deal with
233  * wrong pointers from userspace and the caller should return an error to
234  * userspace as if wrong values or request were passed to the kernel
235  */
236 ENTRY(copy_msg_from_user)
237         /* load the source pointer */
238         mov     4(%esp), %ecx
239         /* load the destination pointer */
240         mov     8(%esp), %edx
242 /*      mov     0*4(%ecx), %eax
243         mov     %eax, 0*4(%edx) */ 
244         mov     1*4(%ecx), %eax
245         mov     %eax, 1*4(%edx)
246         mov     2*4(%ecx), %eax
247         mov     %eax, 2*4(%edx)
248         mov     3*4(%ecx), %eax
249         mov     %eax, 3*4(%edx)
250         mov     4*4(%ecx), %eax
251         mov     %eax, 4*4(%edx)
252         mov     5*4(%ecx), %eax
253         mov     %eax, 5*4(%edx)
254         mov     6*4(%ecx), %eax
255         mov     %eax, 6*4(%edx)
256         mov     7*4(%ecx), %eax
257         mov     %eax, 7*4(%edx)
258         mov     8*4(%ecx), %eax
259         mov     %eax, 8*4(%edx)
261 LABEL(__copy_msg_from_user_end)
262         movl    $0, %eax
263         ret
265 /*===========================================================================*/
266 /*                              copy_msg_to_user                             */
267 /*===========================================================================*/
269  * void copy_msg_to_user(message * src, message * user_mbuf);
271  * Copies a message of 36 bytes to user process space from a kernel buffer.
273  * All the other copy_msg_from_user() comments apply here as well!
274  */
275 ENTRY(copy_msg_to_user)
276         /* load the source pointer */
277         mov     4(%esp), %ecx
278         /* load the destination pointer */
279         mov     8(%esp), %edx
281         mov     0*4(%ecx), %eax
282         mov     %eax, 0*4(%edx)
283         mov     1*4(%ecx), %eax
284         mov     %eax, 1*4(%edx)
285         mov     2*4(%ecx), %eax
286         mov     %eax, 2*4(%edx)
287         mov     3*4(%ecx), %eax
288         mov     %eax, 3*4(%edx)
289         mov     4*4(%ecx), %eax
290         mov     %eax, 4*4(%edx)
291         mov     5*4(%ecx), %eax
292         mov     %eax, 5*4(%edx)
293         mov     6*4(%ecx), %eax
294         mov     %eax, 6*4(%edx)
295         mov     7*4(%ecx), %eax
296         mov     %eax, 7*4(%edx)
297         mov     8*4(%ecx), %eax
298         mov     %eax, 8*4(%edx)
300 LABEL(__copy_msg_to_user_end)
301         movl    $0, %eax
302         ret
305  * if a function from a selected set of copies from or to userspace fails, it is
306  * because of a wrong pointer supplied by the userspace. We have to clean up and
307  * and return -1 to indicated that something wrong has happend. The place it was
308  * called from has to handle this situation. The exception handler redirect us
309  * here to continue, clean up and report the error
310  */
311 ENTRY(__user_copy_msg_pointer_failure)
312         movl    $-1, %eax
313         ret
315 /*===========================================================================*/
316 /*                              phys_memset                                  */
317 /*===========================================================================*/
319  * PUBLIC void phys_memset(phys_bytes source, unsigned long pattern, 
320  *      phys_bytes bytecount); 
321  * Fill a block of physical memory with pattern. 
322  */
323 ENTRY(phys_memset)
324         push    %ebp
325         mov     %esp, %ebp
326         push    %esi
327         push    %ebx
329         mov     8(%ebp), %esi
330         mov     16(%ebp), %eax
331         mov     12(%ebp), %ebx
332         shr     $2, %eax
333 fill_start:
334         mov     %ebx, (%esi)
335         add     $4, %esi
336         dec     %eax
337         jne     fill_start
338 /* Any remaining bytes? */
339         mov     16(%ebp), %eax
340         and     $3, %eax
341 remain_fill:
342         cmp     $0, %eax
343         je      fill_done
344         movb    12(%ebp), %bl
345         movb    %bl, (%esi)
346         add     $1, %esi
347         inc     %ebp
348         dec     %eax
349         jmp     remain_fill
351 fill_done:
352 LABEL(memset_fault)             /* kernel can send us here */
353         mov     $0, %eax                /* 0 means: no fault */
354         pop     %ebx
355         pop     %esi
356         pop     %ebp
357         ret
359 LABEL(memset_fault_in_kernel)           /* kernel can send us here */
360         pop     %ebx
361         pop     %esi
362         pop     %ebp
363         mov     %cr2, %eax
364         ret
366 /*===========================================================================*/
367 /*                              x86_triplefault                              */
368 /*===========================================================================*/
370  * PUBLIC void x86_triplefault(); 
371  * Reset the system by loading IDT with offset 0 and interrupting. 
372  */
373 ENTRY(x86_triplefault)
374         lidt    idt_zero
375         int     $3      /* anything goes, the 386 will not like it */
376 .data
377 idt_zero:
378 .long   0, 0
379 .text
382 /*===========================================================================*/
383 /*                              halt_cpu                                     */
384 /*===========================================================================*/
386  * PUBLIC void halt_cpu(void);
387  * reanables interrupts and puts the cpu in the halts state. Once an interrupt
388  * is handled the execution resumes by disabling interrupts and continues
389  */
390 ENTRY(halt_cpu)
391         sti
392         hlt /* interrupts enabled only after this instruction is executed! */
393         /*
394          * interrupt handlers make sure that the interrupts are disabled when we
395          * get here so we take only _one_ interrupt after halting the CPU
396          */
397         ret
399 /*===========================================================================*/
400 /*                            read_flags                                     */
401 /*===========================================================================*/
403  * PUBLIC unsigned long read_cpu_flags(void);
404  * Read CPU status flags from C.
405  */
406 ENTRY(read_cpu_flags)
407         pushf
408         mov     (%esp), %eax
409         add     $4, %esp
410         ret
412 ENTRY(read_ds)
413         mov     $0, %eax
414         mov     %ds, %ax
415         ret
417 ENTRY(read_cs)
418         mov     $0, %eax
419         mov     %cs, %ax
420         ret
422 ENTRY(read_ss)
423         mov     $0, %eax
424         mov     %ss, %ax
425         ret
427 /*===========================================================================*/
428 /*                            fpu_routines                                   */
429 /*===========================================================================*/
431 /* non-waiting FPU initialization */
432 ENTRY(fninit)
433         fninit
434         ret
436 ENTRY(clts)
437         clts
438         ret
440 /* store status word (non-waiting) */
441 ENTRY(fnstsw)
442         xor     %eax, %eax
444         /* DO NOT CHANGE THE OPERAND!!! gas2ack does not handle it yet */
445         fnstsw  %ax
446         ret
448 /*===========================================================================*/
449 /*                              fxrstor                                      */
450 /*===========================================================================*/
451 ENTRY(fxrstor)
452         mov     4(%esp), %eax
453         fxrstor (%eax)
454 ENTRY(__fxrstor_end)
455         xor     %eax, %eax
456         ret
458 /*===========================================================================*/
459 /*                              frstor                                       */
460 /*===========================================================================*/
461 ENTRY(frstor)
462         mov     4(%esp), %eax
463         frstor  (%eax)
464 ENTRY(__frstor_end)
465         xor     %eax, %eax
466         ret
468 /* Shared exception handler for both fxrstor and frstor. */
469 ENTRY(__frstor_failure)
470         mov     $1, %eax
471         ret
473 /* Read/write control registers */
474 ARG_EAX_RETURN(read_cr0, %cr0);
475 ARG_EAX_RETURN(read_cr2, %cr2);
476 ARG_EAX_RETURN(read_cr3, %cr3);
477 ARG_EAX_RETURN(read_cr4, %cr4);
478 ARG_EAX_SET(write_cr4, %cr4);
479 ARG_EAX_SET(write_cr0, %cr0);
480 ARG_EAX_SET(write_cr3, %cr3);
482 /* Read/write various descriptor tables */
483 ARG_EAX_ACTION(x86_ltr, ltr STACKARG );
484 ARG_EAX_ACTION(x86_lidt, lidtl (%eax));
485 ARG_EAX_ACTION(x86_lgdt, lgdt (%eax));
486 ARG_EAX_ACTION(x86_lldt, lldt STACKARG);
487 ARG_EAX_ACTION(x86_sgdt, sgdt (%eax));
488 ARG_EAX_ACTION(x86_sidt, sidt (%eax));
490 /* Load segments */
491 ARG_AX_SET(x86_load_ds, %ds)
492 ARG_AX_SET(x86_load_es, %es)
493 ARG_AX_SET(x86_load_fs, %fs)
494 ARG_AX_SET(x86_load_gs, %gs)
495 ARG_AX_SET(x86_load_ss, %ss)
497 /* FPU */
498 ARG_EAX_ACTION(fnsave, fnsave (%eax) ; fwait);
499 ARG_EAX_ACTION(fxsave, fxsave (%eax));
500 ARG_EAX_ACTION(fnstcw, fnstcw (%eax));
502 /* invlpg */
503 ARG_EAX_ACTION(i386_invlpg, invlpg (%eax));
505 ENTRY(x86_load_kerncs)
506         push    %ebp
507         mov     %esp, %ebp
508         mov     8(%ebp), %eax
509         jmp     $KERN_CS_SELECTOR, $newcs
510 newcs:
511         pop     %ebp
512         ret
515  * Read the Model Specific Register (MSR) of IA32 architecture
517  * void ia32_msr_read(u32_t reg, u32_t * hi, u32_t * lo)
518  */
519 ENTRY(ia32_msr_read)
520         push    %ebp
521         mov     %esp, %ebp
523         mov     8(%ebp), %ecx
524         rdmsr
525         mov     12(%ebp), %ecx
526         mov     %edx, (%ecx)
527         mov     16(%ebp), %ecx
528         mov     %eax, (%ecx)
530         pop     %ebp
531         ret
534  * Write the Model Specific Register (MSR) of IA32 architecture
536  * void ia32_msr_write(u32_t reg, u32_t hi, u32_t lo)
537  */
538 ENTRY(ia32_msr_write)
539         push    %ebp
540         mov     %esp, %ebp
542         mov     12(%ebp), %edx
543         mov     16(%ebp), %eax
544         mov     8(%ebp), %ecx
545         wrmsr
547         pop     %ebp
548         ret
550 /*===========================================================================*/
551 /*                            __switch_address_space                         */
552 /*===========================================================================*/
553 /* PUBLIC void __switch_address_space(struct proc *p, struct ** ptproc)
555  * sets the %cr3 register to the supplied value if it is not already set to the
556  * same value in which case it would only result in an extra TLB flush which is
557  * not desirable
558  */
559 ENTRY(__switch_address_space)
560         /* read the process pointer */
561         mov     4(%esp), %edx
562         /* get the new cr3 value */
563         movl    P_CR3(%edx), %eax
564         /* test if the new cr3 != NULL */
565         cmpl    $0, %eax
566         je      0f
568         /*
569          * test if the cr3 is loaded with the current value to avoid unnecessary
570          * TLB flushes
571          */
572         mov     %cr3, %ecx
573         cmp     %ecx, %eax
574         je      0f
575         mov     %eax, %cr3
576         /* get ptproc */
577         mov     8(%esp), %eax
578         mov     %edx, (%eax)
580         ret
582 /* acknowledge just the master PIC */
583 ENTRY(eoi_8259_master)
584         movb    $END_OF_INT, %al
585         outb    $INT_CTL
586         ret
587         
588 /* we have to acknowledge both PICs */
589 ENTRY(eoi_8259_slave)
590         movb    $END_OF_INT, %al
591         outb    $INT_CTL
592         outb    $INT2_CTL
593         ret
594         
595 /* in some cases we need to force TLB update, reloading cr3 does the trick */
596 ENTRY(refresh_tlb)
597         mov     %cr3, %eax
598         mov     %eax, %cr3
599         ret
601 #ifdef CONFIG_SMP
603 /*===========================================================================*/
604 /*                            smp_get_htt                                    */
605 /*===========================================================================*/
606 /*  PUBLIC int smp_get_htt(void); */
607 /*  return true if the processor is hyper-threaded. */
608 ENTRY(smp_get_htt)
609         push    %ebp
610         mov     %esp, %ebp
611         pushf
612         pop     %eax
613         mov     %eax, %ebx
614         and     $0x200000, %eax
615         je      0f
616         mov     $0x1, %eax
617 /* FIXME don't use the byte code */
618 .byte   0x0f, 0xa2      /*  opcode for cpuid  */
619         mov     %edx, %eax
620         pop     %ebp
621         ret
623         xor     %eax, %eax
624         pop     %ebp
625         ret
627 /*===========================================================================*/
628 /*                            smp_get_num_htt                                */
629 /*===========================================================================*/
630 /*  PUBLIC int smp_get_num_htt(void); */
631 /*  Get the number of hyper-threaded processor cores */
632 ENTRY(smp_get_num_htt)
633         push    %ebp
634         mov     %esp, %ebp
635         pushf
636         pop     %eax
637         mov     %eax, %ebx
638         and     $0x200000, %eax
639         je      0f
640         mov     $0x1, %eax
641 /* FIXME don't use the byte code */
642 .byte   0x0f, 0xa2      /*  opcode for cpuid  */
643         mov     %ebx, %eax
644         pop     %ebp
645         ret
647         xor     %eax, %eax
648         pop     %ebp
649         ret
651 /*===========================================================================*/
652 /*                            smp_get_cores                                 */
653 /*===========================================================================*/
654 /*  PUBLIC int smp_get_cores(void); */
655 /*  Get the number of cores. */
656 ENTRY(smp_get_cores)
657         push    %ebp
658         mov     %esp, %ebp
659         pushf
660         pop     %eax
661         mov     %eax, %ebx
662         and     $0x200000, %eax
663         je      0f
664         push    %ecx
665         xor     %ecx, %ecx
666         mov     $0x4, %eax
667 /* FIXME don't use the byte code */
668 .byte   0x0f, 0xa2      /*  opcode for cpuid  */
669         pop     %ebp
670         ret
672         xor     %eax, %eax
673         pop     %ebp
674         ret
676 /*===========================================================================*/
677 /*                              arch_spinlock_lock                                  */
678 /*===========================================================================*/
679 /* void arch_spinlock_lock (u32_t  *lock_data)
680  * {
681  *      while (test_and_set(lock_data) == 1)
682  *              while (*lock_data == 1)
683  *                      ;
684  * }
685  * eax register is clobbered.
686  */
687 ENTRY(arch_spinlock_lock)
688         mov     4(%esp), %eax
689         mov     $1, %edx
691         mov     $1, %ecx
692         xchg    %ecx, (%eax)
693         test    %ecx, %ecx
694         je      0f
696         cmp     $(1<< 16), %edx
697         je      1f
698         shl     %edx
700         mov     %edx, %ecx
702         pause
703         sub     $1, %ecx
704         test    %ecx, %ecx
705         jz      2b
706         jmp     3b
708         mfence
709         ret
711 /*===========================================================================*/
712 /*                              arch_spinlock_unlock                                 */
713 /*===========================================================================*/
714 /* * void arch_spinlock_unlock (unsigned int *lockp) */
715 /*  spin lock release routine. */
716 ENTRY(arch_spinlock_unlock)
717         mov     4(%esp), %eax
718         mov     $0, %ecx
719         xchg    %ecx, (%eax)
720         mfence
721         ret
723 #endif /* CONFIG_SMP */
725 /*===========================================================================*/
726 /*                            mfence                                         */
727 /*===========================================================================*/
728 /*  PUBLIC void mfence (void); */
729 /*  architecture specific memory barrier routine. */
730 ENTRY(mfence)
731         mfence
732         ret
734 /*===========================================================================*/
735 /*                            arch_pause                                     */
736 /*===========================================================================*/
737 /*  PUBLIC void arch_pause (void); */
738 /*  architecture specific pause routine. */
739 ENTRY(arch_pause)
740         pause
741         ret
743 /*===========================================================================*/
744 /*                            read_ebp                                       */
745 /*===========================================================================*/
746 /*  PUBLIC u16_t cpuid(void) */
747 ENTRY(read_ebp)
748         mov     %ebp, %eax
749         ret
751 ENTRY(interrupts_enable)
752         sti
753         ret
755 ENTRY(interrupts_disable)
756         cli
757         ret
761  * void switch_k_stack(void * esp, void (* continuation)(void));
763  * sets the current stack pointer to the given value and continues execution at
764  * the given address
765  */
766 ENTRY(switch_k_stack)
767         /* get the arguments from the stack */
768         mov     8(%esp), %eax
769         mov     4(%esp), %ecx
770         mov     $0, %ebp        /* reset %ebp for stack trace */
771         mov     %ecx, %esp      /* set the new stack */
772         jmp     *%eax           /* and jump to the continuation */
774         /* NOT_REACHABLE */
775 0:      jmp     0b
777 .data
778 idt_ptr:
779         .short 0x3ff
780         .long 0x0
782 ldtsel:
783         .long LDT_SELECTOR