16d7d7433SHuang, Ying /* 26d7d7433SHuang, Ying * Architecture specific debugfs files 36d7d7433SHuang, Ying * 46d7d7433SHuang, Ying * Copyright (C) 2007, Intel Corp. 56d7d7433SHuang, Ying * Huang Ying <ying.huang@intel.com> 66d7d7433SHuang, Ying * 76d7d7433SHuang, Ying * This file is released under the GPLv2. 86d7d7433SHuang, Ying */ 96d7d7433SHuang, Ying #include <linux/debugfs.h> 10*c14b2adfSHuang, Ying #include <linux/uaccess.h> 116d7d7433SHuang, Ying #include <linux/stat.h> 126d7d7433SHuang, Ying #include <linux/init.h> 13*c14b2adfSHuang, Ying #include <linux/io.h> 14*c14b2adfSHuang, Ying #include <linux/mm.h> 156d7d7433SHuang, Ying 166d7d7433SHuang, Ying #include <asm/setup.h> 176d7d7433SHuang, Ying 186d7d7433SHuang, Ying #ifdef CONFIG_DEBUG_BOOT_PARAMS 19*c14b2adfSHuang, Ying struct setup_data_node { 20*c14b2adfSHuang, Ying u64 paddr; 21*c14b2adfSHuang, Ying u32 type; 22*c14b2adfSHuang, Ying u32 len; 23*c14b2adfSHuang, Ying }; 24*c14b2adfSHuang, Ying 25*c14b2adfSHuang, Ying static ssize_t 26*c14b2adfSHuang, Ying setup_data_read(struct file *file, char __user *user_buf, size_t count, 27*c14b2adfSHuang, Ying loff_t *ppos) 28*c14b2adfSHuang, Ying { 29*c14b2adfSHuang, Ying struct setup_data_node *node = file->private_data; 30*c14b2adfSHuang, Ying unsigned long remain; 31*c14b2adfSHuang, Ying loff_t pos = *ppos; 32*c14b2adfSHuang, Ying struct page *pg; 33*c14b2adfSHuang, Ying void *p; 34*c14b2adfSHuang, Ying u64 pa; 35*c14b2adfSHuang, Ying 36*c14b2adfSHuang, Ying if (pos < 0) 37*c14b2adfSHuang, Ying return -EINVAL; 38*c14b2adfSHuang, Ying if (pos >= node->len) 39*c14b2adfSHuang, Ying return 0; 40*c14b2adfSHuang, Ying 41*c14b2adfSHuang, Ying if (count > node->len - pos) 42*c14b2adfSHuang, Ying count = node->len - pos; 43*c14b2adfSHuang, Ying pa = node->paddr + sizeof(struct setup_data) + pos; 44*c14b2adfSHuang, Ying pg = pfn_to_page((pa + count - 1) >> PAGE_SHIFT); 45*c14b2adfSHuang, Ying if (PageHighMem(pg)) { 46*c14b2adfSHuang, Ying p = ioremap_cache(pa, count); 47*c14b2adfSHuang, Ying if (!p) 48*c14b2adfSHuang, Ying return -ENXIO; 49*c14b2adfSHuang, Ying } else { 50*c14b2adfSHuang, Ying p = __va(pa); 51*c14b2adfSHuang, Ying } 52*c14b2adfSHuang, Ying 53*c14b2adfSHuang, Ying remain = copy_to_user(user_buf, p, count); 54*c14b2adfSHuang, Ying 55*c14b2adfSHuang, Ying if (PageHighMem(pg)) 56*c14b2adfSHuang, Ying iounmap(p); 57*c14b2adfSHuang, Ying 58*c14b2adfSHuang, Ying if (remain) 59*c14b2adfSHuang, Ying return -EFAULT; 60*c14b2adfSHuang, Ying 61*c14b2adfSHuang, Ying *ppos = pos + count; 62*c14b2adfSHuang, Ying 63*c14b2adfSHuang, Ying return count; 64*c14b2adfSHuang, Ying } 65*c14b2adfSHuang, Ying 66*c14b2adfSHuang, Ying static int setup_data_open(struct inode *inode, struct file *file) 67*c14b2adfSHuang, Ying { 68*c14b2adfSHuang, Ying file->private_data = inode->i_private; 69*c14b2adfSHuang, Ying return 0; 70*c14b2adfSHuang, Ying } 71*c14b2adfSHuang, Ying 72*c14b2adfSHuang, Ying static const struct file_operations fops_setup_data = { 73*c14b2adfSHuang, Ying .read = setup_data_read, 74*c14b2adfSHuang, Ying .open = setup_data_open, 75*c14b2adfSHuang, Ying }; 76*c14b2adfSHuang, Ying 77*c14b2adfSHuang, Ying static int __init 78*c14b2adfSHuang, Ying create_setup_data_node(struct dentry *parent, int no, 79*c14b2adfSHuang, Ying struct setup_data_node *node) 80*c14b2adfSHuang, Ying { 81*c14b2adfSHuang, Ying struct dentry *d, *type, *data; 82*c14b2adfSHuang, Ying char buf[16]; 83*c14b2adfSHuang, Ying int error; 84*c14b2adfSHuang, Ying 85*c14b2adfSHuang, Ying sprintf(buf, "%d", no); 86*c14b2adfSHuang, Ying d = debugfs_create_dir(buf, parent); 87*c14b2adfSHuang, Ying if (!d) { 88*c14b2adfSHuang, Ying error = -ENOMEM; 89*c14b2adfSHuang, Ying goto err_return; 90*c14b2adfSHuang, Ying } 91*c14b2adfSHuang, Ying type = debugfs_create_x32("type", S_IRUGO, d, &node->type); 92*c14b2adfSHuang, Ying if (!type) { 93*c14b2adfSHuang, Ying error = -ENOMEM; 94*c14b2adfSHuang, Ying goto err_dir; 95*c14b2adfSHuang, Ying } 96*c14b2adfSHuang, Ying data = debugfs_create_file("data", S_IRUGO, d, node, &fops_setup_data); 97*c14b2adfSHuang, Ying if (!data) { 98*c14b2adfSHuang, Ying error = -ENOMEM; 99*c14b2adfSHuang, Ying goto err_type; 100*c14b2adfSHuang, Ying } 101*c14b2adfSHuang, Ying return 0; 102*c14b2adfSHuang, Ying 103*c14b2adfSHuang, Ying err_type: 104*c14b2adfSHuang, Ying debugfs_remove(type); 105*c14b2adfSHuang, Ying err_dir: 106*c14b2adfSHuang, Ying debugfs_remove(d); 107*c14b2adfSHuang, Ying err_return: 108*c14b2adfSHuang, Ying return error; 109*c14b2adfSHuang, Ying } 110*c14b2adfSHuang, Ying 111*c14b2adfSHuang, Ying static int __init create_setup_data_nodes(struct dentry *parent) 112*c14b2adfSHuang, Ying { 113*c14b2adfSHuang, Ying struct setup_data_node *node; 114*c14b2adfSHuang, Ying struct setup_data *data; 115*c14b2adfSHuang, Ying int error, no = 0; 116*c14b2adfSHuang, Ying struct dentry *d; 117*c14b2adfSHuang, Ying struct page *pg; 118*c14b2adfSHuang, Ying u64 pa_data; 119*c14b2adfSHuang, Ying 120*c14b2adfSHuang, Ying d = debugfs_create_dir("setup_data", parent); 121*c14b2adfSHuang, Ying if (!d) { 122*c14b2adfSHuang, Ying error = -ENOMEM; 123*c14b2adfSHuang, Ying goto err_return; 124*c14b2adfSHuang, Ying } 125*c14b2adfSHuang, Ying 126*c14b2adfSHuang, Ying pa_data = boot_params.hdr.setup_data; 127*c14b2adfSHuang, Ying 128*c14b2adfSHuang, Ying while (pa_data) { 129*c14b2adfSHuang, Ying node = kmalloc(sizeof(*node), GFP_KERNEL); 130*c14b2adfSHuang, Ying if (!node) { 131*c14b2adfSHuang, Ying error = -ENOMEM; 132*c14b2adfSHuang, Ying goto err_dir; 133*c14b2adfSHuang, Ying } 134*c14b2adfSHuang, Ying pg = pfn_to_page((pa_data+sizeof(*data)-1) >> PAGE_SHIFT); 135*c14b2adfSHuang, Ying if (PageHighMem(pg)) { 136*c14b2adfSHuang, Ying data = ioremap_cache(pa_data, sizeof(*data)); 137*c14b2adfSHuang, Ying if (!data) { 138*c14b2adfSHuang, Ying error = -ENXIO; 139*c14b2adfSHuang, Ying goto err_dir; 140*c14b2adfSHuang, Ying } 141*c14b2adfSHuang, Ying } else { 142*c14b2adfSHuang, Ying data = __va(pa_data); 143*c14b2adfSHuang, Ying } 144*c14b2adfSHuang, Ying 145*c14b2adfSHuang, Ying node->paddr = pa_data; 146*c14b2adfSHuang, Ying node->type = data->type; 147*c14b2adfSHuang, Ying node->len = data->len; 148*c14b2adfSHuang, Ying error = create_setup_data_node(d, no, node); 149*c14b2adfSHuang, Ying pa_data = data->next; 150*c14b2adfSHuang, Ying 151*c14b2adfSHuang, Ying if (PageHighMem(pg)) 152*c14b2adfSHuang, Ying iounmap(data); 153*c14b2adfSHuang, Ying if (error) 154*c14b2adfSHuang, Ying goto err_dir; 155*c14b2adfSHuang, Ying no++; 156*c14b2adfSHuang, Ying } 157*c14b2adfSHuang, Ying return 0; 158*c14b2adfSHuang, Ying 159*c14b2adfSHuang, Ying err_dir: 160*c14b2adfSHuang, Ying debugfs_remove(d); 161*c14b2adfSHuang, Ying err_return: 162*c14b2adfSHuang, Ying return error; 163*c14b2adfSHuang, Ying } 164*c14b2adfSHuang, Ying 1656d7d7433SHuang, Ying static struct debugfs_blob_wrapper boot_params_blob = { 1666d7d7433SHuang, Ying .data = &boot_params, 1676d7d7433SHuang, Ying .size = sizeof(boot_params), 1686d7d7433SHuang, Ying }; 1696d7d7433SHuang, Ying 1706d7d7433SHuang, Ying static int __init boot_params_kdebugfs_init(void) 1716d7d7433SHuang, Ying { 1726d7d7433SHuang, Ying struct dentry *dbp, *version, *data; 173*c14b2adfSHuang, Ying int error; 1746d7d7433SHuang, Ying 1756d7d7433SHuang, Ying dbp = debugfs_create_dir("boot_params", NULL); 1766d7d7433SHuang, Ying if (!dbp) { 1776d7d7433SHuang, Ying error = -ENOMEM; 1786d7d7433SHuang, Ying goto err_return; 1796d7d7433SHuang, Ying } 1806d7d7433SHuang, Ying version = debugfs_create_x16("version", S_IRUGO, dbp, 1816d7d7433SHuang, Ying &boot_params.hdr.version); 1826d7d7433SHuang, Ying if (!version) { 1836d7d7433SHuang, Ying error = -ENOMEM; 1846d7d7433SHuang, Ying goto err_dir; 1856d7d7433SHuang, Ying } 1866d7d7433SHuang, Ying data = debugfs_create_blob("data", S_IRUGO, dbp, 1876d7d7433SHuang, Ying &boot_params_blob); 1886d7d7433SHuang, Ying if (!data) { 1896d7d7433SHuang, Ying error = -ENOMEM; 1906d7d7433SHuang, Ying goto err_version; 1916d7d7433SHuang, Ying } 192*c14b2adfSHuang, Ying error = create_setup_data_nodes(dbp); 193*c14b2adfSHuang, Ying if (error) 194*c14b2adfSHuang, Ying goto err_data; 1956d7d7433SHuang, Ying return 0; 196*c14b2adfSHuang, Ying 197*c14b2adfSHuang, Ying err_data: 198*c14b2adfSHuang, Ying debugfs_remove(data); 1996d7d7433SHuang, Ying err_version: 2006d7d7433SHuang, Ying debugfs_remove(version); 2016d7d7433SHuang, Ying err_dir: 2026d7d7433SHuang, Ying debugfs_remove(dbp); 2036d7d7433SHuang, Ying err_return: 2046d7d7433SHuang, Ying return error; 2056d7d7433SHuang, Ying } 2066d7d7433SHuang, Ying #endif 2076d7d7433SHuang, Ying 2086d7d7433SHuang, Ying static int __init arch_kdebugfs_init(void) 2096d7d7433SHuang, Ying { 2106d7d7433SHuang, Ying int error = 0; 2116d7d7433SHuang, Ying 2126d7d7433SHuang, Ying #ifdef CONFIG_DEBUG_BOOT_PARAMS 2136d7d7433SHuang, Ying error = boot_params_kdebugfs_init(); 2146d7d7433SHuang, Ying #endif 2156d7d7433SHuang, Ying 2166d7d7433SHuang, Ying return error; 2176d7d7433SHuang, Ying } 2186d7d7433SHuang, Ying arch_initcall(arch_kdebugfs_init); 219