292 lines
11 KiB
Plaintext
292 lines
11 KiB
Plaintext
# @(#)25 1.15 src/bos/kernel/ml/POWER/start.m4, sysml, bos411, 9428A410j 5/31/94 10:25:57
|
|
|
|
#*****************************************************************************
|
|
#
|
|
# COMPONENT_NAME: (SYSML) Kernel Assembler Code
|
|
#
|
|
# FUNCTIONS: start
|
|
#
|
|
# ORIGINS: 27, 83
|
|
#
|
|
# IBM CONFIDENTIAL -- (IBM Confidential Restricted when
|
|
# combined with the aggregated modules for this product)
|
|
# SOURCE MATERIALS
|
|
# (C) COPYRIGHT International Business Machines Corp. 1989, 1994
|
|
# All Rights Reserved
|
|
#
|
|
# US Government Users Restricted Rights - Use, duplication or
|
|
# disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
|
|
#
|
|
#
|
|
# LEVEL 1, 5 Years Bull Confidential Information
|
|
#
|
|
#****************************************************************************
|
|
|
|
################################################################################
|
|
## ##
|
|
## NAME: start ##
|
|
## ##
|
|
## FUNCTION: Entry point from ROS IPL code ##
|
|
## ##
|
|
## This routine gains control via a branch from the ROS IPL ##
|
|
## code, which passes in GPR 3 a pointer to the IPL Control ##
|
|
## block. ##
|
|
## This program MUST appear first in the kernel, because its ##
|
|
## job is to copy the memory image of the kernel into ##
|
|
## its proper place starting at address zero, overlaying the ##
|
|
## module header which preceeds the actual executable code. ##
|
|
## This header is present because the kernel is just an ordinary ##
|
|
## load module built by the ordinary AIX tools; when the ROS IPL ##
|
|
## code reads it from disk or diskette into address 0, the header ##
|
|
## is at address zero and the code (which logically belongs ##
|
|
## at 0) follows it. The header is copied into a kernel data ##
|
|
## structure, and the entire kernel image is shifted down to ##
|
|
## start at 0. This shift is accomplished by the code at ##
|
|
## label "start", below. ##
|
|
## ##
|
|
## This job is not exactly a trivial ##
|
|
## task given that the executing routine must copy itself ##
|
|
## as well and make sure that the instruction cache and data ##
|
|
## don't get in each other's way while the self-modifying ##
|
|
## code is running. ##
|
|
## ##
|
|
## Here's the plan of attack: ##
|
|
## 1) Branch-and-link to discover the actual address at ##
|
|
## which "start" begins executing. This will NOT be the ##
|
|
## address shown in the assembly listing or load map, ##
|
|
## because the code is offset by the length of the header. ##
|
|
## 2) Copy the module header into a data structure further ##
|
|
## on in the kernel. ##
|
|
## 3) Copy the FIRST PART of this routine down to location 0, ##
|
|
## using a loop which is located in higher addresses and ##
|
|
## thus doesn't get copied yet. ##
|
|
## 4) Flush the caches and branch to the newly-moved routine. ##
|
|
## 5) Copy the rest of the kernel to the proper place, and ##
|
|
## flush the caches again. ##
|
|
## 6) Set the front panel LEDs to blanks. ##
|
|
## 7) Branch to "start1", which creates a C environment for ##
|
|
## the rest of kernel initialization. ##
|
|
## ##
|
|
################################################################################
|
|
|
|
.machine "com"
|
|
|
|
include(iplcb.m4)
|
|
|
|
start:
|
|
# N.B. Do NOT use "ENTRY(start)" because
|
|
# the string "start" is the one that
|
|
# the kernel build utility will match.
|
|
|
|
bl start10 # Find out where we are, and branch
|
|
# to move loop in SECOND part
|
|
# of this routine
|
|
start25:
|
|
# N.B. this label used at start10 -
|
|
# do not move
|
|
|
|
#*******************************************************************#
|
|
# Move latter part of kernel down; this loop gains control #
|
|
# AFTER it has been copied down to its final position. #
|
|
#*******************************************************************#
|
|
|
|
start30:
|
|
lu r6,4(r2) # Get next 4 bytes to move
|
|
stu r6,4(r1) # Move to proper loction
|
|
cmp cr0,r2,r0 # Check if all data moved
|
|
blt start30
|
|
|
|
# Now must insure the dcache is stored in memory
|
|
|
|
andiu. r6,r17,PPC_MODEL
|
|
bne cr0,start42 # PPC model
|
|
|
|
ifdef(`_KDB',`
|
|
# nop first(power-pc) branches to millicode routines for early calls
|
|
# to millicode. Patch out the PowerPC branch, and allow fall through
|
|
# to the Power branch case for Power machines.
|
|
# This code depends on the subsequent cache flushes to cover it.
|
|
|
|
lis r8,0x6000 # NOP instruction (ori 0,0,0)
|
|
stw r8,mulh_addr
|
|
stw r8,mull_addr
|
|
stw r8,divss_addr
|
|
stw r8,divus_addr
|
|
stw r8,quoss_addr
|
|
stw r8,quous_addr
|
|
') #endif _KDB
|
|
|
|
.machine "pwr"
|
|
clcs r5,0xe # Get minimum cache line size
|
|
.machine "com"
|
|
cal r8,imove(0) # Start at end of move routine
|
|
sf r8,r5,r8 # Back up one cache line worth
|
|
start40:
|
|
.machine "pwr"
|
|
clf r8,r5 # Flush line containing byte at
|
|
# r8+r5, update r8
|
|
.machine "com"
|
|
cmp cr0,r8,r0 # Check if done
|
|
blt start40
|
|
dcs # Wait for memory to be updated
|
|
ics # Also instruction cache
|
|
b start48
|
|
|
|
# PPC model
|
|
# Use one loop to flush dcache, another one to invalidate icache.
|
|
# This is necessary because cache line sizes of these two caches may differ
|
|
|
|
start42:
|
|
cal r8,imove(0)
|
|
start43: # begin flushing dcache
|
|
.machine "ppc"
|
|
dcbf 0,r8
|
|
.machine "com"
|
|
cmp cr0,r8,r0
|
|
a r8,r8,r16
|
|
blt start43
|
|
|
|
sync
|
|
cal r8,imove(0)
|
|
start46: # begin invalidating icache
|
|
.machine "ppc"
|
|
icbi 0,r8
|
|
.machine "com"
|
|
cmp cr0,r8,r0
|
|
a r8,r8,r15
|
|
blt start46
|
|
sync
|
|
isync
|
|
|
|
# Branch to "start1"
|
|
start48:
|
|
.extern ENTRY(start1[PR])
|
|
ba ENTRY(start1[PR])
|
|
|
|
#*******************************************************************#
|
|
# N.B. This first loop FOLLOWS the second so the first half of #
|
|
# the move never clobbers itself! #
|
|
#*******************************************************************#
|
|
imove:
|
|
.long low_com_start # force a reference to low_com
|
|
|
|
startakh:
|
|
.extern DATA(kernel_header)
|
|
.long DATA(kernel_header)
|
|
|
|
startalkh:
|
|
.extern DATA(kernel_header_length)
|
|
.long DATA(kernel_header_length)
|
|
|
|
start10:
|
|
mfspr r13,LR # LR contains address of start10
|
|
|
|
#
|
|
# Fix up IPL controll block pointers. Two defined states:
|
|
# ROS:
|
|
# r3 - iplcb
|
|
# ROS EMULATION:
|
|
# r3 - -1
|
|
# r4 - iplcb
|
|
# r5 - extended iplcb
|
|
#
|
|
# Change to:
|
|
# r3 = iplcb
|
|
# r4 = extended iplcb or 0 if not present
|
|
|
|
cmpi cr0, r3, -1 # check for ROS emulation flag
|
|
beq cr0, ros_emul # branch if called from ROS emulation
|
|
|
|
lil r4, 0 # clear extended IPLCB pointer
|
|
b ros_done # continue
|
|
ros_emul:
|
|
mr r3, r4 # r3 = iplcb pointer
|
|
mr r4, r5 # r4 = extended iplcb pointer
|
|
ros_done:
|
|
|
|
ai r13,r13,real0-start25 # r13 contains real address of low 0
|
|
|
|
include(memcheck.m4)
|
|
|
|
# Set up to move header into kernel_header in loader - we just move
|
|
# a lot of bytes so we always get it right!
|
|
|
|
l r1,startakh(r13) # address of kernel_header
|
|
l r2,startalkh(r13) # address of length of kernel_header
|
|
lx r2,r2,r13 # length - note use of r13 to relocate
|
|
a r1,r1,r13 # relocate kernel_header address
|
|
a r2,r1,r2 # compute stopping address
|
|
cal r5,-4(r0) # initialize from pointer at -4
|
|
|
|
start11:
|
|
lu r8,4(r5)
|
|
st r8,0(r1)
|
|
cal r1,4(r1)
|
|
cmp cr0,r1,r2
|
|
blt start11
|
|
|
|
# Determine machine model.
|
|
# If it is a PPC machine, determine instruction cache line and data cache
|
|
# line sizes from iplcb.
|
|
# r15: icache line size
|
|
# r16: dcache line size
|
|
# r17: machine model
|
|
|
|
l r5,IPLINFO(r3) # offset of ipl_info structure
|
|
a r5,r5,r3 # addr of ipl_info structure
|
|
l r17,MODEL(r5) # model field in ipl_info structure
|
|
andiu. r5,r17,PPC_MODEL # test if PPC model
|
|
beq cr0,start12 # not a PPC model
|
|
l r5,PROCINFO(r3) # offset of proc_info structure
|
|
a r5,r5,r3 # addr of proc_info structure
|
|
l r15,ICACHEBK(r5) # icache block size
|
|
l r16,DCACHEBK(r5) # dcache block size
|
|
|
|
# Compute how many bytes to move in order to overlay the header at 0
|
|
|
|
start12:
|
|
l r1,DATA(lowcore_ram_disk_start)(r13) # addr of start of RAM disk
|
|
cal r0,-4(r1) # less 4 so we stop in time
|
|
cal r1,-4(0) # put -4 in r1; first "stu" will go to 0
|
|
ai r2,r13,-4 # set from address -4 to r2
|
|
cal r14,imove-real0(0) # compute number of bytes for
|
|
# first (short) move
|
|
|
|
# First move this routine so that we can guarantee the integrity of cache
|
|
|
|
andiu. r5,r17,PPC_MODEL # test if PPC model
|
|
bne cr0,start22 # PPC model
|
|
|
|
start20:
|
|
lu r6,4(r2) # get next 4 bytes to move
|
|
stu r6,4(r1) # move to proper location
|
|
.machine "pwr"
|
|
clf 0,r1 # we can afford to flush every
|
|
# store for short move
|
|
.machine "com"
|
|
cmp cr0,r1,r14 # check if all data moved
|
|
blt start20
|
|
|
|
# If here, the size of the TOC/XCOFF header in bytes has been moved to
|
|
# location 0. The kernel remains unchanged above this.
|
|
|
|
dcs # following example from Appendix C
|
|
# of architecture
|
|
ics # make sure we get the new values
|
|
# just moved above
|
|
ba start25 # this instruction will branch to
|
|
# the absolute location of start25
|
|
start22:
|
|
lu r6,4(r2) # get next 4 bytes to move
|
|
stu r6,4(r1) # move to proper location
|
|
.machine "ppc"
|
|
dcbf 0,r1 # flush dcache block
|
|
sync
|
|
icbi 0,r1 # invalidate icache block
|
|
.machine "com"
|
|
cmp cr0,r1,r14 # check if all data moved
|
|
blt start22
|
|
sync
|
|
isync
|
|
ba start25
|