File:  [MW Coherent from dump] / coherent / b / kernel / i386 / as.s
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Wed May 29 04:56:37 2019 UTC (7 years ago) by root
Branches: MarkWilliams, MAIN
CVS tags: relic, HEAD
coherent

	.unixorder
	.llen	132
	.include	as.inc

IODELAY	.macro
	jmp	.+2		/ DELAY
	jmp	.+2		/ DELAY
	.endm

/ Most places where %cr3 is refreshed, it can be done through a Ring 0 gate.
MMUUPD	.macro
	pushfl
	cli
	lcall	$SEG_MMUUPD,$0	/ gate to mmuupdfR0
	popfl
	.endm

/
/ USTART and ESP_START map kernel stack and u area within top 4k page
/ of virtual space.
/ NDP context starts 0x100 bytes below u area.
/ See also U_OFFSET, NDP_OFFSET in uproc.h
/
	.set	USTART,0xFFFFFC00
	.set	ESP0_START,0xFFFFF300
	.set	ESP1_START,USTART

	.set	u,USTART
	.set	PSW_VAL,0x1200	/ set system IOPL to 1, enable IRQ
/	.set	PSW_VAL,0x3200	/ set system IOPL to 3, enable IRQ

/ (lgl-
/	The information contained herein is a trade secret of Mark Williams
/	Company, and  is confidential information.  It is provided  under a
/	license agreement,  and may be  copied or disclosed  only under the
/	terms of  that agreement.  Any  reproduction or disclosure  of this
/	material without the express written authorization of Mark Williams
/	Company or persuant to the license agreement is unlawful.

/	Copyright (c) 1982, 1992.
/	An unpublished work by Mark Williams Company, Chicago.
/	All rights reserved.

/	Intel 386 port and extensions
/	Copyright (c) Ciaran O'Donnell, Bievres (FRANCE), 1991
/ -lgl)
/ 
/ $Log: as.s,v $
/ Revision 1.1.1.1  2019/05/29 04:56:37  root
/ coherent
/
/Revision 1.18  93/06/14  13:42:14  bin
/Hal: kernel 78 update
/
/ Revision 1.17  92/12/08  16:43:10  root
/ ker 70
/ 
/ Revision 1.16  92/11/12  10:04:31  root
/ Ker #68
/ 
/ Revision 1.15  92/11/09  17:08:28  root
/ Just before adding vio segs.
/ 
/ Revision 1.13  92/10/06  23:47:48  root
/ Ker #64
/ 
/ Revision 1.12  92/10/06  20:45:40  root
/ Ker #63d
/ 
/ Revision 1.10  92/07/27  18:15:43  hal
/ Kernel #59
/ 
/ Revision 1.9  92/07/16  16:38:14  hal
/ Kernel #58
/ 
/ Revision 1.8  92/07/15  13:50:55  root
/ COH 4.0.0
/ 
/ Revision 1.6  92/04/03  11:05:28  hal
/ Fix missed IRQ bug.
/ Add read_t0(), read_psw(), getusd(), putusd().
/ 

///////
/ Machine language assist for
/ Intel 80386/80486 Coherent. This contains the parts
/ that are common to all machines as well as the machine-specific code
/ for the IBM PC-386


///////

/ System entry point.

/ When this code is entered, the boot program has done the following:
/	Relocate itself above where the kernel will be (e.g., 0x20600).
/	Load as.s binary; text at 0x02000, data at next paragraph (16-byte)
/		boundary at or beyond end of kernel text.
/	CS = 0x02000 <- start of kernel text ("physical" stext)
/	ES = 0x02xxx <- start of kernel data
/	SS,DS = 0x20xxx <- ....some address in boot data space....

/ Due to the way the kernel has been linked (see ld.master), symbol "stext"
/ has a value of 0xFFC0_0000, which is the start of the last 4 meg segment.
/ This value is the address in linear space once we have entered paging mode,
/ but until that time relocation arithmetic is necessary:
/
/ Before segmentation is turned on, symbols in kernel text or data space
/ must be relocated by -SBASE<<BPCSHIFT for memory reference instructions
/ to work.

///////

stext:					/ kernel code starts at stext+0x100
	.org .+0x100			/ reserve stack space
	cli				/ No interrupts, please.

/ put up a debugging "!" on the screen.  We can still use the BIOS.
	push    %si                      / Save registers.
	push    %di

	movb	$'!', %al

	movw	$0x0007, %bx             / Page 0, white on black
	movb	$0x0E, %ah               / Write TTY.
	int	$VIDEO                   / Call video I/O in ROM.
	pop	%di
	pop	%si

	/ equipment status word to AX
	int	$0x11			/ Obtain int 11 value before printf().
	movl	%eax,%ecx		/ esw -> cx

	/ val11 is a long, initially zero, in the CS.
	/ copy (long)esw to val11
	.byte	PX_ADDR			/ 32-bit address
	.byte	PX_OPND			/ 32-bit operand
	movl	%ecx,%cs:[[-SBASE]<<BPCSHIFT]+val11

   					/ last use of boot block's stack
	.byte	PX_ADDR			/ 32-bit address
	.byte	PX_OPND			/ 32-bit operand
	lgdtl	%cs:[[-SBASE]<<BPCSHIFT]+gdtinit

	/ turn on lsbit of cr0 - Protection Enable
	mov	%cr0,%eax
	orb	$1,%al
	mov	%eax,%cr0

	/ intersegment jump (48-bit address)
	/ jumping flushes the cache...
	/ 
	.byte	PX_OPND
	ljmp	$SEG_386_II, $next

next:
	mov	$SEG_386_ID,%eax
	movw	%ax,%ds
	movw	%ax,%ss
	mov	$SEG_386_UD|R_USR,%eax
	movw	%ax,%es
	mov	$stext+0x100,%eax	/ 256 byte stack for initialization
	mov	%eax,%esp

	push	$'@'			/ Debugging checkpoint:
	call	chirp			/ protected mode is on
	pop	%ecx

/ Enable the A20 address line, which is normally disabled by the ROM BIOS.
/ This line is under the control of the 8042 keyboard interface controller.

	sub	%ecx, %ecx
loc0:	inb	$KBCTRL		/ Wait for 8042 input buffer to empty.
	testb	$2,%al
	loopne	loc0
	IODELAY

	movb	$0xD1, %al 	/ Request next output byte to be
	outb	$KBCTRL		/	sent to the 8042 output port.
	IODELAY

	sub	%ecx, %ecx
loc1:	inb	$KBCTRL		/ Wait for 8042 input buffer to empty.
	testb	$2, %al
	loopne	loc1
	IODELAY

	movb	$0xDF,%al	/ Enable A20 address line.
	outb	$KBDATA		/ See Page 1-44, IBM-AT Tech Ref.
	IODELAY

	sub	%ecx, %ecx
loc2:	inb	$KBCTRL		/ Wait for 8042 input buffer to empty.
	testb	$2,%al		/ NOTE: A20 not enabled for up to 20 us.
	loopne	loc2


/ Reprogram the 8253 timer so that channel 0, 
/ which is used as the clock, interrupts at exactly
/ 100 HZ, instead of 18.2 HZ.

	movb	$0x36,%al	/ Timer 0, LSB, MSB, mode 3
	outb	$PIT+3
	IODELAY
	movb	$0x9C,%al	/ Lsb of 59659/5 = 11932
	outb	$PIT
	IODELAY
	movb	$0x2E,%al	/ Msb of 59659/5 = 11932
	outb	$PIT
	IODELAY

/ Reprogram the 1st programmable interrupt controller.
/ Its default vector table collides with iAPX 286 protection vectors.
	movb	$0x11,%al	/ ICW1 - edge, ICW4
	outb	$PIC
	IODELAY
	movb	$0x20,%al	/ ICW2 - Reserve 1st 32 vectors for 286
	outb	$PICM
	IODELAY
	movb	$0x04,%al	/ ICW3 - master level 2
	outb	$PICM
	IODELAY
	movb	$0x01,%al	/ ICW4 - 8086 mode, master.
	outb	$PICM
	IODELAY

/ NIGEL: The original code here (and related code in "i386/md.c") turned off
/ the chain bit in the first PIC by default (and at every subsequent
/ opportunity) even though all the mask bits in the slave PIC are set to off.
/ In order to support an enhanced interrupt architecture for the STREAMS and
/ DDI/DDK subsystems I want to remove the state knowledge from the code in
/ "i386/md.c" so that the chain bit is always left on.
/ In order to do this, I have modified the startup code below so that the
/ system by default allows the slave PIC to interrupt (of course, it still
/ won't interrupt unless it is enabled to; the masking I have removed was
/ totally redundant).

	movb	$0xFA,%al	/ Disable interrupts from master PIC.
	outb	$PICM		/ (except for clock and slave PIC interrupt).

	movb	$0x11,%al	/ ICW1 - edge, ICW4
	outb	$SPIC
	IODELAY
	movb	$0x70,%al	/ ICW2 - slave starts at 0x70th interrupt
	outb	$SPICM
	IODELAY
	movb	$0x02,%al	/ ICW3 - master level 2
	outb	$SPICM
	IODELAY
	movb	$0x01,%al	/ ICW4 - 8086 mode.
	outb	$SPICM
	IODELAY
	movb	$0xFF,%al
	outb	$SPICM		/ Disable interrupts from slave PIC.
/DEBUG
	cli
	call	__cinit
	call	mchinit		/ C initialization
	mov	%cr0,%eax	/ Turn on paging
/ use 80000001 to allow FP
/	or	$0x80000001,%eax
/ use 80000005 to disallow FP
	or	$0x80000005,%eax
	mov	%eax,%cr0
	ljmp	$SEG_RNG0_TXT,$loc3	/ clear pipeline; jump far, direct

/
/ Ring 0 startup code
/
loc3:
	movw	$SEG_386_KD,%ax
	movw	%ax,%ds
	movw	$SEG_RNG0_STK,%ax
	movw	%ax,%ss
	movl	$ESP0_START,%esp	/ Stack pointer for init
	clts				/ Clear task switched flag.

/ Call the machine setup code.
/ Call Coherent main.
/ On return, send control off to the user
/ at its entry point.

	sub	%eax, %eax	/ Load local descriptor table register.
	lldt	%ax

/	movw	$tss,%ax	/ Fix low 16 bits of tss base in gdt
/	movw	%ax,gdt+SEG_TSS+2

	/ Fix tss base in gdt
	movl	$tss,%eax
	movw	%ax,gdt+SEG_TSS+2	/ Fix bits  0..15
	rorl	$16,%eax		/ Get tss bits 16..31
	movb	%al,gdt+SEG_TSS+4	/ Fix bits 16..23
	movb	%ah,gdt+SEG_TSS+7	/ Fix bits 24..31

	movw	$SEG_TSS,%ax		/ Load task state segment register.
	ltr	%ax
	lidt	idtmap			/ Load interrupt descriptor table
	lgdt	gdtmap

/	movw	$ldt,%ax		/ Relocate ldt in gdt
/	movw	%ax,gdt+SEG_LDT+2

	/ Fix ldt base in gdt
	movl	$ldt,%eax
	movw	%ax,gdt+SEG_LDT+2	/ Fix bits  0..15
	rorl	$16,%eax		/ Get ldt bits 16..31
	movb	%al,gdt+SEG_LDT+4	/ Fix bits 16..23
	movb	%ah,gdt+SEG_LDT+7	/ Fix bits 24..31

	movw	$SEG_LDT,%ax 
	lldt	%ax

	call	i8086			/ i8086() does fixup of tss_sp0

/
/ Enter Ring 1 kernel from Ring 0
/
	push	$SEG_RNG1_STK		/ SS
	push	$ESP1_START		/ ESP
	push	$PSW_VAL		/ PSW
	push	$SEG_RNG1_TXT		/ CS
	push	$__xmain__		/ IP
	movw	$SEG_386_KD,%ax		/ DS, ES
	movw	%ax, %ds		/ Map data segment
	movw	%ax, %es		/ Map extra segment
	iret				/ Go to user state.

/
/ Start of Ring 1 kernel.
/ Need Ring 1 because interrupts are about to turn on, and all irpt gates
/ have DPL (descriptor privilege level) 1.
/
__xmain__:
	sti				/ Interrupts on, and
	call	main			/ call Coherent mainline.
	cli				/ Interrupts off.

/
/ Enter User mode from Ring 1 kernel
/
	push	$SEG_386_UD|R_USR	/ SS
	push	$NBPC			/ ESP
	push	$PSW_VAL		/ PSW
	push	$SEG_386_UI|R_USR	/ CS
	push	$0			/ IP
	movw	$SEG_386_UD|R_USR,%ax	/ DS, ES
	movw	%ax, %ds		/ Map data segment
	movw	%ax, %es		/ Map extra segment
	iret				/ Go to user state.

///////
/
/ Trap and interrupt save.
/
/ This version of tsave runs from Ring 1 trap/irpt gates.
/
///////
	.globl	disflag

tsave:					/ What level of interrupt ? 
	pusha
	push	%ds			/ Save current state
	push	%es
	push	%fs
	push	%gs

	mov	$SEG_386_KD,%eax	/ Map ds
	movw	%ax,%ds
	mov	$SEG_386_UD|R_USR,%eax	/ Map es
	movw	%ax,%es			/ to system ds

	sti
	icall	X_TRAPNO(%esp)		/ and call the caller
	cli

/ if got here from user mode or from idle process, call stand()
/ else just do cleanup and return

	movb	X_ERR+8(%esp),%al	/ trapped CS:  user RPL?
	andb	$3,%al
	cmpb	$R_USR,%al
	je	tsave1a			/ jmp if user mode
	cmpl	$__idle__,X_ERR+4(%esp)	/ trapped EIP == idle process?
	jnz	tsave1b			/ Call stand() only if idle
	movl	$1,disflag

tsave1a:
	sti
	call	stand
tsave1b:
	cli				/ No more interrupts
	pop	%gs			/ Restore
	pop	%fs
	pop	%es
	pop	%ds
	popa
	add	$8,%esp			/ forget err, trapno
	iret				/ Done.

/
/ Here is another version of tsave, called only from the GP vector (RING 0)
/

BYPASS	.macro	addr
	cmpl	$addr,X_ERR+4(%esp)	/ trapped EIP
	jz	tsave0b
	.endm
	
tsave0:					/ What level of interrupt ? 
	pusha
	push	%ds			/ Save current state
	push	%es
	push	%fs
	push	%gs

	mov	$SEG_386_KD,%eax	/ Map ds
	movw	%ax,%ds
	mov	$SEG_386_UD|R_USR,%eax	/ Map es
	movw	%ax,%es			/ to system ds

	jmp	tsave0b

//The following lines help find traps during startup.
	BYPASS	read_cr0
	BYPASS	read_cr2
	BYPASS	read_cr3
tsave0q:
 	mov	52(%esp),%eax		/ Print fault code.
 	cmpb	$0x40,%al
 	je	tsave0b			/ Skip over hardware interrupts.
 	push	%eax
 	call	print32
 	pop	%ecx
 
 	push	$' '
 	call	mchirp
 	pop	%ecx
 
 	mov	56(%esp),%eax		/ Print eip.
 	push	%eax
 	call	print32
 	pop	%ecx

 	push	$' '
 	call	mchirp
 	pop	%ecx

 	push	%esp			/ Print esp.
 	call	print32
 	pop	%ecx
 
 tsave0a:	jmp	tsave0a
 tsave0b:
//

	icall	X_TRAPNO(%esp)		/ and call the caller

	pop	%gs			/ Restore
	pop	%fs
	pop	%es
	pop	%ds
	popa
	add	$8,%esp			/ forget err, trapno
	iret				/ Done.

///////

/ Save the environment of a process
/ envsave(p)
/ MENV *p;

/ Save the context of a process
/ consave(p)
/ MCON *p;

///////

envsave:
consave:
	mov	%edi,%ecx		/ Hide di.
	mov	4(%esp), %edi 		/ di at the MCON block.

	movw	%es,%dx		/ save = setspace(SEG_386_KD) -- should be %edx
	movw	$SEG_386_KD,%ax
	movw	%ax,%es

	cld				/ Ensure increment.
	mov	%ecx, %eax		/ Save di
	stosl
	mov	%esi, %eax		/ Save si
	stosl
	mov	%ebx, %eax		/ Save bx
	stosl
	mov	%ebp, %eax		/ Save bp
	stosl
	mov	%esp, %eax		/ Save sp
	stosl
	mov	(%esp), %eax		/ Save ra as pc
	stosl
	pushfl				/ Save fw
	pop	%eax
	stosl
	mov	%ecx, %edi		/ Put di back,
	sub	%eax, %eax		/ indicate a state save and
	movw	%dx,%es			/ setspace(save)
	ret				/ return to caller.

///////

/ Restore the environment of a process.
/ envrest(p)
/ MENV *p;

///////

envrest:
	cli
	cld
	mov	4(%esp),%esi		/ Pointer to context
	lodsl				/ Restore di
	mov	%eax, %edi
	lodsl				/ Restore si
	mov	%eax, %ecx		/ Save for later
	lodsl				/ Restore bx
	mov	%eax, %ebx
	lodsl				/ Restore bp
	mov	%eax, %ebp
	lodsl				/ Restore sp
	mov	%eax, %esp
	push	%cs			/ Push current CS
	lodsl				/ Restore pc
	push	%eax
	lodsl				/ Restore flags
	mov	%eax, 8(%esp)		/ Stack now in form PSW,CS,IP.
	mov	%ecx, %esi		/ Restore si
	mov	$1,%eax			/ We are restoring
	iret				/ Return through PSW,CS,IP.

///////

/ Restore the context of a process.
/ Called with interrupts disabled from dispatch.
/ conrest(u, o)
/ saddr_t u;

///////

conrest:
	mov	8(%esp), %esi		/ Fetch syscon offset

	cli				/ Interrupts on hold
	cld

	/ Map new u area into linear space and update paging hardware

	mov	4(%esp),%eax		/ Fetch new u area saddr_t
	orb	$SEG_SRW,%al
	mov	%eax,[PTABLE1_V<<BPCSHIFT]+UADDR

	lcall	$SEG_MMUUPD,$0	/ strobe CR3

	/ Restore context

	lodsl				/ Restore di
	mov	%eax,%edi
	lodsl		 		/ Restore si
	mov	%eax,%ecx		/ Save for later
	lodsl				/ Restore bx
	mov	%eax,%ebx
	lodsl				/ Restore bp
	mov	%eax,%ebp
	lodsl				/ Restore sp
	mov	%eax,%esp
	push	%cs			/ Push current CS
	lodsl				/ Restore pc
	push	%eax

	lodsl				/ Restore flags
	mov	%eax,8(%esp)		/ Stack now in form PSW,CS,IP.
	mov	%ecx,%esi		/ Restore si
	mov	$1,%eax			/ We are restoring
	iret				/ Return through PSW,CS,IP.

/ Save useful registers.

/ msysgen(p)
/ MGEN *p;

msysgen:
	ret				/ Nothing useful to save

/ Disable interrupts.  Previous value is returned.

sphi:
	pushf				/ Save flags
	pop	%eax			/ Return current value
	cli				/ Disable interrupts
	ret				/ And return

/ Enable interrupts.  Previous value is returned.

splo:
	pushf
	pop	%eax
	sti
	ret

/ Change interrupt flag.  Previous value is returned.

spl:
	pop	%eax			/ ip
	pop	%edx			/ psw
	push	%edx
	push	%edx			/ push psw, cs, ip for iret
	push	%cs
	push	%eax
	pushf				/ old psw
	pop	%eax
	iret

///////

/ Idle routine.
/ Enable interupts, and wait for something to
/ happen. Does not do anything to the 8259, bacause
/ this will be set up correctly.

///////
	.globl	idle
idle:
	sti				/ Interupts on.
__idle__:
	jmp	__idle__		/ Wait for an interrupt
	ret				/ and return.

///////

/ The world is indeed grim.
/ Hang. Keep the interrupts on so that the
/ keyboard can get int.

///////

halt:	sti				/ Be safe,
__halt__
	jmp	__halt__		/ And hang.

///////

/ Basic port level I/O.

/ Byte I/O (8 bits)
/ int	inb(port);
/ int	outb(port, data);

/ Word I/O (16 bits)
/ int	inw(port);
/ int	outw(port, data);

/ Long I/O (32 bits)
/ int	inl(port);
/ int	outl(port, data);

///////

inb:	mov	4(%esp),%edx
	sub	%eax,%eax
	inb	(%dx)
	ret

outb:	movl	4(%esp),%edx
	movl	8(%esp),%eax
	outb	(%dx)
	ret

inw:	mov	4(%esp),%edx
	sub	%eax,%eax
	inw	(%dx)
	ret

outw:	movl	4(%esp),%edx
	movl	8(%esp),%eax
	outw	(%dx)
	ret

inl:	mov	4(%esp),%edx
	sub	%eax,%eax
	inl	(%dx)
	ret

outl:	movl	4(%esp),%edx
	movl	8(%esp),%eax
	outl	(%dx)
	ret

///////

/ AT Hard Disk Assembler Support

/ atsend( va ) - send 512 bytes from virtual address to hard disk
/ atrecv( va ) - receive 512 bytes from hard disk into virtual address
/ DRQ is not checked.  DRQ must be true before atsend/atrecv are called.

/ va is a system global address
///////

	.globl	atsend
atsend:
	enter	$0,$4	/ reserve 4 bytes (1 int) of local storage
	push	%esi
	push	%es
	call	workAlloc	/ get a temp virt page
	movl	%eax,-4(%ebp)	/ this is "work0" - a click number

	movw	$SEG_386_KD,%ax
	movw	%ax,%es			/ save = setspace(SEG_386_KD)

	cld
	mov	20(%esp),%eax		/ fetch argument va
	shr	$BPCSHIFT,%eax		/ get page table index from va
	mov	sysmem,%edx
	leal	(%edx,%eax,4),%esi 	/ base = sysmem.u.pbase + btocrd(va)

/ Since the requested transfer may span a click boundary, have two clicks
/ ready in the page table - the one containing the virtual address of the
/ start of the user area, and the click which follows in virtual memory.

	lodsl				/ ptable1_V[WORK0] = *base++ | SEG_SRW
	or	$SEG_SRW,%eax
	movl	-4(%ebp),%edx		/ work0
	movl	%eax,[PTABLE1_V<<BPCSHIFT](%edx,4)

	lodsl				/ ptable1_V[WORK1] = *base++ | SEG_SRW
	or	$SEG_SRW,%eax
	inc	%edx			/ work1
	movl	%eax,[PTABLE1_V<<BPCSHIFT](%edx,4)

	MMUUPD

/ Now that page boundaries are set, work on the offsets.

	mov	20(%esp),%esi		/ va = ctob(WORK0) + (va & (NBPC-1))
	and	$NBPC-1,%esi		/ get click offset part of va
	movl	-4(%ebp),%edx		/ work0
	shl	$BPCSHIFT,%edx		/ ctob(work0)
	add	%edx,%esi

	mov	$256, %ecx		/ copy one disk block
	mov	$0x1F0, %edx

/ Do the block transfer.

	rep
	outsw

	MMUUPD

	push	-4(%ebp)		/ workFree(work0)
	call	workFree
	pop	%edx
	pop	%es			/ setspace(save) 
	pop	%esi
	leave
	ret

	.globl	atrecv
atrecv:
	enter	$0,$4	/ reserve 4 bytes (1 int) of local storage
	push	%esi
	push	%es
	call	workAlloc	/ get a temp virt page
	movl	%eax,-4(%ebp)	/ this is "work0" - a click number

	movw	$SEG_386_KD,%ax
	movw	%ax,%es			/ save = setspace(SEG_386_KD)

	cld
	mov	20(%esp),%eax
	shr	$BPCSHIFT,%eax
	mov	sysmem,%edx
	leal	(%edx,%eax,4),%esi	/ base = sysmem.u.pbase + btocrd(va)

	lodsl				/ ptable1_V[WORK1] = *base++ | SEG_SRW
	or	$SEG_SRW,%eax
	movl	-4(%ebp),%edx		/ work0
	movl	%eax,[PTABLE1_V<<BPCSHIFT](%edx,4)

	lodsl				/ ptable1_V[WORK1] = *base++ | SEG_SRW
	or	$SEG_SRW,%eax
	inc	%edx			/ work1
	movl	%eax,[PTABLE1_V<<BPCSHIFT](%edx,4)

	MMUUPD

	mov	20(%esp),%esi		/ va = ctob(WORK0) + (va & (NBPC-1))
	and	$NBPC-1,%esi
	movl	-4(%ebp),%edx		/ work0
	shl	$BPCSHIFT,%edx		/ ctob(work0)
	add	%edx,%esi

	mov	$256, %ecx		/ copy one disk block
	mov	$0x1F0, %edx

	xchg	%esi,%edi
	rep				/ Value of the ECX register is not
/	insw	(%dx)			/ updated correctly
	insw
	xchg	%esi,%edi		

	MMUUPD

	push	-4(%ebp)		/ workFree(work0)
	call	workFree
	pop	%edx
	pop	%es			/ setspace(save) 
	pop	%esi
	leave
	ret

///////

/ This dummy routine is put in vector
/ table slots that are unused. All it does is
/ return to the caller.

///////

vret:	ret

/ mmuupd() uses a call gate.
mmuupd:
	pushf
	cli
	lcall	$SEG_MMUUPD,$0	/ gates to mmuupdfR0
	popf
	ret

/ Ring 0 far mmu update.  Called via a gate.  Uses %eax.
/ Want interrupts off when we arrive since the interrupt gates
/ lead into Ring 1.
mmuupdfR0:
	mov	$PTABLE0_P<<BPCSHIFT,%eax
	mov	%eax,%cr3
	lret

/ Ring 0 near mmu update.  Called from ring 0 startup.  Uses %eax.
mmuupdnR0:
	mov	$PTABLE0_P<<BPCSHIFT,%eax
	mov	%eax,%cr3
	ret

///////
/ Get cs selector - return 0 if in kernel, CS if not in kernel.
/ This version is for resident drivers.
/ There is a different version (cs_self.s) for loadable drivers.
/ int	cs_sel();
///////

cs_sel:
	sub	%eax, %eax
	ret

/	load the 'alternate address space register' (es)
/	with the segment reference passed as an argument. 

/	The value returned is the old value of the 'es' register

setspace:
	movl	%esp,%edx
	sub	%eax,%eax
	movw	%es,%ax
	movl	4(%edx),%edx
	movw	%dx,%es
	ret

/////////////////////////
/
/ From __xtrap_on__ to __xtrap_off__, GP fault and page fault will not
/ cause panic.  Normally, these two traps coming from kernel text result
/ in panic.
/
/////////////////////////
	.globl	__xtrap_on__
	.globl	__xtrap_break__
	.globl	__xtrap_off__
__xtrap_on__:

///////

/ Fetch a short from the user's data space.
/	Coherent 386 fetches a 16 bit short

/ getusd(u)
/ char *u;

///////

getusd:
	call	start_copy
	mov	4(%edx),%ecx
	sub	%eax,%eax
	movw	%es:(%ecx),%ax
	jmp	end_copy

///////

/ Fetch a word from the user's data space.
/	Coherent 386 fetches a 32 bit word

/ getuwd(u)
/ char *u;

///////

getuwd:
getupd:
	call	start_copy
	mov	4(%edx),%ecx
	mov	%es:(%ecx),%eax
	jmp	end_copy

///////

/ Fetch a byte from the user's data space.

/ getubd(u)
/ char *u;

///////

getubd:
	call	start_copy
	mov	4(%edx),%ecx
	sub	%eax,%eax
	movb	%es:(%ecx),%al
	jmp	end_copy

///////

/ Store a short into the user's data space.
/	Coherent 386 stores a 16 bit short

/ putusd(u, w)
/ char *u;
/ int w;

///////

putusd:
	call	start_copy
	mov	8(%edx),%eax
	mov	4(%edx),%ecx		/ eax
	movw	%ax,%es:(%ecx)
	jmp	end_copy

///////

/ Store a word into the user's data space.
/	Coherent 386 stores a 32 bit word

/ putuwd(u, w)
/ char *u;
/ int w;

///////

putuwi:
putuwd:
	call	start_copy
	mov	8(%edx),%eax
	mov	4(%edx),%ecx		/ eax
	mov	%eax,%es:(%ecx)
	jmp	end_copy

///////

/ Store a byte into the user's data space.

/ putubd(u, w)
/ char *u;
/ int w;

///////

putubd:
	call	start_copy
	mov	8(%edx),%eax	/ get data
	mov	4(%edx),%ecx	/ get addr
	movb	%al,%es:(%ecx)
	jmp	end_copy

///////

/ Read a byte from a selector and offset.

/ selkcopy(sel, off)
/ unsigned long sel;
/ unsigned long off;

///////
	.globl	selkcopy
selkcopy:
	call	start_copy
	push	%es
	sub	%eax,%eax
	mov	4(%edx), %es
	mov	8(%edx), %ecx
	movb	%es:(%ecx), %al
	pop	%es
	jmp	end_copy

/	startup routine for 1-element (byte/word) move

/ Block transfer "n" bytes from location
/ "k" in the system map to location "u" in the
/ user's data space. Return the number of bytes
/ transferred.

/ kucopy(k, u, n)
/ char *k;
/ char *u;
/ int n;

///////

/	.globl	udat
kucopy:
/	mov	8(%esp),%eax		/ verify user address
/	push	%eax
/	call	udat
/	cmp	$0,%eax
/	pop	%eax
/	jne	xx00
/	ret
/xx00:

	call	start_copy

	movl	4(%edx),%esi		/ esi
	movl	8(%edx),%edi		/ edi

	mov	12(%edx),%ecx
	sar	$2,%ecx
	je	loc6

	rep
	movsl

loc6:
	mov	12(%edx),%ecx
	andl	$3,%ecx
	je	loc7

	rep
	movsb

loc7:
	mov	12(%edx),%eax
	jmp	end_copy

///////

/ Block copy "n" bytes from location "u" in
/ the user data space to location "k" in the system
/ data space. Return the actual number of bytes
/ moved.

/ ukcopy(u, k, n)
/ char *u;
/ char *k;
/ int n;

///////

ukcopy:
	call	start_copy

	mov	4(%edx),%esi		/ esi
	mov	8(%edx),%edi		/ edi
	mov	12(%edx),%ecx

	push	%ds			/ exchange ds,es
	movw	%es,%ax			/ don't assume ss=ds
	movw	%ax,%ds
	pop	%es

	sar	$2,%ecx
	je	loc8

	rep
	movsl

loc8:	mov	%ss:12(%edx),%ecx
	andl	$3,%ecx
	je	loc9

	rep
	movsb

loc9:	mov	%ss:12(%edx),%eax
	jmp	end_copy		/ Return

////////
/
/ Block copy "n" bytes from far location "src" in
/ an arbitrary (but valid) to location "dst" in 
/ data space. Return the actual number of bytes
/ moved.
/
/ ffcopy(src, dst, n)
/ char far *src;
/ char far *dst;
/ int n;
/
////////
	.globl	ffcopy
ffcopy:
	call	start_copy

	mov	4(%edx),%esi		/ esi
	mov	8(%edx),%ebx		/  ds
	mov	12(%edx),%edi		/ edi
	mov	16(%edx),%eax		/  es
	mov	20(%edx),%ecx

	movw	%ax,%es			/ now load segment regs
	movw	%bx,%ds

	sar	$2,%ecx
	je	ff01

	rep
	movsl

ff01:	mov	%ss:20(%edx),%ecx
	andl	$3,%ecx
	je	ff01

	rep
	movsb

ff02:	mov	%ss:20(%edx),%eax
	jmp	end_copy		/ Return

////////
/
/ Read a byte from a selector and offset.
/
/ ffbyte(off, sel)
/ unsigned long sel;
/ unsigned long off;
/
////////
	.globl	ffbyte
ffbyte:
	call	start_copy
	push	%es
	sub	%eax,%eax
	mov	4(%edx), %ecx
	mov	8(%edx), %es
	movb	%es:(%ecx), %al
	pop	%es
	jmp	end_copy

////////
/
/ write a byte using a selector and offset.
/
/ sfbyte(off, sel, byte)
/ unsigned long sel;
/ unsigned long off;
/ int byte;
/
////////
	.globl	sfbyte
sfbyte:
	call	start_copy
	push	%es
	mov	4(%edx), %ecx
	mov	8(%edx), %es
	mov	12(%edx), %eax
	movb	%al, %es:(%ecx)
	pop	%es
	jmp	end_copy

////////
/
/ Read a word from a selector and offset.
/
/ ffword(off, sel)
/ unsigned long sel;
/ unsigned long off;
/
////////
	.globl	ffword
ffword:
	call	start_copy
	push	%es
	sub	%eax,%eax
	mov	4(%edx), %ecx
	mov	8(%edx), %es
	movw	%es:(%ecx), %ax
	pop	%es
	jmp	end_copy

////////
/
/ write a word using a selector and offset.
/
/ sfword(off, sel, word)
/ unsigned long sel;
/ unsigned long off;
/ int word;
/
////////
	.globl	sfword
sfword:
	call	start_copy
	push	%es
	mov	4(%edx), %ecx
	mov	8(%edx), %es
	mov	12(%edx), %eax
	movw	%ax, %es:(%ecx)
	pop	%es
	jmp	end_copy

/	startup routine for n-element copy

start_copy:
	pop	%eax
	movl	%esp,%edx
	push	%esi
	push	%edi
	push	%ds
	push	%es
/	lidt	%cs:bdtmap
	ijmp	%eax

///////

/ The n-element copy routines jump here
/ with the stack untouched, if they detect
/ a bounds error on a user address.

///////
__xtrap_break__:

/	add	$16,%esp		/ pop error code, IP, CS, PSW
/	movb	$EFAULT,%ss:u+U_ERROR	/ Bad parameter error
	subl	%eax,%eax		/ Return 0 to indicate error condition.

/	cleanup routine for n-byte copy

end_copy:
/	lidt	%cs:idtmap
	pop	%es
	pop	%ds
	pop	%edi
	pop	%esi
	ret				/ Return

__xtrap_off__:				/ See __xtrap_on__ above.

/	the following four routines are used by [386/fakedma.c]
/	and will disappear when a 386 assembler implementation
/	is available

/	clearseg_b(nbytes, vaddr_t p, long fill)	(byte clear)
/	clearseg_d(nbytes, vaddr_t p, long fill)	(double word clear)


clearseg_b:				/ setspace in caller
	mov	%esp,%edx
	push	%edi
	push	%es

	mov	8(%edx),%edi
	mov	$SEG_386_KD,%eax
	movw	%ax,%es
	mov	12(%edx),%eax
	mov	4(%edx),%ecx

	cld
	rep
	stosb

	pop	%es
	pop	%edi
	ret

clearseg_d:				/ setspace in caller
	mov	%esp,%edx
	push	%edi
	push	%es

	mov	8(%edx),%edi
	mov	$SEG_386_KD,%eax
	movw	%ax,%es
	mov	12(%edx),%eax		/ mov eax,2(dx)
	mov	4(%edx),%ecx
	sar	$2,%ecx			/ char to long

	cld
	rep
	stosl

	pop	%es
	pop	%edi
	ret

/	copyseg_b(nbytes, p, q)				(byte copy)
/	copyseg_d(nbytes, p, q)				(double word copy)

/	copy the user page @ virtual address "p" to virtual address "q"

copyseg_d:				/ setspace in caller
	movl	%esp,%edx
	push	%esi
	push	%edi

	mov	8(%edx),%esi
	mov	12(%edx),%edi
	mov	4(%edx),%ecx 
	sar	$2,%ecx

	cld
	rep
	movsl

	pop	%edi
	pop	%esi
	ret

copyseg_b:				/ setspace in caller
	movl	%esp,%edx
	push	%esi
	push	%edi

	mov	8(%edx),%esi
	mov	12(%edx),%edi
	mov	4(%edx),%ecx 

	cld
	rep
	movsb

	pop	%edi
	pop	%esi
	ret


/	seg2io(long nbytes, vaddr_t p, long port)

/	nbytes must be a short word multiple

seg2io:					/ setspace in caller
	movl	%esp,%edx
	push	%esi

	mov	4(%edx),%ecx
	mov	8(%edx),%esi
	mov	12(%edx),%edx		/ mov edx,2(dx)
	sar	$1,%ecx			/ char to short

	cld
	rep
	outsw

	pop	%esi
	ret



/	io2seg(long nbytes, vaddr_t p, long port)

/	nbytes must be a short word multiple

io2seg:					/ setspace in caller
	mov	%esp,%edx
	push	%edi

	mov	4(%edx),%ecx
	mov	8(%edx),%edi
	mov	12(%edx),%edx		/ mov edx,2(dx)
	sar	$1,%ecx			/ char to short

	cld
	rep				/ Value of the ECX register is not
/	insw	(%dx)			/ updated correctly
	insw

	pop	%edi
	ret


///////
/
/ Profile scaling - special multiply routine is used for speed.
/
/ pscale(a,b) is product a*b shifted right 16 bits
/
///////

	.globl	pscale
pscale:
	mov	4(%esp),%eax	/ fetch first argument
	mull	8(%esp)		/ unsigned multiply by second argument
	shrd	$16,%edx,%eax	/ shift 64-bit product right 16 bits
	ret

///////

/ Trap an interrupt linkage.
/ Each of the machine traps has a special little
/ linkage, that sets up the type code and sends
/ control off to the common trap processor. Device
/ interrupts, other than the clock (IR0), are
/ done here.

///////

trap0:
	push	$0x00			/ Divide error.
	call	tsave
	jmp	trap

/ The debug vector is tricky.
/
/ If single stepping user code, the vector must point into Ring 1 code
/ so that a ptraced child can be synchronized with its parent.
/	use trap1_usr for this
/
/ If single stepping the kernel, the vector must point into Ring 0 code
/ so context switches switch out the debug stack frame.
/	use trap1_ker for this

	.globl	__debug_usr__
trap1_usr:
	push	$0x01			/ Single step.
	call	tsave
	jmp	__debug_usr__

	.globl	__debug_ker__
trap1_ker:
	push	$0x01			/ Single step.
	call	tsave0
	jmp	__debug_ker__

trap2:
	push	$0x02			/ Non-maskable interrupt.
	call	tsave
	jmp	trap

trap3:
	push	$0x03			/ INT 3 (breakpoint).
	call	tsave
	jmp	trap

trap4:
	push	$0x04			/ Overflow.
	call	tsave
	jmp	trap

trap5:
	push	$0x05			/ Bound check.
	call	tsave
	jmp	trap

trap6:
	push	$0x06			/ Invalid opcode.
	call	tsave
	jmp	trap

trap7:
	push	$0x07			/ Processor Extension not available.
	call	tsave
	jmp	emtrap

trap8:
/	pop	%ss:trapcode		/ Get error code from stack [always 0]
	add	$4,%esp
	push	$0x08			/ Double Exception detected
	call	tsave
	jmp	trap

trap9:
	push	$0x09			/ Processor extension segment overrun
	call	tsave
	jmp	trap

trap10:
/	pop	%ss:trapcode		/ Get error code from stack
	add	$4,%esp
	push	$0x0A			/ Invalid task state segment
	call	tsave
	jmp	trap

trap11:
/	pop	%ss:trapcode		/ Get error code from stack
	add	$4,%esp
	push	$0x0B			/ Segment not present
	call	tsave
	jmp	trap

trap12:
/	pop	%ss:trapcode		/ Get error code from stack
	add	$4,%esp
	push	$0x0C			/ Stack segment overrun or not present
	call	tsave
	jmp	trap

trap13:
/	pop	%ss:trapcode		/ Get error code from stack
/	add	$4,%esp
/	push	$0x0D			/ General protection
	call	tsave0
	jmp	gpfault

trap14:
/	pop	%ss:trapcode		/ Get error code from stack
/	add	$4,%esp
/	push	$0x0E			/ Page Fault
	call	tsave
	jmp	pagefault

trap16:
	push	$0x10			/ Floating point error
	call	tsave
	jmp	fptrap

syc:
	push	$0x22			/ Old format system calls.
	call	tsave
	jmp	trap

	.set	FAKE_EFL,12
syc32:
	push	%eax			/ save %eax
	pushf				/ modify current flags
	pop	%eax
	orw    	$PSW_VAL,%ax		/ set IF=1, IOPL=1 (user) on iret
	mov	%eax,FAKE_EFL(%esp)
	pop	%eax			/ restore %eax
	push	$0x20			/ New format system calls.
	call	tsave
	jmp	trap

sig32:
	push	%eax
	pushf
	pop	%eax
	orw    	$PSW_VAL,%ax
	mov	%eax,FAKE_EFL(%esp)
	pop	%eax
	push	$0x20			/ New format signal return.
	call	tsave
	jmp	msigend

ran:
	push	$0x21			/ Random trap.
	call	tsave
	jmp	trap

dev1:
	push	$0x0140			/ Device 1: keyboard
	call	tsave
	icall	[1<<2]+vecs
	jmp	eoi			/ Dismiss interrupt

					/ Device 2: mapped into device 9
dev3:
	push	$0x0340			/ Device 3: al1
	call	tsave
	icall	[3<<2]+vecs
	jmp	eoi			/ Dismiss interrupt

dev4:
	push	$0x0440			/ Device 4: al0
	call	tsave
	icall	[4<<2]+vecs
	jmp	eoi			/ Dismiss interrupt

dev5:
	push	$0x0540			/ Device 5: hard disk
	call	tsave
	icall	[5<<2]+vecs
	jmp	eoi			/ Dismiss interrupt

dev6:
	push	$0x0640			/ Device 6: floppy
	call	tsave
	icall	[6<<2]+vecs
	jmp	eoi			/ Dismiss interrupt

dev7:
	push	$0x0740			/ Device 7: lp
	call	tsave
	icall	[7<<2]+vecs
	jmp	eoi			/ Dismiss interrupt

dev8:
	push	$0x0840			/ Device 8:
	call	tsave
	icall	[8<<2]+vecs
	jmp	eoi2			/ Dismiss interrupt

dev9:
	push	$0x0940			/ Device 9:
	call	tsave
	icall	[9<<2]+vecs
	jmp	eoi2			/ Dismiss interrupt

dev10:
	push	$0x0A40			/ Device 10:
	call	tsave
	icall	[10<<2]+vecs
	jmp	eoi2			/ Dismiss interrupt

dev11:
	push	$0x0B40			/ Device 11:
	call	tsave
	icall	[11<<2]+vecs
	jmp	eoi2			/ Dismiss interrupt

dev12:
	push	$0x0C40			/ Device 12:
	call	tsave
	icall	[12<<2]+vecs
	jmp	eoi2			/ Dismiss interrupt

	.align	4
dev13:
	/ Used to be coprocessor exception interrupt
	/ Coprocessor err had to be cleared by writing a 0 byte to port 0xF0
	/
	push	$0x0D40			/ Device 13:
	call	tsave
	icall	[13<<2]+vecs
	jmp	eoi2			/ Dismiss interrupt

dev14:
	push	$0x0E40			/ Device 14:
	call	tsave
	icall	[14<<2]+vecs
	jmp	eoi2			/ Dismiss interrupt

dev15:
	push	$0x0F40			/ Device 15:
	call	tsave
	icall	[15<<2]+vecs
	jmp	eoi2			/ Dismiss interrupt

///////

/ Clock interrupt.

///////

clk:
	push	$0x0040
	call	tsave			/ Perform trap save.
	mov	X_ERR+12(%esp),%eax	/ ECS at tick time
	and	$3,%eax			/ This will be R_USR iff user mode
	push	%eax
	mov	X_ERR+12(%esp),%eax	/ EIP at tick time
	push	%eax
	call	clock			/ clock(eip, umode)
	add	$8,%esp			/ pop arguments.
	jmp	eoi			/ Dismiss interrupt

///////

/ This co-routine is called to dismiss an interrupt.
/ The interrupt code is in X_ERR(%esp)

/ Control returns to "tsave"

///////

	.globl	eoi2
eoi2:
	cli
	movb	$0x20,%al	/ Send a non specific EOI
	outb	$SPIC		/ to the slave PIC.
	IODELAY
	movb	$0x0B,%al	/ OCW3 - read isr
	outb	$SPIC
	IODELAY
/	inb	$SPIC		/ in-service register to %eax:8..15
/	testb	%al,%al
/	jnz	eoi2x		/ no EOI to master if slave isr nonzero
eoi:
	cli
	movb	$0x20,%al	/ Send a non specific EOI
	outb	$PIC		/ to the master PIC.
	IODELAY
eoi2x:	ret			/ Done.

///////

/ Read the equipment description. Use
/ the "int 11" interface, so that the IBM
/ ROM will do all the details.

///////

int11:	mov	%cs:val11,%eax		/ Ask the ROM
	ret				/ to put stuff in AX

///////

/ Bootstrap.
/ Called by the keyboard driver on control-alt-del.
/ Requests the 8042 controller to initiate a processor reset,
/ which is the only way to terminate protected mode operation.

/	Reference: IBM-AT Technical Reference Manual,
/			Real-time Clock/CMOS RAM [Page 1-45]
/			Keyboard controller [Page 1-40]
/			Test 3, Page 5-68.

///////

boot:
	cli				/ Disable interrupts.

	subl	%ecx,%ecx
loc12:	inb	$KBCTRL			/ Wait for 8042 input buffer to empty.
	testb	$2, %al
	loopne	loc12
	IODELAY

	movb	$0xFE,%al		/ Issue a shutdown command
	outb	$KBCTRL			/ to the 8042 control port.

loc13:	hlt				/ Halt until processor reset occurs.
	jmp	loc13

	.globl	putchar

/	Comment in the line below if debugging output is to go to the
/	printer

/putchar:

	movb	4(%esp),%al
	cmpb	$0xa,%al
	jne	loc18
	push	$0xd
	call	putchar
	add	$4,%esp
loc18:	mov	$LPSTAT,%edx
	inb	(%dx)
	testb	$IBMNBSY,%al
	je	loc18

	mov	$LPCSR,%edx
	movb	$SEL+NINIT, %al
	outb	(%dx)

	mov	$LPDATA, %edx
	movb	4(%esp),%al
	outb	(%dx)

	mov	$LPCSR,%edx
	movb	$SEL+NINIT+STROBE,%al 
	outb	(%dx)
	movb	$8, %cl
l_1:	decb	%cl
	jne	l_1
	movb	$SEL+NINIT, %al
	outb	(%dx)
	ret

/ long _canl(l) long l;
/ This is called by the routines that
/ transform longs to and from the
/ canonical formats.

_canl:
	mov	4(%esp),%eax
	rol	$16,%eax
	ret

regcr2:	mov	%cr2,%eax
	ret

regfp:	mov	%ebp,%eax
	ret

	.align	4		/ CPU resets if val11 isn't aligned.
val11:	.long	0		/ Value obtained from int11 [in code].

aicodep:
	sub	%ebx,%ebx
	sub	$aicodep,%ebx
	lea	fn(%ebx),%eax
	mov	%eax,argl(%ebx)
	lea	a1(%ebx),%eax
	mov	%eax,argl+4(%ebx)
	lea	argl+8(%ebx),%eax	/ No environment
	push	%eax
	lea	argl(%ebx),%eax		/ Argument list
	push	%eax
	lea	fn(%ebx),%eax		/ File name
	push	%eax
	sub	$4,%esp			/ Dummy word for exec
	movl	$59, %eax
	lcall	$0x7,$0
	jmp	.			/ Instant page fault if exec failed!
	.alignoff
	.align	2
argl:	.long	0			/ argv[0] = "/etc/init";
	.long	0			/ argv[1] = "";
	.long	0			/ argv[2] = NULL;

fn:	.byte	"/etc/init",0
a1:	.byte	0
sb:
	.set	aicodes, .-aicodep

///////

/ Task State Segment - Coherent runs as a single protected mode 386 task.

///////
	.alignon
	.align	4
	.globl	tss_sp0		/ Use run-time fixup for tss_sp0
	.globl	tssIoMap
	.globl	tssIoEnd
tss:				/ Task State Segment.
tss_lnk:.long	0		/  0: Back link selector to TSS.
tss_sp0:.long	ESP0_START	/  4: SP for CPL 0.
tss_ss0:.long	SEG_RNG0_STK	/  8: SS for CPL 0.
tss_sp1:.long	ESP1_START	/  C: SP for CPL 1.
tss_ss1:.long	SEG_RNG1_STK	/ 10: SS for CPL 1.
tss_sp2:.long	u+NBPC		/ 14: SP for CPL 2.
tss_ss2:.long	SEG_386_KD	/ 18: SS for CPL 2.
tss_cr3:.long	PTABLE0_P<<BPCSHIFT / 1C: CR3 (PDBR)
tss_ip:	.long	0		/ 20: EIP (Entry point).
tss_psw:.long	0		/ 24: Flag word.
tss_ax:	.long	0		/ 28: Register AX.
tss_cx:	.long	0		/ 2C: Register CX.
tss_dx:	.long	0		/ 30: Register DX.
tss_bx:	.long	0		/ 34: Register BX.
tss_bp:	.long	0		/ 38: Register BP.
tss_sp:	.long	0		/ 3C: Register SP.
tss_si:	.long	0		/ 40: Register SI.
tss_di:	.long	0		/ 44: Register DI.
tss_es:	.long	0		/ 48: Register ES.
tss_cs:	.long	0		/ 4C: Register CS.
tss_ss:	.long	0		/ 50: Register SS.
tss_ds:	.long	0		/ 54: Register DS.
tss_fs:	.long	0		/ 58: Register FS.
tss_gs:	.long	0		/ 5C: Register GS.
tss_ldt:.long	SEG_LDT		/ 60: Task LDT Selector.
	.long	TSS_IOMAP_OFF	/ 64: T bit & I/O map base
/ I/O map is part of tss.
/ Bitmap up to port address TSS_IOMAP_LEN.
/ Initialize to all 1's, meaning no I/O allowed.
/ tss + 0x68 = tssIoMap
tssIoMap:
	.long	[TSS_IOMAP_LEN .div 32] # -1
tssIoEnd:
	.long	-1
///////

/ Data.

///////
	.data
sdata:

vecs:	.long	16 # vret	/ Interrupt vector table

trapcode:.long	0

	.text
///////

/ i8086 coherent clist hack.

///////

/LXXX:	.long	NCPCL+4

/cltinit:
/	pushf			/ s = sphi()
/	cli
/	mov	NCLIST,%eax
/	imull	LXXX,%eax
/	addl	clistp,%eax
/	sub	%ecx,%ecx
/	jmp	loc32

/loc33:	mov	%ecx,(%eax)
/	mov	%eax,%ecx
/loc32:	sub	$NCPCL+4, %eax
/	cmp	clistp,%eax
/	jnb	loc33

/	mov	%ecx,cltfree
/	call	spl
/	add	$0x04,%esp
/	ret

/getq:
/	push	%esi

/	mov	8(%esp),%edx
/	sub	%ecx,%ecx
/	cmp	%ecx,(%edx)	/ if (cqp->cq_cc==0)
/	je	loc21

/	pushf			/ s = sphi()
/	cli
/	mov	12(%edx),%esi	/ op = cqp->cq_op	[%esi]
/	mov	16(%edx),%eax	/ ox = cqp->cq_ox	[%eax]
/	movb	4(%eax,%esi),%cl
/	push	%ecx		/ save = op->cl_ch[ox]
/	decl	(%edx)		/ if (--cqp->cq_cc == 0)
/	je	loc23
/	inc	%eax		/ ++ox
/	mov	%eax,16(%edx)	/ cqp->cq_ox = ox
/	cmp	$NCPCL,%eax	/ if (ox == NCPL)
/	jne	loc24

/loc23:	sub	%eax,%eax
/	mov	%eax,16(%edx)	/ cqp->cq_ox = 0
/	mov	(%esi),%ecx	/ np = op->cl_fp
/	mov	%ecx,12(%edx)	/ cqp->cq_op = np
/	cmp	%eax,%ecx	/ if (np==0)
/	jne	loc25
/	mov	%eax,4(%edx)		/ cqp->cq_ip = 0
/	mov	%eax,8(%edx)		/ cqp->cq_ix = 0

/loc25:	mov	cltfree,%ecx
/	mov	%ecx,(%esi)	/ op->cl_fp = cltfree
/	mov	%esi,cltfree	/ cltfree = op
/	cmp	%eax,cltwant	/ if (cltwant)
/	je	loc24
/	mov	%eax,cltwant		/ cltwant = 0
/	push	$cltwant
/	call	wakeup			/ wakeup(&cltwant)
/	pop	%eax

/loc24:	pop	%esi
/	call	spl		/ spl(s)
/	pop	%eax
/	mov	%esi,%eax	/ return save
/	pop	%esi
/	ret
/loc21:
/	mov	$-1,%eax			/ return -1
/	pop	%esi
/	ret

/putq:
/	push	%esi
/	sub	%eax,%eax
/	pushf			/ s = sphi();
/	cli
/	mov	12(%esp),%edx	/ ebp = cqp
/	mov	4(%edx),%esi	/ ip = cqp->cq_ip	[%esi]
/	mov	8(%edx),%ecx	/ ix = cqp->cq_ix	[%ecx]
/	cmp	%eax,%ecx	/ if (ix==0) {
/	jne	loc26
/	mov	cltfree,%esi		/ ip = cltfree
/	cmp	%eax,%esi		/ if (ip==0)
/	je	loc27			/ goto bad;
/	mov	(%esi),%ecx
/	mov	%ecx,cltfree		/ cltfree = cltfree->cl_fp
/	mov	%eax,(%esi)		/ ip->cl_fp = 0
/	mov	4(%edx),%ecx		/ np = cqp->cq_ip
/	cmp	%eax,%ecx		/ if (np==0)
/	jne	loc29
/	mov	%esi,12(%edx)			/ cqp->cq_op = ip
/	jmp	loc30
/					/ else
/loc29:	mov	%esi,(%ecx)			/ np->cl_fp = ip

/loc30:	mov	%esi,4(%edx)		/ cqp->cq_ip = ip
/	mov	%eax,%ecx		/ ix = 0
/				/ }

/loc26:
/	movb	16(%esp),%al	/ ip->cl_ch[ix] = c
/	movb	%al, 4(%esi,%ecx) 
/	inc	%ecx		/ ix++
/	cmp	$NCPCL,%ecx	/ if (ix==NCPCL)
/	jne	loc31
/	sub	%ecx,%ecx		/ ix = 0

/loc31:	mov	%ecx,8(%edx)	/ cqp->cq_ix = ix
/	incl	(%edx)		/ cqp->cq_cc++
/	call	spl		/ spl(s)
/	add	$4,%esp
/	mov	12(%esp),%eax	/ return (c)
/loc28:
/	pop	%esi
/	ret
/loc27:
/	call	spl		/ 		spl(s)
/	add	$4,%esp
/	mov	$-1,%eax	/ 		return -1
/	jmp	loc28

/clrq:
/	mov	4(%esp),%edx
/	pushf
/	cli

/loc34:	push	%edx
/	call	getq
/	pop	%edx
/	or	%eax,%eax
/	jge	loc34

/	call	spl
/	pop	%eax
/	ret

/loc35:	movl	$0x01,cltwant
/	push	%eax
/	push	%eax
/	push	$0x0100
/	push	$cltwant
/	call	sleep
/	add	$16,%esp
/waitq:
/	sub	%eax,%eax
/	cmp	%eax,cltfree
/	jne	loc35
/	ret

///////

/ atbsyw()	-- wait for AT disk controller to become not busy

/	Return:	0 = timeout
/		* = not busy

///////
/atbsyw:
/	mov	$0x3FFFF, %ecx 
/	mov	ATSREG, %edx
/loc16:	inb	(%dx)
/	testb	$BSY_ST, %al
/	loopne	loc16
/	mov	%ecx, %eax 
/	ret

///////

/ AT Hard Disk Assembler Support
/ atbsyw()	     - wait while controller is busy
/ atdrqw()	     - wait for controller to request data transfer

///////
///////

/ atdrqw()	-- wait for AT disk controller to initiate data request

/	Return:	0 = timeout
/		* = data requested

///////

/atdrqw:
/	mov	$0x3FFFF, %ecx
/	mov	ATSREG, %edx 
/loc17:	inb	(%dx)
/	testb	$DRQ_ST, %al 
/	loope	loc17
/	mov	%ecx, %eax 
/	ret

/       Read a byte from the CMOS.  Takes one argument--the
/       CMOS address to read from as an int; returns the
/       value read as a char.
/
/	int read_cmos(int addr);

read_cmos:
	push	%esi
	push	%edi
        movb    12(%esp), %al	/ Fetch address from stack.
        outb    $CMOSA		/ Send address to CMOS.
	IODELAY
	sub	%eax, %eax	/ Zero out everything we don't want.
        inb     $CMOSD		/ Get Value from CMOS into al.
	pop	%edi
	pop	%esi
        ret                     / Return from read_cmos().

/       Write a byte to the CMOS.
/
/	void write_cmos(int addr, int data)

write_cmos:
	push	%esi
	push	%edi
        movb    12(%esp), %al	/ Fetch address from stack.
        outb    $CMOSA		/ Send address to CMOS.
	IODELAY
        movb    16(%esp), %al	/ Fetch address from stack.
        outb     $CMOSD		/ Get Value from CMOS into al.
	IODELAY
	pop	%edi
	pop	%esi
        ret                     / Return from read_cmos().

/ Read timer channel 0 into int value.  
/ Clock counts down from 11932 to 0 with each clock tick.
	.globl	read_t0
read_t0:
	pushfl
	cli
	xorl	%eax,%eax	/ Counter latch timer 0 and clear return val
	outb	$PIT+3
	IODELAY
	inb	$PIT		/ low byte of counter latch
	IODELAY
	movb	%al,%ah
	inb	$PIT		/ high byte of counter latch
	IODELAY
	xchgb	%al,%ah
	popfl
	ret

/ return current contents of psw
	.globl	read_psw
read_psw:
	pushfl
	popl	%eax
	ret

/ Read master PIC state
/ return 00:xx:yy:zz 4-byte int value
/	xx: interrupt mask
/	yy: isr
/	zz: irr

/	.globl	mchirp
/FOO	.macro	ch
/	push	ch
/	call	mchirp
/	add	$4,%esp
/	.endm

/	.globl	rd_m_pic
/rd_m_pic:
/	pushfl
/	cli
/	sub	%eax,%eax
/	inb	$PICM		/ interrupt mask to %eax:16..23
/	shl	$8,%eax
/	movb	$0x0B,%al	/ OCW3 - read isr
/	outb	$PIC
/	IODELAY
/	inb	$PIC		/ in-service register to %eax:8..15
/	shl	$8,%eax
/	movb	$0x0A,%al	/ OCW3 - read irr
/	outb	$PIC
/	IODELAY
/	inb	$PIC		/ irpt request register to %eax:0..7
/	popfl
/	ret

/ Read slave PIC state
/ return 00:xx:yy:zz 4-byte int value
/	xx: interrupt mask
/	yy: isr
/	zz: irr

/	.globl	rd_s_pic
/rd_s_pic:
/	pushfl
/	cli
/	sub	%eax,%eax
/	inb	$SPICM		/ interrupt mask to %eax:16..23
/	shl	$8,%eax
/	movb	$0x0B,%al	/ OCW3 - read isr
/	outb	$SPIC
/	IODELAY
/	inb	$SPIC		/ in-service register to %eax:8..15
/	shl	$8,%eax
/	movb	$0x0A,%al	/ OCW3 - read irr
/	outb	$SPIC
/	IODELAY
/	inb	$SPIC		/ irpt request register to %eax:0..7
/	popfl
/	ret

/ return current contents of cr0
	.globl	read_cr0
read_cr0:
	movl	%cr0,%eax
	ret

/ return current contents of cr2
	.globl	read_cr2
read_cr2:
	movl	%cr2,%eax
	ret

/ return current contents of cr3
	.globl	read_cr3
read_cr3:
	movl	%cr3,%eax
	ret

/////////
/
/ Debugging support.
/
/////////
	.globl	write_dr0
	.globl	write_dr1
	.globl	write_dr2
	.globl	write_dr3
	.globl	write_dr6
	.globl	write_dr7

	.globl	read_dr0
	.globl	read_dr1
	.globl	read_dr2
	.globl	read_dr3
	.globl	read_dr6
	.globl	read_dr7

/ write arg to dr0
write_dr0:
	movl	4(%esp),%eax
	movl	%eax,%dr0
	ret

/ write arg to dr1
write_dr1:
	movl	4(%esp),%eax
	movl	%eax,%dr1
	ret

/ write arg to dr2
write_dr2:
	movl	4(%esp),%eax
	movl	%eax,%dr2
	ret

/ write arg to dr3
write_dr3:
	movl	4(%esp),%eax
	movl	%eax,%dr3
	ret

/ write arg to dr6
write_dr6:
	movl	4(%esp),%eax
	movl	%eax,%dr6
	ret

/ write arg to dr7
write_dr7:
	movl	4(%esp),%eax
	movl	%eax,%dr7
	ret

read_dr0:
	movl	%dr0,%eax
	ret

read_dr1:
	movl	%dr1,%eax
	ret

read_dr2:
	movl	%dr2,%eax
	ret

read_dr3:
	movl	%dr3,%eax
	ret

read_dr6:
	movl	%dr6,%eax
	ret

read_dr7:
	movl	%dr7,%eax
	ret

/ write to the EM bit of CR0
/ this routine is a stub for the ring 0 code
/ argument is 0 or 1
/
/	void setEm(int bit)
	.globl	setEm
setEm:
	movl	4(%esp),%eax	/ fetch argument
	pushf
	cli
	pushl	%eax
	lcall	$SEG_SET_EM,$0	/ gate to setEmfR0
	/ setEmfR0 will delete 4 bytes worth of args
	popf
	ret

/ Ring 0 write to CR0 EM bit.  Called via a gate.
/ Want interrupts off when we arrive since the interrupt gates
/ lead into Ring 1.
setEmfR0:
	movb	8(%esp),%cl	/ fetch argument

	cmpb	$0,%cl
	movl	%cr0,%eax
	jz	se00
	orb	$4,%al		/ set EM bit
	andb	$0xDF,%al	/ clear NE bit
	jmp	se01
se00:
	andb	$0xFB,%al	/ clear EM bit
	orb	$0x20,%al	/ set NE bit
se01:
	mov	%eax,%cr0
	/ make 4-byte arg list disappear
	lret	$4

/ return nonzero if paging is turned on
	.globl	paging
paging:
	movl	(%esp),%eax		/ fetch return address
	cmpl	$[SBASE<<BPCSHIFT],%eax	/ is it >= unsigned FFC0_0000?
	jae	pagingMaybe
	xorl	%eax,%eax		/ if not, no paging
	ret
pagingMaybe:
	movw	%cs,%ax			/ if return addr high, cs is a selector
	cmpw	$0x58,%ax		/ selectors 58-6F are nonpaging
	jb	pagingYes
	cmpw	$0x6F,%ax		/ selectors 58-6F are nonpaging
	ja	pagingYes
	xorl	%eax,%eax		/ no paging
	ret
pagingYes:
	movl	$1,%eax
	ret

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.