3.1.7 branch.
[minix.git] / kernel / arch / i386 / klib.S
blob98d7171b275591855573da6bf230a02cf03e6290
1 /* sections */
4 #include <minix/config.h>
5 #include <minix/const.h>
6 #include <machine/interrupt.h>
7 #include "archconst.h"
8 #include "kernel/const.h"
9 #include "sconst.h"
12  * This file contains a number of assembly code utility routines needed by the
13  * kernel.  They are:
14  */
16 .globl  _monitor/* exit Minix and return to the monitor */
17 .globl  _int86  /* let the monitor make an 8086 interrupt call */
18 #ifdef __ACK__
19 .globl  _exit   /* dummy for library routines */
20 .globl  __exit  /* dummy for library routines */
21 .globl  ___exit /* dummy for library routines */
22 #endif
23 .globl  ___main /* dummy for GCC */
24 .globl  _phys_insw      /* transfer data from (disk controller) port to memory */
25 .globl  _phys_insb      /* likewise byte by byte */
26 .globl  _phys_outsw     /* transfer data from memory to (disk controller) port */
27 .globl  _phys_outsb     /* likewise byte by byte */
28 .globl  _phys_copy      /* copy data from anywhere to anywhere in memory */
29 .globl  _phys_copy_fault        /* phys_copy pagefault */
30 .globl  _phys_copy_fault_in_kernel /* phys_copy pagefault in kernel */
31 .globl  _phys_memset    /* write pattern anywhere in memory */
32 .globl  _mem_rdw        /* copy one word from [segment:offset] */
33 .globl  _reset  /* reset the system */
34 .globl  _halt_cpu/* halts the current cpu when idle */
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_cr3
41 .globl  _read_cr4
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) */
53 .globl  _fxsave 
54 .globl  _fnsave 
55 .globl  _fxrstor        
56 .globl  _frstor 
57 .globl  _clts   
60  * The routines only guarantee to preserve the registers the C compiler 
61  * expects to be preserved (ebx, esi, edi, ebp, esp, segment registers, and 
62  * direction bit in the flags). 
63  */
65 .text
66 /*===========================================================================*/
67 /*                              monitor                                      */
68 /*===========================================================================*/
69 /* PUBLIC void monitor(); */
70 /* Return to the monitor. */
72 _monitor:
73         movl    _mon_sp, %esp   /* restore monitor stack pointer */
74         movw    $SS_SELECTOR, %dx       /* monitor data segment */
75         mov     %dx, %ds
76         mov     %dx, %es
77         mov     %dx, %fs
78         mov     %dx, %gs
79         mov     %dx, %ss
80         pop     %edi
81         pop     %esi
82         pop     %ebp
83         lretw   /* return to the monitor */
86 /*===========================================================================*/
87 /*                              int86                                        */
88 /*===========================================================================*/
89 /* PUBLIC void int86(); */
90 _int86:
91         cmpb    $0, _mon_return /* is the monitor there? */
92         jne     0f
93         movb    $0x01, %ah      /* an int 13 error seems appropriate */
94         movb    %ah, _reg86+0   /* reg86.w.f = 1 (set carry flag) */
95         movb    %ah, _reg86+13  /* reg86.b.ah = 0x01 = "invalid command" */
96         ret
98         push    %ebp    /* save C registers */
99         push    %esi
100         push    %edi
101         push    %ebx
102         pushf   /* save flags */
103         cli     /* no interruptions */
105         inb     $INT2_CTLMASK
106         movb    %al, %ah
107         inb     $INT_CTLMASK
108         push    %eax    /* save interrupt masks */
109         movl    _irq_use, %eax  /* map of in-use IRQ's */
110         and     $~(1<<CLOCK_IRQ), %eax  /* keep the clock ticking */
111         outb    $INT_CTLMASK    /* enable all unused IRQ's and vv. */
112         movb    %ah, %al
113         outb    $INT2_CTLMASK
115         mov     $SS_SELECTOR, %eax      /* monitor data segment */
116         mov     %ax, %ss
117         xchgl   _mon_sp, %esp   /* switch stacks */
118         push    _reg86+36       /* parameters used in INT call */
119         push    _reg86+32
120         push    _reg86+28
121         push    _reg86+24
122         push    _reg86+20
123         push    _reg86+16
124         push    _reg86+12
125         push    _reg86+8
126         push    _reg86+4
127         push    _reg86+0
128         mov     %ax, %ds        /* remaining data selectors */
129         mov     %ax, %es
130         mov     %ax, %fs
131         mov     %ax, %gs
132         push    %cs
133         push    $return /* kernel return address and selector */
134         ljmpw    *20+2*4+10*4+2*4(%esp)
135 return:
136         pop     _reg86+0
137         pop     _reg86+4
138         pop     _reg86+8
139         pop     _reg86+12
140         pop     _reg86+16
141         pop     _reg86+20
142         pop     _reg86+24
143         pop     _reg86+28
144         pop     _reg86+32
145         pop     _reg86+36
146         lgdt    _gdt+GDT_SELECTOR       /* reload global descriptor table */
147         ljmp    $CS_SELECTOR, $csinit
148 csinit:
149         mov     $DS_SELECTOR, %eax
150         mov     %ax, %ds
151         mov     %ax, %es
152         mov     %ax, %fs
153         mov     %ax, %gs
154         mov     %ax, %ss
155         xchgl   _mon_sp, %esp   /* unswitch stacks */
156         lidt    _gdt+IDT_SELECTOR       /* reload interrupt descriptor table */
158 #ifdef CONFIG_APIC
159         cmpl    $0x0, lapic_addr
160         jne     3f
161         mov     $0, %ebx
162         jmp     4f
165         mov     $FLAT_DS_SELECTOR, %ebx
166         mov     %bx, %fs
167         movl    lapic_addr, %eax
168         add     $0x20, %eax
169         .byte 0x64; mov (%eax), %ebx
170         and     $0xFF000000, %ebx
171         shr     $24, %ebx
172         movzb   %bl, %ebx
175         add     $apicid2cpuid, %ebx
176         movzb   (%ebx), %eax
177         shl     $3, %eax
178         mov     %eax, %ebx
179         add     $TSS_SELECTOR, %eax
180         addl    _gdt+DESC_ACCESS, %eax
181         and     $~0x02, %eax
182         ltr     %bx     /* set TSS register */
184         mov     $DS_SELECTOR, %eax
185         mov     %ax, %fs
187 #endif /* CONFIG_APIC */
189         pop     %eax
190         outb    $INT_CTLMASK    /* restore interrupt masks */
191         movb    %ah, %al
192         outb    $INT2_CTLMASK
195         addl    %ecx, _lost_ticks       /* record lost clock ticks */
197         popf    /* restore flags */
198         pop     %ebx    /* restore C registers */
199         pop     %edi
200         pop     %esi
201         pop     %ebp
202         ret
204 /*===========================================================================*/
205 /*                              exit                                         */
206 /*===========================================================================*/
208  * PUBLIC void exit(); 
209  * Some library routines use exit, so provide a dummy version. 
210  * Actual calls to exit cannot occur in the kernel. 
211  * GNU CC likes to call ___main from main() for nonobvious reasons. 
212  */
213 #ifdef __ACK__
214 _exit:
215 __exit:
216 ___exit:
217         sti
218         jmp     ___exit
219 #endif
221 ___main:
222         ret
225 /*===========================================================================*/
226 /*                              phys_insw                                    */
227 /*===========================================================================*/
229  * PUBLIC void phys_insw(Port_t port, phys_bytes buf, size_t count); 
230  * Input an array from an I/O port.  Absolute address version of insw(). 
231  */
233 _phys_insw:
234         push    %ebp
235         mov     %esp, %ebp
236         cld
237         push    %edi
238         push    %es
240         mov     $FLAT_DS_SELECTOR, %ecx
241         mov     %cx, %es
242         mov     8(%ebp), %edx   /* port to read from */
243         mov     12(%ebp), %edi  /* destination addr */
244         mov     16(%ebp), %ecx  /* byte count */
245         shr     $1, %ecx        /* word count */
246         rep insw        /* input many words */
247         pop     %es
248         pop     %edi
249         pop     %ebp
250         ret
253 /*===========================================================================*/
254 /*                              phys_insb                                    */
255 /*===========================================================================*/
257  * PUBLIC void phys_insb(Port_t port, phys_bytes buf, size_t count); 
258  * Input an array from an I/O port.  Absolute address version of insb(). 
259  */
261 _phys_insb:
262         push    %ebp
263         mov     %esp, %ebp
264         cld
265         push    %edi
266         push    %es
268         mov     $FLAT_DS_SELECTOR, %ecx
269         mov     %cx, %es
270         mov     8(%ebp), %edx   /* port to read from */
271         mov     12(%ebp), %edi  /* destination addr */
272         mov     16(%ebp), %ecx  /* byte count */
273         rep insb        /* input many bytes */
274         pop     %es
275         pop     %edi
276         pop     %ebp
277         ret
280 /*===========================================================================*/
281 /*                              phys_outsw                                   */
282 /*===========================================================================*/
284  * PUBLIC void phys_outsw(Port_t port, phys_bytes buf, size_t count); 
285  * Output an array to an I/O port.  Absolute address version of outsw(). 
286  */
288 .balign 16
289 _phys_outsw:
290         push    %ebp
291         mov     %esp, %ebp
292         cld
293         push    %esi
294         push    %ds
296         mov     $FLAT_DS_SELECTOR, %ecx
297         mov     %cx, %ds
298         mov     8(%ebp), %edx   /* port to write to */
299         mov     12(%ebp), %esi  /* source addr */
300         mov     16(%ebp), %ecx  /* byte count */
301         shr     $1, %ecx        /* word count */
302         rep outsw       /* output many words */
303         pop     %ds
304         pop     %esi
305         pop     %ebp
306         ret
309 /*===========================================================================*/
310 /*                              phys_outsb                                   */
311 /*===========================================================================*/
312 /* 
313  * PUBLIC void phys_outsb(Port_t port, phys_bytes buf, size_t count);
314  * Output an array to an I/O port.  Absolute address version of outsb().
315  */
317 .balign 16
318 _phys_outsb:
319         push    %ebp
320         mov     %esp, %ebp
321         cld
322         push    %esi
323         push    %ds
325         mov     $FLAT_DS_SELECTOR, %ecx
326         mov     %cx, %ds
327         mov     8(%ebp), %edx   /* port to write to */
328         mov     12(%ebp), %esi  /* source addr */
329         mov     16(%ebp), %ecx  /* byte count */
330         rep outsb       /* output many bytes */
331         pop     %ds
332         pop     %esi
333         pop     %ebp
334         ret
337 /*===========================================================================*/
338 /*                              phys_copy                                    */
339 /*===========================================================================*/
341  * PUBLIC phys_bytes phys_copy(phys_bytes source, phys_bytes destination,
342  *                      phys_bytes bytecount); 
343  * Copy a block of physical memory. 
344  */
346         PC_ARGS = 4+4+4+4       /* 4 + 4 + 4 */
347 /*              es edi esi eip   src dst len */
349 .balign 16
350 _phys_copy:
351         cld
352         push    %esi
353         push    %edi
354         push    %es
356         mov     $FLAT_DS_SELECTOR, %eax
357         mov     %ax, %es
359         mov     PC_ARGS(%esp), %esi
360         mov     PC_ARGS+4(%esp), %edi
361         mov     PC_ARGS+4+4(%esp), %eax
363         cmp     $10, %eax       /* avoid align overhead for small counts */
364         jb      pc_small
365         mov     %esi, %ecx      /* align source, hope target is too */
366         neg     %ecx
367         and     $3, %ecx        /* count for alignment */
368         sub     %ecx, %eax
370         rep     movsb %es:(%esi), %es:(%edi)
371         mov     %eax, %ecx
372         shr     $2, %ecx        /* count of dwords */
374         rep     movsl %es:(%esi), %es:(%edi)
375         and     $3, %eax
376 pc_small:
377         xchg    %eax, %ecx      /* remainder */
379         rep     movsb %es:(%esi), %es:(%edi)
381         mov     $0, %eax                /* 0 means: no fault */
382 _phys_copy_fault:                       /* kernel can send us here */
383         pop     %es
384         pop     %edi
385         pop     %esi
386         ret
388 _phys_copy_fault_in_kernel:                     /* kernel can send us here */
389         pop     %es
390         pop     %edi
391         pop     %esi
392         mov     %cr2, %eax
393         ret
395 /*===========================================================================*/
396 /*                              copy_msg_from_user                           */
397 /*===========================================================================*/
399  * int copy_msg_from_user(struct proc * p, message * user_mbuf, message * dst);
401  * Copies a message of 36 bytes from user process space to a kernel buffer. This
402  * function assumes that the process address space is installed (cr3 loaded) and
403  * the local descriptor table of this process is loaded too.
405  * The %gs segment register is used to access the userspace memory. We load the
406  * process' data segment in this register.
408  * This function from the callers point of view either succeeds or returns an
409  * error which gives the caller a chance to respond accordingly. In fact it
410  * either succeeds or if it generates a pagefault, general protection or other
411  * exception, the trap handler has to redirect the execution to
412  * __user_copy_msg_pointer_failure where the error is reported to the caller
413  * without resolving the pagefault. It is not kernel's problem to deal with
414  * wrong pointers from userspace and the caller should return an error to
415  * userspace as if wrong values or request were passed to the kernel
416  */
418 .balign 16
419 .globl _copy_msg_from_user
420 _copy_msg_from_user:
421         push    %gs
423         mov     8(%esp), %eax
424         movw    DSREG(%eax), %gs
426         /* load the source pointer */
427         mov     12(%esp), %ecx
428         /* load the destination pointer */
429         mov     16(%esp), %edx
431         mov     %gs:0*4(%ecx), %eax
432         mov     %eax, 0*4(%edx)
433         mov     %gs:1*4(%ecx), %eax
434         mov     %eax, 1*4(%edx)
435         mov     %gs:2*4(%ecx), %eax
436         mov     %eax, 2*4(%edx)
437         mov     %gs:3*4(%ecx), %eax
438         mov     %eax, 3*4(%edx)
439         mov     %gs:4*4(%ecx), %eax
440         mov     %eax, 4*4(%edx)
441         mov     %gs:5*4(%ecx), %eax
442         mov     %eax, 5*4(%edx)
443         mov     %gs:6*4(%ecx), %eax
444         mov     %eax, 6*4(%edx)
445         mov     %gs:7*4(%ecx), %eax
446         mov     %eax, 7*4(%edx)
447         mov     %gs:8*4(%ecx), %eax
448         mov     %eax, 8*4(%edx)
450 .globl ___copy_msg_from_user_end
451 ___copy_msg_from_user_end:
453         pop     %gs
455         movl    $0, %eax
456         ret
458 /*===========================================================================*/
459 /*                              copy_msg_to_user                             */
460 /*===========================================================================*/
462  * void copy_msg_to_user(struct proc * p, message * src, message * user_mbuf);
464  * Copies a message of 36 bytes to user process space from a kernel buffer. This
465  * function assumes that the process address space is installed (cr3 loaded) and
466  * the local descriptor table of this process is loaded too.
468  * All the other copy_msg_from_user() comments apply here as well!
469  */
471 .balign 16
472 .globl _copy_msg_to_user
473 _copy_msg_to_user:
474         push    %gs
476         mov     8(%esp), %eax
477         movw    DSREG(%eax), %gs
479         /* load the source pointer */
480         mov     12(%esp), %ecx
481         /* load the destination pointer */
482         mov     16(%esp), %edx
484         mov     0*4(%ecx), %eax
485         mov     %eax, %gs:0*4(%edx)
486         mov     1*4(%ecx), %eax
487         mov     %eax, %gs:1*4(%edx)
488         mov     2*4(%ecx), %eax
489         mov     %eax, %gs:2*4(%edx)
490         mov     3*4(%ecx), %eax
491         mov     %eax, %gs:3*4(%edx)
492         mov     4*4(%ecx), %eax
493         mov     %eax, %gs:4*4(%edx)
494         mov     5*4(%ecx), %eax
495         mov     %eax, %gs:5*4(%edx)
496         mov     6*4(%ecx), %eax
497         mov     %eax, %gs:6*4(%edx)
498         mov     7*4(%ecx), %eax
499         mov     %eax, %gs:7*4(%edx)
500         mov     8*4(%ecx), %eax
501         mov     %eax, %gs:8*4(%edx)
503 .globl ___copy_msg_to_user_end
504 ___copy_msg_to_user_end:
506         pop     %gs
508         movl    $0, %eax
509         ret
512  * if a function from a selected set of copies from or to userspace fails, it is
513  * because of a wrong pointer supplied by the userspace. We have to clean up and
514  * and return -1 to indicated that something wrong has happend. The place it was
515  * called from has to handle this situation. The exception handler redirect us
516  * here to continue, clean up and report the error
517  */
518 .balign 16
519 .globl ___user_copy_msg_pointer_failure
520 ___user_copy_msg_pointer_failure:
521         pop     %gs
523         movl    $-1, %eax
524         ret
526 /*===========================================================================*/
527 /*                              phys_memset                                  */
528 /*===========================================================================*/
530  * PUBLIC void phys_memset(phys_bytes source, unsigned long pattern, 
531  *      phys_bytes bytecount); 
532  * Fill a block of physical memory with pattern. 
533  */
535 .balign 16
536 _phys_memset:
537         push    %ebp
538         mov     %esp, %ebp
539         push    %esi
540         push    %ebx
541         push    %ds
543         mov     8(%ebp), %esi
544         mov     16(%ebp), %eax
545         mov     $FLAT_DS_SELECTOR, %ebx
546         mov     %bx, %ds
547         mov     12(%ebp), %ebx
548         shr     $2, %eax
549 fill_start:
550         mov     %ebx, (%esi)
551         add     $4, %esi
552         dec     %eax
553         jne     fill_start
554 /* Any remaining bytes? */
555         mov     16(%ebp), %eax
556         and     $3, %eax
557 remain_fill:
558         cmp     $0, %eax
559         je      fill_done
560         movb    12(%ebp), %bl
561         movb    %bl, (%esi)
562         add     $1, %esi
563         inc     %ebp
564         dec     %eax
565         jmp     remain_fill
566 fill_done:
567         pop     %ds
568         pop     %ebx
569         pop     %esi
570         pop     %ebp
571         ret
574 /*===========================================================================*/
575 /*                              mem_rdw                                      */
576 /*===========================================================================*/
577 /* 
578  * PUBLIC u16_t mem_rdw(U16_t segment, u16_t *offset); 
579  * Load and return word at far pointer segment:offset. 
580  */
582 .balign 16
583 _mem_rdw:
584         mov     %ds, %cx
585         mov     4(%esp), %ds
586         mov     4+4(%esp), %eax /* offset */
587         movzwl  (%eax), %eax    /* word to return */
588         mov     %cx, %ds
589         ret
592 /*===========================================================================*/
593 /*                              reset                                        */
594 /*===========================================================================*/
596  * PUBLIC void reset(); 
597  * Reset the system by loading IDT with offset 0 and interrupting. 
598  */
600 _reset:
601         lidt    idt_zero
602         int     $3      /* anything goes, the 386 will not like it */
603 .data
604 idt_zero:
605 .long   0, 0
606 .text
609 /*===========================================================================*/
610 /*                              halt_cpu                                     */
611 /*===========================================================================*/
613  * PUBLIC void halt_cpu(void);
614  * reanables interrupts and puts the cpu in the halts state. Once an interrupt
615  * is handled the execution resumes by disabling interrupts and continues
616  */
617 _halt_cpu:
618         sti
619         hlt /* interrupts enabled only after this instruction is executed! */
620         /*
621          * interrupt handlers make sure that the interrupts are disabled when we
622          * get here so we take only _one_ interrupt after halting the CPU
623          */
624         ret
626 /*===========================================================================*/
627 /*                            read_flags                                     */
628 /*===========================================================================*/
630  * PUBLIC unsigned long read_cpu_flags(void);
631  * Read CPU status flags from C.
632  */
633 .balign 16
634 _read_cpu_flags:
635         pushf
636         mov     (%esp), %eax
637         add     $4, %esp
638         ret
640 _read_ds:
641         mov     $0, %eax
642         mov     %ds, %ax
643         ret
645 _read_cs:
646         mov     $0, %eax
647         mov     %cs, %ax
648         ret
650 _read_ss:
651         mov     $0, %eax
652         mov     %ss, %ax
653         ret
656 /*===========================================================================*/
657 /*                            fpu_routines                                   */
658 /*===========================================================================*/
659 _fninit:
660         fninit
661         ret
663 _clts:
664         clts
665         ret
667 _fnstsw:
668         xor     %eax, %eax
670         /* DO NOT CHANGE THE OPERAND!!! gas2ack does not handle it yet */
671         fnstsw  %ax
672         ret
674 _fnstcw:
675         push    %eax
676         mov     8(%esp), %eax
678         /* DO NOT CHANGE THE OPERAND!!! gas2ack does not handle it yet */
679         fnstcw  (%eax)
680         pop     %eax
681         ret
683 /*===========================================================================*/
684 /*                            fxsave                                    */
685 /*===========================================================================*/
686 _fxsave:
687         mov     4(%esp), %eax
688         fxsave  (%eax)          /* Do not change the operand! (gas2ack) */
689         ret
691 /*===========================================================================*/
692 /*                            fnsave                                    */
693 /*===========================================================================*/
694 _fnsave:
695         mov     4(%esp), %eax
696         fnsave  (%eax)          /* Do not change the operand! (gas2ack) */
697         fwait   /* required for compatibility with processors prior pentium */
698         ret
700 /*===========================================================================*/
701 /*                            fxrstor                                   */
702 /*===========================================================================*/
703 _fxrstor:
704         mov     4(%esp), %eax
705         fxrstor (%eax)          /* Do not change the operand! (gas2ack) */
706         ret
708 /*===========================================================================*/
709 /*                            frstor                                    */
710 /*===========================================================================*/
711 _frstor:
712         mov     4(%esp), %eax
713         frstor  (%eax)          /* Do not change the operand! (gas2ack) */
714         ret
717 /*===========================================================================*/
718 /*                            read_cr0                                       */
719 /*===========================================================================*/
720 /* PUBLIC unsigned long read_cr0(void); */
721 _read_cr0:
722         push    %ebp
723         mov     %esp, %ebp
724         mov     %cr0, %eax
725         pop     %ebp
726         ret
728 /*===========================================================================*/
729 /*                            write_cr0                                      */
730 /*===========================================================================*/
731 /* PUBLIC void write_cr0(unsigned long value); */
732 _write_cr0:
733         push    %ebp
734         mov     %esp, %ebp
735         mov     8(%ebp), %eax
736         mov     %eax, %cr0
737         jmp     0f      /* A jump is required for some flags */
739         pop     %ebp
740         ret
742 /*===========================================================================*/
743 /*                            read_cr2                                       */
744 /*===========================================================================*/
745 /* PUBLIC reg_t read_cr2(void); */
746 _read_cr2:
747         mov     %cr2, %eax
748         ret
750 /*===========================================================================*/
751 /*                            read_cr3                                       */
752 /*===========================================================================*/
753 /* PUBLIC unsigned long read_cr3(void); */
754 _read_cr3:
755         push    %ebp
756         mov     %esp, %ebp
758         /* DO NOT CHANGE THE OPERAND!!! gas2ack does not handle it yet */
759         mov     %cr3, %eax
760         pop     %ebp
761         ret
763 /*===========================================================================*/
764 /*                            read_cr4                                       */
765 /*===========================================================================*/
766 /* PUBLIC unsigned long read_cr4(void); */
767 _read_cr4:
768         push    %ebp
769         mov     %esp, %ebp
771         /* DO NOT CHANGE THE OPERAND!!! gas2ack does not handle it yet */
772         mov     %cr4, %eax
773         pop     %ebp
774         ret
776 /*===========================================================================*/
777 /*                            write_cr4                                      */
778 /*===========================================================================*/
779 /* PUBLIC void write_cr4(unsigned long value); */
780 _write_cr4:
781         push    %ebp
782         mov     %esp, %ebp
783         mov     8(%ebp), %eax
785         /* DO NOT CHANGE THE OPERAND!!! gas2ack does not handle it yet */
786         mov     %eax, %cr4
787         jmp     0f
789         pop     %ebp
790         ret
791 /*===========================================================================*/
792 /*                              getcr3val                                    */
793 /*===========================================================================*/
794 /* PUBLIC unsigned long getcr3val(void); */
795 _getcr3val:
796         mov     %cr3, %eax
797         ret
800  * Read the Model Specific Register (MSR) of IA32 architecture
802  * void ia32_msr_read(u32_t reg, u32_t * hi, u32_t * lo)
803  */
804 .globl _ia32_msr_read
805 _ia32_msr_read:
806         push    %ebp
807         mov     %esp, %ebp
809         mov     8(%ebp), %ecx
810         rdmsr
811         mov     12(%ebp), %ecx
812         mov     %edx, (%ecx)
813         mov     16(%ebp), %ecx
814         mov     %eax, (%ecx)
816         pop     %ebp
817         ret
820  * Write the Model Specific Register (MSR) of IA32 architecture
822  * void ia32_msr_write(u32_t reg, u32_t hi, u32_t lo)
823  */
824 .globl _ia32_msr_write
825 _ia32_msr_write:
826         push    %ebp
827         mov     %esp, %ebp
829         mov     12(%ebp), %edx
830         mov     16(%ebp), %eax
831         mov     8(%ebp), %ecx
832         wrmsr
834         pop     %ebp
835         ret
837 /*===========================================================================*/
838 /*                            idt_reload                                     */
839 /*===========================================================================*/
840 /*  PUBLIC void idt_reload (void); */
841 .balign 16
842 _idt_reload:
843         lidt    _gdt+IDT_SELECTOR       /*  reload interrupt descriptor table */
844         ret
847  * void reload_segment_regs(void)
848  */
850 #define RELOAD_SEG_REG(reg)     \
851         mov     reg, %ax        ;\
852         mov     %ax, reg        ;
854 .globl _reload_ds
855 _reload_ds:
856         RELOAD_SEG_REG(%ds)
857         ret
859 /*===========================================================================*/
860 /*                            switch_address_space                           */
861 /*===========================================================================*/
862 /* PUBLIC void switch_address_space(struct proc *p)
864  * sets the %cr3 register to the supplied value if it is not already set to the
865  * same value in which case it would only result in an extra TLB flush which is
866  * not desirable
867  */
868  .balign 16
869 .globl _switch_address_space
870 _switch_address_space:
872         /* read the process pointer */
873         mov     4(%esp), %edx
874         /* enable process' segment descriptors  */
875         lldt    P_LDT_SEL(%edx)
876         /* get the new cr3 value */
877         movl    P_CR3(%edx), %eax
878         /* test if the new cr3 != NULL */
879         cmpl    $0, %eax
880         je      0f
882         /*
883          * test if the cr3 is loaded with the current value to avoid unnecessary
884          * TLB flushes
885          */
886         mov     %cr3, %ecx
887         cmp     %ecx, %eax
888         je      0f
889         mov     %eax, %cr3
890         mov     %edx, _ptproc
892         ret