forked from Imagelibrary/rtems
468 lines
13 KiB
ArmAsm
468 lines
13 KiB
ArmAsm
/*
|
|
* This file is the main boot and configuration file for the i386ex. It is
|
|
* solely responsible for initializing the internal register set to reflect
|
|
* the proper board configuration. This version is the "generic" i386ex
|
|
* startup:
|
|
*
|
|
* 1) 512K flask ROM @3f80000
|
|
* 2) 1 Mb RAM @ 0x0
|
|
* 3) Timer0 used as RTEMS clock ticker, 1 msec tick rate.
|
|
* 4) READY# is generated by CPU
|
|
*
|
|
* The file is a multi-section file, with sections as follows:
|
|
* 1) interrupt gates, in section "ints"
|
|
* 2) interrupt descriptor table, in section "idt"
|
|
* 3) global descriptor table, in section "gdt"
|
|
* 4) reset in section "reset"
|
|
* 5) and initial boot code in section " initial"
|
|
*
|
|
* Submitted by:
|
|
*
|
|
* Erik Ivanenko
|
|
* University of Toronto
|
|
* erik.ivanenko@utoronto.ca
|
|
*
|
|
* The license and distribution terms for this file may be
|
|
* found in the file LICENSE in this distribution or at
|
|
* http://www.OARcorp.com/rtems/license.html.
|
|
*
|
|
* $Id$
|
|
|
|
|
|
changes:
|
|
SetExRegByte(ICW3S , 0x02 ) # MUST be 0x02 according to intel
|
|
SetExRegByte(ICW3M , 0x04 ) # IR2 is cascaded internally: was 0x02 => IR1 is cascaded
|
|
|
|
*/
|
|
|
|
#include "asm.h"
|
|
#include "macros.inc"
|
|
#include "80386ex.inc"
|
|
|
|
/*
|
|
* Needed for binutils 2.9.1.0.7 and higher
|
|
* #define NEXT_GAS
|
|
*/
|
|
|
|
EXTERN (boot_card) /* exits to bspstart */
|
|
EXTERN (stack_start) /* defined in startup/linkcmds */
|
|
EXTERN (Clock_exit)
|
|
|
|
PUBLIC (Interrupt_descriptor_table)
|
|
PUBLIC ( SYM(IDTR) )
|
|
PUBLIC( SYM(_initInternalRegisters) )
|
|
|
|
BEGIN_DATA
|
|
SYM(IDTR): DESC3( SYM(Interrupt_descriptor_table), 0x07ff );
|
|
|
|
SYM(Interrupt_descriptor_table): /* Now in data section */
|
|
.rept 256
|
|
.word 0,0,0,0
|
|
.endr
|
|
|
|
END_DATA
|
|
|
|
BEGIN_DATA
|
|
/* .section .gdt */
|
|
PUBLIC (_Global_descriptor_table)
|
|
|
|
SYM(GDTR): DESC3( GDT_TABLE, 0x1f ); # one less than the size
|
|
SYM (_Global_descriptor_table):
|
|
SYM(GDT_TABLE): DESC2(0,0,0,0,0,0);
|
|
SYM(GDT_ALIAS): DESC2(32,0x1000,0x0,0x93,0,0x0);
|
|
SYM(GDT_CODE): DESC2(0xffff,0,0x0,0x9B,0xDF,0x00);
|
|
SYM(GDT_DATA): DESC2(0xffff,0,0x0,0x92,0xDF,0x00); # was CF
|
|
SYM(GDT_END):
|
|
|
|
END_DATA
|
|
|
|
|
|
/* This section is the section that is used by the interrupt
|
|
descriptor table. It is used to provide the IDT with the
|
|
correct vector offsets. It is for symbol definition only.
|
|
*/
|
|
|
|
|
|
.section .reset
|
|
|
|
PUBLIC ( SYM(reset) )
|
|
SYM(reset):
|
|
nop
|
|
cli
|
|
jmp SYM(_initInternalRegisters) /* different section in this file */
|
|
.code32 /* in case this section moves */
|
|
nop /* required by CHIP LAB to pad out size */
|
|
nop
|
|
nop
|
|
nop
|
|
nop
|
|
|
|
|
|
|
|
.section .initial
|
|
|
|
/*
|
|
* Enable access to peripheral register at expanded I/O addresses
|
|
*/
|
|
SYM(_initInternalRegisters):
|
|
.code16
|
|
movw $0x8000 , ax
|
|
outb al , $REMAPCFGH
|
|
xchg al , ah
|
|
outb al,$REMAPCFGL
|
|
outw ax, $REMAPCFG ;
|
|
|
|
|
|
/*
|
|
* Configure operation of the A20 Address Line
|
|
*/
|
|
SYM(A20):
|
|
movw $PORT92 , dx
|
|
|
|
inb dx , al # clear A20 port reset
|
|
andb $0xfe , al # b0 Fast Reset(0)=disabled,(1)=reset triggered
|
|
orb $0x02 , al # Bit 1 Fast A20 = 0 (always 0) else enabled.
|
|
outb al , dx
|
|
|
|
SYM(Watchdog):
|
|
movw $WDTSTATUS , dx # address the WDT status port
|
|
inb dx , al # get the WDT status
|
|
orb $0x01 , al # set the CLKDIS bit
|
|
outb al , dx # disable the clock to the WDT
|
|
|
|
/*
|
|
* Initialize Refresh Control Unit for:
|
|
* Refresh Address = 0x0000
|
|
|
|
* Refresh gate between rows is 15.6 uSec
|
|
* Using a CLK2 frequency of 50Mhz ( 25Mhz CPU )
|
|
* The refresh unit is enabled
|
|
* The refresh pin is not used.
|
|
*/
|
|
|
|
SYM(InitRCU):
|
|
SetExRegWord( RFSCIR , 390) # refresh interval was 390, tried 312
|
|
SetExRegWord( RFSBAD , 0x0) # base address
|
|
SetExRegWord( RFSADD , 0x0) # address register
|
|
SetExRegWord( RFSCON , 0x8000) # enable bit
|
|
|
|
/*
|
|
* Initialize clock and power mgmt unit for:
|
|
* Clock Frequency = 50 Mhz
|
|
* Prescaled clock output = 1.19318 Mhz
|
|
* ( matches standard PC )
|
|
* Normal halt instructions
|
|
*/
|
|
|
|
SYM(InitClk):
|
|
SetExRegByte( PWRCON, 0x0 )
|
|
SetExRegWord( CLKPRS, 0x13)
|
|
|
|
/**************************************************************
|
|
* Initialize the Pin Configurations
|
|
*************************************************************/
|
|
|
|
/*
|
|
* Initialize I/O port 1 for:
|
|
* PIN 0 = 1, DCD0# to package pin
|
|
* PIN 1 = 1, RTS0# to package pin
|
|
* PIN 2 = 1, DTR0# to package pin
|
|
* PIN 3 = 1, DSR0# to package pin
|
|
* PIN 4 = 1, RI0# to package pin
|
|
* PIN 5 = 0, Outport (FLASH Vpp Enable, 0=Enable 1=Disable)
|
|
* PIN 6 = 0, Outport (P16_HOLD to 386ex option header JP7 pin 5)
|
|
* PIN 7 = 0, Outport (P17_HOLD to 386ex option header JP7 pin 3)
|
|
*/
|
|
|
|
SYM(InitPort1):
|
|
SetExRegByte( P1LTC , 0xff )
|
|
SetExRegByte( P1DIR , 0x0 )
|
|
SetExRegByte( P1CFG , 0x1f)
|
|
|
|
/*
|
|
* Initialize I/O port 2 for:
|
|
* PIN 0 = 0, Outport (P20_CS0# to 386ex option header JP7 pin 11)
|
|
* PIN 1 = 0, Outport (P21_CS1# to 386ex option header JP7 pin 9)
|
|
* PIN 2 = 1, CS2# (SMRAM) If not using CS2 can be configured as.?
|
|
* PIN 3 = 0, Outport ( no connect )
|
|
* PIN 4 = 1, CS#4 (DRAM)
|
|
* PIN 5 = 1, RXD0 input. See not for I/0 port 1 pins 1-4
|
|
* PIN 6 = 1, TXD0 output.
|
|
* PIN 7 = 1, CTS0# input.
|
|
*/
|
|
|
|
SYM(InitPort2):
|
|
SetExRegByte( P2LTC , 0xff )
|
|
SetExRegByte( P2DIR , 0x0 )
|
|
SetExRegByte( P2CFG , 0xfe)
|
|
|
|
/*
|
|
* Initialize I/O port 3 P3CFG
|
|
* PIN 0 = 1, TMROUT0 to package pin
|
|
* PIN 1 = 0, (TMROUT1 to 386ex option header JP7 pin 23)
|
|
* PIN 2 = 0, INT0 (IR1) disabled, (P3.2 out to JP7 pin 21)
|
|
* PIN 3 = 0, INT1 (IR5) disbled (P3.3 to option header JP7 pin 19)
|
|
* PIN 4 = 0, INT2 (IR6) disbled (P3.4 to option header JP7 pin 17)
|
|
* PIN 5 = 0, INT2 (IR7) disabled (P3.5 to 386ex header JP7 pin 15)
|
|
* PIN 6 = 0, Inport (Debugger Break P3.6/PWRD to package pin )
|
|
* P3.6 selected
|
|
* PIN 7 = 0, COMCLK output disabled, 1.8432 Mhz OSC1 oscillator.
|
|
* ( Debbugger uses COMCLK as the clocking source )
|
|
* P3.7 connected to package pin.
|
|
*/
|
|
|
|
SYM(InitPort3):
|
|
SetExRegByte( P3LTC , 0xff )
|
|
SetExRegByte( P3DIR , 0x41 )
|
|
SetExRegByte( P3CFG , 0x09 ) # can check TMROUT0
|
|
/*
|
|
* Initialize Peripheral Pin Configurations:
|
|
* PIN 0 = 1, RTS1# to package pin
|
|
* PIN 1 = 1, DTR1# to package pin
|
|
* PIN 2 = 1, TXD1 out to package pin
|
|
* PIN 3 = 0, EOP#/TC
|
|
* PIN 4 = 0, DACK0#
|
|
* PIN 5 = 1, Timer2
|
|
* PIN 6 = 0, 0 => CS6# connected to package pin
|
|
* PIN 7 = 0, Don't care
|
|
*/
|
|
|
|
SYM(InitPeriph):
|
|
SetExRegByte( PINCFG , 0x24)
|
|
|
|
/*
|
|
* Initialize the Asynchronous Serial Ports:
|
|
* BIT 7 = 1, Internal SIO1 modem signals
|
|
* BIT 6 = 1, Internal SIO0 modem signals
|
|
* BIT 2 = 0, PSCLK for SSIO clock
|
|
* BIT 1 = 1, SERCLK for SIO1 clock
|
|
* BIT 0 = 1, SERCLK for SIO0 clock
|
|
*/
|
|
|
|
SYM(InitSIO):
|
|
SetExRegByte( SIOCFG, 0xC3 ) # SIOn clocked internally
|
|
|
|
SetExRegByte( LCR0, 0x80 ) # latch DLL0, DLH0
|
|
SetExRegByte( DLL0, 0x51 ) # 0x51 sets to 9600 baud 0x7 -> 115,200
|
|
SetExRegByte( DLH0, 0x00 ) # 0x145 is 2400 baud
|
|
SetExRegByte( LCR0, 0x03 ) # enable r/w buffers, IER0 accessible
|
|
# mode 8-n-1
|
|
SetExRegByte( IER0, 0x00 ) # was 0x0f All interrupts detected
|
|
|
|
SetExRegByte( LCR1, 0x80 ) # latch DLL0, DLH0
|
|
SetExRegByte( DLL1, 0x51 ) # 0x51 set to 9600 baud, 0x7 = 115200
|
|
SetExRegByte( DLH1, 0x00 ) # 0x145 is 2400 baud
|
|
SetExRegByte( LCR1, 0x03 ) # enable r/w buffers, IER1 accessible
|
|
# reg 8-n-1
|
|
SetExRegByte( IER1, 0x00 ) # was 0x0f - All interrupts detected
|
|
|
|
SYM(InitMCR):
|
|
/*
|
|
* Initialize Timer for:
|
|
* BIT 7 = 1, Timer clocks disabled
|
|
* BIT 6 = 0, Reserved
|
|
* BIT 5 = 1, TMRCLK2 instead of Vcc to Gate2
|
|
* BIT 4 = 0, PSCLK to CLK2
|
|
* BIT 3 = 1, TMRCLK1 instead of Vcc to Gate1
|
|
* BIT 2 = 0, PSCLK to Gate1
|
|
* BIT 1 = 0, Vcc to Gate0
|
|
* BIT 0 = 0, PSCLK to Gate0
|
|
*/
|
|
|
|
SYM(InitTimer):
|
|
SetExRegByte(TMRCFG , 0x80 ) # All counters disabled, Gates 0,1
|
|
# and 2 are set to Vcc
|
|
|
|
SetExRegByte(TMRCON , 0x34 ) # prepare to write counter 0 LSB,MSB
|
|
SetExRegByte(TMR0 , 0xA8 ) # LSB = 0B count, followed by MSB
|
|
SetExRegByte(TMR0 , 0x04 ) # for INT every 50 msec. MSB = 0xE900
|
|
# for INT every 5 msec. 0x174c
|
|
# for INT every 1 msec. 0x04A8
|
|
# was 0xe900
|
|
|
|
SetExRegByte(TMRCON , 0x70 ) # mode 0 disables on Gate= Vcc
|
|
SetExRegByte(TMR1 , 0x00 ) # sfa
|
|
SetExRegByte(TMR1 , 0x00 ) # sfa
|
|
|
|
SetExRegByte(TMRCON , 0xB0 ) # mode 0 disables on gate =Vcc
|
|
SetExRegByte(TMR2 , 0x00 ) #
|
|
SetExRegByte(TMR2 , 0x00 ) #
|
|
SetExRegByte(TMRCFG , 0x80 ) # Enable timers = 0x00
|
|
|
|
|
|
/*
|
|
* Initialize the DMACFG register for:
|
|
* BIT 7 = 1 , Disable DACK#1
|
|
* BITs 6:4 = 100, TMROUT2 connected to DRQ1
|
|
* BIT 3 = 1 , Disable DACK0#
|
|
* BIT 2:0 = 000, Pin is connected to DRQ0
|
|
*/
|
|
|
|
SetExRegByte(DMACFG , 0xC0 )
|
|
SetExRegByte(DMACMD1, 0x00 ) # disable both DMA channels
|
|
SetExRegByte(DMAMOD1, 0x40 )
|
|
/*
|
|
* Initialize the INTCFG register for:
|
|
* BIT 7 = 0, 8259 cascade disabled
|
|
* BIT 3 = 0, SLAVE IR6 connected to Vss
|
|
* BIT 2 = 0, SLAVE IR5 connected to Vss
|
|
* BIT 1 = 0, SLAVE IR1 connected to SSIOINT
|
|
* BIT 0 = 0, SLAVE IR0 connected to Vss
|
|
*/
|
|
|
|
SYM(InitInt):
|
|
|
|
cli # !
|
|
|
|
SetExRegByte(ICW1S , 0x11 ) # EDGE TRIGGERED
|
|
SetExRegByte(ICW2S , 0x28 ) # Slave base vector after Master
|
|
SetExRegByte(ICW3S , 0x02 ) # slave cascaded to IR2 on master
|
|
SetExRegByte(ICW4S , 0x01 ) # must be 0x01
|
|
|
|
SetExRegByte(ICW1M , 0x11 ) # edge triggered
|
|
SetExRegByte(ICW2M , 0x20 ) # base vector starts at byte 32
|
|
SetExRegByte(ICW3M , 0x04) # IR2 is cascaded internally
|
|
SetExRegByte(ICW4M , 0x01 ) # idem
|
|
|
|
SetExRegByte(OCW1M , 0xde ) # IR0 only = 0xfe. for IR5 and IR0 active use 0xde
|
|
SetExRegByte(INTCFG , 0x00 )
|
|
|
|
movw $0xFFFB, SYM(i8259s_cache) /* set up same values in cache */
|
|
|
|
SYM(SetCS4):
|
|
SetExRegWord(CS4ADL , 0x702) #Configure chip select 4
|
|
SetExRegWord(CS4ADH , 0x00)
|
|
SetExRegWord(CS4MSKH, 0x03F)
|
|
SetExRegWord(CS4MSKL, 0xFC01)
|
|
|
|
SYM(SetUCS1):
|
|
SetExRegWord(UCSADL , 0x0304) # 512K block starting at 0x80000 until 0x3f80000
|
|
SetExRegWord(UCSADH , 0x03F8)
|
|
SetExRegWord(UCSMSKH, 0x03F7)
|
|
SetExRegWord(UCSMSKL, 0xFC01) # configure upper chip select
|
|
|
|
/******************************************************
|
|
* The GDT must be in RAM since it must be writeable,
|
|
* So, move the whole data section down.
|
|
********************************************************/
|
|
|
|
/* SYM(xfer_gdt):
|
|
movw $ _ram_gdt_offset , di
|
|
movw $ _ram_gdt_segment , cx
|
|
mov cx , es
|
|
|
|
movw $ _gdt_size , cx
|
|
movw $ _rom_gdt_segment , ax
|
|
movw $ _rom_gdt_offset , si
|
|
mov ax , ds
|
|
|
|
repne
|
|
movsb
|
|
*/
|
|
|
|
movw $ _ram_data_offset , di
|
|
movw $ _ram_data_segment, cx
|
|
mov cx , es
|
|
|
|
movw $ _data_size , cx
|
|
movw $ _rom_data_segment, ax
|
|
movw $ _rom_data_offset , si
|
|
mov ax , ds
|
|
|
|
repne
|
|
movsb
|
|
|
|
/*****************************
|
|
* Load the Global Descriptor
|
|
* Table Register
|
|
****************************/
|
|
|
|
/* movw $ _ram_gdt_segment, ax */
|
|
|
|
#ifdef NEXT_GAS
|
|
data32
|
|
addr32
|
|
#endif
|
|
/* lgdt _ram_gdt_offset # location of GDT */
|
|
|
|
lgdt SYM(GDTR) # location of GDT
|
|
|
|
|
|
SYM(SetUCS):
|
|
SetExRegWord(UCSADL, 0x0702) # now 512K starting at 0x3f80000.
|
|
SetExRegWord(UCSADH, 0x03f8)
|
|
SetExRegWord(UCSMSKH, 0x0007)
|
|
SetExRegWord(UCSMSKL, 0xFC01) # configure upper chip select
|
|
|
|
/***************************
|
|
* Switch to Protected Mode
|
|
***************************/
|
|
mov cr0, eax
|
|
orw $0x1, ax
|
|
mov eax, cr0
|
|
|
|
/**************************
|
|
* Flush prefetch queue,
|
|
* and load CS selector
|
|
*********************/
|
|
|
|
/* ljmpl $ GDT_CODE_PTR , $ SYM(_copy_data) # sets the code selector*/
|
|
ljmpl $ GDT_CODE_PTR , $ SYM(_load_segment_registers) # sets the code selector
|
|
|
|
/*
|
|
* Copy the data section down to RAM
|
|
*/
|
|
/*SYM(_copy_data): */
|
|
SYM(_load_segment_registers):
|
|
.code32
|
|
pLOAD_SEGMENT( GDT_DATA_PTR, fs)
|
|
pLOAD_SEGMENT( GDT_DATA_PTR, gs)
|
|
pLOAD_SEGMENT( GDT_DATA_PTR, ss)
|
|
pLOAD_SEGMENT( GDT_DATA_PTR, ds)
|
|
pLOAD_SEGMENT( GDT_DATA_PTR, es)
|
|
|
|
/* movl $ SYM(_data_start) , edi # ram destination
|
|
movl $ SYM(_rom_data_start) , esi # rom data source
|
|
movl $ SYM(_data_size) , ecx # amount to move
|
|
repne # while ecx != 0
|
|
movsb # move a byte
|
|
*/
|
|
/*
|
|
* Set up the stack
|
|
*/
|
|
|
|
SYM(lidtr):
|
|
lidt SYM(IDTR)
|
|
|
|
SYM (_establish_stack):
|
|
movl $end, eax # stack starts right after bss
|
|
movl $stack_origin, esp # this is the high starting address
|
|
movl $stack_origin, ebp
|
|
/*
|
|
* Zero out the BSS segment
|
|
*/
|
|
SYM (zero_bss):
|
|
cld # make direction flag count up
|
|
movl $ SYM (end),ecx # find end of .bss
|
|
movl $ SYM (_bss_start),edi # edi = beginning of .bss
|
|
subl edi,ecx # ecx = size of .bss in bytes
|
|
shrl ecx # size of .bss in longs
|
|
shrl ecx
|
|
xorl eax,eax # value to clear out memory
|
|
repne # while ecx != 0
|
|
stosl # clear a long in the bss
|
|
|
|
/*
|
|
* Transfer control to User's Board Support Package
|
|
*/
|
|
pushl $0 # environp
|
|
pushl $0 # argv
|
|
pushl $0 # argc
|
|
call SYM(boot_card)
|
|
addl $12,esp
|
|
|
|
hlt
|
|
|
|
END
|
|
|