small asmconv cleanups.
[minix.git] / kernel / arch / i386 / klib386.S
blob6e136cc11911ff8c5a5383eda8077b890c011fb5
1 /* sections */
3 .text; .data; .data; .bss
5 #include <minix/config.h>
6 #include <minix/const.h>
7 #include <ibm/interrupt.h>
8 #include <archconst.h>
9 #include "../../const.h"
10 #include "sconst.h"
13  * This file contains a number of assembly code utility routines needed by the
14  * kernel.  They are:
15  */
17 .globl  monitor /* exit Minix and return to the monitor */
18 .globl  int86   /* let the monitor make an 8086 interrupt call */
19 .globl  exit    /* dummy for library routines */
20 .globl  _exit   /* dummy for library routines */
21 .globl  __exit  /* dummy for library routines */
22 .globl  __main  /* dummy for GCC */
23 .globl  phys_insw       /* transfer data from (disk controller) port to memory */
24 .globl  phys_insb       /* likewise byte by byte */
25 .globl  phys_outsw      /* transfer data from memory to (disk controller) port */
26 .globl  phys_outsb      /* likewise byte by byte */
27 .globl  phys_copy       /* copy data from anywhere to anywhere in memory */
28 .globl  phys_copy_fault /* phys_copy pagefault */
29 .globl  phys_copy_fault_in_kernel /* phys_copy pagefault in kernel */
30 .globl  phys_memset     /* write pattern anywhere in memory */
31 .globl  mem_rdw /* copy one word from [segment:offset] */
32 .globl  reset   /* reset the system */
33 .globl  halt_cpu/* halts the current cpu when idle */
34 .globl  level0  /* call a function at level 0 */
35 .globl  read_cpu_flags  /* read the cpu flags */
36 .globl  read_cr0        /* read cr0 */
37 .globl  read_cr2        /* read cr2 */
38 .globl  getcr3val
39 .globl  write_cr0       /* write a value in cr0 */
40 .globl  read_cr4
41 .globl  thecr3
42 .globl  write_cr4
44 .globl  catch_pagefaults
45 .globl  read_ds
46 .globl  read_cs
47 .globl  read_ss
48 .globl  idt_reload      /* reload idt when returning to monitor. */
50 .globl  fninit                  /* non-waiting FPU initialization */
51 .globl  fnstsw                  /* store status word (non-waiting) */
52 .globl  fnstcw                  /* store control word (non-waiting) */
55  * The routines only guarantee to preserve the registers the C compiler 
56  * expects to be preserved (ebx, esi, edi, ebp, esp, segment registers, and 
57  * direction bit in the flags). 
58  */
60 .text
61 /*===========================================================================*/
62 /*                              monitor                                      */
63 /*===========================================================================*/
64 /* PUBLIC void monitor(); */
65 /* Return to the monitor. */
67 monitor:
68         movl    mon_sp, %esp    /* restore monitor stack pointer */
69         movw    $SS_SELECTOR, %dx       /* monitor data segment */
70         mov     %dx, %ds
71         mov     %dx, %es
72         mov     %dx, %fs
73         mov     %dx, %gs
74         mov     %dx, %ss
75         pop     %edi
76         pop     %esi
77         pop     %ebp
78         lretw   /* return to the monitor */
81 /*===========================================================================*/
82 /*                              int86                                        */
83 /*===========================================================================*/
84 /* PUBLIC void int86(); */
85 int86:
86         cmpb    $0, mon_return  /* is the monitor there? */
87         jne     0f
88         movb    $0x01, %ah      /* an int 13 error seems appropriate */
89         movb    %ah, reg86+0    /* reg86.w.f = 1 (set carry flag) */
90         movb    %ah, reg86+13   /* reg86.b.ah = 0x01 = "invalid command" */
91         ret
93         push    %ebp    /* save C registers */
94         push    %esi
95         push    %edi
96         push    %ebx
97         pushf   /* save flags */
98         cli     /* no interruptions */
100         inb     $INT2_CTLMASK
101         movb    %al, %ah
102         inb     $INT_CTLMASK
103         push    %eax    /* save interrupt masks */
104         movl    irq_use, %eax   /* map of in-use IRQ's */
105         and     $~(1<<CLOCK_IRQ), %eax  /* keep the clock ticking */
106         outb    $INT_CTLMASK    /* enable all unused IRQ's and vv. */
107         movb    %ah, %al
108         outb    $INT2_CTLMASK
110         mov     $SS_SELECTOR, %eax      /* monitor data segment */
111         mov     %ax, %ss
112         xchgl   mon_sp, %esp    /* switch stacks */
113         push    reg86+36        /* parameters used in INT call */
114         push    reg86+32
115         push    reg86+28
116         push    reg86+24
117         push    reg86+20
118         push    reg86+16
119         push    reg86+12
120         push    reg86+8
121         push    reg86+4
122         push    reg86+0
123         mov     %ax, %ds        /* remaining data selectors */
124         mov     %ax, %es
125         mov     %ax, %fs
126         mov     %ax, %gs
127         push    %cs
128         push    $return /* kernel return address and selector */
129         ljmpw    *20+2*4+10*4+2*4(%esp)
130 return:
131         pop     reg86+0
132         pop     reg86+4
133         pop     reg86+8
134         pop     reg86+12
135         pop     reg86+16
136         pop     reg86+20
137         pop     reg86+24
138         pop     reg86+28
139         pop     reg86+32
140         pop     reg86+36
141         lgdt    gdt+GDT_SELECTOR        /* reload global descriptor table */
142         ljmp    $CS_SELECTOR, $csinit
143 csinit:
144         mov     $DS_SELECTOR, %eax
145         mov     %ax, %ds
146         mov     %ax, %es
147         mov     %ax, %fs
148         mov     %ax, %gs
149         mov     %ax, %ss
150         xchgl   mon_sp, %esp    /* unswitch stacks */
151         lidt    gdt+IDT_SELECTOR        /* reload interrupt descriptor table */
153 #ifdef CONFIG_APIC
154         cmpl    $0x0, lapic_addr
155         jne     3f
156         mov     $0, %ebx
157         jmp     4f
160         mov     $FLAT_DS_SELECTOR, %ebx
161         mov     %bx, %fs
162         movl    lapic_addr, %eax
163         add     $0x20, %eax
164         .byte 0x64; mov (%eax), %ebx
165         and     $0xFF000000, %ebx
166         shr     $24, %ebx
167         movzb   %bl, %ebx
170         add     $apicid2cpuid, %ebx
171         movzb   (%ebx), %eax
172         shl     $3, %eax
173         mov     %eax, %ebx
174         add     $TSS_SELECTOR, %eax
175         addl    gdt+DESC_ACCESS, %eax
176         and     $~0x02, %eax
177         ltr     %bx     /* set TSS register */
179         mov     $DS_SELECTOR, %eax
180         mov     %ax, %fs
182 #endif /* CONFIG_APIC */
184         pop     %eax
185         outb    $INT_CTLMASK    /* restore interrupt masks */
186         movb    %ah, %al
187         outb    $INT2_CTLMASK
190         addl    %ecx, lost_ticks        /* record lost clock ticks */
192         popf    /* restore flags */
193         pop     %ebx    /* restore C registers */
194         pop     %edi
195         pop     %esi
196         pop     %ebp
197         ret
199 /*===========================================================================*/
200 /*                              exit                                         */
201 /*===========================================================================*/
203  * PUBLIC void exit(); 
204  * Some library routines use exit, so provide a dummy version. 
205  * Actual calls to exit cannot occur in the kernel. 
206  * GNU CC likes to call ___main from main() for nonobvious reasons. 
207  */
209 exit:
210 _exit:
211 __exit:
212         sti
213         jmp     __exit
215 __main:
216         ret
219 /*===========================================================================*/
220 /*                              phys_insw                                    */
221 /*===========================================================================*/
223  * PUBLIC void phys_insw(Port_t port, phys_bytes buf, size_t count); 
224  * Input an array from an I/O port.  Absolute address version of insw(). 
225  */
227 phys_insw:
228         push    %ebp
229         mov     %esp, %ebp
230         cld
231         push    %edi
232         push    %es
234         mov     $FLAT_DS_SELECTOR, %ecx
235         mov     %cx, %es
236         mov     8(%ebp), %edx   /* port to read from */
237         mov     12(%ebp), %edi  /* destination addr */
238         mov     16(%ebp), %ecx  /* byte count */
239         shr     $1, %ecx        /* word count */
240         rep insw        /* input many words */
241         pop     %es
242         pop     %edi
243         pop     %ebp
244         ret
247 /*===========================================================================*/
248 /*                              phys_insb                                    */
249 /*===========================================================================*/
251  * PUBLIC void phys_insb(Port_t port, phys_bytes buf, size_t count); 
252  * Input an array from an I/O port.  Absolute address version of insb(). 
253  */
255 phys_insb:
256         push    %ebp
257         mov     %esp, %ebp
258         cld
259         push    %edi
260         push    %es
262         mov     $FLAT_DS_SELECTOR, %ecx
263         mov     %cx, %es
264         mov     8(%ebp), %edx   /* port to read from */
265         mov     12(%ebp), %edi  /* destination addr */
266         mov     16(%ebp), %ecx  /* byte count */
267         rep insb        /* input many bytes */
268         pop     %es
269         pop     %edi
270         pop     %ebp
271         ret
274 /*===========================================================================*/
275 /*                              phys_outsw                                   */
276 /*===========================================================================*/
278  * PUBLIC void phys_outsw(Port_t port, phys_bytes buf, size_t count); 
279  * Output an array to an I/O port.  Absolute address version of outsw(). 
280  */
282 .balign 16
283 phys_outsw:
284         push    %ebp
285         mov     %esp, %ebp
286         cld
287         push    %esi
288         push    %ds
290         mov     $FLAT_DS_SELECTOR, %ecx
291         mov     %cx, %ds
292         mov     8(%ebp), %edx   /* port to write to */
293         mov     12(%ebp), %esi  /* source addr */
294         mov     16(%ebp), %ecx  /* byte count */
295         shr     $1, %ecx        /* word count */
296         rep outsw       /* output many words */
297         pop     %ds
298         pop     %esi
299         pop     %ebp
300         ret
303 /*===========================================================================*/
304 /*                              phys_outsb                                   */
305 /*===========================================================================*/
306 /* 
307  * PUBLIC void phys_outsb(Port_t port, phys_bytes buf, size_t count);
308  * Output an array to an I/O port.  Absolute address version of outsb().
309  */
311 .balign 16
312 phys_outsb:
313         push    %ebp
314         mov     %esp, %ebp
315         cld
316         push    %esi
317         push    %ds
319         mov     $FLAT_DS_SELECTOR, %ecx
320         mov     %cx, %ds
321         mov     8(%ebp), %edx   /* port to write to */
322         mov     12(%ebp), %esi  /* source addr */
323         mov     16(%ebp), %ecx  /* byte count */
324         rep outsb       /* output many bytes */
325         pop     %ds
326         pop     %esi
327         pop     %ebp
328         ret
331 /*===========================================================================*/
332 /*                              phys_copy                                    */
333 /*===========================================================================*/
335  * PUBLIC phys_bytes phys_copy(phys_bytes source, phys_bytes destination,
336  *                      phys_bytes bytecount); 
337  * Copy a block of physical memory. 
338  */
340         PC_ARGS = 4+4+4+4       /* 4 + 4 + 4 */
341 /*              es edi esi eip   src dst len */
343 .balign 16
344 phys_copy:
345         cld
346         push    %esi
347         push    %edi
348         push    %es
350         mov     $FLAT_DS_SELECTOR, %eax
351         mov     %ax, %es
353         mov     PC_ARGS(%esp), %esi
354         mov     PC_ARGS+4(%esp), %edi
355         mov     PC_ARGS+4+4(%esp), %eax
357         cmp     $10, %eax       /* avoid align overhead for small counts */
358         jb      pc_small
359         mov     %esi, %ecx      /* align source, hope target is too */
360         neg     %ecx
361         and     $3, %ecx        /* count for alignment */
362         sub     %ecx, %eax
364         rep     movsb %es:(%esi), %es:(%edi)
365         mov     %eax, %ecx
366         shr     $2, %ecx        /* count of dwords */
368         rep     movsl %es:(%esi), %es:(%edi)
369         and     $3, %eax
370 pc_small:
371         xchg    %eax, %ecx      /* remainder */
373         rep     movsb %es:(%esi), %es:(%edi)
375         mov     $0, %eax                /* 0 means: no fault */
376 phys_copy_fault:                        /* kernel can send us here */
377         pop     %es
378         pop     %edi
379         pop     %esi
380         ret
382 phys_copy_fault_in_kernel:                      /* kernel can send us here */
383         pop     %es
384         pop     %edi
385         pop     %esi
386         mov     %cr2, %eax
387         ret
389 /*===========================================================================*/
390 /*                              phys_memset                                  */
391 /*===========================================================================*/
393  * PUBLIC void phys_memset(phys_bytes source, unsigned long pattern, 
394  *      phys_bytes bytecount); 
395  * Fill a block of physical memory with pattern. 
396  */
398 .balign 16
399 phys_memset:
400         push    %ebp
401         mov     %esp, %ebp
402         push    %esi
403         push    %ebx
404         push    %ds
406         mov     8(%ebp), %esi
407         mov     16(%ebp), %eax
408         mov     $FLAT_DS_SELECTOR, %ebx
409         mov     %bx, %ds
410         mov     12(%ebp), %ebx
411         shr     $2, %eax
412 fill_start:
413         mov     %ebx, (%esi)
414         add     $4, %esi
415         dec     %eax
416         jne     fill_start
417 /* Any remaining bytes? */
418         mov     16(%ebp), %eax
419         and     $3, %eax
420 remain_fill:
421         cmp     $0, %eax
422         je      fill_done
423         movb    12(%ebp), %bl
424         movb    %bl, (%esi)
425         add     $1, %esi
426         inc     %ebp
427         dec     %eax
428         jmp     remain_fill
429 fill_done:
430         pop     %ds
431         pop     %ebx
432         pop     %esi
433         pop     %ebp
434         ret
437 /*===========================================================================*/
438 /*                              mem_rdw                                      */
439 /*===========================================================================*/
440 /* 
441  * PUBLIC u16_t mem_rdw(U16_t segment, u16_t *offset); 
442  * Load and return word at far pointer segment:offset. 
443  */
445 .balign 16
446 mem_rdw:
447         mov     %ds, %cx
448         mov     4(%esp), %ds
449         mov     4+4(%esp), %eax /* offset */
450         movzwl  (%eax), %eax    /* word to return */
451         mov     %cx, %ds
452         ret
455 /*===========================================================================*/
456 /*                              reset                                        */
457 /*===========================================================================*/
459  * PUBLIC void reset(); 
460  * Reset the system by loading IDT with offset 0 and interrupting. 
461  */
463 reset:
464         lidt    idt_zero
465         int     $3      /* anything goes, the 386 will not like it */
466 .data
467 idt_zero:
468 .long   0, 0
469 .text
472 /*===========================================================================*/
473 /*                              halt_cpu                                     */
474 /*===========================================================================*/
476  * PUBLIC void halt_cpu(void);
477  * reanables interrupts and puts the cpu in the halts state. Once an interrupt
478  * is handled the execution resumes by disabling interrupts and continues
479  */
480 halt_cpu:
481         sti
482         hlt
483         cli
484         ret
486 /*===========================================================================*/
487 /*                            level0                                         */
488 /*===========================================================================*/
490  * PUBLIC void level0(void (*func)(void)) 
491  * Call a function at permission level 0.  This allows kernel tasks to do 
492  * things that are only possible at the most privileged CPU level. 
493  */ 
494 level0:
495         /* check whether we are already running in kernel, the kernel cs
496          * selector has 3 lower bits zeroed */
497         mov     %cs, %ax
498         cmpw    $CS_SELECTOR, %ax
499         jne     0f
501         /* call the function directly as if it was a normal function call */
502         mov     4(%esp), %eax
503         call    *%eax
504         ret
507         /* if not runnig in the kernel yet, trap to kernel */
509         mov     4(%esp), %eax
510         int     $LEVEL0_VECTOR
511         ret
513 /*===========================================================================*/
514 /*                            read_flags                                     */
515 /*===========================================================================*/
517  * PUBLIC unsigned long read_cpu_flags(void);
518  * Read CPU status flags from C.
519  */
520 .balign 16
521 read_cpu_flags:
522         pushf
523         mov     (%esp), %eax
524         add     $4, %esp
525         ret
527 read_ds:
528         mov     $0, %eax
529         mov     %ds, %ax
530         ret
532 read_cs:
533         mov     $0, %eax
534         mov     %cs, %ax
535         ret
537 read_ss:
538         mov     $0, %eax
539         mov     %ss, %ax
540         ret
543 /*===========================================================================*/
544 /*                            fpu_routines                                   */
545 /*===========================================================================*/
546 fninit:
547         fninit
548         ret
550 fnstsw:
551         xor     %eax, %eax
553         /* DO NOT CHANGE THE OPERAND!!! gas2ack does not handle it yet */
554         fnstsw  %ax
555         ret
557 fnstcw:
558         push    %eax
559         mov     8(%esp), %eax
561         /* DO NOT CHANGE THE OPERAND!!! gas2ack does not handle it yet */
562         fnstcw  (%eax)
563         pop     %eax
564         ret
566 /*===========================================================================*/
567 /*                            read_cr0                                       */
568 /*===========================================================================*/
569 /* PUBLIC unsigned long read_cr0(void); */
570 read_cr0:
571         push    %ebp
572         mov     %esp, %ebp
573         mov     %cr0, %eax
574         pop     %ebp
575         ret
577 /*===========================================================================*/
578 /*                            write_cr0                                      */
579 /*===========================================================================*/
580 /* PUBLIC void write_cr0(unsigned long value); */
581 write_cr0:
582         push    %ebp
583         mov     %esp, %ebp
584         mov     8(%ebp), %eax
585         mov     %eax, %cr0
586         jmp     0f      /* A jump is required for some flags */
588         pop     %ebp
589         ret
591 /*===========================================================================*/
592 /*                            read_cr2                                       */
593 /*===========================================================================*/
594 /* PUBLIC reg_t read_cr2(void); */
595 read_cr2:
596         mov     %cr2, %eax
597         ret
599 /*===========================================================================*/
600 /*                            read_cr4                                       */
601 /*===========================================================================*/
602 /* PUBLIC unsigned long read_cr4(void); */
603 read_cr4:
604         push    %ebp
605         mov     %esp, %ebp
607         /* DO NOT CHANGE THE OPERAND!!! gas2ack does not handle it yet */
608         mov     %cr4, %eax
609         pop     %ebp
610         ret
612 /*===========================================================================*/
613 /*                            write_cr4                                      */
614 /*===========================================================================*/
615 /* PUBLIC void write_cr4(unsigned long value); */
616 write_cr4:
617         push    %ebp
618         mov     %esp, %ebp
619         mov     8(%ebp), %eax
621         /* DO NOT CHANGE THE OPERAND!!! gas2ack does not handle it yet */
622         mov     %eax, %cr4
623         jmp     0f
625         pop     %ebp
626         ret
627 /*===========================================================================*/
628 /*                              getcr3val                                    */
629 /*===========================================================================*/
630 /* PUBLIC unsigned long getcr3val(void); */
631 getcr3val:
632         mov     %cr3, %eax
633         mov     %eax, thecr3
634         ret
637  * Read the Model Specific Register (MSR) of IA32 architecture
639  * void ia32_msr_read(u32_t reg, u32_t * hi, u32_t * lo)
640  */
641 .globl ia32_msr_read
642 ia32_msr_read:
643         push    %ebp
644         mov     %esp, %ebp
646         mov     8(%ebp), %ecx
647         rdmsr
648         mov     12(%ebp), %ecx
649         mov     %edx, (%ecx)
650         mov     16(%ebp), %ecx
651         mov     %eax, (%ecx)
653         pop     %ebp
654         ret
657  * Write the Model Specific Register (MSR) of IA32 architecture
659  * void ia32_msr_write(u32_t reg, u32_t hi, u32_t lo)
660  */
661 .globl ia32_msr_write
662 ia32_msr_write:
663         push    %ebp
664         mov     %esp, %ebp
666         mov     12(%ebp), %edx
667         mov     16(%ebp), %eax
668         mov     8(%ebp), %ecx
669         wrmsr
671         pop     %ebp
672         ret
674 /*===========================================================================*/
675 /*                            idt_reload                                     */
676 /*===========================================================================*/
677 /*  PUBLIC void idt_reload (void); */
678 .balign 16
679 idt_reload:
680         lidt    gdt+IDT_SELECTOR        /*  reload interrupt descriptor table */
681         ret
684  * void reload_segment_regs(void)
685  */
687 #define RELOAD_SEG_REG(reg)     \
688         mov     reg, %ax        ;\
689         mov     %ax, reg        ;
691 .globl reload_ds
692 reload_ds:
693         RELOAD_SEG_REG(%ds)
694         ret