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 * 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 * 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 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