patch-2.2.14 linux/arch/s390/kernel/head.S
Next file: linux/arch/s390/kernel/ieee.h
Previous file: linux/arch/s390/kernel/gdb-stub.c
Back to the patch index
Back to the overall index
- Lines: 582
- Date:
Tue Jan 4 10:12:12 2000
- Orig file:
v2.2.13/linux/arch/s390/kernel/head.S
- Orig date:
Wed Dec 31 16:00:00 1969
diff -u --recursive --new-file v2.2.13/linux/arch/s390/kernel/head.S linux/arch/s390/kernel/head.S
@@ -0,0 +1,581 @@
+/*
+ * arch/s390/kernel/head.S
+ *
+ * S390 version
+ * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ * Author(s): Hartmut Penner (hp@de.ibm.com),
+ * Martin Schwidefsky (schwidefsky@de.ibm.com),
+ *
+ * There are 4 different IPL methods
+ * 1) load the image directly into ram at address 0 and do an PSW restart
+ * 2) linload will load the image from address 0x10000 to memory 0x10000
+ * and start the code thru LPSW 0x0008000080010000 (VM only, deprecated)
+ * 3) generate the tape ipl header, store the generated image on a tape
+ * and ipl from it
+ * 4) generate the vm reader ipl header, move the generated image to the
+ * VM reader (use option NOH!) and do a ipl from reader (VM only)
+ * We use the cpuid to distinguish between VM and native ipl
+ * params for kernel are pushed to 0x10400 (see setup.h)
+ */
+
+#include <linux/config.h>
+#include <asm/setup.h>
+#include <asm/lowcore.h>
+
+#ifndef CONFIG_IPL
+ .org 0
+ .long 0x00080000,0x80000000+start # Just a restart PSW
+#else
+#ifdef CONFIG_IPL_TAPE
+#define IPL_BS 1024
+ .org 0
+ .long 0x00080000,0x80000000+iplstart # The first 24 bytes are loaded
+ .long 0x07000000,0x60000001 # by ipl to addresses 0-23.
+ .long 0x02000000,0x20000000+IPL_BS # (a PSW and two CCWs).
+ .long 0x00000000,0x00000000 # external old psw
+ .long 0x00000000,0x00000000 # svc old psw
+ .long 0x00000000,0x00000000 # program check old psw
+ .long 0x00000000,0x00000000 # machine check old psw
+ .long 0x00000000,0x00000000 # io old psw
+ .long 0x00000000,0x00000000
+ .long 0x00000000,0x00000000
+ .long 0x00000000,0x00000000
+ .long 0x000a0000,0x00000058 # external new psw
+ .long 0x000a0000,0x00000060 # svc new psw
+ .long 0x000a0000,0x00000068 # program check new psw
+ .long 0x000a0000,0x00000070 # machine check new psw
+ .long 0x00080000,0x80000000+.Lioint # io new psw
+
+ .org 0x100
+iplstart:
+ l %r1,0xb8 # load ipl subchannel number
+ lhi %r2,IPL_BS # load start address
+ bras %r14,.Lloader # load rest of ipl image
+ l %r12,.Lparm # pointer to parameter area
+#
+# load parameter file from tape
+#
+ l %r2,INITRD_START-PARMAREA(%r12) # use ramdisk location as temp
+ bras %r14,.Lloader # load parameter file
+ ltr %r2,%r2 # got anything ?
+ jz .Lnopf
+ chi %r2,896
+ jnh .Lnotrunc
+ lhi %r2,896
+.Lnotrunc:
+ l %r4,INITRD_START-PARMAREA(%r12)
+ clc 0(6,%r4),.Lebcdic # prefix EBCDIC in parm file ?
+ jne .Lnocv
+ ahi %r4,6 # skip EBCDIC
+ ahi %r2,-6
+ jnp .Lnopf
+ l %r3,.Lcvtab
+ tr 0(256,%r4),0(%r3) # convert parameters to ascii
+ tr 256(256,%r4),0(%r3)
+ tr 512(256,%r4),0(%r3)
+ tr 768(128,%r4),0(%r3)
+.Lnocv: la %r3,COMMAND_LINE-PARMAREA(%r12) # load adr. of command line
+ mvc 0(256,%r3),0(%r4)
+ mvc 256(256,%r3),256(%r4)
+ mvc 512(256,%r3),512(%r4)
+ mvc 768(128,%r3),768(%r4)
+ slr %r0,%r0
+ j .Lcntlp
+.Ldelspc:
+ ic %r0,0(%r2,%r3)
+ chi %r0,0x20 # is it a space ?
+ je .Lcntlp
+ ahi %r2,1
+ j .Leolp
+.Lcntlp:
+ brct %r2,.Ldelspc
+.Leolp:
+ slr %r0,%r0
+ stc %r0,0(%r2,%r3) # terminate buffer
+.Lnopf:
+
+#
+# load ramdisk from tape
+#
+ l %r2,INITRD_START-PARMAREA(%r12) # load adr. of ramdisk
+ bras %r14,.Lloader # load ramdisk
+ st %r2,INITRD_SIZE-PARMAREA(%r12) # store size of ramdisk
+ ltr %r2,%r2
+ jnz .Lrdcont
+ st %r2,INITRD_START-PARMAREA(%r12) # no ramdisk found, null it
+.Lrdcont:
+#
+# everything loaded, go for it
+#
+ j start
+#
+# subroutine for loading from tape
+# Paramters:
+# R1 = device number
+# R2 = load address
+.Lloader:
+ st %r14,.Lldret
+ la %r3,.Lorbread # r3 = address of orb
+ la %r5,.Lirb # r5 = address of irb
+ st %r2,.Lccwread+4 # initialize CCW data addresses
+ lctl %c6,%c6,.Lcr6
+ slr %r2,%r2
+.Lldlp:
+ lhi %r6,3 # 3 retries
+.Lssch:
+ ssch 0(%r3) # load chunk of IPL_BS bytes
+ jnz .Llderr
+.Lw4end:
+ bras %r14,.Lwait4io
+ tm 8(%r5),0x82 # do we have a problem ?
+ jnz .Lrecov
+ slr %r7,%r7
+ icm %r7,3,10(%r5) # get residual count
+ lcr %r7,%r7
+ ahi %r7,IPL_BS # IPL_BS-residual=#bytes read
+ ar %r2,%r7 # add to total size
+ tm 8(%r5),0x01 # found a tape mark ?
+ jnz .Ldone
+ l %r0,.Lccwread+4 # update CCW data addresses
+ ar %r0,%r7
+ st %r0,.Lccwread+4
+ j .Lldlp
+.Ldone:
+ l %r14,.Lldret
+ br %r14 # r2 contains the total size
+.Lrecov:
+ bras %r14,.Lsense # do the sensing
+ brct %r6,.Lssch # dec. retry count & branch
+ j .Llderr
+#
+# Sense subroutine
+#
+.Lsense:
+ st %r14,.Lsnsret
+ la %r7,.Lorbsense
+ ssch 0(%r7) # start sense command
+ jnz .Llderr
+ bras %r14,.Lwait4io
+ l %r14,.Lsnsret
+ tm 8(%r5),0x82 # do we have a problem ?
+ jnz .Llderr
+ br %r14
+#
+# Wait for interrupt subroutine
+#
+.Lwait4io:
+ lpsw .Lwaitpsw
+.Lioint:
+ c %r1,0xb8 # compare subchannel number
+ jne .Lwait4io
+ tsch 0(%r5)
+ slr %r0,%r0
+ tm 8(%r5),0x82 # do we have a problem ?
+ jnz .Lwtexit
+ tm 8(%r5),0x04 # got device end ?
+ jz .Lwait4io
+.Lwtexit:
+ br %r14
+.Llderr:
+ lpsw .Lcrash
+
+ .align 8
+.Lorbread:
+ .long 0x00000000,0x0080ff00,.Lccwread
+ .align 8
+.Lorbsense:
+ .long 0x00000000,0x0080ff00,.Lccwsense
+ .align 8
+.Lccwread:
+ .long 0x02200000+IPL_BS,0x00000000
+.Lccwsense:
+ .long 0x04200001,0x00000000
+.Lwaitpsw:
+ .long 0x020a0000,0x80000000+.Lioint
+
+.Lirb: .long 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
+.Lcr6: .long 0xff000000
+ .align 8
+.Lcrash:.long 0x000a0000,0x00000000
+.Lparm: .long PARMAREA
+.Lldret:.long 0
+.Lsnsret: .long 0
+.Lebcdic:.long 0xc5c2c3c4,0xc9c30000
+.Lcvtab:.long _ebcasc # ebcdic to ascii table
+
+#endif /* CONFIG_IPL_TAPE */
+
+#ifdef CONFIG_IPL_VM
+ .org 0
+ .long 0x00080000,0x80000000+iplstart # The first 24 bytes are loaded
+ .long 0x02000018,0x60000050 # by ipl to addresses 0-23.
+ .long 0x02000068,0x60000050 # (a PSW and two CCWs).
+ .fill 80-24,1,0x40 # bytes 24-79 are discarded !!
+ .long 0x020000f0,0x60000050 # The next 160 byte are loaded
+ .long 0x02000140,0x60000050 # to addresses 0x18-0xb7
+ .long 0x02000190,0x60000050 # They form the continuation
+ .long 0x020001e0,0x60000050 # of the CCW program started
+ .long 0x02000230,0x60000050 # by ipl and load the range
+ .long 0x02000280,0x60000050 # 0x0f0-0x730 from the image
+ .long 0x020002d0,0x60000050 # to the range 0x0f0-0x730
+ .long 0x02000320,0x60000050 # in memory. At the end of
+ .long 0x02000370,0x60000050 # the channel program the PSW
+ .long 0x020003c0,0x60000050 # at location 0 is loaded.
+ .long 0x02000410,0x60000050 # Initial processing starts
+ .long 0x02000460,0x60000050 # at 0xf0 = iplstart.
+ .long 0x020004b0,0x60000050
+ .long 0x02000500,0x60000050
+ .long 0x02000550,0x60000050
+ .long 0x020005a0,0x60000050
+ .long 0x020005f0,0x60000050
+ .long 0x02000640,0x60000050
+ .long 0x02000690,0x60000050
+ .long 0x020006e0,0x20000050
+
+
+ .org 0xf0
+iplstart:
+ stidp __LC_CPUID # store cpuid
+ tm __LC_CPUID,0xff # running under VM ?
+ jno start # no -> skip loader part
+ l %r1,0xb8 # load ipl subchannel number
+ lhi %r2,0x730 # load start address
+ bras %r14,.Lloader # load rest of ipl image
+
+ l %r12,.Lparm # pointer to parameter area
+
+#
+# load parameter file from reader
+#
+ la %r2,COMMAND_LINE-PARMAREA(%r12) # load adr. of command line
+ bras %r14,.Lloader # load parameter file
+ ltr %r2,%r2 # got anything ?
+ jz .Lnopf
+ la %r3,COMMAND_LINE-PARMAREA(%r12) # load adr. of command line
+ l %r4,.Lcvtab
+ tr 0(256,3),0(4) # convert parameters to ascii
+ l %r4,.Lcvtab
+ tr 256(256,3),0(4)
+ l %r4,.Lcvtab
+ tr 512(256,3),0(4)
+ l %r4,.Lcvtab
+ tr 768(128,3),0(4)
+ slr %r0,%r0
+ j .Lcntlp
+.Ldelspc:
+ ic %r0,0(%r2,%r3)
+ chi %r0,0x20 # is it a space ?
+ je .Lcntlp
+ ahi %r2,1
+ j .Leolp
+.Lcntlp:
+ brct %r2,.Ldelspc
+.Leolp:
+ slr %r0,%r0
+ stc %r0,0(%r2,%r3) # terminate buffer
+.Lnopf:
+
+#
+# load ramdisk from reader
+#
+ l %r2,INITRD_START-PARMAREA(%r12) # load adr. of ramdisk
+ bras %r14,.Lloader # load ramdisk
+ st %r2,INITRD_SIZE-PARMAREA(%r12) # store size of ramdisk
+ ltr %r2,%r2
+ jnz .Lrdcont
+ st %r2,INITRD_START-PARMAREA(%r12) # no ramdisk found, null it
+.Lrdcont:
+
+#
+# everything loaded, reset files in reader, then go for it
+#
+ la %r2,.Lreset
+ lhi %r3,26
+ .long 0x83230008
+ j start
+
+#
+# subroutine for loading cards from the reader
+#
+.Lloader:
+ la %r3,.Lorb # r2 = address of orb into r2
+ la %r5,.Lirb # r4 = address of irb
+ la %r6,.Lccws
+ la %r7,20
+.Linit:
+ st %r2,4(%r6) # initialize CCW data addresses
+ ahi %r2,0x50
+ ahi %r6,8
+ brct 7,.Linit
+
+ lctl %c6,%c6,.Lcr6 # set IO subclass mask
+ slr %r2,%r2
+.Lldlp:
+ ssch 0(%r3) # load chunk of 1600 bytes
+ jnz .Llderr
+.Lwait4irq:
+ mvc __LC_IO_NEW_PSW(8),.Lnewpsw # set up IO interrupt psw
+ lpsw .Lwaitpsw
+.Lioint:
+ c %r1,0xb8 # compare subchannel number
+ jne .Lwait4irq
+ tsch 0(%r5)
+
+ slr %r0,%r0
+ ic %r0,8(%r5) # get device status
+ chi %r0,8 # channel end ?
+ je .Lcont
+ chi %r0,12 # channel end + device end ?
+ je .Lcont
+
+ l %r0,4(%r5)
+ s %r0,8(%r3) # r0/8 = number of ccws executed
+ mhi %r0,10 # *10 = number of bytes in ccws
+ lh %r3,10(%r5) # get residual count
+ sr %r0,%r3 # #ccws*80-residual=#bytes read
+ ar %r2,%r0
+
+ br %r14 # r2 contains the total size
+
+.Lcont:
+ ahi %r2,0x640 # add 0x640 to total size
+ la %r6,.Lccws
+ la %r7,20
+.Lincr:
+ l %r0,4(%r6) # update CCW data addresses
+ ahi %r0,0x640
+ st %r0,4(%r6)
+ ahi %r6,8
+ brct 7,.Lincr
+
+ j .Lldlp
+.Llderr:
+ lpsw .Lcrash
+
+ .align 8
+.Lorb: .long 0x00000000,0x0080ff00,.Lccws
+.Lirb: .long 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
+.Lcr6: .long 0xff000000
+.Lloadp:.long 0,0
+.Lparm: .long PARMAREA
+.Lcvtab:.long _ebcasc # ebcdic to ascii table
+.Lreset:.byte 0xc3,0xc8,0xc1,0xd5,0xc7,0xc5,0x40,0xd9,0xc4,0xd9,0x40
+ .byte 0xc1,0xd3,0xd3,0x40,0xd2,0xc5,0xc5,0xd7,0x40,0xd5,0xd6
+ .byte 0xc8,0xd6,0xd3,0xc4 # "change rdr all keep nohold"
+ .align 8
+.Lcrash:
+ .long 0x000a0000,0x00000000
+.Lnewpsw:
+ .long 0x00080000,0x80000000+.Lioint
+.Lwaitpsw:
+ .long 0x020a0000,0x80000000+.Lioint
+
+ .align 8
+.Lccws: .rept 19
+ .long 0x02600050,0x00000000
+ .endr
+ .long 0x02200050,0x00000000
+
+ .org 0x730 # end of the area loaded by the ipl channel program
+#endif /* CONFIG_IPL_VM */
+
+#endif /* CONFIG_IPL */
+
+#
+# startup-code at 0x10000, running in real mode
+# this is called either by the ipl loader or directly by PSW restart or linload
+#
+ .org 0x10000
+ .globl start
+start: basr %r13,0 # get base
+.LPG1: lctl %c1,%c1,.Lpstd-.LPG1(%r13) # load pstd
+ lctl %c7,%c7,.Lpstd-.LPG1(%r13) # load sstd
+ lctl %c13,%c13,.Lpstd-.LPG1(%r13) # load hstd
+ lctl %c0,%c0,.Lcr0-.LPG1(%r13) # set CR0
+ l %r12,.Lparm1-.LPG1(%r13) # pointer to parameter area
+
+#
+# find out memory size
+#
+ mvc 104(8,0),.Lpcmem-.LPG1(%r13) # setup program check handler
+ slr %r1,%r1
+ lhi %r2,1
+ sll %r2,20
+.Lloop:
+ l %r0,0(%r1) # test page
+ ar %r1,%r2 # add 1M
+ jnm .Lloop # r1 < 0x80000000 -> loop
+.Lchkmem:
+ n %r1,.L4malign-.LPG1(%r13) # align to multiples of 4M
+ st %r1,MEMORY_SIZE-PARMAREA(%r12) # store memory size
+
+#
+# find out if we are running under VM
+#
+ stidp __LC_CPUID # store cpuid
+ tm __LC_CPUID,0xff # running under VM ?
+ jno .Lnovm
+ oi MACHINE_FLAGS+3-PARMAREA(%r12),1 # set VM flag
+.Lnovm:
+
+#
+# find out if we have an IEEE fpu
+#
+ mvc 104(8,0),.Lpcfpu-.LPG1(%r13) # setup program check handler
+ ld %f0,.Lflt0-.LPG1(%r13) # load (float) 0.0
+ ldr %f2,%f0
+ adbr %f0,%f2 # test IEEE add instruction
+ oi MACHINE_FLAGS+3-PARMAREA(%r12),2 # set IEEE fpu flag
+.Lchkfpu:
+
+#
+# move ramdisk to the end of storage, out of the way of the paging tables
+#
+ icm %r2,15,INITRD_START-PARMAREA(%r12) # load adr. of ramdisk
+ jz .Lnocprd
+ icm %r3,15,INITRD_SIZE-PARMAREA(%r12) # store size of ramdisk
+ jz .Lnocprd
+ l %r4,MEMORY_SIZE-PARMAREA(%r12)
+ sr %r4,%r3
+ srl %r4,12
+ sll %r4,12
+ st %r4,INITRD_START-PARMAREA(%r12)
+ lr %r5,%r3
+.Lcprd:
+ mvcle %r4,%r2,0
+ jo .Lcprd
+.Lnocprd:
+ lpsw .Lentry-.LPG1(13) # jump to _stext in primary-space,
+ # virtual and never return ...
+ .align 8
+.Lentry:.long 0x0408C000,0x80000000 + _stext
+.Lpstd: .long .Lpgd+0x7F # segment-table
+.Lcr0: .long 0x04b50002
+.Lpcmem:.long 0x00080000,0x80000000 + .Lchkmem
+.Lpcfpu:.long 0x00080000,0x80000000 + .Lchkfpu
+.Lflt0: .double 0
+.Lparm1:.long PARMAREA
+.L4malign:.long 0xffc00000
+
+#
+# params at 10400 (setup.h)
+#
+ .org PARMAREA
+ .long 0x0100 # ORIG_ROOT_DEV: ramdisk major/minor
+ .word 0 # MOUNT_ROOT_RDONLY: no
+ .long 0 # MEMORY_SIZE
+ .long 0 # MACHINE_FLAGS (bit 0:VM, bit 1:IEEE)
+ .long RAMDISK_ORIGIN # INITRD_START
+ .long 0x800000 # INITRD_SIZE
+ .word 0 # RAMDISK_FLAGS
+
+ .org COMMAND_LINE
+# .byte "root=/dev/nfs rw nfsroot=9.164.160.7:/home/mschwide/nfsboot "
+# .byte "ip=9.164.147.12:9.164.160.7:9.164.147.1:255.255.255.0:vmlinux:tr0:off"
+# .byte "root=/dev/nfs nfsroot=9.164.160.7:/home/mschwide/nfsboot "
+# .byte "ip=9.164.181.228:9.164.160.7:9.164.181.1:255.255.224.0:vmlinux:tr0:off"
+# .byte "root=/dev/nfs nfsroot=9.164.160.7:/home/pasch/nfsboot "
+# .byte "ip=9.164.185.120:9.164.160.7:9.164.181.1:255.255.224.0:vmlinux:tr0:off"
+# .byte "mdisk=402:65536:1229,403:131072:2780 root=/dev/mnda ro"
+# .byte "root=/dev/nfs rw nfsroot=9.164.160.209:/usr/local/nfsboot "
+# .byte "ip=9.164.181.228:9.164.160.209:9.164.181.1:255.255.224.0:vmlinux:tr0:off"
+ .byte "root=/dev/ram0 ro"
+# .byte 0
+
+#
+# startup-code, running in virtual mode
+#
+ .org 0x10800
+ .globl _stext
+_stext: basr %r13,0 # get base
+.LPG2:
+#
+# Setup lowcore
+#
+ spx .Lprefix-.LPG2(%r13) # set prefix to linux lowcore
+ l %r15,.Linittu-.LPG2(%r13)
+ ahi %r15,8192 # init_task_union + 8191
+ st %r15,__LC_KERNEL_STACK # set end of kernel stack
+ ahi %r15,-96
+ lhi %r0,-1
+ st %r0,__LC_KERNEL_LEVEL # set interrupt count to -1
+#
+# clear bss memory
+#
+ l %r2,.Lbss_bgn-.LPG2(%r13) # start of bss
+ l %r3,.Lbss_end-.LPG2(%r13) # end of bss
+ sr %r3,%r2 # length of bss
+ sr %r4,%r4 #
+ sr %r5,%r5 # set src,length and pad to zero
+ sr %r0,%r0 #
+ mvcle %r2,%r4,0 # clear mem
+ jo .-4 # branch back, if not finish
+# check control registers
+ stctl %c0,%c15,0(%r15)
+ l %r0,0(%r15)
+ o %r0,.Lcr0or-.LPG2(%r13) # enable sigp external ints.
+ st %r0,0(%r15)
+ lctl %c0,%c15,0(%r15)
+
+#
+ lam 0,15,.Laregs-.LPG2(%r13) # load access regs needed by uaccess
+ l %r14,.Lstart-.LPG2(%r13)
+ basr %r14,%r14 # call start_kernel
+#
+# We returned from start_kernel ?!? PANIK
+#
+ basr %r13,0
+ lpsw .Ldw-.(%r13) # load disabled wait psw
+#
+.Lstart: .long start_kernel
+ .align 8
+.Lprefix: .long init_S390_lowcore
+.Linittu: .long init_task_union
+.Lbss_bgn: .long __bss_start
+.Lbss_end: .long _end
+.Lcr0or: .long 0x00002000
+ .align 4
+.Laregs: .long 0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0
+ .align 8
+.Ldw: .long 0x000a0000,0x00000000
+
+#
+# tempory segment-table at 0x11000
+#
+ .org 0x11000
+.Lpgd: .long .Lpt0+0x1f # 00000000-000fffff
+ .long .Lpt1+0x1f # 00100000-001fffff
+ .long .Lpt2+0x1f # 00200000-002fffff
+ .long .Lpt3+0x1f # 00300000-003fffff
+ .fill 2044,4,0x20 # 00400000-7fffffff
+
+#
+# tempory page-tables at 0x12000-0x15fff
+#
+ .macro mktable from,to
+ .long \from*0x10000
+ .long \from*0x10000+0x1000
+ .long \from*0x10000+0x2000
+ .long \from*0x10000+0x3000
+ .long \from*0x10000+0x4000
+ .long \from*0x10000+0x5000
+ .long \from*0x10000+0x6000
+ .long \from*0x10000+0x7000
+ .long \from*0x10000+0x8000
+ .long \from*0x10000+0x9000
+ .long \from*0x10000+0xa000
+ .long \from*0x10000+0xb000
+ .long \from*0x10000+0xc000
+ .long \from*0x10000+0xd000
+ .long \from*0x10000+0xe000
+ .long \from*0x10000+0xf000
+ .if \to-\from
+ mktable "(\from+1)",\to
+ .endif
+ .endm
+
+.Lpt0: mktable 0,15
+.Lpt1: mktable 16,31
+.Lpt2: mktable 32,47
+.Lpt3: mktable 48,63
+
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)