1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
|
#
# kexec: Linux boots Linux
#
# Copyright (C) 2004 - 2005, Milton D Miller II, IBM Corporation
# Copyright (C) 2006, Mohan Kumar M (mohan@in.ibm.com), IBM Corporation
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation (version 2 of the License).
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
#include "ppc64_asm.h"
# v2wrap.S
# a wrapper to call purgatory code to backup first
# 32kB of first kernel into the backup region
# reserved by kexec-tools.
# Invokes ppc64 kernel with the expected arguments
# of kernel(device-tree, phys-offset, 0)
#
# calling convention:
# r3 = physical number of this cpu (all cpus)
# r4 = address of this chunk (master only)
# master enters at purgatory_start (aka first byte of this chunk)
# slaves (additional cpus), if any, enter a copy of the
# first 0x100 bytes of this code relocated to 0x0
#
# in other words,
# a copy of the first 0x100 bytes of this code is copied to 0
# and the slaves are sent to address 0x60
# with r3 = their physical cpu number.
#define LOADADDR(rn,name) \
lis rn,name##@highest; \
ori rn,rn,name##@higher; \
rldicr rn,rn,32,31; \
oris rn,rn,name##@h; \
ori rn,rn,name##@l
.machine ppc64
.align 8
.globl purgatory_start
purgatory_start: b master
.org purgatory_start + 0x5c # ABI: possible run_at_load flag at 0x5c
.globl run_at_load
run_at_load:
.long 0
.size run_at_load, . - run_at_load
.org purgatory_start + 0x60 # ABI: slaves start at 60 with r3=phys
slave: b $
.org purgatory_start + 0x100 # ABI: end of copied region
.size purgatory_start, . - purgatory_start
#
# The above 0x100 bytes at purgatory_start are replaced with the
# code from the kernel (or next stage) by kexec/arch/ppc64/kexec-elf-ppc64.c
#
master:
or 1,1,1 # low priority to let other threads catchup
isync
mr 17,3 # save cpu id to r17
mr 15,4 # save physical address in reg15
LOADADDR(6,my_toc)
ld 2,0(6) #setup toc
LOADADDR(6,stack)
ld 1,0(6) #setup stack
subi 1,1,112
bl DOTSYM(purgatory)
nop
or 3,3,3 # ok now to high priority, lets boot
lis 6,0x1
mtctr 6 # delay a bit for slaves to catch up
83: bdnz 83b # before we overwrite 0-100 again
LOADADDR(16, dt_offset)
ld 3,0(16) # load device-tree address
mr 16,3 # save dt address in reg16
#ifdef __BIG_ENDIAN__
lwz 6,20(3) # fetch version number
#else
li 4,20
lwbrx 6,3,4 # fetch BE version number
#endif
cmpwi 0,6,2 # v2 ?
blt 80f
#ifdef __BIG_ENDIAN__
stw 17,28(3) # save my cpu number as boot_cpu_phys
#else
li 4,28
stwbrx 17,3,4 # Store my cpu as BE value
#endif
80:
LOADADDR(6,opal_base) # For OPAL early debug
ld 8,0(6) # load the OPAL base address in r8
LOADADDR(6,opal_entry) # For OPAL early debug
ld 9,0(6) # load the OPAL entry address in r9
LOADADDR(6,kernel)
ld 4,0(6) # load the kernel address
LOADADDR(6,run_at_load) # the load flag
lwz 7,0(6) # possibly patched by kexec-elf-ppc64
stw 7,0x5c(4) # and patch it into the kernel
mr 3,16 # restore dt address
mfmsr 5
andi. 10,5,1 # test MSR_LE
bne little_endian
li 5,0 # r5 will be 0 for kernel
mtctr 4 # prepare branch to
bctr # start kernel
little_endian: # book3s-only
mtsrr0 4 # prepare branch to
clrrdi 5,5,1 # clear MSR_LE
mtsrr1 5
li 5,0 # r5 will be 0 for kernel
# skip cache flush, do we care?
rfid # update MSR and start kernel
|