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>
10 #include "kernel/const.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) ;\
30 /* Make a function of the form ret = func() */
31 #define ARG_EAX_RETURN(FUNCTION, EXPR) ;\
39 /* Make a function of the form ret = func() */
40 #define ARG_EAX_SET(FUNCTION, DEST) ;\
46 jmp 0f /* a jump is required for some sets */ ;\
50 /* Make a function of the form ret = func() */
51 #define ARG_AX_SET(FUNCTION, DEST) ;\
57 jmp 0f /* a jump is required for some sets */ ;\
62 * This file contains a number of assembly code utility routines needed by the
70 /*===========================================================================*/
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().
77 /* transfer data from (disk controller) port to memory */
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 */
94 /*===========================================================================*/
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().
101 /* transfer data from (disk controller) port to memory byte by byte */
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 */
117 /*===========================================================================*/
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().
124 /* transfer data from memory to (disk controller) port */
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 */
141 /*===========================================================================*/
143 /*===========================================================================*/
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().
148 /* transfer data from memory to (disk controller) port byte by byte */
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 */
164 /*===========================================================================*/
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.
172 /* es edi esi eip src dst len */
185 cmp $10, %eax /* avoid align overhead for small counts */
187 mov %esi, %ecx /* align source, hope target is too */
189 and $3, %ecx /* count for alignment */
192 rep movsb (%esi), (%edi)
194 shr $2, %ecx /* count of dwords */
196 rep movsl (%esi), (%edi)
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 */
210 LABEL(phys_copy_fault_in_kernel) /* kernel can send us here */
218 /*===========================================================================*/
219 /* copy_msg_from_user */
220 /*===========================================================================*/
222 * int copy_msg_from_user(message * user_mbuf, message * dst);
224 * Copies a message of 64 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
236 ENTRY(copy_msg_from_user)
237 /* load the source pointer */
239 /* load the destination pointer */
242 /* mov 0*4(%ecx), %eax
243 mov %eax, 0*4(%edx) */
276 LABEL(__copy_msg_from_user_end)
280 /*===========================================================================*/
281 /* copy_msg_to_user */
282 /*===========================================================================*/
284 * void copy_msg_to_user(message * src, message * user_mbuf);
286 * Copies a message of 64 bytes to user process space from a kernel buffer.
288 * All the other copy_msg_from_user() comments apply here as well!
290 ENTRY(copy_msg_to_user)
291 /* load the source pointer */
293 /* load the destination pointer */
331 LABEL(__copy_msg_to_user_end)
336 * if a function from a selected set of copies from or to userspace fails, it is
337 * because of a wrong pointer supplied by the userspace. We have to clean up and
338 * and return -1 to indicated that something wrong has happend. The place it was
339 * called from has to handle this situation. The exception handler redirect us
340 * here to continue, clean up and report the error
342 ENTRY(__user_copy_msg_pointer_failure)
346 /*===========================================================================*/
348 /*===========================================================================*/
350 * PUBLIC void phys_memset(phys_bytes dst, unsigned long pattern,
351 * phys_bytes bytecount);
352 * Fill a block of physical memory with pattern.
366 /* Any remaining bytes? */
371 LABEL(memset_fault) /* kernel can send us here */
372 mov $0, %eax /* 0 means: no fault */
377 LABEL(memset_fault_in_kernel) /* kernel can send us here */
383 /*===========================================================================*/
384 /* x86_triplefault */
385 /*===========================================================================*/
387 * PUBLIC void x86_triplefault();
388 * Reset the system by loading IDT with offset 0 and interrupting.
390 ENTRY(x86_triplefault)
392 int $3 /* anything goes, the 386 will not like it */
399 /*===========================================================================*/
401 /*===========================================================================*/
403 * PUBLIC void halt_cpu(void);
404 * reanables interrupts and puts the cpu in the halts state. Once an interrupt
405 * is handled the execution resumes by disabling interrupts and continues
409 hlt /* interrupts enabled only after this instruction is executed! */
411 * interrupt handlers make sure that the interrupts are disabled when we
412 * get here so we take only _one_ interrupt after halting the CPU
416 /*===========================================================================*/
417 /* poweroff_vmware_clihlt */
418 /*===========================================================================*/
420 * PUBLIC void poweroff_vmware_clihlt(void);
421 * VMware detects this peculiar sequence and forces the virtual machine off
422 * when the parameter gui.exitOnCLIHLT is set to TRUE.
423 * Otherwise this sequence just hangs the CPU, requiring a power down action.
425 ENTRY(poweroff_vmware_clihlt)
426 #ifndef NO_VMWARE_DETECTION
429 test $[1<<31], %ecx /* "virtualized" */
430 jz 1f /* always 0 on real hardware */
431 mov $0x40000000, %eax /* select hypervisor-use leaf */
433 cmp $0x61774D56, %ebx /* ASCII "VMwa" */
435 cmp $0x4D566572, %ecx /* ASCII "reVM" */
437 cmp $0x65726177, %edx /* ASCII "ware" */
439 /* we are virtualized by some VMware product! */
445 /*===========================================================================*/
447 /*===========================================================================*/
449 * PUBLIC unsigned long read_cpu_flags(void);
450 * Read CPU status flags from C.
452 ENTRY(read_cpu_flags)
473 /*===========================================================================*/
475 /*===========================================================================*/
477 /* non-waiting FPU initialization */
486 /* store status word (non-waiting) */
490 /* DO NOT CHANGE THE OPERAND!!! gas2ack does not handle it yet */
494 /*===========================================================================*/
496 /*===========================================================================*/
504 /*===========================================================================*/
506 /*===========================================================================*/
514 /* Shared exception handler for both fxrstor and frstor. */
515 ENTRY(__frstor_failure)
519 /* Read/write control registers */
520 ARG_EAX_RETURN(read_cr0, %cr0);
521 ARG_EAX_RETURN(read_cr2, %cr2);
522 ARG_EAX_RETURN(read_cr3, %cr3);
523 ARG_EAX_RETURN(read_cr4, %cr4);
524 ARG_EAX_SET(write_cr4, %cr4);
525 ARG_EAX_SET(write_cr0, %cr0);
526 ARG_EAX_SET(write_cr3, %cr3);
528 /* Read/write various descriptor tables */
529 ARG_EAX_ACTION(x86_ltr, ltr STACKARG );
530 ARG_EAX_ACTION(x86_lidt, lidtl (%eax));
531 ARG_EAX_ACTION(x86_lgdt, lgdt (%eax));
532 ARG_EAX_ACTION(x86_lldt, lldt STACKARG);
533 ARG_EAX_ACTION(x86_sgdt, sgdt (%eax));
534 ARG_EAX_ACTION(x86_sidt, sidt (%eax));
537 ARG_AX_SET(x86_load_ds, %ds)
538 ARG_AX_SET(x86_load_es, %es)
539 ARG_AX_SET(x86_load_fs, %fs)
540 ARG_AX_SET(x86_load_gs, %gs)
541 ARG_AX_SET(x86_load_ss, %ss)
544 ARG_EAX_ACTION(fnsave, fnsave (%eax) ; fwait);
545 ARG_EAX_ACTION(fxsave, fxsave (%eax));
546 ARG_EAX_ACTION(fnstcw, fnstcw (%eax));
549 ARG_EAX_ACTION(i386_invlpg, invlpg (%eax));
551 ENTRY(x86_load_kerncs)
555 jmp $KERN_CS_SELECTOR, $newcs
561 * Read the Model Specific Register (MSR) of IA32 architecture
563 * void ia32_msr_read(u32_t reg, u32_t * hi, u32_t * lo)
580 * Write the Model Specific Register (MSR) of IA32 architecture
582 * void ia32_msr_write(u32_t reg, u32_t hi, u32_t lo)
584 ENTRY(ia32_msr_write)
596 /*===========================================================================*/
597 /* __switch_address_space */
598 /*===========================================================================*/
599 /* PUBLIC void __switch_address_space(struct proc *p, struct ** ptproc)
601 * sets the %cr3 register to the supplied value if it is not already set to the
602 * same value in which case it would only result in an extra TLB flush which is
605 ENTRY(__switch_address_space)
606 /* read the process pointer */
608 /* get the new cr3 value */
609 movl P_CR3(%edx), %eax
610 /* test if the new cr3 != NULL */
615 * test if the cr3 is loaded with the current value to avoid unnecessary
628 /* acknowledge just the master PIC */
629 ENTRY(eoi_8259_master)
630 movb $END_OF_INT, %al
634 /* we have to acknowledge both PICs */
635 ENTRY(eoi_8259_slave)
636 movb $END_OF_INT, %al
641 /* in some cases we need to force TLB update, reloading cr3 does the trick */
649 /*===========================================================================*/
651 /*===========================================================================*/
652 /* PUBLIC int smp_get_htt(void); */
653 /* return true if the processor is hyper-threaded. */
663 /* FIXME don't use the byte code */
664 .byte 0x0f, 0xa2 /* opcode for cpuid */
673 /*===========================================================================*/
674 /* smp_get_num_htt */
675 /*===========================================================================*/
676 /* PUBLIC int smp_get_num_htt(void); */
677 /* Get the number of hyper-threaded processor cores */
678 ENTRY(smp_get_num_htt)
687 /* FIXME don't use the byte code */
688 .byte 0x0f, 0xa2 /* opcode for cpuid */
697 /*===========================================================================*/
699 /*===========================================================================*/
700 /* PUBLIC int smp_get_cores(void); */
701 /* Get the number of cores. */
713 /* FIXME don't use the byte code */
714 .byte 0x0f, 0xa2 /* opcode for cpuid */
722 /*===========================================================================*/
723 /* arch_spinlock_lock */
724 /*===========================================================================*/
725 /* void arch_spinlock_lock (u32_t *lock_data)
727 * while (test_and_set(lock_data) == 1)
728 * while (*lock_data == 1)
731 * eax register is clobbered.
733 ENTRY(arch_spinlock_lock)
757 /*===========================================================================*/
758 /* arch_spinlock_unlock */
759 /*===========================================================================*/
760 /* * void arch_spinlock_unlock (unsigned int *lockp) */
761 /* spin lock release routine. */
762 ENTRY(arch_spinlock_unlock)
769 #endif /* CONFIG_SMP */
771 /*===========================================================================*/
773 /*===========================================================================*/
774 /* PUBLIC void mfence (void); */
775 /* architecture specific memory barrier routine. */
780 /*===========================================================================*/
782 /*===========================================================================*/
783 /* PUBLIC void arch_pause (void); */
784 /* architecture specific pause routine. */
789 /*===========================================================================*/
791 /*===========================================================================*/
792 /* PUBLIC u16_t cpuid(void) */
797 ENTRY(interrupts_enable)
801 ENTRY(interrupts_disable)
807 * void switch_k_stack(void * esp, void (* continuation)(void));
809 * sets the current stack pointer to the given value and continues execution at
812 ENTRY(switch_k_stack)
813 /* get the arguments from the stack */
816 mov $0, %ebp /* reset %ebp for stack trace */
817 mov %ecx, %esp /* set the new stack */
818 jmp *%eax /* and jump to the continuation */