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 * Microkernel interface to common profiling. 33 */ 34 35#include <profiling/profile-mk.h> 36#include <string.h> 37#include <kern/cpu_number.h> 38#include <kern/processor.h> 39#include <kern/spl.h> 40#include <kern/misc_protos.h> 41#include <vm/vm_kern.h> 42#include <mach/vm_param.h> 43 44#include <device/ds_routines.h> 45#include <device/io_req.h> 46#include <device/buf.h> 47 48extern char etext[], pstart[]; 49 50void * 51_profile_alloc_pages (size_t size) 52{ 53 vm_offset_t addr; 54 55 /* 56 * For the MK, we can't support allocating pages at runtime, because we 57 * might be at interrupt level, so abort if we didn't size the table 58 * properly. 59 */ 60 61 if (PROFILE_VARS(0)->active) { 62 panic("Call to _profile_alloc_pages while profiling is running."); 63 } 64 65 if (kmem_alloc(kernel_map, &addr, size)) { 66 panic("Could not allocate memory for profiling"); 67 } 68 69 memset((void *)addr, '\0', size); 70 if (PROFILE_VARS(0)->debug) { 71 printf("Allocated %d bytes for profiling, address 0x%x\n", (int)size, (int)addr); 72 } 73 74 return((caddr_t)addr); 75} 76 77void 78_profile_free_pages(void *addr, size_t size) 79{ 80 if (PROFILE_VARS(0)->debug) { 81 printf("Freed %d bytes for profiling, address 0x%x\n", (int)size, (int)addr); 82 } 83 84 kmem_free(kernel_map, (vm_offset_t)addr, size); 85 return; 86} 87 88void _profile_error(struct profile_vars *pv) 89{ 90 panic("Fatal error in profiling"); 91} 92 93void 94kmstartup(void) 95{ 96 prof_uptrint_t textsize; 97 prof_uptrint_t monsize; 98 prof_uptrint_t lowpc; 99 prof_uptrint_t highpc; 100 struct profile_vars *pv; 101 102 /* 103 * round lowpc and highpc to multiples of the density we're using 104 * so the rest of the scaling (here and in gprof) stays in ints. 105 */ 106 107 lowpc = ROUNDDOWN((prof_uptrint_t)&pstart[0], HISTFRACTION*sizeof(LHISTCOUNTER)); 108 highpc = ROUNDUP((prof_uptrint_t)&etext[0], HISTFRACTION*sizeof(LHISTCOUNTER)); 109 textsize = highpc - lowpc; 110 monsize = (textsize / HISTFRACTION) * sizeof(LHISTCOUNTER); 111 112 pv = PROFILE_VARS(0); 113 114#ifdef DEBUG_PROFILE 115 pv->debug = 1; 116#endif 117 pv->page_size = PAGE_SIZE; 118 _profile_md_init(pv, PROFILE_GPROF, PROFILE_ALLOC_MEM_YES); 119 120 /* Profil related variables */ 121 pv->profil_buf = _profile_alloc (pv, monsize, ACONTEXT_PROFIL); 122 pv->profil_info.highpc = highpc; 123 pv->profil_info.lowpc = lowpc; 124 pv->profil_info.text_len = textsize; 125 pv->profil_info.profil_len = monsize; 126 pv->profil_info.counter_size = sizeof(LHISTCOUNTER); 127 pv->profil_info.scale = 0x10000 / HISTFRACTION; 128 pv->stats.profil_buckets = monsize / sizeof(LHISTCOUNTER); 129 130 /* Other gprof variables */ 131 pv->stats.my_cpu = 0; 132 pv->stats.max_cpu = 1; /* initial number of cpus */ 133 pv->init = 1; 134 pv->active = 1; 135 pv->use_dci = 0; 136 pv->use_profil = 1; 137 pv->check_funcs = 1; /* for now */ 138 139 if (pv->debug) { 140 printf("Profiling kernel, s_textsize=%ld, monsize=%ld [0x%lx..0x%lx], cpu = %d\n", 141 (long)textsize, 142 (long)monsize, 143 (long)lowpc, 144 (long)highpc, 145 0); 146 } 147 148 _profile_md_start(); 149} 150 151/* driver component */ 152 153int 154gprofprobe(caddr_t port, void *ctlr) 155{ 156 return(1); 157} 158 159void 160gprofattach(void) 161{ 162 kmstartup(); 163 return; 164} 165 166/* struct bus_device *gprofinfo[NGPROF]; */ 167struct bus_device *gprofinfo[1]; 168 169struct bus_driver gprof_driver = { 170 gprofprobe, 0, gprofattach, 0, 0, "gprof", gprofinfo, "gprofc", 0, 0}; 171 172 173io_return_t 174gprofopen(dev_t dev, 175 int flags, 176 io_req_t ior) 177{ 178 ior->io_error = D_SUCCESS; 179 return(0); 180} 181 182void 183gprofclose(dev_t dev) 184{ 185 return; 186} 187 188void 189gprofstrategy(io_req_t ior) 190{ 191 void *sys_ptr = (void *)0; 192 193 long count = _profile_kgmon(!(ior->io_op & IO_READ), 194 ior->io_count, 195 ior->io_recnum, 196 1, 197 &sys_ptr, 198 (void (*)(kgmon_control_t))0); 199 200 if (count < 0) { 201 ior->io_error = D_INVALID_RECNUM; 202 203 } else { 204 if (count > 0 && sys_ptr != (void *)0) { 205 if (ior->io_op & IO_READ) { 206 memcpy((void *)ior->io_data, sys_ptr, count); 207 } else { 208 memcpy(sys_ptr, (void *)ior->io_data, count); 209 } 210 } 211 212 ior->io_error = D_SUCCESS; 213 ior->io_residual = ior->io_count - count; 214 } 215 216 iodone(ior); 217} 218 219io_return_t 220gprofread(dev_t dev, 221 io_req_t ior) 222{ 223 return(block_io(gprofstrategy, minphys, ior)); 224} 225 226io_return_t 227gprofwrite(dev_t dev, 228 io_req_t ior) 229{ 230 return (block_io(gprofstrategy, minphys, ior)); 231} 232