From: Tomas Hruby Date: Fri, 30 Oct 2009 16:00:44 +0000 (+0000) Subject: Conversion of kernel assembly from ACK to GNU X-Git-Tag: v3.1.6~230 X-Git-Url: http://zhaoyanbai.com/repos/doc/zlib_tech.html?a=commitdiff_plain;h=403764c538772922bde0c638fe48a208f591b2e3;p=minix.git Conversion of kernel assembly from ACK to GNU - .s files removed and replaced by .S as the .S is a standard extension for assembly that needs preprocessing --- diff --git a/kernel/arch/i386/Makefile b/kernel/arch/i386/Makefile index 20d9181e4..afbeea668 100755 --- a/kernel/arch/i386/Makefile +++ b/kernel/arch/i386/Makefile @@ -23,18 +23,18 @@ OBJS= arch_do_vmctl.o \ system.o CPPFLAGS=-Iinclude -CFLAGS=$(CPPFLAGS) -Wall +CFLAGS=$(CPPFLAGS) -Wall $(CPROFILE) build: $(HEAD) $(ARCHAR) $(ARCHAR): $(OBJS) - aal cr $@ *.o + aal cr $@ $(OBJS) depend: - mkdep "$(CC) -E $(CPPFLAGS)" *.c *.s > .depend + mkdep "$(CC) -E $(CPPFLAGS)" *.c *.S > .depend clean: - rm -f *.a *.o *~ + rm -f *.a *.o *~ *.tmp *.s # How to build it $(ARCHAR)(exception.o): exception.c @@ -70,11 +70,15 @@ $(ARCHAR)(do_sdevio.o): do_sdevio.c $(ARCHAR)(clock.o): clock.c $(CC) $(CFLAGS) -c $< -$(ARCHAR)(klib386.o): klib386.s - $(CC) $(CFLAGS) -c $< +klib386.o: klib386.S + $(CC) $(CFLAGS) -E -D__ASSEMBLY__ -o $@.tmp $< + gas2ack $@.tmp $@.s + $(CC) $(CFLAGS) -c -o $@ $@.s -.s.o: - $(CC) $(CFLAGS) -c -o $@ $< +mpx386.o: mpx386.S + $(CC) $(CFLAGS) -E -D__ASSEMBLY__ -o $@.tmp $< + gas2ack $@.tmp $@.s + $(CC) $(CFLAGS) -c -o $@ $@.s .c.o: $(CC) $(CFLAGS) -c -o $@ $< diff --git a/kernel/arch/i386/klib386.S b/kernel/arch/i386/klib386.S new file mode 100644 index 000000000..e160c582e --- /dev/null +++ b/kernel/arch/i386/klib386.S @@ -0,0 +1,642 @@ +/* sections */ + +.text; .data; .data; .bss + +#include +#include +#include +#include +#include "../../const.h" +#include "sconst.h" + +/* + * This file contains a number of assembly code utility routines needed by the + * kernel. They are: + */ + +.globl monitor /* exit Minix and return to the monitor */ +.globl int86 /* let the monitor make an 8086 interrupt call */ +.globl exit /* dummy for library routines */ +.globl _exit /* dummy for library routines */ +.globl __exit /* dummy for library routines */ +.globl __main /* dummy for GCC */ +.globl phys_insw /* transfer data from (disk controller) port to memory */ +.globl phys_insb /* likewise byte by byte */ +.globl phys_outsw /* transfer data from memory to (disk controller) port */ +.globl phys_outsb /* likewise byte by byte */ +.globl intr_unmask /* enable an irq at the 8259 controller */ +.globl intr_mask /* disable an irq */ +.globl phys_copy /* copy data from anywhere to anywhere in memory */ +.globl phys_copy_fault /* phys_copy pagefault */ +.globl phys_memset /* write pattern anywhere in memory */ +.globl mem_rdw /* copy one word from [segment:offset] */ +.globl reset /* reset the system */ +.globl idle_task /* task executed when there is no work */ +.globl level0 /* call a function at level 0 */ +.globl read_cpu_flags /* read the cpu flags */ +.globl read_cr0 /* read cr0 */ +.globl getcr3val +.globl write_cr0 /* write a value in cr0 */ +.globl read_cr4 +.globl thecr3 +.globl write_cr4 + +.globl catch_pagefaults +.globl read_ds +.globl read_cs +.globl read_ss + +/* + * The routines only guarantee to preserve the registers the C compiler + * expects to be preserved (ebx, esi, edi, ebp, esp, segment registers, and + * direction bit in the flags). + */ + +.text +/*===========================================================================*/ +/* monitor */ +/*===========================================================================*/ +/* PUBLIC void monitor(); */ +/* Return to the monitor. */ + +monitor: + movl mon_sp, %esp /* restore monitor stack pointer */ + movw $SS_SELECTOR, %dx /* monitor data segment */ + mov %dx, %ds + mov %dx, %es + mov %dx, %fs + mov %dx, %gs + mov %dx, %ss + pop %edi + pop %esi + pop %ebp + lretw /* return to the monitor */ + + +/*===========================================================================*/ +/* int86 */ +/*===========================================================================*/ +/* PUBLIC void int86(); */ +int86: + cmpb $0, mon_return /* is the monitor there? */ + jne 0f + movb $0x01, %ah /* an int 13 error seems appropriate */ + movb %ah, reg86+0 /* reg86.w.f = 1 (set carry flag) */ + movb %ah, reg86+13 /* reg86.b.ah = 0x01 = "invalid command" */ + ret +0: + push %ebp /* save C registers */ + push %esi + push %edi + push %ebx + pushf /* save flags */ + cli /* no interruptions */ + + inb $INT2_CTLMASK + movb %al, %ah + inb $INT_CTLMASK + push %eax /* save interrupt masks */ + movl irq_use, %eax /* map of in-use IRQ's */ + and $~(1<irq < 8: + * if ((irq_actids[hook->irq] &= ~hook->id) == 0) + * outb(INT_CTLMASK, inb(INT_CTLMASK) & ~(1 << irq)); + */ + +.balign 16 +intr_unmask: + push %ebp + mov %esp, %ebp + pushf + cli + mov 8(%ebp), %eax /* hook */ + mov 8(%eax), %ecx /* irq */ + mov 12(%eax), %eax /* id bit */ + not %eax + and %eax, irq_actids(,%ecx) /* clear this id bit */ + jne en_done /* still masked by other handlers? */ + movb $~1, %ah + rolb %cl, %ah /* ah = ~(1 << (irq % 8)) */ + mov $INT_CTLMASK, %edx /* enable irq < 8 at the master 8259 */ + cmpb $8, %cl + jb 0f + mov $INT2_CTLMASK, %edx /* enable irq >= 8 at the slave 8259 */ +0: + inb %dx + andb %ah, %al + outb %dx /* clear bit at the 8259 */ +en_done: + popf + leave + ret + + +/*==========================================================================*/ +/* intr_mask */ +/*==========================================================================*/ +/* + * PUBLIC int intr_mask(irq_hook_t *hook) + * Disable an interrupt request line by setting an 8259 bit. + * Equivalent C code for irq < 8: + * irq_actids[hook->irq] |= hook->id; + * outb(INT_CTLMASK, inb(INT_CTLMASK) | (1 << irq)); + * Returns true iff the interrupt was not already disabled. + */ + +.balign 16 +intr_mask: + push %ebp + mov %esp, %ebp + pushf + cli + mov 8(%ebp), %eax /* hook */ + mov 8(%eax), %ecx /* irq */ + mov 12(%eax), %eax /* id bit */ + or %eax, irq_actids(,%ecx) /* set this id bit */ + movb $1, %ah + rolb %cl, %ah /* ah = (1 << (irq % 8)) */ + mov $INT_CTLMASK, %edx /* disable irq < 8 at the master 8259 */ + cmpb $8, %cl + jb 0f + mov $INT2_CTLMASK, %edx /* disable irq >= 8 at the slave 8259 */ +0: + inb %dx + testb %ah, %al + jne dis_already /* already disabled? */ + orb %ah, %al + outb %dx /* set bit at the 8259 */ + mov $1, %eax /* disabled by this function */ + popf + leave + ret +dis_already: + xor %eax, %eax /* already disabled */ + popf + leave + ret + + +/*===========================================================================*/ +/* phys_copy */ +/*===========================================================================*/ +/* + * PUBLIC phys_bytes phys_copy(phys_bytes source, phys_bytes destination, + * phys_bytes bytecount); + * Copy a block of physical memory. + */ + + PC_ARGS = 4+4+4+4 /* 4 + 4 + 4 */ +/* es edi esi eip src dst len */ + +.balign 16 +phys_copy: + cld + push %esi + push %edi + push %es + + mov $FLAT_DS_SELECTOR, %eax + mov %ax, %es + + mov PC_ARGS(%esp), %esi + mov PC_ARGS+4(%esp), %edi + mov PC_ARGS+4+4(%esp), %eax + + cmp $10, %eax /* avoid align overhead for small counts */ + jb pc_small + mov %esi, %ecx /* align source, hope target is too */ + neg %ecx + and $3, %ecx /* count for alignment */ + sub %ecx, %eax + + rep movsb %es:(%esi), %es:(%edi) + mov %eax, %ecx + shr $2, %ecx /* count of dwords */ + + rep movsl %es:(%esi), %es:(%edi) + and $3, %eax +pc_small: + xchg %eax, %ecx /* remainder */ + + rep movsb %es:(%esi), %es:(%edi) + + mov $0, %eax /* 0 means: no fault */ +phys_copy_fault: /* kernel can send us here */ + pop %es + pop %edi + pop %esi + ret + +/*===========================================================================*/ +/* phys_memset */ +/*===========================================================================*/ +/* + * PUBLIC void phys_memset(phys_bytes source, unsigned long pattern, + * phys_bytes bytecount); + * Fill a block of physical memory with pattern. + */ + +.balign 16 +phys_memset: + push %ebp + mov %esp, %ebp + push %esi + push %ebx + push %ds + + mov 8(%ebp), %esi + mov 16(%ebp), %eax + mov $FLAT_DS_SELECTOR, %ebx + mov %bx, %ds + mov 12(%ebp), %ebx + shr $2, %eax +fill_start: + mov %ebx, (%esi) + add $4, %esi + dec %eax + jne fill_start +/* Any remaining bytes? */ + mov 16(%ebp), %eax + and $3, %eax +remain_fill: + cmp $0, %eax + je fill_done + movb 12(%ebp), %bl + movb %bl, (%esi) + add $1, %esi + inc %ebp + dec %eax + jmp remain_fill +fill_done: + pop %ds + pop %ebx + pop %esi + pop %ebp + ret + + +/*===========================================================================*/ +/* mem_rdw */ +/*===========================================================================*/ +/* + * PUBLIC u16_t mem_rdw(U16_t segment, u16_t *offset); + * Load and return word at far pointer segment:offset. + */ + +.balign 16 +mem_rdw: + mov %ds, %cx + mov 4(%esp), %ds + mov 4+4(%esp), %eax /* offset */ + movzwl (%eax), %eax /* word to return */ + mov %cx, %ds + ret + + +/*===========================================================================*/ +/* reset */ +/*===========================================================================*/ +/* + * PUBLIC void reset(); + * Reset the system by loading IDT with offset 0 and interrupting. + */ + +reset: + lidt idt_zero + int $3 /* anything goes, the 386 will not like it */ +.data +idt_zero: +.long 0, 0 +.text + + +/*===========================================================================*/ +/* idle_task */ +/*===========================================================================*/ +idle_task: +/* + * This task is called when the system has nothing else to do. The HLT + * instruction puts the processor in a state where it draws minimum power. + */ + push $halt + call level0 /* level0(halt) */ + pop %eax + jmp idle_task +halt: + sti + hlt + cli + ret + +/*===========================================================================*/ +/* level0 */ +/*===========================================================================*/ +/* + * PUBLIC void level0(void (*func)(void)) + * Call a function at permission level 0. This allows kernel tasks to do + * things that are only possible at the most privileged CPU level. + */ +level0: + mov 4(%esp), %eax + cmpb $-1, k_reenter + jne 0f + int $LEVEL0_VECTOR + ret + +0: + call *%eax + ret + + + + +/*===========================================================================*/ +/* read_flags */ +/*===========================================================================*/ +/* + * PUBLIC unsigned long read_cpu_flags(void); + * Read CPU status flags from C. + */ +.balign 16 +read_cpu_flags: + pushf + mov (%esp), %eax + popf + ret + +read_ds: + mov $0, %eax + mov %ds, %ax + ret + +read_cs: + mov $0, %eax + mov %cs, %ax + ret + +read_ss: + mov $0, %eax + mov %ss, %ax + ret + + +/*===========================================================================*/ +/* read_cr0 */ +/*===========================================================================*/ +/* PUBLIC unsigned long read_cr0(void); */ +read_cr0: + push %ebp + mov %esp, %ebp + mov %cr0, %eax + pop %ebp + ret + +/*===========================================================================*/ +/* write_cr0 */ +/*===========================================================================*/ +/* PUBLIC void write_cr0(unsigned long value); */ +write_cr0: + push %ebp + mov %esp, %ebp + mov 8(%ebp), %eax + mov %eax, %cr0 + jmp 0f /* A jump is required for some flags */ +0: + pop %ebp + ret + +/*===========================================================================*/ +/* read_cr4 */ +/*===========================================================================*/ +/* PUBLIC unsigned long read_cr4(void); */ +read_cr4: + push %ebp + mov %esp, %ebp + mov %cr4, %eax + pop %ebp + ret + +/*===========================================================================*/ +/* write_cr4 */ +/*===========================================================================*/ +/* PUBLIC void write_cr4(unsigned long value); */ +write_cr4: + push %ebp + mov %esp, %ebp + mov 8(%ebp), %eax + mov %eax, %cr4 + jmp 0f +0: + pop %ebp + ret +/*===========================================================================*/ +/* getcr3val */ +/*===========================================================================*/ +/* PUBLIC unsigned long getcr3val(void); */ +getcr3val: + mov %cr3, %eax + mov %eax, thecr3 + ret + diff --git a/kernel/arch/i386/klib386.s b/kernel/arch/i386/klib386.s deleted file mode 100755 index ed0cc22cb..000000000 --- a/kernel/arch/i386/klib386.s +++ /dev/null @@ -1,607 +0,0 @@ -# -! sections - -.sect .text; .sect .rom; .sect .data; .sect .bss - -#include -#include -#include -#include -#include "../../const.h" -#include "sconst.h" - -! This file contains a number of assembly code utility routines needed by the -! kernel. They are: - -.define _monitor ! exit Minix and return to the monitor -.define _int86 ! let the monitor make an 8086 interrupt call -!.define _cp_mess ! copies messages from source to destination -.define _exit ! dummy for library routines -.define __exit ! dummy for library routines -.define ___exit ! dummy for library routines -.define ___main ! dummy for GCC -.define _phys_insw ! transfer data from (disk controller) port to memory -.define _phys_insb ! likewise byte by byte -.define _phys_outsw ! transfer data from memory to (disk controller) port -.define _phys_outsb ! likewise byte by byte -.define _intr_unmask ! enable an irq at the 8259 controller -.define _intr_mask ! disable an irq -.define _phys_copy ! copy data from anywhere to anywhere in memory -.define _phys_copy_fault! phys_copy pagefault -.define _phys_memset ! write pattern anywhere in memory -.define _mem_rdw ! copy one word from [segment:offset] -.define _reset ! reset the system -.define _idle_task ! task executed when there is no work -.define _level0 ! call a function at level 0 -.define _read_cpu_flags ! read the cpu flags -.define _read_cr0 ! read cr0 -.define _getcr3val -.define _write_cr0 ! write a value in cr0 -.define _read_cr4 -.define _thecr3 -.define _write_cr4 -.define _catch_pagefaults -.define _read_ds -.define _read_cs -.define _read_ss - -! The routines only guarantee to preserve the registers the C compiler -! expects to be preserved (ebx, esi, edi, ebp, esp, segment registers, and -! direction bit in the flags). - -.sect .text -!*===========================================================================* -!* monitor * -!*===========================================================================* -! PUBLIC void monitor(); -! Return to the monitor. - -_monitor: - mov esp, (_mon_sp) ! restore monitor stack pointer - o16 mov dx, SS_SELECTOR ! monitor data segment - mov ds, dx - mov es, dx - mov fs, dx - mov gs, dx - mov ss, dx - pop edi - pop esi - pop ebp - o16 retf ! return to the monitor - - -!*===========================================================================* -!* int86 * -!*===========================================================================* -! PUBLIC void int86(); -_int86: - cmpb (_mon_return), 0 ! is the monitor there? - jnz 0f - movb ah, 0x01 ! an int 13 error seems appropriate - movb (_reg86+ 0), ah ! reg86.w.f = 1 (set carry flag) - movb (_reg86+13), ah ! reg86.b.ah = 0x01 = "invalid command" - ret -0: push ebp ! save C registers - push esi - push edi - push ebx - pushf ! save flags - cli ! no interruptions - - inb INT2_CTLMASK - movb ah, al - inb INT_CTLMASK - push eax ! save interrupt masks - mov eax, (_irq_use) ! map of in-use IRQ's - and eax, ~[1<irq < 8: -! if ((irq_actids[hook->irq] &= ~hook->id) == 0) -! outb(INT_CTLMASK, inb(INT_CTLMASK) & ~(1 << irq)); - - .align 16 -_intr_unmask: - push ebp - mov ebp, esp - pushf - cli - mov eax, 8(ebp) ! hook - mov ecx, 8(eax) ! irq - mov eax, 12(eax) ! id bit - not eax - and _irq_actids(ecx*4), eax ! clear this id bit - jnz en_done ! still masked by other handlers? - movb ah, ~1 - rolb ah, cl ! ah = ~(1 << (irq % 8)) - mov edx, INT_CTLMASK ! enable irq < 8 at the master 8259 - cmpb cl, 8 - jb 0f - mov edx, INT2_CTLMASK ! enable irq >= 8 at the slave 8259 -0: inb dx - andb al, ah - outb dx ! clear bit at the 8259 -en_done:popf - leave - ret - - -!*==========================================================================* -!* intr_mask * -!*==========================================================================*/ -! PUBLIC int intr_mask(irq_hook_t *hook) -! Disable an interrupt request line by setting an 8259 bit. -! Equivalent C code for irq < 8: -! irq_actids[hook->irq] |= hook->id; -! outb(INT_CTLMASK, inb(INT_CTLMASK) | (1 << irq)); -! Returns true iff the interrupt was not already disabled. - - .align 16 -_intr_mask: - push ebp - mov ebp, esp - pushf - cli - mov eax, 8(ebp) ! hook - mov ecx, 8(eax) ! irq - mov eax, 12(eax) ! id bit - or _irq_actids(ecx*4), eax ! set this id bit - movb ah, 1 - rolb ah, cl ! ah = (1 << (irq % 8)) - mov edx, INT_CTLMASK ! disable irq < 8 at the master 8259 - cmpb cl, 8 - jb 0f - mov edx, INT2_CTLMASK ! disable irq >= 8 at the slave 8259 -0: inb dx - testb al, ah - jnz dis_already ! already disabled? - orb al, ah - outb dx ! set bit at the 8259 - mov eax, 1 ! disabled by this function - popf - leave - ret -dis_already: - xor eax, eax ! already disabled - popf - leave - ret - - -!*===========================================================================* -!* phys_copy * -!*===========================================================================* -! PUBLIC phys_bytes phys_copy(phys_bytes source, phys_bytes destination, -! phys_bytes bytecount); -! Copy a block of physical memory. - -PC_ARGS = 4 + 4 + 4 + 4 ! 4 + 4 + 4 -! es edi esi eip src dst len - - .align 16 -_phys_copy: - cld - push esi - push edi - push es - - mov eax, FLAT_DS_SELECTOR - mov es, ax - - mov esi, PC_ARGS(esp) - mov edi, PC_ARGS+4(esp) - mov eax, PC_ARGS+4+4(esp) - - cmp eax, 10 ! avoid align overhead for small counts - jb pc_small - mov ecx, esi ! align source, hope target is too - neg ecx - and ecx, 3 ! count for alignment - sub eax, ecx - rep - eseg movsb - mov ecx, eax - shr ecx, 2 ! count of dwords - rep - eseg movs - and eax, 3 -pc_small: - xchg ecx, eax ! remainder - rep - eseg movsb - - mov eax, 0 ! 0 means: no fault -_phys_copy_fault: ! kernel can send us here - pop es - pop edi - pop esi - ret - -!*===========================================================================* -!* phys_memset * -!*===========================================================================* -! PUBLIC void phys_memset(phys_bytes source, unsigned long pattern, -! phys_bytes bytecount); -! Fill a block of physical memory with pattern. - - .align 16 -_phys_memset: - push ebp - mov ebp, esp - push esi - push ebx - push ds - - mov esi, 8(ebp) - mov eax, 16(ebp) - mov ebx, FLAT_DS_SELECTOR - mov ds, bx - mov ebx, 12(ebp) - shr eax, 2 -fill_start: - mov (esi), ebx - add esi, 4 - dec eax - jnz fill_start - ! Any remaining bytes? - mov eax, 16(ebp) - and eax, 3 -remain_fill: - cmp eax, 0 - jz fill_done - movb bl, 12(ebp) - movb (esi), bl - add esi, 1 - inc ebp - dec eax - jmp remain_fill -fill_done: - pop ds - pop ebx - pop esi - pop ebp - ret - - -!*===========================================================================* -!* mem_rdw * -!*===========================================================================* -! PUBLIC u16_t mem_rdw(U16_t segment, u16_t *offset); -! Load and return word at far pointer segment:offset. - - .align 16 -_mem_rdw: - mov cx, ds - mov ds, 4(esp) ! segment - mov eax, 4+4(esp) ! offset - movzx eax, (eax) ! word to return - mov ds, cx - ret - - -!*===========================================================================* -!* reset * -!*===========================================================================* -! PUBLIC void reset(); -! Reset the system by loading IDT with offset 0 and interrupting. - -_reset: - lidt (idt_zero) - int 3 ! anything goes, the 386 will not like it -.sect .data -idt_zero: .data4 0, 0 -.sect .text - - -!*===========================================================================* -!* idle_task * -!*===========================================================================* -_idle_task: -! This task is called when the system has nothing else to do. The HLT -! instruction puts the processor in a state where it draws minimum power. - push _halt - call _level0 ! level0(halt) - pop eax - jmp _idle_task -_halt: - sti - hlt - cli - ret - -!*===========================================================================* -!* level0 * -!*===========================================================================* -! PUBLIC void level0(void (*func)(void)) -! Call a function at permission level 0. This allows kernel tasks to do -! things that are only possible at the most privileged CPU level. -! -_level0: - mov eax, 4(esp) - cmpb (_k_reenter), -1 - jne direct - int LEVEL0_VECTOR - ret - -direct: - call eax - ret - - -!*===========================================================================* -!* read_flags * -!*===========================================================================* -! PUBLIC unsigned long read_cpu_flags(void); -! Read CPU status flags from C. -.align 16 -_read_cpu_flags: - pushf - mov eax, (esp) - popf - ret - - -!*===========================================================================* -!* read_cr0 * -!*===========================================================================* -! PUBLIC unsigned long read_cr0(void); -_read_cr0: - push ebp - mov ebp, esp - mov eax, cr0 - pop ebp - ret - -!*===========================================================================* -!* write_cr0 * -!*===========================================================================* -! PUBLIC void write_cr0(unsigned long value); -_write_cr0: - push ebp - mov ebp, esp - mov eax, 8(ebp) - mov cr0, eax - jmp 0f ! A jump is required for some flags -0: - pop ebp - ret - -!*===========================================================================* -!* read_cr4 * -!*===========================================================================* -! PUBLIC unsigned long read_cr4(void); -_read_cr4: - push ebp - mov ebp, esp -.data1 0x0f, 0x20, 0xe0 ! mov eax, cr4 - pop ebp - ret - -!*===========================================================================* -!* write_cr4 * -!*===========================================================================* -! PUBLIC void write_cr4(unsigned long value); -_write_cr4: - push ebp - mov ebp, esp - mov eax, 8(ebp) -.data1 0x0f, 0x22, 0xe0 ! mov cr4, eax - jmp 0f -0: - pop ebp - ret - -_read_ds: - mov eax, 0 - mov ax, ds - ret - -_read_cs: - mov eax, 0 - mov ax, cs - ret - -_read_ss: - mov eax, 0 - mov ax, ss - ret - -!*===========================================================================* -!* getcr3val * -!*===========================================================================* -! PUBLIC unsigned long getcr3val(void); -_getcr3val: - mov eax, cr3 - mov (_thecr3), eax - ret - diff --git a/kernel/arch/i386/mpx386.S b/kernel/arch/i386/mpx386.S new file mode 100644 index 000000000..56c68f9a9 --- /dev/null +++ b/kernel/arch/i386/mpx386.S @@ -0,0 +1,656 @@ +/* + * This file, mpx386.s, is included by mpx.s when Minix is compiled for + * 32-bit Intel CPUs. The alternative mpx88.s is compiled for 16-bit CPUs. + * + * This file is part of the lowest layer of the MINIX kernel. (The other part + * is "proc.c".) The lowest layer does process switching and message handling. + * Furthermore it contains the assembler startup code for Minix and the 32-bit + * interrupt handlers. It cooperates with the code in "start.c" to set up a + * good environment for main(). + * + * Every transition to the kernel goes through this file. Transitions to the + * kernel may be nested. The initial entry may be with a system call (i.e., + * send or receive a message), an exception or a hardware interrupt; kernel + * reentries may only be made by hardware interrupts. The count of reentries + * is kept in "k_reenter". It is important for deciding whether to switch to + * the kernel stack and for protecting the message passing code in "proc.c". + * + * For the message passing trap, most of the machine state is saved in the + * proc table. (Some of the registers need not be saved.) Then the stack is + * switched to "k_stack", and interrupts are reenabled. Finally, the system + * call handler (in C) is called. When it returns, interrupts are disabled + * again and the code falls into the restart routine, to finish off held-up + * interrupts and run the process or task whose pointer is in "proc_ptr". + * + * Hardware interrupt handlers do the same, except (1) The entire state must + * be saved. (2) There are too many handlers to do this inline, so the save + * routine is called. A few cycles are saved by pushing the address of the + * appropiate restart routine for a return later. (3) A stack switch is + * avoided when the stack is already switched. (4) The (master) 8259 interrupt + * controller is reenabled centrally in save(). (5) Each interrupt handler + * masks its interrupt line using the 8259 before enabling (other unmasked) + * interrupts, and unmasks it after servicing the interrupt. This limits the + * nest level to the number of lines and protects the handler from itself. + * + * For communication with the boot monitor at startup time some constant + * data are compiled into the beginning of the text segment. This facilitates + * reading the data at the start of the boot process, since only the first + * sector of the file needs to be read. + * + * Some data storage is also allocated at the end of this file. This data + * will be at the start of the data segment of the kernel and will be read + * and modified by the boot monitor before the kernel starts. + */ + +/* sections */ + +#include + +#ifdef __ACK__ +.text +begtext: +#ifdef __ACK__ +.rom +#else +.data +#endif +begrom: +.data +begdata: +.bss +begbss: +#endif + + +#include +#include +#include +#include +#include +#include "../../const.h" +#include "sconst.h" + +/* Selected 386 tss offsets. */ +#define TSS3_S_SP0 4 + +/* + * Exported functions + * Note: in assembly language the .define statement applied to a function name + * is loosely equivalent to a prototype in C code -- it makes it possible to + * link to an entity declared in the assembly code but does not create + * the entity. + */ + +.globl restart +.globl save +.globl reload_cr3 +.globl write_cr3 + +.globl errexception +.globl exception1 +.globl exception + +.globl divide_error +.globl single_step_exception +.globl nmi +.globl breakpoint_exception +.globl overflow +.globl bounds_check +.globl inval_opcode +.globl copr_not_available +.globl double_fault +.globl copr_seg_overrun +.globl inval_tss +.globl segment_not_present +.globl stack_exception +.globl general_protection +.globl page_fault +.globl copr_error +.globl params_size +.globl params_offset +.globl mon_ds +.globl schedcheck +.globl dirtypde + +.globl hwint00 /* handlers for hardware interrupts */ +.globl hwint01 +.globl hwint02 +.globl hwint03 +.globl hwint04 +.globl hwint05 +.globl hwint06 +.globl hwint07 +.globl hwint08 +.globl hwint09 +.globl hwint10 +.globl hwint11 +.globl hwint12 +.globl hwint13 +.globl hwint14 +.globl hwint15 + +.globl s_call +.globl p_s_call +.globl level0_call + +/* Exported variables. */ +.globl begbss +.globl begdata + +.text +/*===========================================================================*/ +/* MINIX */ +/*===========================================================================*/ +.global MINIX +MINIX: +/* this is the entry point for the MINIX kernel */ + jmp over_flags /* skip over the next few bytes */ +.short CLICK_SHIFT /* for the monitor: memory granularity */ + +flags: +/* boot monitor flags: + * call in 386 mode, make bss, make stack, + * load high, don't patch, will return, + * uses generic INT, memory vector, + * new boot code return + */ +.short 0x01FD + nop /* extra byte to sync up disassembler */ +over_flags: + +/* Set up a C stack frame on the monitor stack. (The monitor sets cs and ds */ +/* right. The ss descriptor still references the monitor data segment.) */ + movzwl %sp, %esp /* monitor stack is a 16 bit stack */ + push %ebp + mov %esp, %ebp + push %esi + push %edi + cmp $0, 4(%ebp) /* monitor return vector is */ + je noret /* nonzero if return possible */ + incl mon_return +noret: + movl %esp, mon_sp /* save stack pointer for later return */ + +/* Copy the monitor global descriptor table to the address space of kernel and */ +/* switch over to it. Prot_init() can then update it with immediate effect. */ + + sgdt gdt+GDT_SELECTOR /* get the monitor gdtr */ + movl gdt+GDT_SELECTOR+2, %esi /* absolute address of GDT */ + mov $gdt, %ebx /* address of kernel GDT */ + mov $8*8, %ecx /* copying eight descriptors */ +copygdt: + movb %es:(%esi), %al + movb %al, (%ebx) + inc %esi + inc %ebx + loop copygdt + movl gdt+DS_SELECTOR+2, %eax /* base of kernel data */ + and $0x00FFFFFF, %eax /* only 24 bits */ + add $gdt, %eax /* eax = vir2phys(gdt) */ + movl %eax, gdt+GDT_SELECTOR+2 /* set base of GDT */ + lgdt gdt+GDT_SELECTOR /* switch over to kernel GDT */ + +/* Locate boot parameters, set up kernel segment registers and stack. */ + mov 8(%ebp), %ebx /* boot parameters offset */ + mov 12(%ebp), %edx /* boot parameters length */ + mov 16(%ebp), %eax /* address of a.out headers */ + movl %eax, aout + mov %ds, %ax /* kernel data */ + mov %ax, %es + mov %ax, %fs + mov %ax, %gs + mov %ax, %ss + mov $k_stktop, %esp /* set sp to point to the top of kernel stack */ + +/* Save boot parameters into these global variables for i386 code */ + movl %edx, params_size + movl %ebx, params_offset + movl $SS_SELECTOR, mon_ds + +/* Call C startup code to set up a proper environment to run main(). */ + push %edx + push %ebx + push $SS_SELECTOR + push $DS_SELECTOR + push $CS_SELECTOR + call cstart /* cstart(cs, ds, mds, parmoff, parmlen) */ + add $5*4, %esp + +/* Reload gdtr, idtr and the segment registers to global descriptor table set */ +/* up by prot_init(). */ + + lgdt gdt+GDT_SELECTOR + lidt gdt+IDT_SELECTOR + + ljmp $CS_SELECTOR, $csinit +csinit: + movw $DS_SELECTOR, %ax + mov %ax, %ds + mov %ax, %es + mov %ax, %fs + mov %ax, %gs + mov %ax, %ss + movw $TSS_SELECTOR, %ax /* no other TSS is used */ + ltr %ax + push $0 /* set flags to known good state */ + popf /* esp, clear nested task and int enable */ + jmp main /* main() */ + + +/*===========================================================================*/ +/* interrupt handlers */ +/* interrupt handlers for 386 32-bit protected mode */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* hwint00 - 07 */ +/*===========================================================================*/ +/* Note this is a macro, it just looks like a subroutine. */ +#define hwint_master(irq) \ + call save /* save interrupted process state */;\ + push (irq_handlers+4*irq) /* irq_handlers[irq] */;\ + call intr_handle /* intr_handle(irq_handlers[irq]) */;\ + pop %ecx ;\ + cmp $0, (irq_actids+4*irq) /* interrupt still active? */;\ + jz 0f ;\ + inb $INT_CTLMASK /* get current mask */ ;\ + orb $(1< - -.sect .text -begtext: -.sect .rom -begrom: -.sect .data -begdata: -.sect .bss -begbss: - -#include -#include -#include -#include -#include -#include "../../const.h" -#include "sconst.h" - -/* Selected 386 tss offsets. */ -#define TSS3_S_SP0 4 - -! Exported functions -! Note: in assembly language the .define statement applied to a function name -! is loosely equivalent to a prototype in C code -- it makes it possible to -! link to an entity declared in the assembly code but does not create -! the entity. - -.define _restart -.define save -.define _reload_cr3 -.define _write_cr3 ! write cr3 - -.define errexception -.define exception1 -.define exception - -.define _divide_error -.define _single_step_exception -.define _nmi -.define _breakpoint_exception -.define _overflow -.define _bounds_check -.define _inval_opcode -.define _copr_not_available -.define _double_fault -.define _copr_seg_overrun -.define _inval_tss -.define _segment_not_present -.define _stack_exception -.define _general_protection -.define _page_fault -.define _copr_error -.define _params_size -.define _params_offset -.define _mon_ds -.define _schedcheck -.define _dirtypde - -.define _hwint00 ! handlers for hardware interrupts -.define _hwint01 -.define _hwint02 -.define _hwint03 -.define _hwint04 -.define _hwint05 -.define _hwint06 -.define _hwint07 -.define _hwint08 -.define _hwint09 -.define _hwint10 -.define _hwint11 -.define _hwint12 -.define _hwint13 -.define _hwint14 -.define _hwint15 - -.define _s_call -.define _p_s_call -.define _level0_call - -! Exported variables. -.define begbss -.define begdata - -.sect .text -!*===========================================================================* -!* MINIX * -!*===========================================================================* -MINIX: ! this is the entry point for the MINIX kernel - jmp over_flags ! skip over the next few bytes - .data2 CLICK_SHIFT ! for the monitor: memory granularity -flags: - .data2 0x01FD ! boot monitor flags: - ! call in 386 mode, make bss, make stack, - ! load high, don't patch, will return, - ! uses generic INT, memory vector, - ! new boot code return - nop ! extra byte to sync up disassembler -over_flags: - -! Set up a C stack frame on the monitor stack. (The monitor sets cs and ds -! right. The ss descriptor still references the monitor data segment.) - movzx esp, sp ! monitor stack is a 16 bit stack - push ebp - mov ebp, esp - push esi - push edi - cmp 4(ebp), 0 ! monitor return vector is - jz noret ! nonzero if return possible - inc (_mon_return) -noret: mov (_mon_sp), esp ! save stack pointer for later return - -! Copy the monitor global descriptor table to the address space of kernel and -! switch over to it. Prot_init() can then update it with immediate effect. - - sgdt (_gdt+GDT_SELECTOR) ! get the monitor gdtr - mov esi, (_gdt+GDT_SELECTOR+2) ! absolute address of GDT - mov ebx, _gdt ! address of kernel GDT - mov ecx, 8*8 ! copying eight descriptors -copygdt: - eseg movb al, (esi) - movb (ebx), al - inc esi - inc ebx - loop copygdt - mov eax, (_gdt+DS_SELECTOR+2) ! base of kernel data - and eax, 0x00FFFFFF ! only 24 bits - add eax, _gdt ! eax = vir2phys(gdt) - mov (_gdt+GDT_SELECTOR+2), eax ! set base of GDT - lgdt (_gdt+GDT_SELECTOR) ! switch over to kernel GDT - -! Locate boot parameters, set up kernel segment registers and stack. - mov ebx, 8(ebp) ! boot parameters offset - mov edx, 12(ebp) ! boot parameters length - mov eax, 16(ebp) ! address of a.out headers - mov (_aout), eax - mov ax, ds ! kernel data - mov es, ax - mov fs, ax - mov gs, ax - mov ss, ax - mov esp, k_stktop ! set sp to point to the top of kernel stack - -! Save boot parameters into these global variables for i386 code - mov (_params_size), edx - mov (_params_offset), ebx - mov (_mon_ds), SS_SELECTOR - -! Call C startup code to set up a proper environment to run main(). - push edx - push ebx - push SS_SELECTOR - push DS_SELECTOR - push CS_SELECTOR - call _cstart ! cstart(cs, ds, mds, parmoff, parmlen) - add esp, 5*4 - -! Reload gdtr, idtr and the segment registers to global descriptor table set -! up by prot_init(). - - lgdt (_gdt+GDT_SELECTOR) - lidt (_gdt+IDT_SELECTOR) - - jmpf CS_SELECTOR:csinit -csinit: - o16 mov ax, DS_SELECTOR - mov ds, ax - mov es, ax - mov fs, ax - mov gs, ax - mov ss, ax - o16 mov ax, TSS_SELECTOR ! no other TSS is used - ltr ax - push 0 ! set flags to known good state - popf ! esp, clear nested task and int enable - jmp _main ! main() - - -!*===========================================================================* -!* interrupt handlers * -!* interrupt handlers for 386 32-bit protected mode * -!*===========================================================================* - -!*===========================================================================* -!* hwint00 - 07 * -!*===========================================================================* -! Note this is a macro, it just looks like a subroutine. -#define hwint_master(irq) \ - call save /* save interrupted process state */;\ - push (_irq_handlers+4*irq) /* irq_handlers[irq] */;\ - call _intr_handle /* intr_handle(irq_handlers[irq]) */;\ - pop ecx ;\ - cmp (_irq_actids+4*irq), 0 /* interrupt still active? */;\ - jz 0f ;\ - inb INT_CTLMASK /* get current mask */ ;\ - orb al, [1<