Coherent4.2.10/i386/k0.s
.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