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