www.pudn.com > BSP_pcPentium.rar > sysALib.s
/* sysALib.s - PC-386 system-dependent routines */
/* Copyright 1984-2002 Wind River Systems, Inc. */
/*
modification history
--------------------
01z,13mar02,hdn resumed GDT loading after copying from text to RAM (spr 71298)
01y,02nov01,hdn removed GDT loading not to access sysGdt[] in text (spr 71298)
01x,14aug01,hdn added Pentium4 support in sysCpuProbe().
added sysCsSuper/Exc/Int as task/exc/int code selector.
added FUNC/FUNC_LABEL GTEXT/GDATA macros.
01w,12may98,hdn renamed sysCpuid to sysCpuId.
01v,09apr98,hdn added support for PentiumPro in sysCpuProbe().
01u,25mar97,hdn removed a line of CD=NW=1 from sysCpuProbe().
01t,03sep96,hdn added the compression support. removed BOOTABLE macro.
01s,17jun96,hdn made sysCpuProbe() user-callable.
01r,13jun96,hdn added sysInLong() sysInLongString() sysOutLong()
sysOutLongString().
01q,01nov94,hdn added a way to find out Pentium in sysCpuProbe().
changed a way to find out 386 by checking AC bit.
01p,19oct94,hdn renamed sysInitGdt to sysGdt.
added sysLoadGdt(), sysA20on().
added sysA20Result indicates the state of A20 line.
01o,23sep94,hdn deleted _sysBootType, sysRegSet(), sysRegGet().
added jmp instruction in sysInXX() and sysOutXX().
01n,28apr94,hdn made sysReboot() simple.
01m,06apr94,hdn created a processor checking routine sysCpuProbe().
created the system GDT at GDT_BASE_OFFSET.
01l,17feb94,hdn changed name RAM_ENTRY to RAM_HIGH_ADRS
changed to put the image in upper memory.
01k,27oct93,hdn added _sysBootType.
01j,25aug93,hdn changed a way to enable A20.
01i,12aug93,hdn added codes to load a user defined global descriptor table.
made warm start works changing sysReboot().
deleted sysGDTRSet().
01h,09aug93,hdn added codes to recognize a type of cpu.
01g,17jun93,hdn updated to 5.1.
01f,08arp93,jdi doc cleanup.
01e,26mar93,hdn added sysReg[GS]et, sysGDTRSet. added another sysInit.
01d,16oct92,hdn added Code Descriptors for the nesting interrupt.
01c,29sep92,hdn added i80387 support. deleted __fixdfsi.
01b,28aug92,hdn fixed __fixdfsi temporary.
01a,28feb92,hdn written based on frc386 version.
*/
/*
DESCRIPTION
This module contains system-dependent routines written in assembly
language.
This module must be the first specified in the \f3ld\f1 command used to
build the system. The sysInit() routine is the system start-up code.
INTERNAL
Many routines in this module doesn't use the "c" frame pointer %ebp@ !
This is only for the benefit of the stacktrace facility to allow it
to properly trace tasks executing within these routines.
SEE ALSO:
.I "i80386 32-Bit Microprocessor User's Manual"
*/
#define _ASMLANGUAGE
#include "vxWorks.h"
#include "asm.h"
#include "regs.h"
#include "sysLib.h"
#include "config.h"
.data
.globl FUNC(copyright_wind_river)
.long FUNC(copyright_wind_river)
/* externals */
.globl FUNC(usrInit) /* system initialization routine */
.globl VAR(sysProcessor) /* initialized to NONE(-1) in sysLib.c */
/* internals */
.globl sysInit /* start of system code */
.globl _sysInit /* start of system code */
.globl GTEXT(sysInByte)
.globl GTEXT(sysInWord)
.globl GTEXT(sysInLong)
.globl GTEXT(sysInWordString)
.globl GTEXT(sysInLongString)
.globl GTEXT(sysOutByte)
.globl GTEXT(sysOutWord)
.globl GTEXT(sysOutLong)
.globl GTEXT(sysOutWordString)
.globl GTEXT(sysOutLongString)
.globl GTEXT(sysReboot)
.globl GTEXT(sysWait)
.globl GTEXT(sysCpuProbe)
.globl GTEXT(sysLoadGdt)
.globl GTEXT(sysGdtr)
.globl GTEXT(sysGdt)
.globl GDATA(sysCsSuper) /* code selector: supervisor mode */
.globl GDATA(sysCsExc) /* code selector: exception */
.globl GDATA(sysCsInt) /* code selector: interrupt */
.text
.balign 16
/*******************************************************************************
*
* sysInit - start after boot
*
* This routine is the system start-up entry point for VxWorks in RAM, the
* first code executed after booting. It disables interrupts, sets up
* the stack, and jumps to the C routine usrInit() in usrConfig.c.
*
* The initial stack is set to grow down from the address of sysInit(). This
* stack is used only by usrInit() and is never used again. Memory for the
* stack must be accounted for when determining the system load address.
*
* NOTE: This routine should not be called by the user.
*
* RETURNS: N/A
* sysInit () /@ THIS IS NOT A CALLABLE ROUTINE @/
*/
sysInit:
_sysInit:
cli /* LOCK INTERRUPT */
movl $ BOOT_WARM_AUTOBOOT,%ebx /* %ebx has the startType */
movl $ FUNC(sysInit),%esp /* initialize stack pointer */
movl $0,%ebp /* initialize frame pointer */
ARCH_REGS_INIT /* initialize DR[0-7] CR[04] EFLAGS */
movl $ FUNC(sysGdt),%esi /* set src addr (&sysGdt) */
movl FUNC(pSysGdt),%edi /* set dst addr (pSysGdt) */
movl %edi,%eax
movl $ GDT_ENTRIES,%ecx /* number of GDT entries */
movl %ecx,%edx
shll $1,%ecx /* set (nLongs of GDT) to copy */
cld
rep
movsl /* copy GDT from src to dst */
pushl %eax /* push the (GDT base addr) */
shll $3,%edx /* get (nBytes of GDT) */
decl %edx /* get (nBytes of GDT) - 1 */
shll $16,%edx /* move it to the upper 16 */
pushl %edx /* push the nBytes of GDT - 1 */
leal 2(%esp),%eax /* get the addr of (size:addr) */
pushl %eax /* push it as a parameter */
call FUNC(sysLoadGdt) /* load the brand new GDT in RAM */
pushl %ebx /* push the startType */
movl $ FUNC(usrInit),%eax
movl $ FUNC(sysInit),%edx /* push return address */
pushl %edx /* for emulation for call */
pushl $0 /* push EFLAGS, 0 */
pushl $0x0008 /* a selector 0x08 is 2nd one */
pushl %eax /* push EIP, FUNC(usrInit) */
iret /* iret */
/*******************************************************************************
*
* sysInByte - input one byte from I/O space
*
* RETURNS: Byte data from the I/O port.
* UCHAR sysInByte (address)
* int address; /@ I/O port address @/
*/
.balign 16,0x90
FUNC_LABEL(sysInByte)
movl SP_ARG1(%esp),%edx
movl $0,%eax
inb %dx,%al
jmp sysInByte0
sysInByte0:
ret
/*******************************************************************************
*
* sysInWord - input one word from I/O space
*
* RETURNS: Word data from the I/O port.
* USHORT sysInWord (address)
* int address; /@ I/O port address @/
*/
.balign 16,0x90
FUNC_LABEL(sysInWord)
movl SP_ARG1(%esp),%edx
movl $0,%eax
inw %dx,%ax
jmp sysInWord0
sysInWord0:
ret
/*******************************************************************************
*
* sysInLong - input one long-word from I/O space
*
* RETURNS: Long-Word data from the I/O port.
* USHORT sysInLong (address)
* int address; /@ I/O port address @/
*/
.balign 16,0x90
FUNC_LABEL(sysInLong)
movl SP_ARG1(%esp),%edx
movl $0,%eax
inl %dx,%eax
jmp sysInLong0
sysInLong0:
ret
/*******************************************************************************
*
* sysOutByte - output one byte to I/O space
*
* RETURNS: N/A
* void sysOutByte (address, data)
* int address; /@ I/O port address @/
* char data; /@ data written to the port @/
*/
.balign 16,0x90
FUNC_LABEL(sysOutByte)
movl SP_ARG1(%esp),%edx
movl SP_ARG2(%esp),%eax
outb %al,%dx
jmp sysOutByte0
sysOutByte0:
ret
/*******************************************************************************
*
* sysOutWord - output one word to I/O space
*
* RETURNS: N/A
* void sysOutWord (address, data)
* int address; /@ I/O port address @/
* short data; /@ data written to the port @/
*/
.balign 16,0x90
FUNC_LABEL(sysOutWord)
movl SP_ARG1(%esp),%edx
movl SP_ARG2(%esp),%eax
outw %ax,%dx
jmp sysOutWord0
sysOutWord0:
ret
/*******************************************************************************
*
* sysOutLong - output one long-word to I/O space
*
* RETURNS: N/A
* void sysOutLong (address, data)
* int address; /@ I/O port address @/
* long data; /@ data written to the port @/
*/
.balign 16,0x90
FUNC_LABEL(sysOutLong)
movl SP_ARG1(%esp),%edx
movl SP_ARG2(%esp),%eax
outl %eax,%dx
jmp sysOutLong0
sysOutLong0:
ret
/*******************************************************************************
*
* sysInWordString - input word string from I/O space
*
* RETURNS: N/A
* void sysInWordString (port, address, count)
* int port; /@ I/O port address @/
* short *address; /@ address of data read from the port @/
* int count; /@ count @/
*/
.balign 16,0x90
FUNC_LABEL(sysInWordString)
pushl %edi
movl SP_ARG1+4(%esp),%edx
movl SP_ARG2+4(%esp),%edi
movl SP_ARG3+4(%esp),%ecx
cld
rep
insw %dx,(%edi)
movl %edi,%eax
popl %edi
ret
/*******************************************************************************
*
* sysInLongString - input long string from I/O space
*
* RETURNS: N/A
* void sysInLongString (port, address, count)
* int port; /@ I/O port address @/
* long *address; /@ address of data read from the port @/
* int count; /@ count @/
*/
.balign 16,0x90
FUNC_LABEL(sysInLongString)
pushl %edi
movl SP_ARG1+4(%esp),%edx
movl SP_ARG2+4(%esp),%edi
movl SP_ARG3+4(%esp),%ecx
cld
rep
insl %dx,(%edi)
movl %edi,%eax
popl %edi
ret
/*******************************************************************************
*
* sysOutWordString - output word string to I/O space
*
* RETURNS: N/A
* void sysOutWordString (port, address, count)
* int port; /@ I/O port address @/
* short *address; /@ address of data written to the port @/
* int count; /@ count @/
*/
.balign 16,0x90
FUNC_LABEL(sysOutWordString)
pushl %esi
movl SP_ARG1+4(%esp),%edx
movl SP_ARG2+4(%esp),%esi
movl SP_ARG3+4(%esp),%ecx
cld
rep
outsw (%esi),%dx
movl %esi,%eax
popl %esi
ret
/*******************************************************************************
*
* sysOutLongString - output long string to I/O space
*
* RETURNS: N/A
* void sysOutLongString (port, address, count)
* int port; /@ I/O port address @/
* long *address; /@ address of data written to the port @/
* int count; /@ count @/
*/
.balign 16,0x90
FUNC_LABEL(sysOutLongString)
pushl %esi
movl SP_ARG1+4(%esp),%edx
movl SP_ARG2+4(%esp),%esi
movl SP_ARG3+4(%esp),%ecx
cld
rep
outsl (%esi),%dx
movl %esi,%eax
popl %esi
ret
/*******************************************************************************
*
* sysWait - wait until the input buffer become empty
*
* wait until the input buffer become empty
*
* RETURNS: N/A
* void sysWait (void)
*/
.balign 16,0x90
FUNC_LABEL(sysWait)
xorl %ecx,%ecx
sysWait0:
movl $0x64,%edx /* Check if it is ready to write */
inb %dx,%al
andb $2,%al
loopnz sysWait0
ret
/*******************************************************************************
*
* sysReboot - warm start
*
* RETURNS: N/A
*
* NOMANUAL
* void sysReboot ()
*/
.balign 16,0x90
FUNC_LABEL(sysReboot)
movl $0,%eax
lgdt (%eax) /* crash the global descriptor table */
ret
/*******************************************************************************
*
* sysCpuProbe - perform CPUID if supported and check a type of CPU FAMILY
*
* This routine performs CPUID if supported and check a type of CPU FAMILY.
* This routine is called only once in cacheArchLibInit(). If it is
* called later, it returns the previously obtained result.
*
* RETURNS: a type of CPU FAMILY; 0(386), 1(486), 2(P5/Pentium),
* 4(P6/PentiumPro) or 5(P7/Pentium4).
*
* UINT sysCpuProbe (void)
*/
.balign 16,0x90
FUNC_LABEL(sysCpuProbe)
cmpl $ NONE, FUNC(sysProcessor) /* is it executed already? */
je sysCpuProbeStart /* no: start the CPU probing */
movl FUNC(sysProcessor), %eax /* return the sysProcessor */
ret
sysCpuProbeStart:
pushfl /* save EFLAGS */
cli /* LOCK INTERRUPT */
/* check 386. AC bit is a new bit for 486, 386 can not toggle */
pushfl /* push EFLAGS */
popl %edx /* pop EFLAGS on EDX */
movl %edx, %ecx /* save original EFLAGS to ECX */
xorl $ EFLAGS_AC, %edx /* toggle AC bit */
pushl %edx /* push new EFLAGS */
popfl /* set new EFLAGS */
pushfl /* push EFLAGS */
popl %edx /* pop EFLAGS on EDX */
xorl %edx, %ecx /* if AC bit is toggled ? */
jz sysCpuProbe386 /* no: it is 386 */
pushl %ecx /* push original EFLAGS */
popfl /* restore original EFLAGS */
/* check 486. ID bit is a new bit for Pentium, 486 can not toggle */
pushfl /* push EFLAGS */
popl %edx /* pop EFLAGS on EDX */
movl %edx, %ecx /* save original EFLAGS to ECX */
xorl $ EFLAGS_ID, %edx /* toggle ID bit */
pushl %edx /* push new EFLAGS */
popfl /* set new EFLAGS */
pushfl /* push EFLAGS */
popl %edx /* pop EFLAGS on EDX */
xorl %edx, %ecx /* if ID bit is toggled ? */
jz sysCpuProbe486 /* no: it is 486 */
/* execute CPUID to get vendor, family, model, stepping, features */
pushl %ebx /* save EBX */
movl $ CPUID_486, FUNC(sysCpuId)+CPUID_SIGNATURE /* set it 486 */
/* EAX=0, get the highest value and the vendor ID */
movl $0, %eax /* set EAX 0 */
cpuid /* execute CPUID */
movl %eax, FUNC(sysCpuId)+CPUID_HIGHVALUE /* save high value */
movl %ebx, FUNC(sysCpuId)+CPUID_VENDORID /* save vendor id[0] */
movl %edx, FUNC(sysCpuId)+CPUID_VENDORID+4 /* save vendor id[1] */
movl %ecx, FUNC(sysCpuId)+CPUID_VENDORID+8 /* save vendor id[2] */
cmpl $1, %eax /* is CPUID(1) ok? */
jl sysCpuProbeEnd /* no: end probe */
/* EAX=1, get the processor signature and feature flags */
movl $1, %eax /* set EAX 1 */
cpuid /* execute CPUID */
movl %eax, FUNC(sysCpuId)+CPUID_SIGNATURE /* save signature */
movl %edx, FUNC(sysCpuId)+CPUID_FEATURES_EDX /* save feature EDX */
movl %ecx, FUNC(sysCpuId)+CPUID_FEATURES_ECX /* save feature ECX */
movl %ebx, FUNC(sysCpuId)+CPUID_FEATURES_EBX /* save feature EBX */
cmpl $2, FUNC(sysCpuId)+CPUID_HIGHVALUE /* is CPUID(2) ok? */
jl sysCpuProbeEnd /* no: end probe */
/* EAX=2, get the configuration parameters */
movl $2, %eax /* set EAX 2 */
cpuid /* execute CPUID */
movl %eax, FUNC(sysCpuId)+CPUID_CACHE_EAX /* save config EAX */
movl %ebx, FUNC(sysCpuId)+CPUID_CACHE_EBX /* save config EBX */
movl %ecx, FUNC(sysCpuId)+CPUID_CACHE_ECX /* save config ECX */
movl %edx, FUNC(sysCpuId)+CPUID_CACHE_EDX /* save config EDX */
cmpl $3, FUNC(sysCpuId)+CPUID_HIGHVALUE /* is CPUID(3) ok? */
jl sysCpuProbeEnd /* no: end probe */
/* EAX=3, get the processor serial no */
movl $3, %eax /* set EAX 3 */
cpuid /* execute CPUID */
movl %edx, FUNC(sysCpuId)+CPUID_SERIALNO /* save serialno[2] */
movl %ecx, FUNC(sysCpuId)+CPUID_SERIALNO+4 /* save serialno[3] */
/* EAX=0x80000000, to see if the Brand String is supported */
movl $0x80000000, %eax /* set EAX 0x80000000 */
cpuid /* execute CPUID */
cmpl $0x80000000, %eax /* is Brand String supported? */
jbe sysCpuProbeEnd /* no: end probe */
/* EAX=0x8000000[234], get the Brand String */
movl $0x80000002, %eax /* set EAX 0x80000002 */
cpuid /* execute CPUID */
movl %eax, FUNC(sysCpuId)+CPUID_BRAND_STR /* save brandStr[0] */
movl %ebx, FUNC(sysCpuId)+CPUID_BRAND_STR+4 /* save brandStr[1] */
movl %ecx, FUNC(sysCpuId)+CPUID_BRAND_STR+8 /* save brandStr[2] */
movl %edx, FUNC(sysCpuId)+CPUID_BRAND_STR+12 /* save brandStr[3] */
movl $0x80000003, %eax /* set EAX 0x80000003 */
cpuid /* execute CPUID */
movl %eax, FUNC(sysCpuId)+CPUID_BRAND_STR+16 /* save brandStr[4] */
movl %ebx, FUNC(sysCpuId)+CPUID_BRAND_STR+20 /* save brandStr[5] */
movl %ecx, FUNC(sysCpuId)+CPUID_BRAND_STR+24 /* save brandStr[6] */
movl %edx, FUNC(sysCpuId)+CPUID_BRAND_STR+28 /* save brandStr[7] */
movl $0x80000004, %eax /* set EAX 0x80000004 */
cpuid /* execute CPUID */
movl %eax, FUNC(sysCpuId)+CPUID_BRAND_STR+32 /* save brandStr[8] */
movl %ebx, FUNC(sysCpuId)+CPUID_BRAND_STR+36 /* save brandStr[9] */
movl %ecx, FUNC(sysCpuId)+CPUID_BRAND_STR+40 /* save brandStr[10] */
movl %edx, FUNC(sysCpuId)+CPUID_BRAND_STR+44 /* save brandStr[11] */
sysCpuProbeEnd:
popl %ebx /* restore EBX */
movl FUNC(sysCpuId)+CPUID_SIGNATURE, %eax /* get the signature */
andl $ CPUID_FAMILY, %eax /* mask it with FAMILY */
cmpl $ CPUID_486, %eax /* is the CPU FAMILY 486 ? */
je sysCpuProbe486 /* yes: jump to ..486 */
cmpl $ CPUID_PENTIUM, %eax /* is the CPU FAMILY PENTIUM ? */
je sysCpuProbePentium /* yes: jump to ..Pentium */
cmpl $ CPUID_PENTIUMPRO, %eax /* is the CPU FAMILY PENTIUMPRO ? */
je sysCpuProbePentiumpro /* yes: jump to ..Pentiumpro */
cmpl $ CPUID_EXTENDED, %eax /* is the CPU FAMILY EXTENDED ? */
je sysCpuProbeExtended /* yes: jump to ..Extended */
sysCpuProbe486:
movl $ X86CPU_486, %eax /* set 1 for 486 */
jmp sysCpuProbeExit
sysCpuProbePentium:
movl $ X86CPU_PENTIUM, %eax /* set 2 for P5/Pentium */
jmp sysCpuProbeExit
sysCpuProbePentiumpro:
movl $ X86CPU_PENTIUMPRO, %eax /* set 4 for P6/PentiumPro */
jmp sysCpuProbeExit
sysCpuProbeExtended:
movl FUNC(sysCpuId)+CPUID_SIGNATURE, %eax /* get the signature */
andl $ CPUID_EXT_FAMILY, %eax /* mask it with EXTENDED FAMILY */
cmpl $ CPUID_PENTIUM4, %eax /* is the CPU FAMILY 486 ? */
je sysCpuProbePentium4 /* yes: jump to ..Pentium4 */
jmp sysCpuProbe486 /* unknown CPU. assume it 486 */
sysCpuProbePentium4:
movl $ X86CPU_PENTIUM4, %eax /* set 5 for P7/Pentium4 */
jmp sysCpuProbeExit
sysCpuProbe386:
movl $ X86CPU_386, %eax /* set 0 for 386 */
sysCpuProbeExit:
popfl /* restore EFLAGS */
movl %eax, FUNC(sysProcessor) /* set the CPU FAMILY */
ret
/*******************************************************************************
*
* sysLoadGdt - load the global descriptor table.
*
* RETURNS: N/A
*
* NOMANUAL
* void sysLoadGdt (char *sysGdtr)
*/
.balign 16,0x90
FUNC_LABEL(sysLoadGdt)
movl 4(%esp),%eax
lgdt (%eax)
movw $0x0010,%ax /* a selector 0x10 is 3rd one */
movw %ax,%ds
movw %ax,%es
movw %ax,%fs
movw %ax,%gs
movw %ax,%ss
ret
/*******************************************************************************
*
* sysGdt - the global descriptor table.
*
* RETURNS: N/A
*
* NOMANUAL
*
*/
.text
.balign 16,0x90
FUNC_LABEL(sysGdtr)
.word 0x0027 /* size : 39(8 * 5 - 1) bytes */
.long FUNC(sysGdt)
.balign 16,0x90
FUNC_LABEL(sysGdt)
/* 0(selector=0x0000): Null descriptor */
.word 0x0000
.word 0x0000
.byte 0x00
.byte 0x00
.byte 0x00
.byte 0x00
/* 1(selector=0x0008): Code descriptor, for the supervisor mode task */
.word 0xffff /* limit: xffff */
.word 0x0000 /* base : xxxx0000 */
.byte 0x00 /* base : xx00xxxx */
.byte 0x9a /* Code e/r, Present, DPL0 */
.byte 0xcf /* limit: fxxxx, Page Gra, 32bit */
.byte 0x00 /* base : 00xxxxxx */
/* 2(selector=0x0010): Data descriptor */
.word 0xffff /* limit: xffff */
.word 0x0000 /* base : xxxx0000 */
.byte 0x00 /* base : xx00xxxx */
.byte 0x92 /* Data r/w, Present, DPL0 */
.byte 0xcf /* limit: fxxxx, Page Gra, 32bit */
.byte 0x00 /* base : 00xxxxxx */
/* 3(selector=0x0018): Code descriptor, for the exception */
.word 0xffff /* limit: xffff */
.word 0x0000 /* base : xxxx0000 */
.byte 0x00 /* base : xx00xxxx */
.byte 0x9a /* Code e/r, Present, DPL0 */
.byte 0xcf /* limit: fxxxx, Page Gra, 32bit */
.byte 0x00 /* base : 00xxxxxx */
/* 4(selector=0x0020): Code descriptor, for the interrupt */
.word 0xffff /* limit: xffff */
.word 0x0000 /* base : xxxx0000 */
.byte 0x00 /* base : xx00xxxx */
.byte 0x9a /* Code e/r, Present, DPL0 */
.byte 0xcf /* limit: fxxxx, Page Gra, 32bit */
.byte 0x00 /* base : 00xxxxxx */
.data
.balign 32,0x90
FUNC_LABEL(sysCsSuper)
.long 0x00000008 /* CS for supervisor mode task */
FUNC_LABEL(sysCsExc)
.long 0x00000018 /* CS for exception */
FUNC_LABEL(sysCsInt)
.long 0x00000020 /* CS for interrupt */