1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 #pragma ident "%Z%%M% %I% %E% SMI"
28
29 #include <sys/types.h>
30 #include <sys/machsystm.h>
31 #include <sys/machparam.h>
32 #include <sys/cmn_err.h>
33 #include <sys/cpuvar.h>
34 #include <sys/note.h>
35 #include <sys/hypervisor_api.h>
36 #include <sys/lpad.h>
37
38 typedef struct {
39 uint64_t inuse;
40 uint64_t buf[LPAD_SIZE / sizeof (uint64_t)];
41 } lpad_t;
42
43 /*
44 * A global pool of landing pad memory. Currently, CPUs are only
45 * brought into the system one at a time, so the pool is only a
46 * single landing pad. In the future, it may be desirable to bring
47 * CPUs into the systems in parallel. At that time, the size of
48 * the pool can be increased by changing the pool size constant.
49 */
50 #define LPAD_POOL_SIZE 1
51
52 static lpad_t lpad_pool[LPAD_POOL_SIZE];
53
54 #ifdef DEBUG
55 static int lpad_dbg = 0;
56
57 #define LPAD_DBG if (lpad_dbg) printf
58 #define LPAD_DUMP_DATA lpad_dump_data
59
60 static void lpad_dump_data(uint64_t *lpd_start, uint64_t *lpd_end);
61
62 #else /* DEBUG */
63
64 #define LPAD_DBG _NOTE(CONSTCOND) if (0) printf
65 #define LPAD_DUMP_DATA
66 #endif /* DEBUG */
67
68 extern void mach_cpu_startup(uint64_t rabase, uint64_t memsize);
69 extern void mach_cpu_startup_end(void);
70 extern int promif_in_cif(void);
71
72 static lpad_t *lpad_alloc(void);
73
74 uint64_t *
lpad_setup(int cpuid,uint64_t pc,uint64_t arg)75 lpad_setup(int cpuid, uint64_t pc, uint64_t arg)
76 {
77 lpad_t *lpp;
78 uint64_t textsz;
79 uint64_t datasz;
80 lpad_data_t *lpd;
81 lpad_map_t *lpm;
82
83 /* external parameters */
84 extern caddr_t textva;
85 extern caddr_t datava;
86 extern tte_t ktext_tte;
87 extern tte_t kdata_tte;
88 extern caddr_t mmu_fault_status_area;
89
90 LPAD_DBG("lpad_setup...\n");
91
92 if ((cpuid < 0) || (cpuid > NCPU)) {
93 cmn_err(CE_PANIC, "lpad_setup: invalid cpuid");
94 }
95
96 /* allocate our landing pad */
97 if ((lpp = lpad_alloc()) == NULL) {
98 cmn_err(CE_PANIC, "lpad_setup: unable to allocate lpad");
99 }
100
101 /* calculate the size of our text */
102 textsz = (uint64_t)mach_cpu_startup_end - (uint64_t)mach_cpu_startup;
103
104 LPAD_DBG("lpad textsz=%ld\n", textsz);
105
106 ASSERT(textsz <= LPAD_TEXT_SIZE);
107
108 /* copy over text section */
109 bcopy((void *)mach_cpu_startup, lpp->buf, textsz);
110
111 lpd = (lpad_data_t *)(((caddr_t)lpp->buf) + LPAD_TEXT_SIZE);
112 lpm = (lpad_map_t *)lpd->map;
113
114 ASSERT(mmu_fault_status_area);
115
116 bzero(lpd, LPAD_TEXT_SIZE);
117 lpd->magic = LPAD_MAGIC_VAL;
118 lpd->inuse = &(lpp->inuse);
119 lpd->mmfsa_ra = va_to_pa(mmu_fault_status_area) + (MMFSA_SIZE * cpuid);
120 lpd->pc = pc;
121 lpd->arg = arg;
122
123 /*
124 * List of mappings:
125 *
126 * - permanent inst/data mapping for kernel text
127 * - permanent data mapping for kernel data
128 * - non-permanent inst mapping for kernel data,
129 * required for landing pad text
130 */
131 lpd->nmap = 3;
132
133 /* verify the lpad has enough room for the data */
134 datasz = sizeof (lpad_data_t);
135 datasz += (lpd->nmap - 1) * sizeof (lpad_map_t);
136
137 ASSERT(datasz <= LPAD_DATA_SIZE);
138
139 /*
140 * Kernel Text Mapping
141 */
142 lpm->va = (uint64_t)textva;
143 lpm->tte = ktext_tte;
144 lpm->flag_mmuflags = (MAP_ITLB | MAP_DTLB);
145 lpm->flag_perm = 1;
146 lpm++;
147
148 /*
149 * Kernel Data Mapping
150 */
151 lpm->va = (uint64_t)datava;
152 lpm->tte = kdata_tte;
153 lpm->flag_mmuflags = MAP_DTLB;
154 lpm->flag_perm = 1;
155 lpm++;
156
157 /*
158 * Landing Pad Text Mapping
159 *
160 * Because this mapping should not be permanent,
161 * the permanent mapping above cannot be used.
162 */
163 lpm->va = (uint64_t)datava;
164 lpm->tte = kdata_tte;
165 lpm->flag_mmuflags = MAP_ITLB;
166 lpm->flag_perm = 0;
167 lpm++;
168
169 ASSERT(((uint64_t)lpm - (uint64_t)lpd) == datasz);
170
171 LPAD_DBG("copied %ld bytes of data into lpad\n", datasz);
172
173 LPAD_DUMP_DATA((uint64_t *)lpd, (uint64_t *)lpm);
174
175 return (lpp->buf);
176 }
177
178 static lpad_t *
lpad_alloc(void)179 lpad_alloc(void)
180 {
181 int idx;
182
183 /*
184 * No locking is required for the global lpad pool since
185 * it should only be accessed while in the CIF which is
186 * single threaded. If this assumption changes, locking
187 * would be required.
188 */
189 ASSERT(promif_in_cif());
190
191 /*
192 * Wait until an lpad buffer becomes available.
193 */
194 for (;;) {
195 LPAD_DBG("checking lpad pool:\n");
196
197 /* walk the lpad buffer array */
198 for (idx = 0; idx < LPAD_POOL_SIZE; idx++) {
199
200 LPAD_DBG("\tchecking lpad_pool[%d]\n", idx);
201
202 if (lpad_pool[idx].inuse == 0) {
203 LPAD_DBG("found empty lpad (%d)\n", idx);
204
205 /* mark the buffer as busy */
206 lpad_pool[idx].inuse = 1;
207
208 return (&lpad_pool[idx]);
209 }
210 }
211 }
212 }
213
214 #ifdef DEBUG
215 static void
lpad_dump_data(uint64_t * lpd_start,uint64_t * lpd_end)216 lpad_dump_data(uint64_t *lpd_start, uint64_t *lpd_end)
217 {
218 uint64_t *lp;
219 uint_t offset = 0;
220
221 if (lpad_dbg == 0)
222 return;
223
224 printf("lpad data:\n");
225
226 for (lp = lpd_start; lp < lpd_end; lp++) {
227 printf("\t0x%02x 0x%016lx\n", offset, *lp);
228 offset += sizeof (uint64_t);
229 }
230 }
231 #endif /* DEBUG */
232