3 .text; .data; .data; .bss
5 #include <minix/config.h>
6 #include <minix/const.h>
7 #include <ibm/interrupt.h>
9 #include "../../const.h"
13 * This file contains a number of assembly code utility routines needed by the
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 */
39 .globl write_cr0 /* write a value in cr0 */
44 .globl catch_pagefaults
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).
61 /*===========================================================================*/
63 /*===========================================================================*/
64 /* PUBLIC void monitor(); */
65 /* Return to the monitor. */
68 movl mon_sp, %esp /* restore monitor stack pointer */
69 movw $SS_SELECTOR, %dx /* monitor data segment */
78 lretw /* return to the monitor */
81 /*===========================================================================*/
83 /*===========================================================================*/
84 /* PUBLIC void int86(); */
86 cmpb $0, mon_return /* is the monitor there? */
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" */
93 push %ebp /* save C registers */
97 pushf /* save flags */
98 cli /* no interruptions */
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. */
110 mov $SS_SELECTOR, %eax /* monitor data segment */
112 xchgl mon_sp, %esp /* switch stacks */
113 push reg86+36 /* parameters used in INT call */
123 mov %ax, %ds /* remaining data selectors */
128 push $return /* kernel return address and selector */
129 ljmpw *20+2*4+10*4+2*4(%esp)
141 lgdt gdt+GDT_SELECTOR /* reload global descriptor table */
142 ljmp $CS_SELECTOR, $csinit
144 mov $DS_SELECTOR, %eax
150 xchgl mon_sp, %esp /* unswitch stacks */
151 lidt gdt+IDT_SELECTOR /* reload interrupt descriptor table */
154 cmpl $0x0, lapic_addr
160 mov $FLAT_DS_SELECTOR, %ebx
162 movl lapic_addr, %eax
164 .byte 0x64; mov (%eax), %ebx
165 and $0xFF000000, %ebx
170 add $apicid2cpuid, %ebx
174 add $TSS_SELECTOR, %eax
175 addl gdt+DESC_ACCESS, %eax
177 ltr %bx /* set TSS register */
179 mov $DS_SELECTOR, %eax
182 #endif /* CONFIG_APIC */
185 outb $INT_CTLMASK /* restore interrupt masks */
190 addl %ecx, lost_ticks /* record lost clock ticks */
192 popf /* restore flags */
193 pop %ebx /* restore C registers */
199 /*===========================================================================*/
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.
219 /*===========================================================================*/
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().
234 mov $FLAT_DS_SELECTOR, %ecx
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 */
247 /*===========================================================================*/
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().
262 mov $FLAT_DS_SELECTOR, %ecx
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 */
274 /*===========================================================================*/
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().
290 mov $FLAT_DS_SELECTOR, %ecx
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 */
303 /*===========================================================================*/
305 /*===========================================================================*/
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().
319 mov $FLAT_DS_SELECTOR, %ecx
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 */
331 /*===========================================================================*/
333 /*===========================================================================*/
335 * PUBLIC phys_bytes phys_copy(phys_bytes source, phys_bytes destination,
336 * phys_bytes bytecount);
337 * Copy a block of physical memory.
340 PC_ARGS = 4+4+4+4 /* 4 + 4 + 4 */
341 /* es edi esi eip src dst len */
350 mov $FLAT_DS_SELECTOR, %eax
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 */
359 mov %esi, %ecx /* align source, hope target is too */
361 and $3, %ecx /* count for alignment */
364 rep movsb %es:(%esi), %es:(%edi)
366 shr $2, %ecx /* count of dwords */
368 rep movsl %es:(%esi), %es:(%edi)
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 */
382 phys_copy_fault_in_kernel: /* kernel can send us here */
389 /*===========================================================================*/
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.
408 mov $FLAT_DS_SELECTOR, %ebx
417 /* Any remaining bytes? */
437 /*===========================================================================*/
439 /*===========================================================================*/
441 * PUBLIC u16_t mem_rdw(U16_t segment, u16_t *offset);
442 * Load and return word at far pointer segment:offset.
449 mov 4+4(%esp), %eax /* offset */
450 movzwl (%eax), %eax /* word to return */
455 /*===========================================================================*/
457 /*===========================================================================*/
459 * PUBLIC void reset();
460 * Reset the system by loading IDT with offset 0 and interrupting.
465 int $3 /* anything goes, the 386 will not like it */
472 /*===========================================================================*/
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
486 /*===========================================================================*/
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.
495 /* check whether we are already running in kernel, the kernel cs
496 * selector has 3 lower bits zeroed */
498 cmpw $CS_SELECTOR, %ax
501 /* call the function directly as if it was a normal function call */
507 /* if not runnig in the kernel yet, trap to kernel */
513 /*===========================================================================*/
515 /*===========================================================================*/
517 * PUBLIC unsigned long read_cpu_flags(void);
518 * Read CPU status flags from C.
543 /*===========================================================================*/
545 /*===========================================================================*/
553 /* DO NOT CHANGE THE OPERAND!!! gas2ack does not handle it yet */
561 /* DO NOT CHANGE THE OPERAND!!! gas2ack does not handle it yet */
566 /*===========================================================================*/
568 /*===========================================================================*/
569 /* PUBLIC unsigned long read_cr0(void); */
577 /*===========================================================================*/
579 /*===========================================================================*/
580 /* PUBLIC void write_cr0(unsigned long value); */
586 jmp 0f /* A jump is required for some flags */
591 /*===========================================================================*/
593 /*===========================================================================*/
594 /* PUBLIC reg_t read_cr2(void); */
599 /*===========================================================================*/
601 /*===========================================================================*/
602 /* PUBLIC unsigned long read_cr4(void); */
607 /* DO NOT CHANGE THE OPERAND!!! gas2ack does not handle it yet */
612 /*===========================================================================*/
614 /*===========================================================================*/
615 /* PUBLIC void write_cr4(unsigned long value); */
621 /* DO NOT CHANGE THE OPERAND!!! gas2ack does not handle it yet */
627 /*===========================================================================*/
629 /*===========================================================================*/
630 /* PUBLIC unsigned long getcr3val(void); */
637 * Read the Model Specific Register (MSR) of IA32 architecture
639 * void ia32_msr_read(u32_t reg, u32_t * hi, u32_t * lo)
657 * Write the Model Specific Register (MSR) of IA32 architecture
659 * void ia32_msr_write(u32_t reg, u32_t hi, u32_t lo)
661 .globl ia32_msr_write
674 /*===========================================================================*/
676 /*===========================================================================*/
677 /* PUBLIC void idt_reload (void); */
680 lidt gdt+IDT_SELECTOR /* reload interrupt descriptor table */
684 * void reload_segment_regs(void)
687 #define RELOAD_SEG_REG(reg) \