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
This commit is contained in:
parent
41d481b065
commit
403764c538
6 changed files with 1337 additions and 1257 deletions
|
@ -23,18 +23,18 @@ OBJS= arch_do_vmctl.o \
|
||||||
system.o
|
system.o
|
||||||
|
|
||||||
CPPFLAGS=-Iinclude
|
CPPFLAGS=-Iinclude
|
||||||
CFLAGS=$(CPPFLAGS) -Wall
|
CFLAGS=$(CPPFLAGS) -Wall $(CPROFILE)
|
||||||
|
|
||||||
build: $(HEAD) $(ARCHAR)
|
build: $(HEAD) $(ARCHAR)
|
||||||
|
|
||||||
$(ARCHAR): $(OBJS)
|
$(ARCHAR): $(OBJS)
|
||||||
aal cr $@ *.o
|
aal cr $@ $(OBJS)
|
||||||
|
|
||||||
depend:
|
depend:
|
||||||
mkdep "$(CC) -E $(CPPFLAGS)" *.c *.s > .depend
|
mkdep "$(CC) -E $(CPPFLAGS)" *.c *.S > .depend
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f *.a *.o *~
|
rm -f *.a *.o *~ *.tmp *.s
|
||||||
|
|
||||||
# How to build it
|
# How to build it
|
||||||
$(ARCHAR)(exception.o): exception.c
|
$(ARCHAR)(exception.o): exception.c
|
||||||
|
@ -70,11 +70,15 @@ $(ARCHAR)(do_sdevio.o): do_sdevio.c
|
||||||
$(ARCHAR)(clock.o): clock.c
|
$(ARCHAR)(clock.o): clock.c
|
||||||
$(CC) $(CFLAGS) -c $<
|
$(CC) $(CFLAGS) -c $<
|
||||||
|
|
||||||
$(ARCHAR)(klib386.o): klib386.s
|
klib386.o: klib386.S
|
||||||
$(CC) $(CFLAGS) -c $<
|
$(CC) $(CFLAGS) -E -D__ASSEMBLY__ -o $@.tmp $<
|
||||||
|
gas2ack $@.tmp $@.s
|
||||||
|
$(CC) $(CFLAGS) -c -o $@ $@.s
|
||||||
|
|
||||||
.s.o:
|
mpx386.o: mpx386.S
|
||||||
$(CC) $(CFLAGS) -c -o $@ $<
|
$(CC) $(CFLAGS) -E -D__ASSEMBLY__ -o $@.tmp $<
|
||||||
|
gas2ack $@.tmp $@.s
|
||||||
|
$(CC) $(CFLAGS) -c -o $@ $@.s
|
||||||
|
|
||||||
.c.o:
|
.c.o:
|
||||||
$(CC) $(CFLAGS) -c -o $@ $<
|
$(CC) $(CFLAGS) -c -o $@ $<
|
||||||
|
|
642
kernel/arch/i386/klib386.S
Normal file
642
kernel/arch/i386/klib386.S
Normal file
|
@ -0,0 +1,642 @@
|
||||||
|
/* sections */
|
||||||
|
|
||||||
|
.text; .data; .data; .bss
|
||||||
|
|
||||||
|
#include <minix/config.h>
|
||||||
|
#include <minix/const.h>
|
||||||
|
#include <ibm/interrupt.h>
|
||||||
|
#include <archconst.h>
|
||||||
|
#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<<CLOCK_IRQ), %eax /* keep the clock ticking */
|
||||||
|
outb $INT_CTLMASK /* enable all unused IRQ's and vv. */
|
||||||
|
movb %ah, %al
|
||||||
|
outb $INT2_CTLMASK
|
||||||
|
|
||||||
|
mov $SS_SELECTOR, %eax /* monitor data segment */
|
||||||
|
mov %ax, %ss
|
||||||
|
xchgl mon_sp, %esp /* switch stacks */
|
||||||
|
push reg86+36 /* parameters used in INT call */
|
||||||
|
push reg86+32
|
||||||
|
push reg86+28
|
||||||
|
push reg86+24
|
||||||
|
push reg86+20
|
||||||
|
push reg86+16
|
||||||
|
push reg86+12
|
||||||
|
push reg86+8
|
||||||
|
push reg86+4
|
||||||
|
push reg86+0
|
||||||
|
mov %ax, %ds /* remaining data selectors */
|
||||||
|
mov %ax, %es
|
||||||
|
mov %ax, %fs
|
||||||
|
mov %ax, %gs
|
||||||
|
push %cs
|
||||||
|
push $return /* kernel return address and selector */
|
||||||
|
ljmpw *20+2*4+10*4+2*4(%esp)
|
||||||
|
return:
|
||||||
|
pop reg86+0
|
||||||
|
pop reg86+4
|
||||||
|
pop reg86+8
|
||||||
|
pop reg86+12
|
||||||
|
pop reg86+16
|
||||||
|
pop reg86+20
|
||||||
|
pop reg86+24
|
||||||
|
pop reg86+28
|
||||||
|
pop reg86+32
|
||||||
|
pop reg86+36
|
||||||
|
lgdt gdt+GDT_SELECTOR /* reload global descriptor table */
|
||||||
|
ljmp $CS_SELECTOR, $csinit
|
||||||
|
csinit:
|
||||||
|
mov $DS_SELECTOR, %eax
|
||||||
|
mov %ax, %ds
|
||||||
|
mov %ax, %es
|
||||||
|
mov %ax, %fs
|
||||||
|
mov %ax, %gs
|
||||||
|
mov %ax, %ss
|
||||||
|
xchgl mon_sp, %esp /* unswitch stacks */
|
||||||
|
lidt gdt+IDT_SELECTOR /* reload interrupt descriptor table */
|
||||||
|
andb $~0x02, gdt+TSS_SELECTOR+DESC_ACCESS /* clear TSS busy bit */
|
||||||
|
mov $TSS_SELECTOR, %eax
|
||||||
|
ltr %ax /* set TSS register */
|
||||||
|
|
||||||
|
pop %eax
|
||||||
|
outb $INT_CTLMASK /* restore interrupt masks */
|
||||||
|
movb %ah, %al
|
||||||
|
outb $INT2_CTLMASK
|
||||||
|
|
||||||
|
addl %ecx, lost_ticks /* record lost clock ticks */
|
||||||
|
|
||||||
|
popf /* restore flags */
|
||||||
|
pop %ebx /* restore C registers */
|
||||||
|
pop %edi
|
||||||
|
pop %esi
|
||||||
|
pop %ebp
|
||||||
|
ret
|
||||||
|
|
||||||
|
/*===========================================================================*/
|
||||||
|
/* exit */
|
||||||
|
/*===========================================================================*/
|
||||||
|
/*
|
||||||
|
* PUBLIC void exit();
|
||||||
|
* Some library routines use exit, so provide a dummy version.
|
||||||
|
* Actual calls to exit cannot occur in the kernel.
|
||||||
|
* GNU CC likes to call ___main from main() for nonobvious reasons.
|
||||||
|
*/
|
||||||
|
|
||||||
|
exit:
|
||||||
|
_exit:
|
||||||
|
__exit:
|
||||||
|
sti
|
||||||
|
jmp __exit
|
||||||
|
|
||||||
|
__main:
|
||||||
|
ret
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*/
|
||||||
|
/* phys_insw */
|
||||||
|
/*===========================================================================*/
|
||||||
|
/*
|
||||||
|
* PUBLIC void phys_insw(Port_t port, phys_bytes buf, size_t count);
|
||||||
|
* Input an array from an I/O port. Absolute address version of insw().
|
||||||
|
*/
|
||||||
|
|
||||||
|
phys_insw:
|
||||||
|
push %ebp
|
||||||
|
mov %esp, %ebp
|
||||||
|
cld
|
||||||
|
push %edi
|
||||||
|
push %es
|
||||||
|
|
||||||
|
mov $FLAT_DS_SELECTOR, %ecx
|
||||||
|
mov %cx, %es
|
||||||
|
mov 8(%ebp), %edx /* port to read from */
|
||||||
|
mov 12(%ebp), %edi /* destination addr */
|
||||||
|
mov 16(%ebp), %ecx /* byte count */
|
||||||
|
shr $1, %ecx /* word count */
|
||||||
|
rep insw /* input many words */
|
||||||
|
pop %es
|
||||||
|
pop %edi
|
||||||
|
pop %ebp
|
||||||
|
ret
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*/
|
||||||
|
/* phys_insb */
|
||||||
|
/*===========================================================================*/
|
||||||
|
/*
|
||||||
|
* PUBLIC void phys_insb(Port_t port, phys_bytes buf, size_t count);
|
||||||
|
* Input an array from an I/O port. Absolute address version of insb().
|
||||||
|
*/
|
||||||
|
|
||||||
|
phys_insb:
|
||||||
|
push %ebp
|
||||||
|
mov %esp, %ebp
|
||||||
|
cld
|
||||||
|
push %edi
|
||||||
|
push %es
|
||||||
|
|
||||||
|
mov $FLAT_DS_SELECTOR, %ecx
|
||||||
|
mov %cx, %es
|
||||||
|
mov 8(%ebp), %edx /* port to read from */
|
||||||
|
mov 12(%ebp), %edi /* destination addr */
|
||||||
|
mov 16(%ebp), %ecx /* byte count */
|
||||||
|
rep insb /* input many bytes */
|
||||||
|
pop %es
|
||||||
|
pop %edi
|
||||||
|
pop %ebp
|
||||||
|
ret
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*/
|
||||||
|
/* phys_outsw */
|
||||||
|
/*===========================================================================*/
|
||||||
|
/*
|
||||||
|
* PUBLIC void phys_outsw(Port_t port, phys_bytes buf, size_t count);
|
||||||
|
* Output an array to an I/O port. Absolute address version of outsw().
|
||||||
|
*/
|
||||||
|
|
||||||
|
.balign 16
|
||||||
|
phys_outsw:
|
||||||
|
push %ebp
|
||||||
|
mov %esp, %ebp
|
||||||
|
cld
|
||||||
|
push %esi
|
||||||
|
push %ds
|
||||||
|
|
||||||
|
mov $FLAT_DS_SELECTOR, %ecx
|
||||||
|
mov %cx, %ds
|
||||||
|
mov 8(%ebp), %edx /* port to write to */
|
||||||
|
mov 12(%ebp), %esi /* source addr */
|
||||||
|
mov 16(%ebp), %ecx /* byte count */
|
||||||
|
shr $1, %ecx /* word count */
|
||||||
|
rep outsw /* output many words */
|
||||||
|
pop %ds
|
||||||
|
pop %esi
|
||||||
|
pop %ebp
|
||||||
|
ret
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*/
|
||||||
|
/* phys_outsb */
|
||||||
|
/*===========================================================================*/
|
||||||
|
/*
|
||||||
|
* PUBLIC void phys_outsb(Port_t port, phys_bytes buf, size_t count);
|
||||||
|
* Output an array to an I/O port. Absolute address version of outsb().
|
||||||
|
*/
|
||||||
|
|
||||||
|
.balign 16
|
||||||
|
phys_outsb:
|
||||||
|
push %ebp
|
||||||
|
mov %esp, %ebp
|
||||||
|
cld
|
||||||
|
push %esi
|
||||||
|
push %ds
|
||||||
|
|
||||||
|
mov $FLAT_DS_SELECTOR, %ecx
|
||||||
|
mov %cx, %ds
|
||||||
|
mov 8(%ebp), %edx /* port to write to */
|
||||||
|
mov 12(%ebp), %esi /* source addr */
|
||||||
|
mov 16(%ebp), %ecx /* byte count */
|
||||||
|
rep outsb /* output many bytes */
|
||||||
|
pop %ds
|
||||||
|
pop %esi
|
||||||
|
pop %ebp
|
||||||
|
ret
|
||||||
|
|
||||||
|
|
||||||
|
/*==========================================================================*/
|
||||||
|
/* intr_unmask */
|
||||||
|
/*==========================================================================*/
|
||||||
|
/*
|
||||||
|
* PUBLIC void intr_unmask(irq_hook_t *hook)
|
||||||
|
* Enable an interrupt request line by clearing an 8259 bit.
|
||||||
|
* Equivalent C code for hook->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
|
||||||
|
|
|
@ -1,607 +0,0 @@
|
||||||
#
|
|
||||||
! sections
|
|
||||||
|
|
||||||
.sect .text; .sect .rom; .sect .data; .sect .bss
|
|
||||||
|
|
||||||
#include <minix/config.h>
|
|
||||||
#include <minix/const.h>
|
|
||||||
#include <ibm/interrupt.h>
|
|
||||||
#include <archconst.h>
|
|
||||||
#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<<CLOCK_IRQ] ! keep the clock ticking
|
|
||||||
outb INT_CTLMASK ! enable all unused IRQ's and vv.
|
|
||||||
movb al, ah
|
|
||||||
outb INT2_CTLMASK
|
|
||||||
|
|
||||||
mov eax, SS_SELECTOR ! monitor data segment
|
|
||||||
mov ss, ax
|
|
||||||
xchg esp, (_mon_sp) ! switch stacks
|
|
||||||
push (_reg86+36) ! parameters used in INT call
|
|
||||||
push (_reg86+32)
|
|
||||||
push (_reg86+28)
|
|
||||||
push (_reg86+24)
|
|
||||||
push (_reg86+20)
|
|
||||||
push (_reg86+16)
|
|
||||||
push (_reg86+12)
|
|
||||||
push (_reg86+ 8)
|
|
||||||
push (_reg86+ 4)
|
|
||||||
push (_reg86+ 0)
|
|
||||||
mov ds, ax ! remaining data selectors
|
|
||||||
mov es, ax
|
|
||||||
mov fs, ax
|
|
||||||
mov gs, ax
|
|
||||||
push cs
|
|
||||||
push return ! kernel return address and selector
|
|
||||||
o16 jmpf 20+2*4+10*4+2*4(esp) ! make the call
|
|
||||||
return:
|
|
||||||
pop (_reg86+ 0)
|
|
||||||
pop (_reg86+ 4)
|
|
||||||
pop (_reg86+ 8)
|
|
||||||
pop (_reg86+12)
|
|
||||||
pop (_reg86+16)
|
|
||||||
pop (_reg86+20)
|
|
||||||
pop (_reg86+24)
|
|
||||||
pop (_reg86+28)
|
|
||||||
pop (_reg86+32)
|
|
||||||
pop (_reg86+36)
|
|
||||||
lgdt (_gdt+GDT_SELECTOR) ! reload global descriptor table
|
|
||||||
jmpf CS_SELECTOR:csinit ! restore everything
|
|
||||||
csinit: mov eax, DS_SELECTOR
|
|
||||||
mov ds, ax
|
|
||||||
mov es, ax
|
|
||||||
mov fs, ax
|
|
||||||
mov gs, ax
|
|
||||||
mov ss, ax
|
|
||||||
xchg esp, (_mon_sp) ! unswitch stacks
|
|
||||||
lidt (_gdt+IDT_SELECTOR) ! reload interrupt descriptor table
|
|
||||||
andb (_gdt+TSS_SELECTOR+DESC_ACCESS), ~0x02 ! clear TSS busy bit
|
|
||||||
mov eax, TSS_SELECTOR
|
|
||||||
ltr ax ! set TSS register
|
|
||||||
|
|
||||||
pop eax
|
|
||||||
outb INT_CTLMASK ! restore interrupt masks
|
|
||||||
movb al, ah
|
|
||||||
outb INT2_CTLMASK
|
|
||||||
|
|
||||||
add (_lost_ticks), ecx ! record lost clock ticks
|
|
||||||
|
|
||||||
popf ! restore flags
|
|
||||||
pop ebx ! restore C registers
|
|
||||||
pop edi
|
|
||||||
pop esi
|
|
||||||
pop ebp
|
|
||||||
ret
|
|
||||||
|
|
||||||
|
|
||||||
!*===========================================================================*
|
|
||||||
!* exit *
|
|
||||||
!*===========================================================================*
|
|
||||||
! PUBLIC void exit();
|
|
||||||
! Some library routines use exit, so provide a dummy version.
|
|
||||||
! Actual calls to exit cannot occur in the kernel.
|
|
||||||
! GNU CC likes to call ___main from main() for nonobvious reasons.
|
|
||||||
|
|
||||||
_exit:
|
|
||||||
__exit:
|
|
||||||
___exit:
|
|
||||||
sti
|
|
||||||
jmp ___exit
|
|
||||||
|
|
||||||
___main:
|
|
||||||
ret
|
|
||||||
|
|
||||||
|
|
||||||
!*===========================================================================*
|
|
||||||
!* phys_insw *
|
|
||||||
!*===========================================================================*
|
|
||||||
! PUBLIC void phys_insw(Port_t port, phys_bytes buf, size_t count);
|
|
||||||
! Input an array from an I/O port. Absolute address version of insw().
|
|
||||||
|
|
||||||
_phys_insw:
|
|
||||||
push ebp
|
|
||||||
mov ebp, esp
|
|
||||||
cld
|
|
||||||
push edi
|
|
||||||
push es
|
|
||||||
|
|
||||||
mov ecx, FLAT_DS_SELECTOR
|
|
||||||
mov es, cx
|
|
||||||
mov edx, 8(ebp) ! port to read from
|
|
||||||
mov edi, 12(ebp) ! destination addr
|
|
||||||
mov ecx, 16(ebp) ! byte count
|
|
||||||
shr ecx, 1 ! word count
|
|
||||||
rep o16 ins ! input many words
|
|
||||||
pop es
|
|
||||||
pop edi
|
|
||||||
pop ebp
|
|
||||||
ret
|
|
||||||
|
|
||||||
|
|
||||||
!*===========================================================================*
|
|
||||||
!* phys_insb *
|
|
||||||
!*===========================================================================*
|
|
||||||
! PUBLIC void phys_insb(Port_t port, phys_bytes buf, size_t count);
|
|
||||||
! Input an array from an I/O port. Absolute address version of insb().
|
|
||||||
|
|
||||||
_phys_insb:
|
|
||||||
push ebp
|
|
||||||
mov ebp, esp
|
|
||||||
cld
|
|
||||||
push edi
|
|
||||||
push es
|
|
||||||
|
|
||||||
mov ecx, FLAT_DS_SELECTOR
|
|
||||||
mov es, cx
|
|
||||||
mov edx, 8(ebp) ! port to read from
|
|
||||||
mov edi, 12(ebp) ! destination addr
|
|
||||||
mov ecx, 16(ebp) ! byte count
|
|
||||||
! shr ecx, 1 ! word count
|
|
||||||
rep insb ! input many bytes
|
|
||||||
pop es
|
|
||||||
pop edi
|
|
||||||
pop ebp
|
|
||||||
ret
|
|
||||||
|
|
||||||
|
|
||||||
!*===========================================================================*
|
|
||||||
!* phys_outsw *
|
|
||||||
!*===========================================================================*
|
|
||||||
! PUBLIC void phys_outsw(Port_t port, phys_bytes buf, size_t count);
|
|
||||||
! Output an array to an I/O port. Absolute address version of outsw().
|
|
||||||
|
|
||||||
.align 16
|
|
||||||
_phys_outsw:
|
|
||||||
push ebp
|
|
||||||
mov ebp, esp
|
|
||||||
cld
|
|
||||||
push esi
|
|
||||||
push ds
|
|
||||||
|
|
||||||
mov ecx, FLAT_DS_SELECTOR
|
|
||||||
mov ds, cx
|
|
||||||
mov edx, 8(ebp) ! port to write to
|
|
||||||
mov esi, 12(ebp) ! source addr
|
|
||||||
mov ecx, 16(ebp) ! byte count
|
|
||||||
shr ecx, 1 ! word count
|
|
||||||
rep o16 outs ! output many words
|
|
||||||
pop ds
|
|
||||||
pop esi
|
|
||||||
pop ebp
|
|
||||||
ret
|
|
||||||
|
|
||||||
|
|
||||||
!*===========================================================================*
|
|
||||||
!* phys_outsb *
|
|
||||||
!*===========================================================================*
|
|
||||||
! PUBLIC void phys_outsb(Port_t port, phys_bytes buf, size_t count);
|
|
||||||
! Output an array to an I/O port. Absolute address version of outsb().
|
|
||||||
|
|
||||||
.align 16
|
|
||||||
_phys_outsb:
|
|
||||||
push ebp
|
|
||||||
mov ebp, esp
|
|
||||||
cld
|
|
||||||
push esi
|
|
||||||
push ds
|
|
||||||
|
|
||||||
mov ecx, FLAT_DS_SELECTOR
|
|
||||||
mov ds, cx
|
|
||||||
mov edx, 8(ebp) ! port to write to
|
|
||||||
mov esi, 12(ebp) ! source addr
|
|
||||||
mov ecx, 16(ebp) ! byte count
|
|
||||||
rep outsb ! output many bytes
|
|
||||||
pop ds
|
|
||||||
pop esi
|
|
||||||
pop ebp
|
|
||||||
ret
|
|
||||||
|
|
||||||
|
|
||||||
!*==========================================================================*
|
|
||||||
!* intr_unmask *
|
|
||||||
!*==========================================================================*/
|
|
||||||
! PUBLIC void intr_unmask(irq_hook_t *hook)
|
|
||||||
! Enable an interrupt request line by clearing an 8259 bit.
|
|
||||||
! Equivalent C code for hook->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
|
|
||||||
|
|
656
kernel/arch/i386/mpx386.S
Normal file
656
kernel/arch/i386/mpx386.S
Normal file
|
@ -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 <sys/vm_i386.h>
|
||||||
|
|
||||||
|
#ifdef __ACK__
|
||||||
|
.text
|
||||||
|
begtext:
|
||||||
|
#ifdef __ACK__
|
||||||
|
.rom
|
||||||
|
#else
|
||||||
|
.data
|
||||||
|
#endif
|
||||||
|
begrom:
|
||||||
|
.data
|
||||||
|
begdata:
|
||||||
|
.bss
|
||||||
|
begbss:
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#include <minix/config.h>
|
||||||
|
#include <minix/const.h>
|
||||||
|
#include <minix/com.h>
|
||||||
|
#include <ibm/interrupt.h>
|
||||||
|
#include <archconst.h>
|
||||||
|
#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<<irq), %al /* mask irq */ ;\
|
||||||
|
outb $INT_CTLMASK /* disable the irq */;\
|
||||||
|
0: movb $END_OF_INT, %al ;\
|
||||||
|
outb $INT_CTL /* reenable master 8259 */;\
|
||||||
|
ret /* restart (another) process */
|
||||||
|
|
||||||
|
/* Each of these entry points is an expansion of the hwint_master macro */
|
||||||
|
.balign 16
|
||||||
|
hwint00:
|
||||||
|
/* Interrupt routine for irq 0 (the clock). */
|
||||||
|
hwint_master(0)
|
||||||
|
|
||||||
|
.balign 16
|
||||||
|
hwint01:
|
||||||
|
/* Interrupt routine for irq 1 (keyboard) */
|
||||||
|
hwint_master(1)
|
||||||
|
|
||||||
|
.balign 16
|
||||||
|
hwint02:
|
||||||
|
/* Interrupt routine for irq 2 (cascade!) */
|
||||||
|
hwint_master(2)
|
||||||
|
|
||||||
|
.balign 16
|
||||||
|
hwint03:
|
||||||
|
/* Interrupt routine for irq 3 (second serial) */
|
||||||
|
hwint_master(3)
|
||||||
|
|
||||||
|
.balign 16
|
||||||
|
hwint04:
|
||||||
|
/* Interrupt routine for irq 4 (first serial) */
|
||||||
|
hwint_master(4)
|
||||||
|
|
||||||
|
.balign 16
|
||||||
|
hwint05:
|
||||||
|
/* Interrupt routine for irq 5 (XT winchester) */
|
||||||
|
hwint_master(5)
|
||||||
|
|
||||||
|
.balign 16
|
||||||
|
hwint06:
|
||||||
|
/* Interrupt routine for irq 6 (floppy) */
|
||||||
|
hwint_master(6)
|
||||||
|
|
||||||
|
.balign 16
|
||||||
|
hwint07:
|
||||||
|
/* Interrupt routine for irq 7 (printer) */
|
||||||
|
hwint_master(7)
|
||||||
|
|
||||||
|
/*===========================================================================*/
|
||||||
|
/* hwint08 - 15 */
|
||||||
|
/*===========================================================================*/
|
||||||
|
/* Note this is a macro, it just looks like a subroutine. */
|
||||||
|
#define hwint_slave(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 $INT2_CTLMASK ;\
|
||||||
|
orb $(1<<(irq-8)), %al ;\
|
||||||
|
outb $INT2_CTLMASK /* disable the irq */;\
|
||||||
|
0: movb $END_OF_INT, %al ;\
|
||||||
|
outb $INT_CTL /* reenable master 8259 */;\
|
||||||
|
outb $INT2_CTL /* reenable slave 8259 */;\
|
||||||
|
ret /* restart (another) process */
|
||||||
|
|
||||||
|
/* Each of these entry points is an expansion of the hwint_slave macro */
|
||||||
|
.balign 16
|
||||||
|
hwint08:
|
||||||
|
/* Interrupt routine for irq 8 (realtime clock) */
|
||||||
|
hwint_slave(8)
|
||||||
|
|
||||||
|
.balign 16
|
||||||
|
hwint09:
|
||||||
|
/* Interrupt routine for irq 9 (irq 2 redirected) */
|
||||||
|
hwint_slave(9)
|
||||||
|
|
||||||
|
.balign 16
|
||||||
|
hwint10:
|
||||||
|
/* Interrupt routine for irq 10 */
|
||||||
|
hwint_slave(10)
|
||||||
|
|
||||||
|
.balign 16
|
||||||
|
hwint11:
|
||||||
|
/* Interrupt routine for irq 11 */
|
||||||
|
hwint_slave(11)
|
||||||
|
|
||||||
|
.balign 16
|
||||||
|
hwint12:
|
||||||
|
/* Interrupt routine for irq 12 */
|
||||||
|
hwint_slave(12)
|
||||||
|
|
||||||
|
.balign 16
|
||||||
|
hwint13:
|
||||||
|
/* Interrupt routine for irq 13 (FPU exception) */
|
||||||
|
hwint_slave(13)
|
||||||
|
|
||||||
|
.balign 16
|
||||||
|
hwint14:
|
||||||
|
/* Interrupt routine for irq 14 (AT winchester) */
|
||||||
|
hwint_slave(14)
|
||||||
|
|
||||||
|
.balign 16
|
||||||
|
hwint15:
|
||||||
|
/* Interrupt routine for irq 15 */
|
||||||
|
hwint_slave(15)
|
||||||
|
|
||||||
|
/*===========================================================================*/
|
||||||
|
/* save */
|
||||||
|
/*===========================================================================*/
|
||||||
|
/*
|
||||||
|
* Save for protected mode.
|
||||||
|
* This is much simpler than for 8086 mode, because the stack already points
|
||||||
|
* into the process table, or has already been switched to the kernel stack.
|
||||||
|
*/
|
||||||
|
|
||||||
|
.balign 16
|
||||||
|
save:
|
||||||
|
cld /* set direction flag to a known value */
|
||||||
|
pushal /* save "general" registers */
|
||||||
|
pushw %ds /* save ds */
|
||||||
|
pushw %es /* save es */
|
||||||
|
pushw %fs /* save fs */
|
||||||
|
pushw %gs /* save gs */
|
||||||
|
mov %ss, %dx /* ss is kernel data segment */
|
||||||
|
mov %dx, %ds /* load rest of kernel segments */
|
||||||
|
mov %dx, %es /* kernel does not use fs, gs */
|
||||||
|
mov %esp, %eax /* prepare to return */
|
||||||
|
incb k_reenter /* from -1 if not reentering */
|
||||||
|
jne set_restart1 /* stack is already kernel stack */
|
||||||
|
mov $k_stktop, %esp
|
||||||
|
push $restart /* build return address for int handler */
|
||||||
|
xor %ebp, %ebp /* for stacktrace */
|
||||||
|
jmp *RETADR-P_STACKBASE(%eax)
|
||||||
|
|
||||||
|
.balign 4
|
||||||
|
set_restart1:
|
||||||
|
push $restart1
|
||||||
|
jmp *RETADR-P_STACKBASE(%eax)
|
||||||
|
|
||||||
|
/*===========================================================================*/
|
||||||
|
/* _s_call */
|
||||||
|
/*===========================================================================*/
|
||||||
|
.balign 16
|
||||||
|
s_call:
|
||||||
|
p_s_call:
|
||||||
|
cld /* set direction flag to a known value */
|
||||||
|
sub $4, %esp /* skip RETADR */
|
||||||
|
pusha /* save "general" registers */
|
||||||
|
pushw %ds
|
||||||
|
pushw %es
|
||||||
|
pushw %fs
|
||||||
|
pushw %gs
|
||||||
|
|
||||||
|
mov %ss, %si /* ss is kernel data segment */
|
||||||
|
mov %si, %ds /* load rest of kernel segments */
|
||||||
|
mov %si, %es /* kernel does not use fs, gs */
|
||||||
|
incb k_reenter /* increment kernel entry count */
|
||||||
|
mov %esp, %esi /* assumes P_STACKBASE == 0 */
|
||||||
|
mov $k_stktop, %esp
|
||||||
|
xor %ebp, %ebp /* for stacktrace */
|
||||||
|
/* end of inline save */
|
||||||
|
/* now set up parameters for sys_call() */
|
||||||
|
push %edx /* event set or flags bit map */
|
||||||
|
push %ebx /* pointer to user message */
|
||||||
|
push %eax /* source / destination */
|
||||||
|
push %ecx /* call number (ipc primitive to use) */
|
||||||
|
|
||||||
|
call sys_call /* sys_call(call_nr, src_dst, m_ptr, bit_map) */
|
||||||
|
/* caller is now explicitly in proc_ptr */
|
||||||
|
mov %eax, AXREG(%esi)
|
||||||
|
|
||||||
|
/* Fall into code to restart proc/task running. */
|
||||||
|
|
||||||
|
/*===========================================================================*/
|
||||||
|
/* restart */
|
||||||
|
/*===========================================================================*/
|
||||||
|
restart:
|
||||||
|
|
||||||
|
/* Restart the current process or the next process if it is set. */
|
||||||
|
|
||||||
|
cli
|
||||||
|
call schedcheck
|
||||||
|
movl proc_ptr, %esp /* will assume P_STACKBASE == 0 */
|
||||||
|
lldt P_LDT_SEL(%esp) /* enable process' segment descriptors */
|
||||||
|
cmpl $0, P_CR3(%esp)
|
||||||
|
jz 0f
|
||||||
|
mov P_CR3(%esp), %eax
|
||||||
|
cmpl loadedcr3, %eax
|
||||||
|
jz 0f
|
||||||
|
mov %eax, %cr3
|
||||||
|
mov %eax, loadedcr3
|
||||||
|
mov proc_ptr, %eax
|
||||||
|
mov %eax, ptproc
|
||||||
|
movl $0, dirtypde
|
||||||
|
0:
|
||||||
|
lea P_STACKTOP(%esp), %eax /* arrange for next interrupt */
|
||||||
|
movl %eax, tss+TSS3_S_SP0 /* to save state in process table */
|
||||||
|
restart1:
|
||||||
|
decb k_reenter
|
||||||
|
popw %gs
|
||||||
|
popw %fs
|
||||||
|
popw %es
|
||||||
|
popw %ds
|
||||||
|
popal
|
||||||
|
add $4, %esp /* skip return adr */
|
||||||
|
iret /* continue process */
|
||||||
|
|
||||||
|
/*===========================================================================*/
|
||||||
|
/* exception handlers */
|
||||||
|
/*===========================================================================*/
|
||||||
|
divide_error:
|
||||||
|
push $DIVIDE_VECTOR
|
||||||
|
jmp handle_exception
|
||||||
|
|
||||||
|
single_step_exception:
|
||||||
|
push $DEBUG_VECTOR
|
||||||
|
jmp handle_exception
|
||||||
|
|
||||||
|
nmi:
|
||||||
|
push $NMI_VECTOR
|
||||||
|
jmp handle_exception
|
||||||
|
|
||||||
|
breakpoint_exception:
|
||||||
|
push $BREAKPOINT_VECTOR
|
||||||
|
jmp handle_exception
|
||||||
|
|
||||||
|
overflow:
|
||||||
|
push $OVERFLOW_VECTOR
|
||||||
|
jmp handle_exception
|
||||||
|
|
||||||
|
bounds_check:
|
||||||
|
push $BOUNDS_VECTOR
|
||||||
|
jmp handle_exception
|
||||||
|
|
||||||
|
inval_opcode:
|
||||||
|
push $INVAL_OP_VECTOR
|
||||||
|
jmp handle_exception
|
||||||
|
|
||||||
|
copr_not_available:
|
||||||
|
push $COPROC_NOT_VECTOR
|
||||||
|
jmp handle_exception
|
||||||
|
|
||||||
|
double_fault:
|
||||||
|
push $DOUBLE_FAULT_VECTOR
|
||||||
|
jmp errexception
|
||||||
|
|
||||||
|
copr_seg_overrun:
|
||||||
|
push $COPROC_SEG_VECTOR
|
||||||
|
jmp handle_exception
|
||||||
|
|
||||||
|
inval_tss:
|
||||||
|
push $INVAL_TSS_VECTOR
|
||||||
|
jmp errexception
|
||||||
|
|
||||||
|
segment_not_present:
|
||||||
|
push $SEG_NOT_VECTOR
|
||||||
|
jmp errexception
|
||||||
|
|
||||||
|
stack_exception:
|
||||||
|
push $STACK_FAULT_VECTOR
|
||||||
|
jmp errexception
|
||||||
|
|
||||||
|
general_protection:
|
||||||
|
push $PROTECTION_VECTOR
|
||||||
|
jmp errexception
|
||||||
|
|
||||||
|
page_fault:
|
||||||
|
push $PAGE_FAULT_VECTOR
|
||||||
|
push %eax
|
||||||
|
mov %cr2, %eax
|
||||||
|
movl %eax, %ss:pagefaultcr2
|
||||||
|
pop %eax
|
||||||
|
jmp errexception
|
||||||
|
|
||||||
|
copr_error:
|
||||||
|
push $COPROC_ERR_VECTOR
|
||||||
|
jmp handle_exception
|
||||||
|
|
||||||
|
/*===========================================================================*/
|
||||||
|
/* handle_exception */
|
||||||
|
/*===========================================================================*/
|
||||||
|
/* This is called for all exceptions which do not push an error code. */
|
||||||
|
|
||||||
|
.balign 16
|
||||||
|
handle_exception:
|
||||||
|
movl $0, %ss:trap_errno /* clear trap_errno */
|
||||||
|
pop %ss:ex_number
|
||||||
|
jmp exception1
|
||||||
|
|
||||||
|
/*===========================================================================*/
|
||||||
|
/* errexception */
|
||||||
|
/*===========================================================================*/
|
||||||
|
/* This is called for all exceptions which push an error code. */
|
||||||
|
|
||||||
|
.balign 16
|
||||||
|
errexception:
|
||||||
|
pop %ss:ex_number
|
||||||
|
pop %ss:trap_errno
|
||||||
|
exception1:
|
||||||
|
/* Common for all exceptions. */
|
||||||
|
movl %esp, %ss:old_eax_ptr /* where will eax be saved */
|
||||||
|
subl $PCREG-AXREG, %ss:old_eax_ptr /* here */
|
||||||
|
|
||||||
|
push %eax /* eax is scratch register */
|
||||||
|
|
||||||
|
mov 0+4(%esp), %eax /* old eip */
|
||||||
|
movl %eax, %ss:old_eip
|
||||||
|
mov %esp, %eax
|
||||||
|
add $4, %eax
|
||||||
|
mov %eax, %ss:old_eip_ptr
|
||||||
|
movzwl 4+4(%esp), %eax /* old cs */
|
||||||
|
movl %eax, %ss:old_cs
|
||||||
|
mov 8+4(%esp), %eax /* old eflags */
|
||||||
|
movl %eax, %ss:old_eflags
|
||||||
|
|
||||||
|
pop %eax
|
||||||
|
call save
|
||||||
|
push pagefaultcr2
|
||||||
|
push old_eax_ptr
|
||||||
|
push old_eip_ptr
|
||||||
|
push old_eflags
|
||||||
|
push old_cs
|
||||||
|
push old_eip
|
||||||
|
push trap_errno
|
||||||
|
push ex_number
|
||||||
|
call exception /* (ex_number, trap_errno, old_eip, */
|
||||||
|
/* old_cs, old_eflags) */
|
||||||
|
add $8*4, %esp
|
||||||
|
ret
|
||||||
|
|
||||||
|
/*===========================================================================*/
|
||||||
|
/* write_cr3 */
|
||||||
|
/*===========================================================================*/
|
||||||
|
/* PUBLIC void write_cr3(unsigned long value); */
|
||||||
|
write_cr3:
|
||||||
|
push %ebp
|
||||||
|
mov %esp, %ebp
|
||||||
|
mov 8(%ebp), %eax
|
||||||
|
cmpl loadedcr3, %eax
|
||||||
|
jz 0f
|
||||||
|
mov %eax, %cr3
|
||||||
|
mov %eax, loadedcr3
|
||||||
|
movl $0, dirtypde
|
||||||
|
0:
|
||||||
|
pop %ebp
|
||||||
|
ret
|
||||||
|
|
||||||
|
/*===========================================================================*/
|
||||||
|
/* level0_call */
|
||||||
|
/*===========================================================================*/
|
||||||
|
level0_call:
|
||||||
|
/*
|
||||||
|
* which level0 function to call was passed here by putting it in eax, so
|
||||||
|
* we get that from the saved state.
|
||||||
|
*/
|
||||||
|
call save
|
||||||
|
movl proc_ptr, %eax
|
||||||
|
movl AXREG(%eax), %eax
|
||||||
|
jmp *%eax
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*/
|
||||||
|
/* reload_cr3 */
|
||||||
|
/*===========================================================================*/
|
||||||
|
/* PUBLIC void reload_cr3(void); */
|
||||||
|
reload_cr3:
|
||||||
|
push %ebp
|
||||||
|
mov %esp, %ebp
|
||||||
|
movl $0, dirtypde
|
||||||
|
mov %cr3, %eax
|
||||||
|
mov %eax, %cr3
|
||||||
|
pop %ebp
|
||||||
|
ret
|
||||||
|
|
||||||
|
/*===========================================================================*/
|
||||||
|
/* data */
|
||||||
|
/*===========================================================================*/
|
||||||
|
|
||||||
|
#ifdef __ACK__
|
||||||
|
.rom /* Before the string table please */
|
||||||
|
#else
|
||||||
|
.data
|
||||||
|
#endif
|
||||||
|
.short 0x526F /* this must be the first data entry (magic #) */
|
||||||
|
|
||||||
|
.bss
|
||||||
|
k_stack:
|
||||||
|
.space K_STACK_BYTES /* kernel stack */
|
||||||
|
k_stktop:
|
||||||
|
/* top of kernel stack */
|
||||||
|
.lcomm ex_number, 4
|
||||||
|
.lcomm trap_errno, 4
|
||||||
|
.lcomm old_eip_ptr, 4
|
||||||
|
.lcomm old_eax_ptr, 4
|
||||||
|
.lcomm old_eip, 4
|
||||||
|
.lcomm old_cs, 4
|
||||||
|
.lcomm old_eflags, 4
|
||||||
|
.lcomm pagefaultcr2, 4
|
||||||
|
.lcomm loadedcr3, 4
|
|
@ -1,615 +0,0 @@
|
||||||
#
|
|
||||||
! 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 <sys/vm_i386.h>
|
|
||||||
|
|
||||||
.sect .text
|
|
||||||
begtext:
|
|
||||||
.sect .rom
|
|
||||||
begrom:
|
|
||||||
.sect .data
|
|
||||||
begdata:
|
|
||||||
.sect .bss
|
|
||||||
begbss:
|
|
||||||
|
|
||||||
#include <minix/config.h>
|
|
||||||
#include <minix/const.h>
|
|
||||||
#include <minix/com.h>
|
|
||||||
#include <ibm/interrupt.h>
|
|
||||||
#include <archconst.h>
|
|
||||||
#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<<irq] /* mask irq */ ;\
|
|
||||||
outb INT_CTLMASK /* disable the irq */;\
|
|
||||||
0: movb al, END_OF_INT ;\
|
|
||||||
outb INT_CTL /* reenable master 8259 */;\
|
|
||||||
ret /* restart (another) process */
|
|
||||||
|
|
||||||
! Each of these entry points is an expansion of the hwint_master macro
|
|
||||||
.align 16
|
|
||||||
_hwint00: ! Interrupt routine for irq 0 (the clock).
|
|
||||||
hwint_master(0)
|
|
||||||
|
|
||||||
.align 16
|
|
||||||
_hwint01: ! Interrupt routine for irq 1 (keyboard)
|
|
||||||
hwint_master(1)
|
|
||||||
|
|
||||||
.align 16
|
|
||||||
_hwint02: ! Interrupt routine for irq 2 (cascade!)
|
|
||||||
hwint_master(2)
|
|
||||||
|
|
||||||
.align 16
|
|
||||||
_hwint03: ! Interrupt routine for irq 3 (second serial)
|
|
||||||
hwint_master(3)
|
|
||||||
|
|
||||||
.align 16
|
|
||||||
_hwint04: ! Interrupt routine for irq 4 (first serial)
|
|
||||||
hwint_master(4)
|
|
||||||
|
|
||||||
.align 16
|
|
||||||
_hwint05: ! Interrupt routine for irq 5 (XT winchester)
|
|
||||||
hwint_master(5)
|
|
||||||
|
|
||||||
.align 16
|
|
||||||
_hwint06: ! Interrupt routine for irq 6 (floppy)
|
|
||||||
hwint_master(6)
|
|
||||||
|
|
||||||
.align 16
|
|
||||||
_hwint07: ! Interrupt routine for irq 7 (printer)
|
|
||||||
hwint_master(7)
|
|
||||||
|
|
||||||
!*===========================================================================*
|
|
||||||
!* hwint08 - 15 *
|
|
||||||
!*===========================================================================*
|
|
||||||
! Note this is a macro, it just looks like a subroutine.
|
|
||||||
#define hwint_slave(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 INT2_CTLMASK ;\
|
|
||||||
orb al, [1<<[irq-8]] ;\
|
|
||||||
outb INT2_CTLMASK /* disable the irq */;\
|
|
||||||
0: movb al, END_OF_INT ;\
|
|
||||||
outb INT_CTL /* reenable master 8259 */;\
|
|
||||||
outb INT2_CTL /* reenable slave 8259 */;\
|
|
||||||
ret /* restart (another) process */
|
|
||||||
|
|
||||||
! Each of these entry points is an expansion of the hwint_slave macro
|
|
||||||
.align 16
|
|
||||||
_hwint08: ! Interrupt routine for irq 8 (realtime clock)
|
|
||||||
hwint_slave(8)
|
|
||||||
|
|
||||||
.align 16
|
|
||||||
_hwint09: ! Interrupt routine for irq 9 (irq 2 redirected)
|
|
||||||
hwint_slave(9)
|
|
||||||
|
|
||||||
.align 16
|
|
||||||
_hwint10: ! Interrupt routine for irq 10
|
|
||||||
hwint_slave(10)
|
|
||||||
|
|
||||||
.align 16
|
|
||||||
_hwint11: ! Interrupt routine for irq 11
|
|
||||||
hwint_slave(11)
|
|
||||||
|
|
||||||
.align 16
|
|
||||||
_hwint12: ! Interrupt routine for irq 12
|
|
||||||
hwint_slave(12)
|
|
||||||
|
|
||||||
.align 16
|
|
||||||
_hwint13: ! Interrupt routine for irq 13 (FPU exception)
|
|
||||||
hwint_slave(13)
|
|
||||||
|
|
||||||
.align 16
|
|
||||||
_hwint14: ! Interrupt routine for irq 14 (AT winchester)
|
|
||||||
hwint_slave(14)
|
|
||||||
|
|
||||||
.align 16
|
|
||||||
_hwint15: ! Interrupt routine for irq 15
|
|
||||||
hwint_slave(15)
|
|
||||||
|
|
||||||
!*===========================================================================*
|
|
||||||
!* save *
|
|
||||||
!*===========================================================================*
|
|
||||||
! Save for protected mode.
|
|
||||||
! This is much simpler than for 8086 mode, because the stack already points
|
|
||||||
! into the process table, or has already been switched to the kernel stack.
|
|
||||||
|
|
||||||
.align 16
|
|
||||||
save:
|
|
||||||
cld ! set direction flag to a known value
|
|
||||||
pushad ! save "general" registers
|
|
||||||
o16 push ds ! save ds
|
|
||||||
o16 push es ! save es
|
|
||||||
o16 push fs ! save fs
|
|
||||||
o16 push gs ! save gs
|
|
||||||
mov dx, ss ! ss is kernel data segment
|
|
||||||
mov ds, dx ! load rest of kernel segments
|
|
||||||
mov es, dx ! kernel does not use fs, gs
|
|
||||||
mov eax, esp ! prepare to return
|
|
||||||
incb (_k_reenter) ! from -1 if not reentering
|
|
||||||
jnz set_restart1 ! stack is already kernel stack
|
|
||||||
mov esp, k_stktop
|
|
||||||
push _restart ! build return address for int handler
|
|
||||||
xor ebp, ebp ! for stacktrace
|
|
||||||
jmp RETADR-P_STACKBASE(eax)
|
|
||||||
|
|
||||||
.align 4
|
|
||||||
set_restart1:
|
|
||||||
push restart1
|
|
||||||
jmp RETADR-P_STACKBASE(eax)
|
|
||||||
|
|
||||||
!*===========================================================================*
|
|
||||||
!* _s_call *
|
|
||||||
!*===========================================================================*
|
|
||||||
.align 16
|
|
||||||
_s_call:
|
|
||||||
_p_s_call:
|
|
||||||
cld ! set direction flag to a known value
|
|
||||||
sub esp, 4 ! skip RETADR
|
|
||||||
pushad ! save "general" registers
|
|
||||||
o16 push ds
|
|
||||||
o16 push es
|
|
||||||
o16 push fs
|
|
||||||
o16 push gs
|
|
||||||
|
|
||||||
mov si, ss ! ss is kernel data segment
|
|
||||||
mov ds, si ! load rest of kernel segments
|
|
||||||
mov es, si ! kernel does not use fs, gs
|
|
||||||
incb (_k_reenter) ! increment kernel entry count
|
|
||||||
mov esi, esp ! assumes P_STACKBASE == 0
|
|
||||||
mov esp, k_stktop
|
|
||||||
xor ebp, ebp ! for stacktrace
|
|
||||||
! end of inline save
|
|
||||||
! now set up parameters for sys_call()
|
|
||||||
push edx ! event set or flags bit map
|
|
||||||
push ebx ! pointer to user message
|
|
||||||
push eax ! source / destination
|
|
||||||
push ecx ! call number (ipc primitive to use)
|
|
||||||
|
|
||||||
call _sys_call ! sys_call(call_nr, src_dst, m_ptr, bit_map)
|
|
||||||
! caller is now explicitly in proc_ptr
|
|
||||||
mov AXREG(esi), eax
|
|
||||||
|
|
||||||
! Fall into code to restart proc/task running.
|
|
||||||
|
|
||||||
!*===========================================================================*
|
|
||||||
!* restart *
|
|
||||||
!*===========================================================================*
|
|
||||||
_restart:
|
|
||||||
|
|
||||||
! Restart the current process or the next process if it is set.
|
|
||||||
|
|
||||||
cli
|
|
||||||
call _schedcheck ! ask C function who we're running
|
|
||||||
mov esp, (_proc_ptr) ! will assume P_STACKBASE == 0
|
|
||||||
lldt P_LDT_SEL(esp) ! enable process' segment descriptors
|
|
||||||
cmp P_CR3(esp), 0 ! process does not have its own PT
|
|
||||||
jz 0f
|
|
||||||
mov eax, P_CR3(esp)
|
|
||||||
cmp eax, (loadedcr3)
|
|
||||||
jz 0f
|
|
||||||
mov cr3, eax
|
|
||||||
mov (loadedcr3), eax
|
|
||||||
mov eax, (_proc_ptr)
|
|
||||||
mov (_ptproc), eax
|
|
||||||
mov (_dirtypde), 0
|
|
||||||
0:
|
|
||||||
lea eax, P_STACKTOP(esp) ! arrange for next interrupt
|
|
||||||
mov (_tss+TSS3_S_SP0), eax ! to save state in process table
|
|
||||||
restart1:
|
|
||||||
decb (_k_reenter)
|
|
||||||
o16 pop gs
|
|
||||||
o16 pop fs
|
|
||||||
o16 pop es
|
|
||||||
o16 pop ds
|
|
||||||
popad
|
|
||||||
add esp, 4 ! skip return adr
|
|
||||||
iretd ! continue process
|
|
||||||
|
|
||||||
!*===========================================================================*
|
|
||||||
!* exception handlers *
|
|
||||||
!*===========================================================================*
|
|
||||||
_divide_error:
|
|
||||||
push DIVIDE_VECTOR
|
|
||||||
jmp exception
|
|
||||||
|
|
||||||
_single_step_exception:
|
|
||||||
push DEBUG_VECTOR
|
|
||||||
jmp exception
|
|
||||||
|
|
||||||
_nmi:
|
|
||||||
push NMI_VECTOR
|
|
||||||
jmp exception
|
|
||||||
|
|
||||||
_breakpoint_exception:
|
|
||||||
push BREAKPOINT_VECTOR
|
|
||||||
jmp exception
|
|
||||||
|
|
||||||
_overflow:
|
|
||||||
push OVERFLOW_VECTOR
|
|
||||||
jmp exception
|
|
||||||
|
|
||||||
_bounds_check:
|
|
||||||
push BOUNDS_VECTOR
|
|
||||||
jmp exception
|
|
||||||
|
|
||||||
_inval_opcode:
|
|
||||||
push INVAL_OP_VECTOR
|
|
||||||
jmp exception
|
|
||||||
|
|
||||||
_copr_not_available:
|
|
||||||
push COPROC_NOT_VECTOR
|
|
||||||
jmp exception
|
|
||||||
|
|
||||||
_double_fault:
|
|
||||||
push DOUBLE_FAULT_VECTOR
|
|
||||||
jmp errexception
|
|
||||||
|
|
||||||
_copr_seg_overrun:
|
|
||||||
push COPROC_SEG_VECTOR
|
|
||||||
jmp exception
|
|
||||||
|
|
||||||
_inval_tss:
|
|
||||||
push INVAL_TSS_VECTOR
|
|
||||||
jmp errexception
|
|
||||||
|
|
||||||
_segment_not_present:
|
|
||||||
push SEG_NOT_VECTOR
|
|
||||||
jmp errexception
|
|
||||||
|
|
||||||
_stack_exception:
|
|
||||||
push STACK_FAULT_VECTOR
|
|
||||||
jmp errexception
|
|
||||||
|
|
||||||
_general_protection:
|
|
||||||
push PROTECTION_VECTOR
|
|
||||||
jmp errexception
|
|
||||||
|
|
||||||
_page_fault:
|
|
||||||
push PAGE_FAULT_VECTOR
|
|
||||||
push eax
|
|
||||||
mov eax, cr2
|
|
||||||
sseg mov (pagefaultcr2), eax
|
|
||||||
pop eax
|
|
||||||
jmp errexception
|
|
||||||
|
|
||||||
_copr_error:
|
|
||||||
push COPROC_ERR_VECTOR
|
|
||||||
jmp exception
|
|
||||||
|
|
||||||
!*===========================================================================*
|
|
||||||
!* exception *
|
|
||||||
!*===========================================================================*
|
|
||||||
! This is called for all exceptions which do not push an error code.
|
|
||||||
|
|
||||||
.align 16
|
|
||||||
exception:
|
|
||||||
sseg mov (trap_errno), 0 ! clear trap_errno
|
|
||||||
sseg pop (ex_number)
|
|
||||||
jmp exception1
|
|
||||||
|
|
||||||
!*===========================================================================*
|
|
||||||
!* errexception *
|
|
||||||
!*===========================================================================*
|
|
||||||
! This is called for all exceptions which push an error code.
|
|
||||||
|
|
||||||
.align 16
|
|
||||||
errexception:
|
|
||||||
sseg pop (ex_number)
|
|
||||||
sseg pop (trap_errno)
|
|
||||||
exception1: ! Common for all exceptions.
|
|
||||||
sseg mov (old_eax_ptr), esp ! where will eax be saved?
|
|
||||||
sseg sub (old_eax_ptr), PCREG-AXREG ! here
|
|
||||||
|
|
||||||
push eax ! eax is scratch register
|
|
||||||
|
|
||||||
mov eax, 0+4(esp) ! old eip
|
|
||||||
sseg mov (old_eip), eax
|
|
||||||
mov eax, esp
|
|
||||||
add eax, 4
|
|
||||||
sseg mov (old_eip_ptr), eax
|
|
||||||
movzx eax, 4+4(esp) ! old cs
|
|
||||||
sseg mov (old_cs), eax
|
|
||||||
mov eax, 8+4(esp) ! old eflags
|
|
||||||
sseg mov (old_eflags), eax
|
|
||||||
|
|
||||||
pop eax
|
|
||||||
call save
|
|
||||||
push (pagefaultcr2)
|
|
||||||
push (old_eax_ptr)
|
|
||||||
push (old_eip_ptr)
|
|
||||||
push (old_eflags)
|
|
||||||
push (old_cs)
|
|
||||||
push (old_eip)
|
|
||||||
push (trap_errno)
|
|
||||||
push (ex_number)
|
|
||||||
call _exception ! (ex_number, trap_errno, old_eip,
|
|
||||||
! old_cs, old_eflags)
|
|
||||||
add esp, 8*4
|
|
||||||
ret
|
|
||||||
|
|
||||||
|
|
||||||
!*===========================================================================*
|
|
||||||
!* write_cr3 *
|
|
||||||
!*===========================================================================*
|
|
||||||
! PUBLIC void write_cr3(unsigned long value);
|
|
||||||
_write_cr3:
|
|
||||||
push ebp
|
|
||||||
mov ebp, esp
|
|
||||||
mov eax, 8(ebp)
|
|
||||||
cmp eax, (loadedcr3)
|
|
||||||
jz 0f
|
|
||||||
mov cr3, eax
|
|
||||||
mov (loadedcr3), eax
|
|
||||||
mov (_dirtypde), 0
|
|
||||||
0:
|
|
||||||
pop ebp
|
|
||||||
ret
|
|
||||||
|
|
||||||
!*===========================================================================*
|
|
||||||
!* reload_cr3 *
|
|
||||||
!*===========================================================================*
|
|
||||||
! PUBLIC void reload_cr3(void);
|
|
||||||
_reload_cr3:
|
|
||||||
push ebp
|
|
||||||
mov ebp, esp
|
|
||||||
mov (_dirtypde), 0
|
|
||||||
mov eax, cr3
|
|
||||||
mov cr3, eax
|
|
||||||
pop ebp
|
|
||||||
ret
|
|
||||||
|
|
||||||
!*===========================================================================*
|
|
||||||
!* level0_call *
|
|
||||||
!*===========================================================================*
|
|
||||||
_level0_call:
|
|
||||||
! which level0 function to call was passed here by putting it in eax, so
|
|
||||||
! we get that from the saved state.
|
|
||||||
call save
|
|
||||||
mov eax, (_proc_ptr)
|
|
||||||
mov eax, AXREG(eax)
|
|
||||||
jmp eax
|
|
||||||
|
|
||||||
!*===========================================================================*
|
|
||||||
!* data *
|
|
||||||
!*===========================================================================*
|
|
||||||
|
|
||||||
.sect .rom ! Before the string table please
|
|
||||||
.data2 0x526F ! this must be the first data entry (magic #)
|
|
||||||
|
|
||||||
.sect .bss
|
|
||||||
k_stack:
|
|
||||||
.space K_STACK_BYTES ! kernel stack
|
|
||||||
k_stktop: ! top of kernel stack
|
|
||||||
.comm ex_number, 4
|
|
||||||
.comm trap_errno, 4
|
|
||||||
.comm old_eip_ptr, 4
|
|
||||||
.comm old_eax_ptr, 4
|
|
||||||
.comm old_eip, 4
|
|
||||||
.comm old_cs, 4
|
|
||||||
.comm old_eflags, 4
|
|
||||||
.comm pagefaultcr2, 4
|
|
||||||
.comm loadedcr3, 4
|
|
||||||
|
|
|
@ -1,28 +1,28 @@
|
||||||
! Miscellaneous constants used in assembler code.
|
/* Miscellaneous constants used in assembler code. */
|
||||||
W = _WORD_SIZE ! Machine word size.
|
W = _WORD_SIZE /* Machine word size. */
|
||||||
|
|
||||||
! Offsets in struct proc. They MUST match proc.h.
|
/* Offsets in struct proc. They MUST match proc.h. */
|
||||||
P_STACKBASE = 0
|
P_STACKBASE = 0
|
||||||
GSREG = P_STACKBASE
|
GSREG = P_STACKBASE
|
||||||
FSREG = GSREG + 2 ! 386 introduces FS and GS segments
|
FSREG = GSREG+2 /* 386 introduces FS and GS segments*/
|
||||||
ESREG = FSREG + 2
|
ESREG = FSREG+2
|
||||||
DSREG = ESREG + 2
|
DSREG = ESREG+2
|
||||||
DIREG = DSREG + 2
|
DIREG = DSREG+2
|
||||||
SIREG = DIREG + W
|
SIREG = DIREG+W
|
||||||
BPREG = SIREG + W
|
BPREG = SIREG+W
|
||||||
STREG = BPREG + W ! hole for another SP
|
STREG = BPREG+W /* hole for another SP*/
|
||||||
BXREG = STREG + W
|
BXREG = STREG+W
|
||||||
DXREG = BXREG + W
|
DXREG = BXREG+W
|
||||||
CXREG = DXREG + W
|
CXREG = DXREG+W
|
||||||
AXREG = CXREG + W
|
AXREG = CXREG+W
|
||||||
RETADR = AXREG + W ! return address for save() call
|
RETADR = AXREG+W /* return address for save() call*/
|
||||||
PCREG = RETADR + W
|
PCREG = RETADR+W
|
||||||
CSREG = PCREG + W
|
CSREG = PCREG+W
|
||||||
PSWREG = CSREG + W
|
PSWREG = CSREG+W
|
||||||
SPREG = PSWREG + W
|
SPREG = PSWREG+W
|
||||||
SSREG = SPREG + W
|
SSREG = SPREG+W
|
||||||
P_STACKTOP = SSREG + W
|
P_STACKTOP = SSREG+W
|
||||||
P_LDT_SEL = P_STACKTOP
|
P_LDT_SEL = P_STACKTOP
|
||||||
P_CR3 = P_LDT_SEL + W
|
P_CR3 = P_LDT_SEL+W
|
||||||
P_LDT = P_CR3 + W
|
P_LDT = P_CR3+W
|
||||||
Msize = 9 ! size of a message in 32-bit words
|
Msize = 9 /* size of a message in 32-bit words*/
|
||||||
|
|
Loading…
Reference in a new issue