aboutsummaryrefslogtreecommitdiff
path: root/arch/s390/kernel/head.S
diff options
context:
space:
mode:
Diffstat (limited to 'arch/s390/kernel/head.S')
-rw-r--r--arch/s390/kernel/head.S401
1 files changed, 207 insertions, 194 deletions
diff --git a/arch/s390/kernel/head.S b/arch/s390/kernel/head.S
index 0cf59bb7a85..e88d35d7495 100644
--- a/arch/s390/kernel/head.S
+++ b/arch/s390/kernel/head.S
@@ -1,7 +1,5 @@
/*
- * arch/s390/kernel/head.S
- *
- * Copyright (C) IBM Corp. 1999,2006
+ * Copyright IBM Corp. 1999, 2010
*
* Author(s): Hartmut Penner <hp@de.ibm.com>
* Martin Schwidefsky <schwidefsky@de.ibm.com>
@@ -23,8 +21,8 @@
*
*/
-#include <asm/setup.h>
-#include <asm/lowcore.h>
+#include <linux/init.h>
+#include <linux/linkage.h>
#include <asm/asm-offsets.h>
#include <asm/thread_info.h>
#include <asm/page.h>
@@ -35,125 +33,8 @@
#define ARCH_OFFSET 0
#endif
-#ifndef CONFIG_IPL
- .org 0
- .long 0x00080000,0x80000000+startup # 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 0x27000000,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
-#
-# 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:
- la %r6,3 # 3 retries
-.Lssch:
- ssch 0(%r3) # load chunk of IPL_BS bytes
- bnz .Llderr
-.Lw4end:
- bas %r14,.Lwait4io
- tm 8(%r5),0x82 # do we have a problem ?
- bnz .Lrecov
- slr %r7,%r7
- icm %r7,3,10(%r5) # get residual count
- lcr %r7,%r7
- la %r7,IPL_BS(%r7) # IPL_BS-residual=#bytes read
- ar %r2,%r7 # add to total size
- tm 8(%r5),0x01 # found a tape mark ?
- bnz .Ldone
- l %r0,.Lccwread+4 # update CCW data addresses
- ar %r0,%r7
- st %r0,.Lccwread+4
- b .Lldlp
-.Ldone:
- l %r14,.Lldret
- br %r14 # r2 contains the total size
-.Lrecov:
- bas %r14,.Lsense # do the sensing
- bct %r6,.Lssch # dec. retry count & branch
- b .Llderr
-#
-# Sense subroutine
-#
-.Lsense:
- st %r14,.Lsnsret
- la %r7,.Lorbsense
- ssch 0(%r7) # start sense command
- bnz .Llderr
- bas %r14,.Lwait4io
- l %r14,.Lsnsret
- tm 8(%r5),0x82 # do we have a problem ?
- bnz .Llderr
- br %r14
-#
-# Wait for interrupt subroutine
-#
-.Lwait4io:
- lpsw .Lwaitpsw
-.Lioint:
- c %r1,0xb8 # compare subchannel number
- bne .Lwait4io
- tsch 0(%r5)
- slr %r0,%r0
- tm 8(%r5),0x82 # do we have a problem ?
- bnz .Lwtexit
- tm 8(%r5),0x04 # got device end ?
- bz .Lwait4io
-.Lwtexit:
- br %r14
-.Llderr:
- lpsw .Lcrash
+__HEAD
- .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
-.Lldret:.long 0
-.Lsnsret: .long 0
-#endif /* CONFIG_IPL_TAPE */
-
-#ifdef CONFIG_IPL_VM
#define IPL_BS 0x730
.org 0
.long 0x00080000,0x80000000+iplstart # The first 24 bytes are loaded
@@ -171,7 +52,7 @@
.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 0x02000460,0x60000050 # at 0x200 = iplstart.
.long 0x020004b0,0x60000050
.long 0x02000500,0x60000050
.long 0x02000550,0x60000050
@@ -181,11 +62,54 @@
.long 0x02000690,0x60000050
.long 0x020006e0,0x20000050
- .org 0xf0
+ .org 0x200
+#
+# subroutine to set architecture mode
+#
+.Lsetmode:
+#ifdef CONFIG_64BIT
+ mvi __LC_AR_MODE_ID,1 # set esame flag
+ slr %r0,%r0 # set cpuid to zero
+ lhi %r1,2 # mode 2 = esame (dump)
+ sigp %r1,%r0,0x12 # switch to esame mode
+ bras %r13,0f
+ .fill 16,4,0x0
+0: lmh %r0,%r15,0(%r13) # clear high-order half of gprs
+ sam31 # switch to 31 bit addressing mode
+#else
+ mvi __LC_AR_MODE_ID,0 # set ESA flag (mode 0)
+#endif
+ br %r14
+
+#
+# subroutine to wait for end I/O
+#
+.Lirqwait:
+#ifdef CONFIG_64BIT
+ mvc 0x1f0(16),.Lnewpsw # set up IO interrupt psw
+ lpsw .Lwaitpsw
+.Lioint:
+ br %r14
+ .align 8
+.Lnewpsw:
+ .quad 0x0000000080000000,.Lioint
+#else
+ mvc 0x78(8),.Lnewpsw # set up IO interrupt psw
+ lpsw .Lwaitpsw
+.Lioint:
+ br %r14
+ .align 8
+.Lnewpsw:
+ .long 0x00080000,0x80000000+.Lioint
+#endif
+.Lwaitpsw:
+ .long 0x020a0000,0x80000000+.Lioint
+
#
# subroutine for loading cards from the reader
#
.Lloader:
+ la %r4,0(%r14)
la %r3,.Lorb # r2 = address of orb into r2
la %r5,.Lirb # r4 = address of irb
la %r6,.Lccws
@@ -202,9 +126,7 @@
ssch 0(%r3) # load chunk of 1600 bytes
bnz .Llderr
.Lwait4irq:
- mvc 0x78(8),.Lnewpsw # set up IO interrupt psw
- lpsw .Lwaitpsw
-.Lioint:
+ bas %r14,.Lirqwait
c %r1,0xb8 # compare subchannel number
bne .Lwait4irq
tsch 0(%r5)
@@ -223,7 +145,7 @@
sr %r0,%r3 # #ccws*80-residual=#bytes read
ar %r2,%r0
- br %r14 # r2 contains the total size
+ br %r4 # r2 contains the total size
.Lcont:
ahi %r2,0x640 # add 0x640 to total size
@@ -247,19 +169,15 @@
.Lloadp:.long 0,0
.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
-#endif /* CONFIG_IPL_VM */
iplstart:
+ bas %r14,.Lsetmode # Immediately switch to 64 bit mode
lh %r1,0xb8 # test if subchannel number
bct %r1,.Lnoload # is valid
l %r1,0xb8 # load ipl subchannel number
@@ -287,19 +205,7 @@ iplstart:
bz .Lagain1 # skip dateset trailer
la %r5,0(%r4,%r2)
lr %r3,%r2
-.Lidebc:
- tm 0(%r5),0x80 # high order bit set ?
- bo .Ldocv # yes -> convert from EBCDIC
- ahi %r5,-1
- bct %r3,.Lidebc
- b .Lnocv
-.Ldocv:
- 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(122,%r4),0(%r3)
-.Lnocv: la %r3,COMMAND_LINE-PARMAREA(%r12) # load adr. of command line
+ 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)
@@ -338,12 +244,11 @@ iplstart:
clc 0(3,%r2),.L_eof
bz .Lagain2
-#ifdef CONFIG_IPL_VM
#
# reset files in VM reader
#
- stidp __LC_CPUID # store cpuid
- tm __LC_CPUID,0xff # running VM ?
+ stidp .Lcpuid # store cpuid
+ tm .Lcpuid,0xff # running VM ?
bno .Lnoreset
la %r2,.Lreset
lhi %r3,26
@@ -355,24 +260,14 @@ iplstart:
tm 31(%r5),0xff # bits is set in the schib
bz .Lnoreset
.Lwaitforirq:
- mvc 0x78(8),.Lrdrnewpsw # set up IO interrupt psw
-.Lwaitrdrirq:
- lpsw .Lrdrwaitpsw
-.Lrdrint:
+ bas %r14,.Lirqwait # wait for IO interrupt
c %r1,0xb8 # compare subchannel number
- bne .Lwaitrdrirq
+ bne .Lwaitforirq
la %r5,.Lirb
tsch 0(%r5)
.Lnoreset:
b .Lnoload
- .align 8
-.Lrdrnewpsw:
- .long 0x00080000,0x80000000+.Lrdrint
-.Lrdrwaitpsw:
- .long 0x020a0000,0x80000000+.Lrdrint
-#endif
-
#
# everything loaded, go for it
#
@@ -380,17 +275,16 @@ iplstart:
l %r1,.Lstartup
br %r1
-.Linitrd:.long _end + 0x400000 # default address of initrd
+.Linitrd:.long _end # default address of initrd
.Lparm: .long PARMAREA
.Lstartup: .long startup
-.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"
.L_eof: .long 0xc5d6c600 /* C'EOF' */
.L_hdr: .long 0xc8c4d900 /* C'HDR' */
-
-#endif /* CONFIG_IPL */
+ .align 8
+.Lcpuid:.fill 8,1,0
#
# SALIPL loader support. Based on a patch by Rob van der Heij.
@@ -398,9 +292,9 @@ iplstart:
# doesn't need a builtin ipl record.
#
.org 0x800
- .globl start
-start:
+ENTRY(start)
stm %r0,%r15,0x07b0 # store registers
+ bas %r14,.Lsetmode # Immediately switch to 64 bit mode
basr %r12,%r0
.base:
l %r11,.parm
@@ -416,36 +310,12 @@ start:
.sk8x8:
mvc 0(240,%r8),0(%r9) # copy iplparms into buffer
.gotr:
- l %r10,.tbl # EBCDIC to ASCII table
- tr 0(240,%r8),0(%r10)
- stidp __LC_CPUID # Are we running on VM maybe
- cli __LC_CPUID,0xff
- bnz .test
- .long 0x83300060 # diag 3,0,x'0060' - storage size
- b .done
-.test:
- mvc 0x68(8),.pgmnw # set up pgm check handler
- l %r2,.fourmeg
- lr %r3,%r2
- bctr %r3,%r0 # 4M-1
-.loop: iske %r0,%r3
- ar %r3,%r2
-.pgmx:
- sr %r3,%r2
- la %r3,1(%r3)
-.done:
- l %r1,.memsize
- st %r3,ARCH_OFFSET(%r1)
slr %r0,%r0
st %r0,INITRD_SIZE+ARCH_OFFSET-PARMAREA(%r11)
st %r0,INITRD_START+ARCH_OFFSET-PARMAREA(%r11)
j startup # continue with startup
-.tbl: .long _ebcasc # translate table
.cmd: .long COMMAND_LINE # address of command line buffer
.parm: .long PARMAREA
-.memsize: .long memory_size
-.fourmeg: .long 0x00400000 # 4M
-.pgmnw: .long 0x00080000,.pgmx
.lowcase:
.byte 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07
.byte 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f
@@ -481,8 +351,151 @@ start:
.byte 0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7
.byte 0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0xff
+#
+# startup-code at 0x10000, running in absolute addressing mode
+# this is called either by the ipl loader or directly by PSW restart
+# or linload or SALIPL
+#
+ .org 0x10000
+ENTRY(startup)
+ j .Lep_startup_normal
+ .org 0x10008
+#
+# This is a list of s390 kernel entry points. At address 0x1000f the number of
+# valid entry points is stored.
+#
+# IMPORTANT: Do not change this table, it is s390 kernel ABI!
+#
+ .ascii "S390EP"
+ .byte 0x00,0x01
+#
+# kdump startup-code at 0x10010, running in 64 bit absolute addressing mode
+#
+ .org 0x10010
+ENTRY(startup_kdump)
+ j .Lep_startup_kdump
+.Lep_startup_normal:
+#ifdef CONFIG_64BIT
+ mvi __LC_AR_MODE_ID,1 # set esame flag
+ slr %r0,%r0 # set cpuid to zero
+ lhi %r1,2 # mode 2 = esame (dump)
+ sigp %r1,%r0,0x12 # switch to esame mode
+ bras %r13,0f
+ .fill 16,4,0x0
+0: lmh %r0,%r15,0(%r13) # clear high-order half of gprs
+ sam31 # switch to 31 bit addressing mode
+#else
+ mvi __LC_AR_MODE_ID,0 # set ESA flag (mode 0)
+#endif
+ basr %r13,0 # get base
+.LPG0:
+ xc 0x200(256),0x200 # partially clear lowcore
+ xc 0x300(256),0x300
+ xc 0xe00(256),0xe00
+ stck __LC_LAST_UPDATE_CLOCK
+ spt 6f-.LPG0(%r13)
+ mvc __LC_LAST_UPDATE_TIMER(8),6f-.LPG0(%r13)
+ xc __LC_STFL_FAC_LIST(8),__LC_STFL_FAC_LIST
+#ifndef CONFIG_MARCH_G5
+ # check capabilities against MARCH_{G5,Z900,Z990,Z9_109,Z10}
+ .insn s,0xb2b10000,__LC_STFL_FAC_LIST # store facility list
+ tm __LC_STFL_FAC_LIST,0x01 # stfle available ?
+ jz 0f
+ la %r0,1
+ .insn s,0xb2b00000,__LC_STFL_FAC_LIST # store facility list extended
+ # verify if all required facilities are supported by the machine
+0: la %r1,__LC_STFL_FAC_LIST
+ la %r2,3f+8-.LPG0(%r13)
+ l %r3,0(%r2)
+1: l %r0,0(%r1)
+ n %r0,4(%r2)
+ cl %r0,4(%r2)
+ jne 2f
+ la %r1,4(%r1)
+ la %r2,4(%r2)
+ ahi %r3,-1
+ jnz 1b
+ j 4f
+2: l %r15,.Lstack-.LPG0(%r13)
+ ahi %r15,-96
+ la %r2,.Lals_string-.LPG0(%r13)
+ l %r3,.Lsclp_print-.LPG0(%r13)
+ basr %r14,%r3
+ lpsw 3f-.LPG0(%r13) # machine type not good enough, crash
+.Lals_string:
+ .asciz "The Linux kernel requires more recent processor hardware"
+.Lsclp_print:
+ .long _sclp_print_early
+.Lstack:
+ .long 0x8000 + (1<<(PAGE_SHIFT+THREAD_ORDER))
+ .align 16
+3: .long 0x000a0000,0x8badcccc
+
+# List of facilities that are required. If not all facilities are present
+# the kernel will crash. Format is number of facility words with bits set,
+# followed by the facility words.
+
+#if defined(CONFIG_64BIT)
+#if defined(CONFIG_MARCH_ZEC12)
+ .long 3, 0xc100eff2, 0xf46ce800, 0x00400000
+#elif defined(CONFIG_MARCH_Z196)
+ .long 2, 0xc100eff2, 0xf46c0000
+#elif defined(CONFIG_MARCH_Z10)
+ .long 2, 0xc100eff2, 0xf0680000
+#elif defined(CONFIG_MARCH_Z9_109)
+ .long 1, 0xc100efc2
+#elif defined(CONFIG_MARCH_Z990)
+ .long 1, 0xc0002000
+#elif defined(CONFIG_MARCH_Z900)
+ .long 1, 0xc0000000
+#endif
+#else
+#if defined(CONFIG_MARCH_ZEC12)
+ .long 1, 0x8100c880
+#elif defined(CONFIG_MARCH_Z196)
+ .long 1, 0x8100c880
+#elif defined(CONFIG_MARCH_Z10)
+ .long 1, 0x8100c880
+#elif defined(CONFIG_MARCH_Z9_109)
+ .long 1, 0x8100c880
+#elif defined(CONFIG_MARCH_Z990)
+ .long 1, 0x80002000
+#elif defined(CONFIG_MARCH_Z900)
+ .long 1, 0x80000000
+#endif
+#endif
+4:
+#endif
+
#ifdef CONFIG_64BIT
-#include "head64.S"
+ /* Continue with 64bit startup code in head64.S */
+ sam64 # switch to 64 bit mode
+ jg startup_continue
#else
-#include "head31.S"
+ /* Continue with 31bit startup code in head31.S */
+ l %r13,5f-.LPG0(%r13)
+ b 0(%r13)
+ .align 8
+5: .long startup_continue
#endif
+
+ .align 8
+6: .long 0x7fffffff,0xffffffff
+
+#include "head_kdump.S"
+
+#
+# params at 10400 (setup.h)
+#
+ .org PARMAREA
+ .long 0,0 # IPL_DEVICE
+ .long 0,0 # INITRD_START
+ .long 0,0 # INITRD_SIZE
+ .long 0,0 # OLDMEM_BASE
+ .long 0,0 # OLDMEM_SIZE
+
+ .org COMMAND_LINE
+ .byte "root=/dev/ram0 ro"
+ .byte 0
+
+ .org 0x11000