Coherent4.2.10/i386/k0.s

Compare this file to the similar file:
Show the results in this format:

	.unixorder
	.llen	132
	.include	"as.inc"
	.include	"lib/struct.inc"
	.include	"lib/intr.inc"
	.include	"lib/ddi.inc"

IODELAY	.macro
/	jmp	.+2		/ DELAY
/	jmp	.+2		/ DELAY
	pushl	%eax
	inb	$0x61
	popl	%eax
	.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,0xFFFFFB00
	.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:	k0.s,v $
/
/ Revision 1.1  93/10/29  00:56:47  nigel
/ R98 (aka 4.2 Beta) prior to removing System Global memory
/
/ Revision 2.4  93/09/02  18:10:06  nigel
/ Many edits for library and preparation for new interrupt system,
/ plus removal of much dead code and icodep cleanup.
/
/ Revision 2.3  93/07/26  13:55:44  nigel
/ Nigel's R80
/
/ 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.
///////

///
/ Start with the assembler in 16-bit mode, such as it is...
///
	.16
stext:					/ kernel code starts at stext+0x100
	.org .+0x100			/ reserve stack space
	cli				/ No interrupts, please.

/ Some systems come up with NT (Nested Task) flag in PSW undefined. 
/ Clear it NOW.

	pushfw
	popw	%ax
	andw	$0xBFFF,%ax
	pushw	%ax
	popfw

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

	movb	$'!', %al

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

	/ equipment status word to AX
	int	$0x11			/ Obtain int 11 value before printf().
	xorl	%ecx,%ecx		/ clear high 16 bits of ecx
	movw	%ax,%cx			/ esw -> cx

///
/ Although we are still running in 16-bit mode, as has trouble with the
/ addresses in the following "movl" and "lgdtl" instructions, so turn on
/ 32-bit assembly early and hand-code the prefixes.
///
	.32
	/ 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

///
/ Move between CR0 and %eax is always 32 bits, regardless of the current
/ operand/address modes.
///
	/ 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:
	movw	$SEG_386_ID, %ax
	movw	%ax, %ds
	movw	%ax, %es
	movw	%ax, %ss
	movw	$SEG_386_UD|R_USR, %ax
	movw	%ax, %fs
	mov	$stext+0x100,%eax	/ 256 byte stack for initialization
	mov	%eax,%esp

/ 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
	loopne	loc2
	IODELAY

/ A20 may not enabled for up to 400 msec.  The proper handshake is to
/ send another command - we use 0xAE, keyboard enable - to the keyboard
/ controller and wait for its input buffer to be empty.  Then A20 should
/ be enabled.

	movb	$0xAE,%al	/ Send a commnad to the keyboard controller.
	outb	$KBDATA
	IODELAY

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

/ 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	$0xFB,%al	/ Disable interrupts from master PIC.
	outb	$PICM		/ (except for 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
	xor	%ebp, %ebp	/ Halt stack backtraces
	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	%ax, %es		/ Need %es too, for memset () etc...
	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
/
	pushl	$SEG_RNG1_STK		/ SS
	pushl	$ESP1_START		/ ESP
	pushl	$PSW_VAL		/ PSW
	pushl	$SEG_RNG1_TXT		/ CS
	pushl	$__xmain__		/ IP
	movw	$SEG_386_KD, %ax	/ DS, ES
	movw	%ax, %ds		/ Map data segment
	movw	%ax, %es		/ Map extra segment
		xorl	%eax, %eax
		movw	%ax, %fs
		iret			/ Go to ring 1

/
/ 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.

/
/ Enter User mode from Ring 1 kernel
/
	pushl	$SEG_386_UD|R_USR	/ SS
	pushl	$NBPC			/ ESP
	pushfl				/ PSW
	pushl	$SEG_386_UI|R_USR	/ CS
	pushl	$0			/ IP

	cli				/ interrupts off
	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.

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

BYPASS		.macro	addr
		cmpl	$addr, _eip(%esp)	/ trapped EIP
		jz	?tsaveok
		.endm
	
tsave0:
		pusha
		push	%ds			/ Save current state
		push	%es
		push	%fs
		push	%gs
	
		movw	$SEG_386_KD, %ax	/ Map ds
		movw	%ax, %ds
		movw	%ax, %es
		movw	$SEG_386_UD|R_USR, %ax	/ Map es
		movw	%ax, %fs

/ The following code is for helping to debug startup problems

.if	0
		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
 
?loop:		jmp	?loop

?tsaveok:

/ Note that the .endi /must/ be indented to stroke the Coherent 386
/ assembler. Another fine product from MWC like its sickly brethren.

	.endi

		icall	_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.
	
		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
		movzxb	cpu+dc_ipl, %eax	/ current IPL
		stosl				/ save it
		xorl	%eax, %eax
		movw	%fs, %ax		/ save space pointer
		stosl
		mov	%ecx, %edi		/ Put di back,
		sub	%eax, %eax		/ indicate a state save and
		ret				/ return to caller.

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

envrest:
		mov	4(%esp), %esi		/ Pointer to context
do_restore:
		cld
		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
		lodsl				/ Restore pc
		movl	%eax, (%esp)

		lodsl				/ Restore IPL
		movb	%al, cpu+dc_ipl
		movl	_masktab(%eax,4), %eax	/ new mask

	/ send the mask out to the PICs after including the base mask info.

		orl	cpu+dc_base_mask, %eax
		outb	$PICM
		movb	%ah, %al
		outb	$SPICM

		lodsl
		movw	%ax, %fs		/ Restore space
		mov	%ecx, %esi		/ Restore si
		mov	$1, %eax		/ We are restoring
		ret				/ Return

///////
/ 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

	/ 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 with interrupts disabled - unlike envrest (), in
	/ this case the destination %esp may be lower than the caller's.

		jmp	do_restore


/ 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, with no return value. Since we want to test bit 10
/ of the flags word, we test bit 2 of the second byte with a byte test.
/ (An earlier version of this routine used IRET, which is a bad idea beacuse
/ it is a) very slow, and b) dangerous).

spl:
		pushf				/ Transfer previous flags to
		pop	%eax			/ %eax by way of the stack
		testb	$0x2,5(%esp)		/ Test argument interrupt flag
		je	?cleari			/ Branch if flag was clear
		sti
		ret
?cleari:
		cli
		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' (fs)
/	with the segment reference passed as an argument. 
/	The value returned is the old value of the 'fs' register

setspace:
		xorl	%eax, %eax
		movw	%fs, %ax
		movw	4(%esp), %fs
		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__:

///////

start_copy	.macro
		movl	%esp, %edx		/ Frame pointer for copy code
		.endm

end_copy	.macro
		ret
		.endm

copy_frame	.define	%edx

///////
/ Fetch a byte from the user's data space.
/ getubd(u)
/ char *u;
///////

getubd:
		start_copy
		movl	%ss:4(copy_frame), %ecx
		movzxb	%fs:(%ecx), %eax
		end_copy

///////
/ Fetch a short from the user's data space.
/	Coherent 386 fetches a 16 bit short
/ getusd(u)
/ char *u;
///////

getusd:
		start_copy
		movl	%ss:4(copy_frame), %ecx
		movzxw	%fs:(%ecx), %eax
		end_copy

///////
/ Fetch a word from the user's data space.
/	Coherent 386 fetches a 32 bit word
/ getuwd(u)
/ char *u;
///////

getuwd:
getupd:
		start_copy
		movl	%ss:4(copy_frame), %ecx
		movl	%fs:(%ecx), %eax
		end_copy

///////
/ Store a byte into the user's data space.
/ putubd(u, w)
/ char *u;
/ int w;
///////

putubd:	
		start_copy
		movl	%ss:4(copy_frame), %ecx
		movb	%ss:8(copy_frame), %al
		movb	%al, %fs:(%ecx)
		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:
		start_copy
		movl	%ss:4(copy_frame), %ecx
		movw	%ss:8(copy_frame), %ax
		movw	%ax, %fs:(%ecx)
		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:
		start_copy
		movl	%ss:4(copy_frame), %ecx
		movl	%ss:8(copy_frame), %eax
		movl	%eax, %fs:(%ecx)
		end_copy

///////
/ Perform a block-clear of user-space memory
/ size_t umemclear (caddr_t * dest, size_t size)
//////
		.globl	umemclear
umemclear:
		start_copy

		push	%ds			/ Preserve %ds
		push	%es			/ Preserve %es (?)
		pushl	%esi			/ Preserve %esi
		pushl	%edi			/ Preserve %esi

		movw	%fs, %ax
		movw	%ax, %es		/ Dest segment

		movl	%ss:4(copy_frame), %edi	/ Dest

		movl	%ss:8(copy_frame), %ecx	/ Length
		sarl	$2, %ecx		/ in longwords.

		xorl	%eax, %eax		/ Zero-fill target
		rep stosl			/ If %ecx > 0, clear longwords

		movl	%ss:8(copy_frame), %ecx	/ Length
		andl	$3, %ecx		/ residual byte count
		rep stosb			/ If %ecx > 0, clear bytes

		movl	%ss:8(copy_frame), %eax	/ Return value

		popl	%edi			/ Restore registers
		popl	%esi
		pop	%es
		pop	%ds
		end_copy

////////
/ 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;
///////

kucopy:
		start_copy

		push	%ds			/ Preserve %ds
		push	%es			/ Preserve %es (?)
		pushl	%esi			/ Preserve %esi
		pushl	%edi			/ Preserve %esi

		movw	%fs, %ax
		movw	%ax, %es		/ Dest segment

		movl	%ss:4(copy_frame), %esi	/ Source
		movl	%ss:8(copy_frame), %edi	/ Dest

		movl	%ss:12(copy_frame), %eax / Return value
		movl	%eax, %ecx		/ Length
		sarl	$2, %ecx		/ in longwords.
		rep movsl			/ If %ecx > 0, move longwords

		movl	%eax, %ecx		/ Length
		andl	$3, %ecx		/ residual byte count
		rep movsb			/ If %ecx > 0, move bytes

		popl	%edi			/ Restore registers
		popl	%esi
		pop	%es
		pop	%ds
		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:
		start_copy

		push	%ds			/ Preserve %ds
		push	%es			/ Preserve %es (assume == %ds)
		pushl	%esi			/ Preserve %si
		pushl	%edi			/ Preserve %di

		movw	%fs, %ax
		movw	%ax, %ds		/ Source segment

		mov	%ss:4(copy_frame), %esi	/ Source
		mov	%ss:8(copy_frame), %edi	/ Dest

		movl	%ss:12(copy_frame), %eax / Return value
		movl	%eax, %ecx		/ Length
		sarl	$2, %ecx		/ in longwords
		rep movsl			/ If %ecx > 0, move longwords

		movl	%eax, %ecx		/ Length
		andl	$3, %ecx		/ residual byte count
		rep movsb			/ if %ecx > 0, move bytes

		popl	%edi			/ Restore registers
		popl	%esi
		pop	%es
		pop	%ds
		end_copy			/ Return



///////
/ Block copy max of "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 or -1 on a fault.
/ ukstrncopy(u, k, n, eos)
/ char *u;
/ char *k;
/ int n;
///////
.globl ukstrncopy
ukstrncopy:
		start_copy

		push	%ds			/ Preserve %ds
		push	%es			/ Preserve %es (assume == %ds)
		pushl	%esi			/ Preserve %si
		pushl	%edi			/ Preserve %di
		pushl	%ebx			/ Preserve %ebx

		movw	%fs, %ax
		movw	%ax, %ds		/ Source segment

		mov	%ss:4(copy_frame), %esi	/ Source
		mov	%ss:8(copy_frame), %edi	/ Dest

		movl	%ss:12(copy_frame), %ecx / Length

		movl	%ss:16(copy_frame), %ebx / End of segment

		cld

?ukstrcpyloop:
		cmpl	%ebx, %esi		/ Make sure in seg still
		jae     ?uk_badaddr		/ Out of segment ... error
		lodsb
		stosb
		testb	%al,%al			/ Found a null?
		loopne	?ukstrcpyloop

		movl	%ss:12(copy_frame), %ebx
		subl	%ecx, %ebx		/ How many non-zero moved?

		rep	stosb			/ Null-pad destination

		movl	%ebx, %eax		/ Return non-zero moved
		jmp	?uk_out

?uk_badaddr:
		movl	$0xFFFFFFFF, %eax	/ Return -1
?uk_out:

		popl	%ebx
		popl	%edi			/ Restore registers
		popl	%esi
		pop	%es
		pop	%ds
		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:
		start_copy

		push	%ds			/ Preserve %ds
		push	%es			/ Preserve %es
		pushl	%esi			/ Preserve %esi
		pushl	%edi			/ Preserve %edi

		les	%ss:12(copy_frame), %edi / Dest segment, length
		lds	%ss:4(copy_frame), %esi	/ Source segment, length

		movl	%ss:20(copy_frame), %eax / Return value
		movl	%eax, %ecx		/ Length
		sarl	$2, %ecx		/ in longwords
		rep movsl			/ if %ecx > 0, move longwords

		movl	%eax, %ecx		/ Length
		andl	$3, %ecx		/ residual byte count
		rep movsb			/ if %ecx > 0, move bytes

		popl	%edi
		popl	%esi
		pop	%es
		pop	%ds
		end_copy			/ Return

////////
/ Read a byte from a selector and offset.
/
/ ffbyte(off, sel)
/ unsigned long sel;
/ unsigned long off;
////////
		.globl	ffbyte
ffbyte:
		start_copy
		lgs	%ss:4(copy_frame), %ecx	/ Source seg:offset
		movzxb	%gs:(%ecx), %eax	/ Move with zero-fill
		end_copy

////////
/ Read a (short) word from a selector and offset.
/
/ ffword(off, sel)
/ unsigned long sel;
/ unsigned long off;
////////
		.globl	ffword
ffword:
		start_copy
		lgs	%ss:4(copy_frame), %ecx	/ Source seg:offset
		movzxw	%gs:(%ecx), %eax	/ Move with zero-fill
		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:
		start_copy
		lgs	%ss:4(copy_frame), %ecx	/ Dest seg:offset
		movb	%ss:12(copy_frame), %al
		movb	%al, %gs:(%ecx)
		end_copy

////////
/ write a (short) word using a selector and offset.
/
/ sfword(off, sel, word)
/ unsigned long sel;
/ unsigned long off;
/ int word;
////////
		.globl	sfword
sfword:
		start_copy
		lgs	%ss:4(copy_frame), %ecx	/ Dest seg:offset
		movw	%ss:12(copy_frame), %ax
		movw	%ax, %gs:(%ecx)
		end_copy

///////
/ The n-element copy routines jump here with the stack untouched if they
/ detect a bounds error or page fault on a user address. The only routines
/ above that use the stack at all do so with a standard format, so we detect
/ what is on the stack and restore appropriately.
/ [ For simplicity, just assume that the pushed values will either all be
/   there or not be there at all, which is a very good assumption. ]
///////

__xtrap_break__:
		subl	%eax, %eax		/ Return 0 to indicate error
						/ condition.
		cmpl	%esp, %edx		/ Anything on stack?
		je	?no_stack

		popl	%edi			/ Restore registers
		popl	%esi
		pop	%es
		pop	%ds
?no_stack:
		end_copy			/ Return

__xtrap_off__:				/ See __xtrap_on__ above.

///////
/ 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

__gpfault:
/		add	$4 ,%esp			/ discard fault code
/		push	$0x0D			/ General protection
		call	tsave0
		jmp	gpfault

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

__stackfault:
		call	tsave0
		jmp	stackfault

///////
/ 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.
/
/	Reference: IBM-AT Technical Reference Manual,
/			Real-time Clock/CMOS RAM [Page 1-45]
/			Keyboard controller [Page 1-40]
/			Test 3, Page 5-68.
/
/ Modified 03-14-94, Udo
/
/ Extended 94/04/30, Hal
/
/ The following should be cleaned up sometime:
/
/ A halt instruction is only valid from Ring 0.
/ It is only issued from COHERENT when we want to reboot.
/ Some motherboard configurations have glue chips that specifically
/ watch for a write of 0xFE to port 0x64 (KBCTRL) followed by a "hlt"
/ as a trigger for cold boot, so we want to do this whenever rebooting.
/
/ The right way to do this will be to make "boot:" a call gate into
/ a routine which does the i/o's, then loops between hlt and writing
/ FE to port 64 inside the gate.  Since there is not time to do this
/ now, we count on the gp trap on "hlt" to get us into Ring 0, to the
/ "halt:" entry point.
/
/ Also, we should insert code here to call a keyboard routine so as
/ to restore the keyboard to scan code set 1 if it is currently in
/ scan code set 3.
/
///////
boot:
		/ make sure that the shutdown status byte in
		/ CMOS is 0

		movb	$0x0f,%al		/ offset of shutdown status in CMOS
		outb	$0x70			/ CMOS address port
		IODELAY

		movb	$0,%al			/ set the shutdown status
		outb	$0x71			/ to 0 in CMOS
		IODELAY

halt:
		cli				/ Disable interrupts.

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

		hlt				/ Halt until processor reset
		jmp	loc13


/ 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

val11:		.long	0		/ Value obtained from int11 [in code].

aicode:
		push	$envp - aicode		/ Empty environment
		push	$argl - aicode		/ Argument list for init
		push	$fn - aicode		/ File name to exec ()
		push	%eax			/ Dummy word for exec
		movl	$59, %eax
		lcall	$0x7,$0
		jmp	.			/ exec failed, page fault

		.alignoff
		.align	2
argl:		.long	fn - aicode		/ argv[0] = "/etc/init";
		.long	a1 - aicode		/ argv[1] = "";
envp:		.long	0			/ argv[2] = NULL;

fn:		.byte	"/etc/init",0
a1:		.byte	0
aicode_end:

///////
/ 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.
	.word	0		/ 64: T bit.
	.word	TSS_IOMAP_OFF	/ 66: 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 + 31] .div 32] # -1
tssIoEnd:
	.long	[[0x1000 - TSS_IOMAP_LEN] .div 32] # -1
	.long	-1
///////

/ Data.

///////
	.data
sdata:

vecs:	.long	16 # vret	/ Interrupt vector table

	.text
///////
/       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 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

/ write to cr0
	.globl write_cr0
write_cr0:
	movl	4(%esp),%eax
	movl	%eax,%cr0
	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

///////////////////////
/ Data tables for initial GDT, LDT, IDT, TSS.
/
/	the init gdt is in the text segment since the data segment
/	is relocated after we switch into 386 mode (when a
/	valid gdt is required)

	.alignoff
	.align	4

gdtinit:				/ used before turning on paging
	.value	gdtend-gdt-1		/ limit of gdt
					/ gdt physical addr is 0x0040_2000+gdt
	.long	[[[-SBASE]+PBASE]<<BPCSHIFT]+gdt
	.value	0
gdtmap:					/ used after paging is enabled
	.value	gdtend-gdt-1		/ limit of gdt
	.long	gdt
	.value	0

idtmap:					/ used after paging is enabled
	.value	2047
	.long	idt
	.value	0

////
/
/ Macro MEM_SEG specifies a memory segment descriptor.
/ base is 32 bits
/ limit is 20 bits
/ type is 4 bits
/ dpl is 2 bits
/ flags is the 4 high bits of byte at descriptor + 6
/   8's bit of flags is limit granularity (0:byte 1:click)
/   4's bit of flags is default op size (0:16 bit 1:32 bit)
/
////

MEM_SEG	.macro	base,limit,type,dpl,flags
	.value	limit
	.value	base
	.byte	[base] >> 16
	.byte	0x90 | [[[dpl] & 3] << 5] | [[type] & 0xF]
	.byte	[[[flags] << 4] & 0xF0] | [[[limit] >> 16] & 0xF]
	.byte	[base] >> 24
	.endm

////
/
/ Macro TSS_SEG specifies a tss segment descriptor.
/ base is 32 bits
/ limit is 20 bits
/ [type is 0x9]
/ [dpl is 0]
/ gran is limit granularity (0:byte 1:click)
/
////

TSS_SEG	.macro	base,limit,gran
	.value	limit
	.value	base
	.byte	[base] >> 16
	.byte	0x89
	.byte	[[[gran] << 7] & 0x80] | [[[limit] >> 16] & 0xF]
	.byte	[base] >> 24
	.endm

////
/
/ Macro LDT_SEG specifies a tss segment descriptor.
/ base is 32 bits
/ limit is 20 bits
/ [type is 0x2]
/ [dpl is 0]
/ gran is limit granularity (0:byte 1:click)
/
////

LDT_SEG	.macro	base,limit,gran
	.value	limit
	.value	base
	.byte	[base] >> 16
	.byte	0x82
	.byte	[[[gran] << 7] & 0x80] | [[[limit] >> 16] & 0xF]
	.byte	[base] >> 24
	.endm

////
/
/ Macro CALL_GATE specifies a call gate descriptor.
/ selector is 16 bits
/ offset is 32 bits
/ dwdcount is 5 bits
/ dpl is 2 bits
/
/ Would like the following, but can't shift offset since it's a symbol.
/	.value	offset
/	.value	selector
/	.value	0x8C00 | [[dwdcount] & 0x1F] | [[[dpl] & 3] << 13]
/	.value	[offset] >> 16
/
/ IMPORTANT!!!
/ This macro does not create a proper call gate.  
/ Count on idtinit() to swap 16-bit words at macro+2, macro+6.
/
////

CALL_GATE	.macro	selector,offset,dwdcount,dpl

	.long	offset
	.value	0x8C00 | [[dwdcount] & 0x1F] | [[[dpl] & 3] << 13]
	.value	selector
	.endm

////
/
/ "segment xxxx" below gives the value in a segment register corresponding
/ to the given descriptor.  The low 3 bits in a segment register are not
/ used in indexing into the descriptor table.
/
////

	.set	DPL_0,0
	.set	DPL_1,1
	.set	DPL_2,2
	.set	DPL_3,3

gdt:
	/ segment 0000
	.long	0,0			/ null entry

	/ segment 0008 - SEG_386_UI
	MEM_SEG	0,0x7FFFF,0xB,DPL_3,0xC

	/ segment 0010 - SEG_386_UD
	MEM_SEG	0,0x8FFFF,0x3,DPL_3,0xC

	/ segment 0018 - SEG_RNG0_TXT/SEG_386_KI
	MEM_SEG	0,0xFFFFF,0xB,DPL_0,0xC

	/ segment 0020 - SEG_386_KD
	MEM_SEG	0,0xFFFFF,0x3,DPL_1,0xC

	/ segment 0028 - SEG_286_UI
	MEM_SEG	0,0xF,0xB,DPL_3,0x8

	/ segment 0030 - SEG_286_UD
	MEM_SEG	0,0xF,0x3,DPL_3,0x8

	/ segment 0038 - SEG_TSS
	/ limit is 0x68 + (number of bytes in iomap)
	/ This allows the required filler byte beyond desired addressing.
	TSS_SEG	0xFFC00000,TSS_IOMAP_OFF+[TSS_IOMAP_LEN .div 8]+3,0

	/ segment 0040 - SEG_ROM
	MEM_SEG	0xFFFC0000,0xF,0x3,DPL_0,0x8

	/ segment 0048 - SEG_VIDEOa
	MEM_SEG	0xFFFB0000,0xF,0x3,DPL_1,0x8

	/ segment 0050 - SEG_VIDEOb
	MEM_SEG	0xFFFA0000,0xF,0x3,DPL_1,0x8

	/ segment 0058 - SEG_386_II	/ init code (text)
	MEM_SEG	0x400000+[PBASE<<BPCSHIFT],0xFFFFF,0xB,DPL_0,0xC

	/ segment 0060 - SEG_386_ID	/ init code (data)
	MEM_SEG	0x400000+[PBASE<<BPCSHIFT],0xFFFFF,0x3,DPL_0,0xC

	/ segment 0068 - SEG_286_UII
	MEM_SEG	0x400000,0xF,0xB,DPL_3,0x8

	/ segment 0070 - SEG_LDT
	LDT_SEG	0xFFC00000,0xF,0

	/ segment 0078 - SEG_RNG0_STK
	MEM_SEG	0,0xFFBFF,0x7,DPL_0,0xC

	/ segment 0080 - SEG_RNG1_TXT
	MEM_SEG	0,0xFFFFF,0xB,DPL_1,0xC

	/ segment 0088 - SEG_RNG1_STK
	MEM_SEG	0,0xFFFFE,0x7,DPL_1,0xC

	/ Call gates need idtinit() to fix them before they can be used.
	.globl	gdtFixBegin
	.globl	gdtFixEnd
gdtFixBegin:
	/ segment 0090 - SEG_MMUUPD - Call gate for mmu update
	CALL_GATE	SEG_RNG0_TXT,mmuupdfR0,0,DPL_1

	/ segment 0098 - SEG_SET_EM - Call gate for writing CR0 EM bit
	CALL_GATE	SEG_RNG0_TXT,setEmfR0,1,DPL_1
gdtFixEnd:
gdtend:

/	The two entries in the ldt are call gates whose format is somewhat
/	different from the other segment descriptors
/
/	BCS compatibility requires an LDT

ldt:
	/ ldt + 0000
	CALL_GATE	SEG_RNG1_TXT,syscall_386,1,DPL_3
/	.long	syc32				/ call gate for system call
/	.long	0xFFC0EC01

	/ ldt + 0008
/	.long	sig32				/ call gate for signal return
/	.long	0xFFC0EC01
	CALL_GATE	SEG_RNG1_TXT,signal_386,1,DPL_3
ldtend:

////
/
/ Macro IRPT_GATE specifies a call gate descriptor.
/ selector is 16 bits
/ offset is 32 bits
/ dwdcount is 5 bits
/ dpl is 2 bits
/
/ Would like the following, but can't shift offset since it's a symbol.
/	.value	offset
/	.value	selector
/	.value	0x8E00 | [[dwdcount] & 0x1F] | [[[dpl] & 3] << 13]
/	.value	[offset] >> 16
/
/ IMPORTANT!!!
/ This macro does not create a proper interrupt gate.  
/ Count on idtinit() to swap 16-bit words at macro+2, macro+6.
/
////

IRPT_GATE	.macro	selector,offset,dwdcount,dpl

	.long	offset
	.value	0x8E00 | [[dwdcount] & 0x1F] | [[[dpl] & 3] << 13]
	.value	selector
	.endm

idt:
	/ A Fault is an exception reported *before* executing the instruction
	/ in question;  a Trap is an exception reported *after* executing the
	/ instruction;  an Abort is a non-recoverable exception.

	/ Divide Error Fault.
	IRPT_GATE	SEG_RNG1_TXT,trap0,0,DPL_3

	/ Debug Exception Fault/Trap
/	IRPT_GATE	SEG_RNG0_TXT,trap1_ker,0,DPL_3	/ Ring 0
	IRPT_GATE	SEG_RNG1_TXT,trap1_usr,0,DPL_3	/ Ring 1

	/ NMI trap.
	IRPT_GATE	SEG_RNG1_TXT,trap2,0,DPL_3

	/ INT 3 Trap.
	IRPT_GATE	SEG_RNG1_TXT,trap3,0,DPL_3

	/ Overflow Trap.
	IRPT_GATE	SEG_RNG1_TXT,trap4,0,DPL_3

	/ Bounds Check Fault.
	IRPT_GATE	SEG_RNG1_TXT,trap5,0,DPL_3

	/ Invalid Opcode Fault.
	IRPT_GATE	SEG_RNG1_TXT,trap6,0,DPL_3

	/ Coprocessor Device Not Available Fault.
	IRPT_GATE	SEG_RNG1_TXT,trap7,0,DPL_3

	/ Double Fault Abort.
	IRPT_GATE	SEG_RNG1_TXT,trap8,0,DPL_3

	/ Coprocessor Segment Overrun Abort.
	IRPT_GATE	SEG_RNG1_TXT,trap9,0,DPL_3

	/ Invalid TSS Fault.
	IRPT_GATE	SEG_RNG1_TXT,trap10,0,DPL_3

	/ Segment Not Present Fault.
	IRPT_GATE	SEG_RNG1_TXT,trap11,0,DPL_3

	/ Stack Segment Fault.
	IRPT_GATE	SEG_RNG0_TXT,__stackfault,0,DPL_3

	/ General Protection Fault.
	IRPT_GATE	SEG_RNG0_TXT,__gpfault,0,DPL_3	/ Ring 0!

	/ Page Fault.
	IRPT_GATE	SEG_RNG1_TXT,trap14,0,DPL_3

	/  I don't think there is an exception number 15 - hws.
	.long	0,0

	/ Coprocessor Error Fault.
	IRPT_GATE	SEG_RNG1_TXT,trap16,0,DPL_3
	.org	.+0x78

	/ Hardware interrupt vectors IRQ0-7.
	IRPT_GATE	SEG_RNG1_TXT,dev0,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,dev1,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,dev9,0,DPL_3 / Hardware sends 9 to 2.
	IRPT_GATE	SEG_RNG1_TXT,dev3,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,dev4,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,dev5,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,dev6,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,dev7,0,DPL_3

	/ Hardware interrupt vectors IRQ8-15.
	.org	.+0x240
	IRPT_GATE	SEG_RNG1_TXT,dev8,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,dev9,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,dev10,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,dev11,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,dev12,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,dev13,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,dev14,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,dev15,0,DPL_3

	/ 286 COHERENT System call entry points.
	.org	.+0x40
	IRPT_GATE	SEG_RNG1_TXT,syscall_286,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,syscall_286,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,syscall_286,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,syscall_286,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,syscall_286,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,syscall_286,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,syscall_286,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,syscall_286,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,syscall_286,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,syscall_286,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,syscall_286,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,syscall_286,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,syscall_286,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,syscall_286,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,syscall_286,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,syscall_286,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,syscall_286,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,syscall_286,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,syscall_286,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,syscall_286,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,syscall_286,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,syscall_286,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,syscall_286,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,syscall_286,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,syscall_286,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,syscall_286,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,syscall_286,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,syscall_286,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,syscall_286,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,syscall_286,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,syscall_286,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,syscall_286,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,syscall_286,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,syscall_286,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,syscall_286,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,syscall_286,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,syscall_286,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,syscall_286,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,syscall_286,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,syscall_286,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,syscall_286,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,syscall_286,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,syscall_286,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,syscall_286,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,syscall_286,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,syscall_286,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,syscall_286,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,syscall_286,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,syscall_286,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,syscall_286,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,syscall_286,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,syscall_286,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,syscall_286,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,syscall_286,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,syscall_286,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,syscall_286,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,syscall_286,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,syscall_286,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,syscall_286,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,syscall_286,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,syscall_286,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,syscall_286,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,syscall_286,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,syscall_286,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,syscall_286,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,syscall_286,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,syscall_286,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,syscall_286,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,syscall_286,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,syscall_286,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,syscall_286,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,syscall_286,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,syscall_286,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,syscall_286,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,syscall_286,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,syscall_286,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,syscall_286,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,syscall_286,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,syscall_286,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,syscall_286,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,syscall_286,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,syscall_286,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,syscall_286,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,syscall_286,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,syscall_286,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,syscall_286,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,syscall_286,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,syscall_286,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,syscall_286,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,syscall_286,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,syscall_286,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,syscall_286,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,syscall_286,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,syscall_286,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,syscall_286,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,syscall_286,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,syscall_286,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,syscall_286,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,syscall_286,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,syscall_286,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,syscall_286,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,syscall_286,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,syscall_286,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,syscall_286,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,syscall_286,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,syscall_286,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,syscall_286,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,syscall_286,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,syscall_286,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,syscall_286,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,syscall_286,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,syscall_286,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,syscall_286,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,syscall_286,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,syscall_286,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,syscall_286,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,syscall_286,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,syscall_286,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,syscall_286,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,syscall_286,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,syscall_286,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,syscall_286,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,syscall_286,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,syscall_286,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,syscall_286,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,syscall_286,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,syscall_286,0,DPL_3
	IRPT_GATE	SEG_RNG1_TXT,syscall_286,0,DPL_3
	.long	0
idtend:
	.align	4
	.long	0,0,0,0