1/* 2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. 3 * 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. The rights granted to you under the License 10 * may not be used to create, or enable the creation or redistribution of, 11 * unlawful or unlicensed copies of an Apple operating system, or to 12 * circumvent, violate, or enable the circumvention or violation of, any 13 * terms of an Apple operating system software license agreement. 14 * 15 * Please obtain a copy of the License at 16 * http://www.opensource.apple.com/apsl/ and read it before using this file. 17 * 18 * The Original Code and all software distributed under the License are 19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 23 * Please see the License for the specific language governing rights and 24 * limitations under the License. 25 * 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 27 */ 28/* 29 * @OSF_COPYRIGHT@ 30 */ 31/* 32 * HISTORY 33 * 34 * Revision 1.1.1.1 1998/09/22 21:05:49 wsanchez 35 * Import of Mac OS X kernel (~semeria) 36 * 37 * Revision 1.1.1.1 1998/03/07 02:26:08 wsanchez 38 * Import of OSF Mach kernel (~mburg) 39 * 40 * Revision 1.1.5.1 1995/01/06 19:54:04 devrcs 41 * mk6 CR668 - 1.3b26 merge 42 * new file for mk6 43 * [1994/10/12 22:25:34 dwm] 44 * 45 * Revision 1.1.2.1 1994/04/08 17:52:05 meissner 46 * Add callback function to _profile_kgmon. 47 * [1994/02/16 22:38:31 meissner] 48 * 49 * _profile_kgmon now returns pointer to area, doesn't do move itself. 50 * [1994/02/11 16:52:17 meissner] 51 * 52 * Move all printfs into if (pv->debug) { ... } blocks. 53 * Add debug printfs protected by if (pv->debug) for all error conditions. 54 * Add code to reset profiling information. 55 * Add code to get/set debug flag. 56 * Expand copyright. 57 * [1994/02/07 12:41:14 meissner] 58 * 59 * Add support to copy arbitrary regions. 60 * Delete several of the KGMON_GET commands, now that arb. regions are supported. 61 * Explicitly call _profile_update_stats before dumping vars or stats. 62 * [1994/02/03 00:59:05 meissner] 63 * 64 * Combine _profile_{vars,stats,md}; Allow more than one _profile_vars. 65 * [1994/02/01 12:04:09 meissner] 66 * 67 * CR 10198 - Initial version. 68 * [1994/01/28 23:33:37 meissner] 69 * 70 * $EndLog$ 71 */ 72 73#include <profiling/profile-internal.h> 74 75#ifdef MACH_KERNEL 76#include <profiling/machine/profile-md.h> 77#endif 78 79#ifndef PROFILE_VARS 80#define PROFILE_VARS(cpu) (&_profile_vars) 81#endif 82 83/* 84 * Kgmon interface. This returns the count of bytes moved if everything was ok, 85 * or -1 if there were errors. 86 */ 87 88long 89_profile_kgmon(int write, 90 size_t count, 91 long indx, 92 int max_cpus, 93 void **p_ptr, 94 void (*control_func)(kgmon_control_t)) 95{ 96 kgmon_control_t kgmon; 97 int cpu; 98 int error = 0; 99 int i; 100 struct profile_vars *pv; 101 static struct callback dummy_callback; 102 103 *p_ptr = (void *)0; 104 105 /* 106 * If the number passed is not within bounds, just copy the data directly. 107 */ 108 109 if (!LEGAL_KGMON(indx)) { 110 *p_ptr = (void *)indx; 111 if (!write) { 112 if (PROFILE_VARS(0)->debug) { 113 printf("_profile_kgmon: copy %5ld bytes, from 0x%lx\n", 114 (long)count, 115 (long)indx); 116 } 117 118 } else { 119 if (PROFILE_VARS(0)->debug) { 120 printf("_profile_kgmon: copy %5ld bytes, to 0x%lx\n", 121 (long)count, 122 (long)indx); 123 } 124 } 125 126 return count; 127 } 128 129 /* 130 * Decode the record number into the component pieces. 131 */ 132 133 DECODE_KGMON(indx, kgmon, cpu); 134 135 if (PROFILE_VARS(0)->debug) { 136 printf("_profile_kgmon: start: kgmon control = %2d, cpu = %d, count = %ld\n", 137 kgmon, cpu, (long)count); 138 } 139 140 /* Validate the CPU number */ 141 if (cpu < 0 || cpu >= max_cpus) { 142 if (PROFILE_VARS(0)->debug) { 143 printf("KGMON, bad cpu %d\n", cpu); 144 } 145 146 return -1; 147 148 } else { 149 pv = PROFILE_VARS(cpu); 150 151 if (!write) { 152 switch (kgmon) { 153 default: 154 if (PROFILE_VARS(0)->debug) { 155 printf("Unknown KGMON read command\n"); 156 } 157 158 error = -1; 159 break; 160 161 case KGMON_GET_STATUS: /* return whether or not profiling is active */ 162 if (cpu != 0) { 163 if (PROFILE_VARS(0)->debug) { 164 printf("KGMON_GET_STATUS: cpu = %d\n", cpu); 165 } 166 167 error = -1; 168 break; 169 } 170 171 if (count != sizeof(pv->active)) { 172 if (PROFILE_VARS(0)->debug) { 173 printf("KGMON_GET_STATUS: count = %ld, should be %ld\n", 174 (long)count, 175 (long)sizeof(pv->active)); 176 } 177 178 error = -1; 179 break; 180 } 181 182 *p_ptr = (void *)&pv->active; 183 break; 184 185 case KGMON_GET_DEBUG: /* return whether or not debugging is active */ 186 if (cpu != 0) { 187 if (PROFILE_VARS(0)->debug) { 188 printf("KGMON_GET_DEBUG: cpu = %d\n", cpu); 189 } 190 191 error = -1; 192 break; 193 } 194 195 if (count != sizeof(pv->debug)) { 196 if (PROFILE_VARS(0)->debug) { 197 printf("KGMON_GET_DEBUG: count = %ld, should be %ld\n", 198 (long)count, 199 (long)sizeof(pv->active)); 200 } 201 202 error = -1; 203 break; 204 } 205 206 *p_ptr = (void *)&pv->debug; 207 break; 208 209 case KGMON_GET_PROFILE_VARS: /* return the _profile_vars structure */ 210 if (count != sizeof(struct profile_vars)) { 211 if (PROFILE_VARS(0)->debug) { 212 printf("KGMON_GET_PROFILE_VARS: count = %ld, should be %ld\n", 213 (long)count, 214 (long)sizeof(struct profile_vars)); 215 } 216 217 error = -1; 218 break; 219 } 220 221 _profile_update_stats(pv); 222 *p_ptr = (void *)pv; 223 break; 224 225 case KGMON_GET_PROFILE_STATS: /* return the _profile_stats structure */ 226 if (count != sizeof(struct profile_stats)) { 227 if (PROFILE_VARS(0)->debug) { 228 printf("KGMON_GET_PROFILE_STATS: count = %ld, should be = %ld\n", 229 (long)count, 230 (long)sizeof(struct profile_stats)); 231 } 232 233 error = -1; 234 break; 235 } 236 237 _profile_update_stats(pv); 238 *p_ptr = (void *)&pv->stats; 239 break; 240 } 241 242 } else { 243 switch (kgmon) { 244 default: 245 if (PROFILE_VARS(0)->debug) { 246 printf("Unknown KGMON write command\n"); 247 } 248 249 error = -1; 250 break; 251 252 case KGMON_SET_PROFILE_ON: /* turn on profiling */ 253 if (cpu != 0) { 254 if (PROFILE_VARS(0)->debug) { 255 printf("KGMON_SET_PROFILE_ON, cpu = %d\n", cpu); 256 } 257 258 error = -1; 259 break; 260 } 261 262 if (!PROFILE_VARS(0)->active) { 263 for (i = 0; i < max_cpus; i++) { 264 PROFILE_VARS(i)->active = 1; 265 } 266 267 if (control_func) { 268 (*control_func)(kgmon); 269 } 270 271 _profile_md_start(); 272 } 273 274 count = 0; 275 break; 276 277 case KGMON_SET_PROFILE_OFF: /* turn off profiling */ 278 if (cpu != 0) { 279 if (PROFILE_VARS(0)->debug) { 280 printf("KGMON_SET_PROFILE_OFF, cpu = %d\n", cpu); 281 } 282 283 error = -1; 284 break; 285 } 286 287 if (PROFILE_VARS(0)->active) { 288 for (i = 0; i < max_cpus; i++) { 289 PROFILE_VARS(i)->active = 0; 290 } 291 292 _profile_md_stop(); 293 294 if (control_func) { 295 (*control_func)(kgmon); 296 } 297 } 298 299 count = 0; 300 break; 301 302 case KGMON_SET_PROFILE_RESET: /* reset profiling */ 303 if (cpu != 0) { 304 if (PROFILE_VARS(0)->debug) { 305 printf("KGMON_SET_PROFILE_RESET, cpu = %d\n", cpu); 306 } 307 308 error = -1; 309 break; 310 } 311 312 for (i = 0; i < max_cpus; i++) { 313 _profile_reset(PROFILE_VARS(i)); 314 } 315 316 if (control_func) { 317 (*control_func)(kgmon); 318 } 319 320 count = 0; 321 break; 322 323 case KGMON_SET_DEBUG_ON: /* turn on profiling */ 324 if (cpu != 0) { 325 if (PROFILE_VARS(0)->debug) { 326 printf("KGMON_SET_DEBUG_ON, cpu = %d\n", cpu); 327 } 328 329 error = -1; 330 break; 331 } 332 333 if (!PROFILE_VARS(0)->debug) { 334 for (i = 0; i < max_cpus; i++) { 335 PROFILE_VARS(i)->debug = 1; 336 } 337 338 if (control_func) { 339 (*control_func)(kgmon); 340 } 341 } 342 343 count = 0; 344 break; 345 346 case KGMON_SET_DEBUG_OFF: /* turn off profiling */ 347 if (cpu != 0) { 348 if (PROFILE_VARS(0)->debug) { 349 printf("KGMON_SET_DEBUG_OFF, cpu = %d\n", cpu); 350 } 351 352 error = -1; 353 break; 354 } 355 356 if (PROFILE_VARS(0)->debug) { 357 for (i = 0; i < max_cpus; i++) { 358 PROFILE_VARS(i)->debug = 0; 359 } 360 361 if (control_func) { 362 (*control_func)(kgmon); 363 } 364 } 365 366 count = 0; 367 break; 368 } 369 } 370 } 371 372 if (error) { 373 if (PROFILE_VARS(0)->debug) { 374 printf("_profile_kgmon: done: kgmon control = %2d, cpu = %d, error = %d\n", 375 kgmon, cpu, error); 376 } 377 378 return -1; 379 } 380 381 if (PROFILE_VARS(0)->debug) { 382 printf("_profile_kgmon: done: kgmon control = %2d, cpu = %d, count = %ld\n", 383 kgmon, cpu, (long)count); 384 } 385 386 return count; 387} 388