summaryrefslogtreecommitdiff
path: root/usr/src/uts/sun4u/ml/cpr_resume_setup.s
blob: 1fe10fdaa4521b3fbdf2aff45c7753f5aa741c88 (plain)
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
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */
/*
 * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

#include "assym.h"

#include <sys/asm_linkage.h>
#include <sys/machthread.h>		/* for reg definition */

#include <sys/machasi.h>		/* sun4u ASI */
#include <sys/mmu.h>
#include <sys/privregs.h>
#include <sys/machparam.h>
#include <vm/hat_sfmmu.h>
#include <sys/cpr_impl.h>
#include <sys/intreg.h>
#include <sys/clock.h>

/*
 * resume kernel entry point from cprboot
 * 	1. restore I/D TSB registers
 *	2. restore primary and secondary context registers
 *	3. initialize cpu state registers
 *	4. set up the thread and lwp registers for the cpr process
 *	5. switch to kernel trap
 *	6. restore checkpoint pc and stack pointer
 *	7. longjmp back to kernel
 *
 * registers from cprboot:exit_to_kernel()
 *	%o0	prom cookie
 *	%o1	struct sun4u_machdep *mdp
 *
 * Any change to this register assignment
 * require changes to cprboot_srt0.s
 */

	!
	! reserve 4k for cpr tmp stack; tstack should be first,
	! any new data symbols should be added after tstack.
	!
	.seg	".data"
	.global	i_cpr_data_page, i_cpr_tstack_size
	.global	i_cpr_orig_cif

	.align	MMU_PAGESIZE
i_cpr_data_page:
	.skip	4096
i_cpr_tstack:
	.word	0
i_cpr_tstack_size:
	.word	4096

	.align	8
prom_tba:
	.word	0, 0
i_cpr_orig_cif:
	.nword	0
i_cpr_tmp_cif:
	.nword	0


	!
	! set text to begin at a page boundary so we can
	! map this one page and jump to it from cprboot
	!
	.seg	".text"
	.align	MMU_PAGESIZE

	ENTRY(i_cpr_resume_setup)
	!
	! save %o args to locals
	!
	mov	%o0, %l4
	mov	%o1, %l5

	!
	! Restore PCONTEXT
	!
	sethi	%hi(FLUSH_ADDR), %g3
	ld	[%l5 + CPR_MD_PRI], %g1		! mdp->mmu_ctx_pri
	set	MMU_PCONTEXT, %g2
	stxa	%g1, [%g2]ASI_DMMU
	flush	%g3

	!
	! Restore SCONTEXT.  We do not need to set up the TSB
	! registers.  Since we are restoring INVALID_CONTEXT into
	! the secondary context the HAT will do that for us.
	!
	ld	[%l5 + CPR_MD_SEC], %g1		! mdp->mmu_ctx_sec
	set	MMU_SCONTEXT, %g2
	stxa	%g1, [%g2]ASI_DMMU
	flush	%g3

	!
	! Allow user rdtick, and rdstick if applicable
	!
	CLEARTICKNPT

	!
	! copy saved thread pointer to %g7
	!
	ldx	[%l5 + CPR_MD_THRP], THREAD_REG		! mdp->thrp

	!
	! since csu_md_t lives in a cprboot data page,
	! copy select data to registers for later use
	! before freeing cprboot text/data pages
	!
	ldx	[%l5 + CPR_MD_QSAV_PC], %l7	! l7 = mdp->qsav_pc
	ldx	[%l5 + CPR_MD_QSAV_SP], %l6	! l6 = mdp->qsav_sp

	!
	! save cookie from the new/tmp prom
	!
	set	i_cpr_tmp_cif, %g1
	stn	%l4, [%g1]

	!
	! save prom tba
	!
	set	prom_tba, %g1
	rdpr	%tba, %g2
	stx	%g2, [%g1]

	!
	! start slave cpus, pause them within kernel text,
	! and restore the original prom pages
	!
	call	i_cpr_mp_setup
	nop

	!
	! since this routine is entered only by a jmp from cprboot,
	! we can set cpr_suspend_succeeded here
	!
	set	cpr_suspend_succeeded, %l0
	mov	1, %l1
	st	%l1, [%l0]

	!
	! special shortened version of longjmp
	! Don't need to flushw
	!
	mov	%l7, %i7		! i7 = saved pc
	mov	%l6, %fp		! i6 = saved sp
	ret				! return 1
	restore	%g0, 1, %o0		! takes underflow, switches stack
	SET_SIZE(i_cpr_resume_setup)


	!
	! while running on the new/tmp prom, the prom's trap table
	! must be used to handle translations within prom space
	! since the kernel's mappings may not match this prom.
	!
	! always set %tba to the prom's trap table before calling
	! any prom service; after returning, read %tba again;
	! if the %tba wasn't changed by the prom service,
	! restore the original %tba.
	!
	! a call stack looks like this:
	!
	! current prom cookie
	! [i_cpr_cif_wrapper]
	! client_handler
	! p1275_sparc_cif_handler
	! prom_xxx
	!
	ENTRY(i_cpr_cif_wrapper)
	save	%sp, -SA64(MINFRAME64 + 8), %sp
	rdpr	%tba, %o5		! read original %tba
	stx	%o5, [%fp + V9BIAS64 - 8]
	set	prom_tba, %l4
	ldx	[%l4], %o4		! read prom_tba
	wrpr	%o4, %tba		! switch to prom trap table

	set	i_cpr_tmp_cif, %g3	! cookie for new/tmp prom
	ldn	[%g3], %g4
	jmpl	%g4, %o7		! call prom service
	mov	%i0, %o0

	ldx	[%l4], %o4		! read prom_tba
	rdpr	%tba, %o3		! read current %tba
	cmp	%o3, %o4		! did prom change %tba ?
	bne,pn	%xcc, 1f		! yes, dont reset %tba
	nop
	ldx	[%fp + V9BIAS64 - 8], %o5
	wrpr	%o5, %tba		! no change, restore orignal
1:
	ret
	restore	%g0, %o0, %o0
	SET_SIZE(i_cpr_cif_wrapper)


	!
	! write dtlb entry at index
	!
	ENTRY(dtlb_wr_entry)
	sllx    %o0, 3, %o0			! index << 3
	ldx	[%o1], %o5			! o5 = tte.ll
	ldx	[%o2], %o4			! o4 = va_tag
	srlx	%o4, MMU_PAGESHIFT, %o4		! clear any page offset
	sllx	%o4, MMU_PAGESHIFT, %o4		! o4 = va_tag & PAGEMASK
	set	MMU_TAG_ACCESS, %o3
	stxa	%o4, [%o3]ASI_DMMU
	stxa	%o5, [%o0]ASI_DTLB_ACCESS
	membar	#Sync
	retl
	nop
	SET_SIZE(dtlb_wr_entry)


	!
	! write itlb entry at index
	!
	ENTRY(itlb_wr_entry)
	sllx    %o0, 3, %o0			! index << 3
	ldx	[%o1], %o5			! o5 = tte.ll
	ldx	[%o2], %o4			! o4 = va_tag
	srlx	%o4, MMU_PAGESHIFT, %o4		! clear any page offset
	sllx	%o4, MMU_PAGESHIFT, %o4		! o4 = va_tag & PAGEMASK
	set	MMU_TAG_ACCESS, %o3
	stxa	%o4, [%o3]ASI_IMMU
	stxa	%o5, [%o0]ASI_ITLB_ACCESS
	membar	#Sync
	retl
	nop
	SET_SIZE(itlb_wr_entry)