at v2.6.33 11 kB view raw
1/* 2 * debug.c - ACPI debug interface to userspace. 3 */ 4 5#include <linux/proc_fs.h> 6#include <linux/seq_file.h> 7#include <linux/init.h> 8#include <linux/module.h> 9#include <linux/kernel.h> 10#include <linux/moduleparam.h> 11#include <linux/debugfs.h> 12#include <asm/uaccess.h> 13#include <acpi/acpi_drivers.h> 14 15#define _COMPONENT ACPI_SYSTEM_COMPONENT 16ACPI_MODULE_NAME("debug"); 17 18struct acpi_dlayer { 19 const char *name; 20 unsigned long value; 21}; 22struct acpi_dlevel { 23 const char *name; 24 unsigned long value; 25}; 26#define ACPI_DEBUG_INIT(v) { .name = #v, .value = v } 27 28static const struct acpi_dlayer acpi_debug_layers[] = { 29 ACPI_DEBUG_INIT(ACPI_UTILITIES), 30 ACPI_DEBUG_INIT(ACPI_HARDWARE), 31 ACPI_DEBUG_INIT(ACPI_EVENTS), 32 ACPI_DEBUG_INIT(ACPI_TABLES), 33 ACPI_DEBUG_INIT(ACPI_NAMESPACE), 34 ACPI_DEBUG_INIT(ACPI_PARSER), 35 ACPI_DEBUG_INIT(ACPI_DISPATCHER), 36 ACPI_DEBUG_INIT(ACPI_EXECUTER), 37 ACPI_DEBUG_INIT(ACPI_RESOURCES), 38 ACPI_DEBUG_INIT(ACPI_CA_DEBUGGER), 39 ACPI_DEBUG_INIT(ACPI_OS_SERVICES), 40 ACPI_DEBUG_INIT(ACPI_CA_DISASSEMBLER), 41 ACPI_DEBUG_INIT(ACPI_COMPILER), 42 ACPI_DEBUG_INIT(ACPI_TOOLS), 43 44 ACPI_DEBUG_INIT(ACPI_BUS_COMPONENT), 45 ACPI_DEBUG_INIT(ACPI_AC_COMPONENT), 46 ACPI_DEBUG_INIT(ACPI_BATTERY_COMPONENT), 47 ACPI_DEBUG_INIT(ACPI_BUTTON_COMPONENT), 48 ACPI_DEBUG_INIT(ACPI_SBS_COMPONENT), 49 ACPI_DEBUG_INIT(ACPI_FAN_COMPONENT), 50 ACPI_DEBUG_INIT(ACPI_PCI_COMPONENT), 51 ACPI_DEBUG_INIT(ACPI_POWER_COMPONENT), 52 ACPI_DEBUG_INIT(ACPI_CONTAINER_COMPONENT), 53 ACPI_DEBUG_INIT(ACPI_SYSTEM_COMPONENT), 54 ACPI_DEBUG_INIT(ACPI_THERMAL_COMPONENT), 55 ACPI_DEBUG_INIT(ACPI_MEMORY_DEVICE_COMPONENT), 56 ACPI_DEBUG_INIT(ACPI_VIDEO_COMPONENT), 57 ACPI_DEBUG_INIT(ACPI_PROCESSOR_COMPONENT), 58}; 59 60static const struct acpi_dlevel acpi_debug_levels[] = { 61 ACPI_DEBUG_INIT(ACPI_LV_INIT), 62 ACPI_DEBUG_INIT(ACPI_LV_DEBUG_OBJECT), 63 ACPI_DEBUG_INIT(ACPI_LV_INFO), 64 65 ACPI_DEBUG_INIT(ACPI_LV_INIT_NAMES), 66 ACPI_DEBUG_INIT(ACPI_LV_PARSE), 67 ACPI_DEBUG_INIT(ACPI_LV_LOAD), 68 ACPI_DEBUG_INIT(ACPI_LV_DISPATCH), 69 ACPI_DEBUG_INIT(ACPI_LV_EXEC), 70 ACPI_DEBUG_INIT(ACPI_LV_NAMES), 71 ACPI_DEBUG_INIT(ACPI_LV_OPREGION), 72 ACPI_DEBUG_INIT(ACPI_LV_BFIELD), 73 ACPI_DEBUG_INIT(ACPI_LV_TABLES), 74 ACPI_DEBUG_INIT(ACPI_LV_VALUES), 75 ACPI_DEBUG_INIT(ACPI_LV_OBJECTS), 76 ACPI_DEBUG_INIT(ACPI_LV_RESOURCES), 77 ACPI_DEBUG_INIT(ACPI_LV_USER_REQUESTS), 78 ACPI_DEBUG_INIT(ACPI_LV_PACKAGE), 79 80 ACPI_DEBUG_INIT(ACPI_LV_ALLOCATIONS), 81 ACPI_DEBUG_INIT(ACPI_LV_FUNCTIONS), 82 ACPI_DEBUG_INIT(ACPI_LV_OPTIMIZATIONS), 83 84 ACPI_DEBUG_INIT(ACPI_LV_MUTEX), 85 ACPI_DEBUG_INIT(ACPI_LV_THREADS), 86 ACPI_DEBUG_INIT(ACPI_LV_IO), 87 ACPI_DEBUG_INIT(ACPI_LV_INTERRUPTS), 88 89 ACPI_DEBUG_INIT(ACPI_LV_AML_DISASSEMBLE), 90 ACPI_DEBUG_INIT(ACPI_LV_VERBOSE_INFO), 91 ACPI_DEBUG_INIT(ACPI_LV_FULL_TABLES), 92 ACPI_DEBUG_INIT(ACPI_LV_EVENTS), 93}; 94 95/* -------------------------------------------------------------------------- 96 FS Interface (/sys) 97 -------------------------------------------------------------------------- */ 98static int param_get_debug_layer(char *buffer, struct kernel_param *kp) { 99 int result = 0; 100 int i; 101 102 result = sprintf(buffer, "%-25s\tHex SET\n", "Description"); 103 104 for(i = 0; i <ARRAY_SIZE(acpi_debug_layers); i++) { 105 result += sprintf(buffer+result, "%-25s\t0x%08lX [%c]\n", 106 acpi_debug_layers[i].name, 107 acpi_debug_layers[i].value, 108 (acpi_dbg_layer & acpi_debug_layers[i].value) ? '*' : ' '); 109 } 110 result += sprintf(buffer+result, "%-25s\t0x%08X [%c]\n", "ACPI_ALL_DRIVERS", 111 ACPI_ALL_DRIVERS, 112 (acpi_dbg_layer & ACPI_ALL_DRIVERS) == 113 ACPI_ALL_DRIVERS ? '*' : (acpi_dbg_layer & 114 ACPI_ALL_DRIVERS) == 0 ? ' ' : '-'); 115 result += sprintf(buffer+result, "--\ndebug_layer = 0x%08X ( * = enabled)\n", acpi_dbg_layer); 116 117 return result; 118} 119 120static int param_get_debug_level(char *buffer, struct kernel_param *kp) { 121 int result = 0; 122 int i; 123 124 result = sprintf(buffer, "%-25s\tHex SET\n", "Description"); 125 126 for (i = 0; i < ARRAY_SIZE(acpi_debug_levels); i++) { 127 result += sprintf(buffer+result, "%-25s\t0x%08lX [%c]\n", 128 acpi_debug_levels[i].name, 129 acpi_debug_levels[i].value, 130 (acpi_dbg_level & acpi_debug_levels[i]. 131 value) ? '*' : ' '); 132 } 133 result += sprintf(buffer+result, "--\ndebug_level = 0x%08X (* = enabled)\n", 134 acpi_dbg_level); 135 136 return result; 137} 138 139module_param_call(debug_layer, param_set_uint, param_get_debug_layer, &acpi_dbg_layer, 0644); 140module_param_call(debug_level, param_set_uint, param_get_debug_level, &acpi_dbg_level, 0644); 141 142static char trace_method_name[6]; 143module_param_string(trace_method_name, trace_method_name, 6, 0644); 144static unsigned int trace_debug_layer; 145module_param(trace_debug_layer, uint, 0644); 146static unsigned int trace_debug_level; 147module_param(trace_debug_level, uint, 0644); 148 149static int param_set_trace_state(const char *val, struct kernel_param *kp) 150{ 151 int result = 0; 152 153 if (!strncmp(val, "enable", strlen("enable") - 1)) { 154 result = acpi_debug_trace(trace_method_name, trace_debug_level, 155 trace_debug_layer, 0); 156 if (result) 157 result = -EBUSY; 158 goto exit; 159 } 160 161 if (!strncmp(val, "disable", strlen("disable") - 1)) { 162 int name = 0; 163 result = acpi_debug_trace((char *)&name, trace_debug_level, 164 trace_debug_layer, 0); 165 if (result) 166 result = -EBUSY; 167 goto exit; 168 } 169 170 if (!strncmp(val, "1", 1)) { 171 result = acpi_debug_trace(trace_method_name, trace_debug_level, 172 trace_debug_layer, 1); 173 if (result) 174 result = -EBUSY; 175 goto exit; 176 } 177 178 result = -EINVAL; 179exit: 180 return result; 181} 182 183static int param_get_trace_state(char *buffer, struct kernel_param *kp) 184{ 185 if (!acpi_gbl_trace_method_name) 186 return sprintf(buffer, "disable"); 187 else { 188 if (acpi_gbl_trace_flags & 1) 189 return sprintf(buffer, "1"); 190 else 191 return sprintf(buffer, "enable"); 192 } 193 return 0; 194} 195 196module_param_call(trace_state, param_set_trace_state, param_get_trace_state, 197 NULL, 0644); 198 199/* -------------------------------------------------------------------------- 200 DebugFS Interface 201 -------------------------------------------------------------------------- */ 202 203static ssize_t cm_write(struct file *file, const char __user *user_buf, 204 size_t count, loff_t *ppos) 205{ 206 static char *buf; 207 static int uncopied_bytes; 208 struct acpi_table_header table; 209 acpi_status status; 210 211 if (!(*ppos)) { 212 /* parse the table header to get the table length */ 213 if (count <= sizeof(struct acpi_table_header)) 214 return -EINVAL; 215 if (copy_from_user(&table, user_buf, 216 sizeof(struct acpi_table_header))) 217 return -EFAULT; 218 uncopied_bytes = table.length; 219 buf = kzalloc(uncopied_bytes, GFP_KERNEL); 220 if (!buf) 221 return -ENOMEM; 222 } 223 224 if (uncopied_bytes < count) { 225 kfree(buf); 226 return -EINVAL; 227 } 228 229 if (copy_from_user(buf + (*ppos), user_buf, count)) { 230 kfree(buf); 231 return -EFAULT; 232 } 233 234 uncopied_bytes -= count; 235 *ppos += count; 236 237 if (!uncopied_bytes) { 238 status = acpi_install_method(buf); 239 kfree(buf); 240 if (ACPI_FAILURE(status)) 241 return -EINVAL; 242 add_taint(TAINT_OVERRIDDEN_ACPI_TABLE); 243 } 244 245 return count; 246} 247 248static const struct file_operations cm_fops = { 249 .write = cm_write, 250}; 251 252static int acpi_debugfs_init(void) 253{ 254 struct dentry *acpi_dir, *cm_dentry; 255 256 acpi_dir = debugfs_create_dir("acpi", NULL); 257 if (!acpi_dir) 258 goto err; 259 260 cm_dentry = debugfs_create_file("custom_method", S_IWUGO, 261 acpi_dir, NULL, &cm_fops); 262 if (!cm_dentry) 263 goto err; 264 265 return 0; 266 267err: 268 if (acpi_dir) 269 debugfs_remove(acpi_dir); 270 return -EINVAL; 271} 272 273/* -------------------------------------------------------------------------- 274 FS Interface (/proc) 275 -------------------------------------------------------------------------- */ 276#ifdef CONFIG_ACPI_PROCFS 277#define ACPI_SYSTEM_FILE_DEBUG_LAYER "debug_layer" 278#define ACPI_SYSTEM_FILE_DEBUG_LEVEL "debug_level" 279 280static int acpi_system_debug_proc_show(struct seq_file *m, void *v) 281{ 282 unsigned int i; 283 284 seq_printf(m, "%-25s\tHex SET\n", "Description"); 285 286 switch ((unsigned long)m->private) { 287 case 0: 288 for (i = 0; i < ARRAY_SIZE(acpi_debug_layers); i++) { 289 seq_printf(m, "%-25s\t0x%08lX [%c]\n", 290 acpi_debug_layers[i].name, 291 acpi_debug_layers[i].value, 292 (acpi_dbg_layer & acpi_debug_layers[i]. 293 value) ? '*' : ' '); 294 } 295 seq_printf(m, "%-25s\t0x%08X [%c]\n", "ACPI_ALL_DRIVERS", 296 ACPI_ALL_DRIVERS, 297 (acpi_dbg_layer & ACPI_ALL_DRIVERS) == 298 ACPI_ALL_DRIVERS ? '*' : (acpi_dbg_layer & 299 ACPI_ALL_DRIVERS) == 300 0 ? ' ' : '-'); 301 seq_printf(m, 302 "--\ndebug_layer = 0x%08X (* = enabled, - = partial)\n", 303 acpi_dbg_layer); 304 break; 305 case 1: 306 for (i = 0; i < ARRAY_SIZE(acpi_debug_levels); i++) { 307 seq_printf(m, "%-25s\t0x%08lX [%c]\n", 308 acpi_debug_levels[i].name, 309 acpi_debug_levels[i].value, 310 (acpi_dbg_level & acpi_debug_levels[i]. 311 value) ? '*' : ' '); 312 } 313 seq_printf(m, "--\ndebug_level = 0x%08X (* = enabled)\n", 314 acpi_dbg_level); 315 break; 316 } 317 return 0; 318} 319 320static int acpi_system_debug_proc_open(struct inode *inode, struct file *file) 321{ 322 return single_open(file, acpi_system_debug_proc_show, PDE(inode)->data); 323} 324 325static ssize_t acpi_system_debug_proc_write(struct file *file, 326 const char __user * buffer, 327 size_t count, loff_t *pos) 328{ 329 char debug_string[12] = { '\0' }; 330 331 332 if (count > sizeof(debug_string) - 1) 333 return -EINVAL; 334 335 if (copy_from_user(debug_string, buffer, count)) 336 return -EFAULT; 337 338 debug_string[count] = '\0'; 339 340 switch ((unsigned long)PDE(file->f_path.dentry->d_inode)->data) { 341 case 0: 342 acpi_dbg_layer = simple_strtoul(debug_string, NULL, 0); 343 break; 344 case 1: 345 acpi_dbg_level = simple_strtoul(debug_string, NULL, 0); 346 break; 347 default: 348 return -EINVAL; 349 } 350 351 return count; 352} 353 354static const struct file_operations acpi_system_debug_proc_fops = { 355 .owner = THIS_MODULE, 356 .open = acpi_system_debug_proc_open, 357 .read = seq_read, 358 .llseek = seq_lseek, 359 .release = single_release, 360 .write = acpi_system_debug_proc_write, 361}; 362#endif 363 364int __init acpi_procfs_init(void) 365{ 366#ifdef CONFIG_ACPI_PROCFS 367 struct proc_dir_entry *entry; 368 int error = 0; 369 char *name; 370 371 /* 'debug_layer' [R/W] */ 372 name = ACPI_SYSTEM_FILE_DEBUG_LAYER; 373 entry = proc_create_data(name, S_IFREG | S_IRUGO | S_IWUSR, 374 acpi_root_dir, &acpi_system_debug_proc_fops, 375 (void *)0); 376 if (!entry) 377 goto Error; 378 379 /* 'debug_level' [R/W] */ 380 name = ACPI_SYSTEM_FILE_DEBUG_LEVEL; 381 entry = proc_create_data(name, S_IFREG | S_IRUGO | S_IWUSR, 382 acpi_root_dir, &acpi_system_debug_proc_fops, 383 (void *)1); 384 if (!entry) 385 goto Error; 386 387 Done: 388 return error; 389 390 Error: 391 remove_proc_entry(ACPI_SYSTEM_FILE_DEBUG_LEVEL, acpi_root_dir); 392 remove_proc_entry(ACPI_SYSTEM_FILE_DEBUG_LAYER, acpi_root_dir); 393 error = -ENODEV; 394 goto Done; 395#else 396 return 0; 397#endif 398} 399 400int __init acpi_debug_init(void) 401{ 402 acpi_debugfs_init(); 403 acpi_procfs_init(); 404 return 0; 405}