linux-bk/arch/i386/kernel/cpu/mtrr/if.c
<<
>>
Prefs
   1#include <linux/init.h>
   2#include <linux/proc_fs.h>
   3#include <linux/ctype.h>
   4#include <linux/module.h>
   5#include <linux/seq_file.h>
   6#include <asm/uaccess.h>
   7
   8#define LINE_SIZE 80
   9
  10#include <asm/mtrr.h>
  11#include "mtrr.h"
  12
  13/* RED-PEN: this is accessed without any locking */
  14extern unsigned int *usage_table;
  15
  16
  17#define FILE_FCOUNT(f) (((struct seq_file *)((f)->private_data))->private)
  18
  19static char *mtrr_strings[MTRR_NUM_TYPES] =
  20{
  21    "uncachable",               /* 0 */
  22    "write-combining",          /* 1 */
  23    "?",                        /* 2 */
  24    "?",                        /* 3 */
  25    "write-through",            /* 4 */
  26    "write-protect",            /* 5 */
  27    "write-back",               /* 6 */
  28};
  29
  30char *mtrr_attrib_to_str(int x)
  31{
  32        return (x <= 6) ? mtrr_strings[x] : "?";
  33}
  34
  35#ifdef CONFIG_PROC_FS
  36
  37static int
  38mtrr_file_add(unsigned long base, unsigned long size,
  39              unsigned int type, char increment, struct file *file, int page)
  40{
  41        int reg, max;
  42        unsigned int *fcount = FILE_FCOUNT(file); 
  43
  44        max = num_var_ranges;
  45        if (fcount == NULL) {
  46                fcount = kmalloc(max * sizeof *fcount, GFP_KERNEL);
  47                if (!fcount)
  48                        return -ENOMEM;
  49                memset(fcount, 0, max * sizeof *fcount);
  50                FILE_FCOUNT(file) = fcount;
  51        }
  52        if (!page) {
  53                if ((base & (PAGE_SIZE - 1)) || (size & (PAGE_SIZE - 1)))
  54                        return -EINVAL;
  55                base >>= PAGE_SHIFT;
  56                size >>= PAGE_SHIFT;
  57        }
  58        reg = mtrr_add_page(base, size, type, 1);
  59        if (reg >= 0)
  60                ++fcount[reg];
  61        return reg;
  62}
  63
  64static int
  65mtrr_file_del(unsigned long base, unsigned long size,
  66              struct file *file, int page)
  67{
  68        int reg;
  69        unsigned int *fcount = FILE_FCOUNT(file);
  70
  71        if (!page) {
  72                if ((base & (PAGE_SIZE - 1)) || (size & (PAGE_SIZE - 1)))
  73                        return -EINVAL;
  74                base >>= PAGE_SHIFT;
  75                size >>= PAGE_SHIFT;
  76        }
  77        reg = mtrr_del_page(-1, base, size);
  78        if (reg < 0)
  79                return reg;
  80        if (fcount == NULL)
  81                return reg;
  82        if (fcount[reg] < 1)
  83                return -EINVAL;
  84        --fcount[reg];
  85        return reg;
  86}
  87
  88/* RED-PEN: seq_file can seek now. this is ignored. */
  89static ssize_t
  90mtrr_write(struct file *file, const char __user *buf, size_t len, loff_t * ppos)
  91/*  Format of control line:
  92    "base=%Lx size=%Lx type=%s"     OR:
  93    "disable=%d"
  94*/
  95{
  96        int i, err;
  97        unsigned long reg;
  98        unsigned long long base, size;
  99        char *ptr;
 100        char line[LINE_SIZE];
 101
 102        if (!capable(CAP_SYS_ADMIN))
 103                return -EPERM;
 104        memset(line, 0, LINE_SIZE);
 105        if (len > LINE_SIZE)
 106                len = LINE_SIZE;
 107        if (copy_from_user(line, buf, len - 1))
 108                return -EFAULT;
 109        ptr = line + strlen(line) - 1;
 110        if (*ptr == '\n')
 111                *ptr = '\0';
 112        if (!strncmp(line, "disable=", 8)) {
 113                reg = simple_strtoul(line + 8, &ptr, 0);
 114                err = mtrr_del_page(reg, 0, 0);
 115                if (err < 0)
 116                        return err;
 117                return len;
 118        }
 119        if (strncmp(line, "base=", 5))
 120                return -EINVAL;
 121        base = simple_strtoull(line + 5, &ptr, 0);
 122        for (; isspace(*ptr); ++ptr) ;
 123        if (strncmp(ptr, "size=", 5))
 124                return -EINVAL;
 125        size = simple_strtoull(ptr + 5, &ptr, 0);
 126        if ((base & 0xfff) || (size & 0xfff))
 127                return -EINVAL;
 128        for (; isspace(*ptr); ++ptr) ;
 129        if (strncmp(ptr, "type=", 5))
 130                return -EINVAL;
 131        ptr += 5;
 132        for (; isspace(*ptr); ++ptr) ;
 133        for (i = 0; i < MTRR_NUM_TYPES; ++i) {
 134                if (strcmp(ptr, mtrr_strings[i]))
 135                        continue;
 136                base >>= PAGE_SHIFT;
 137                size >>= PAGE_SHIFT;
 138                err =
 139                    mtrr_add_page((unsigned long) base, (unsigned long) size, i,
 140                                  1);
 141                if (err < 0)
 142                        return err;
 143                return len;
 144        }
 145        return -EINVAL;
 146}
 147
 148static int
 149mtrr_ioctl(struct inode *inode, struct file *file,
 150           unsigned int cmd, unsigned long __arg)
 151{
 152        int err;
 153        mtrr_type type;
 154        struct mtrr_sentry sentry;
 155        struct mtrr_gentry gentry;
 156        void __user *arg = (void __user *) __arg;
 157
 158        switch (cmd) {
 159        default:
 160                return -ENOTTY;
 161        case MTRRIOC_ADD_ENTRY:
 162                if (!capable(CAP_SYS_ADMIN))
 163                        return -EPERM;
 164                if (copy_from_user(&sentry, arg, sizeof sentry))
 165                        return -EFAULT;
 166                err =
 167                    mtrr_file_add(sentry.base, sentry.size, sentry.type, 1,
 168                                  file, 0);
 169                if (err < 0)
 170                        return err;
 171                break;
 172        case MTRRIOC_SET_ENTRY:
 173                if (!capable(CAP_SYS_ADMIN))
 174                        return -EPERM;
 175                if (copy_from_user(&sentry, arg, sizeof sentry))
 176                        return -EFAULT;
 177                err = mtrr_add(sentry.base, sentry.size, sentry.type, 0);
 178                if (err < 0)
 179                        return err;
 180                break;
 181        case MTRRIOC_DEL_ENTRY:
 182                if (!capable(CAP_SYS_ADMIN))
 183                        return -EPERM;
 184                if (copy_from_user(&sentry, arg, sizeof sentry))
 185                        return -EFAULT;
 186                err = mtrr_file_del(sentry.base, sentry.size, file, 0);
 187                if (err < 0)
 188                        return err;
 189                break;
 190        case MTRRIOC_KILL_ENTRY:
 191                if (!capable(CAP_SYS_ADMIN))
 192                        return -EPERM;
 193                if (copy_from_user(&sentry, arg, sizeof sentry))
 194                        return -EFAULT;
 195                err = mtrr_del(-1, sentry.base, sentry.size);
 196                if (err < 0)
 197                        return err;
 198                break;
 199        case MTRRIOC_GET_ENTRY:
 200                if (copy_from_user(&gentry, arg, sizeof gentry))
 201                        return -EFAULT;
 202                if (gentry.regnum >= num_var_ranges)
 203                        return -EINVAL;
 204                mtrr_if->get(gentry.regnum, &gentry.base, &gentry.size, &type);
 205
 206                /* Hide entries that go above 4GB */
 207                if (gentry.base + gentry.size > 0x100000
 208                    || gentry.size == 0x100000)
 209                        gentry.base = gentry.size = gentry.type = 0;
 210                else {
 211                        gentry.base <<= PAGE_SHIFT;
 212                        gentry.size <<= PAGE_SHIFT;
 213                        gentry.type = type;
 214                }
 215
 216                if (copy_to_user(arg, &gentry, sizeof gentry))
 217                        return -EFAULT;
 218                break;
 219        case MTRRIOC_ADD_PAGE_ENTRY:
 220                if (!capable(CAP_SYS_ADMIN))
 221                        return -EPERM;
 222                if (copy_from_user(&sentry, arg, sizeof sentry))
 223                        return -EFAULT;
 224                err =
 225                    mtrr_file_add(sentry.base, sentry.size, sentry.type, 1,
 226                                  file, 1);
 227                if (err < 0)
 228                        return err;
 229                break;
 230        case MTRRIOC_SET_PAGE_ENTRY:
 231                if (!capable(CAP_SYS_ADMIN))
 232                        return -EPERM;
 233                if (copy_from_user(&sentry, arg, sizeof sentry))
 234                        return -EFAULT;
 235                err = mtrr_add_page(sentry.base, sentry.size, sentry.type, 0);
 236                if (err < 0)
 237                        return err;
 238                break;
 239        case MTRRIOC_DEL_PAGE_ENTRY:
 240                if (!capable(CAP_SYS_ADMIN))
 241                        return -EPERM;
 242                if (copy_from_user(&sentry, arg, sizeof sentry))
 243                        return -EFAULT;
 244                err = mtrr_file_del(sentry.base, sentry.size, file, 1);
 245                if (err < 0)
 246                        return err;
 247                break;
 248        case MTRRIOC_KILL_PAGE_ENTRY:
 249                if (!capable(CAP_SYS_ADMIN))
 250                        return -EPERM;
 251                if (copy_from_user(&sentry, arg, sizeof sentry))
 252                        return -EFAULT;
 253                err = mtrr_del_page(-1, sentry.base, sentry.size);
 254                if (err < 0)
 255                        return err;
 256                break;
 257        case MTRRIOC_GET_PAGE_ENTRY:
 258                if (copy_from_user(&gentry, arg, sizeof gentry))
 259                        return -EFAULT;
 260                if (gentry.regnum >= num_var_ranges)
 261                        return -EINVAL;
 262                mtrr_if->get(gentry.regnum, &gentry.base, &gentry.size, &type);
 263                gentry.type = type;
 264
 265                if (copy_to_user(arg, &gentry, sizeof gentry))
 266                        return -EFAULT;
 267                break;
 268        }
 269        return 0;
 270}
 271
 272static int
 273mtrr_close(struct inode *ino, struct file *file)
 274{
 275        int i, max;
 276        unsigned int *fcount = FILE_FCOUNT(file);
 277
 278        if (fcount != NULL) {
 279                max = num_var_ranges;
 280                for (i = 0; i < max; ++i) {
 281                        while (fcount[i] > 0) {
 282                                mtrr_del(i, 0, 0);
 283                                --fcount[i];
 284                        }
 285                }
 286                kfree(fcount);
 287                FILE_FCOUNT(file) = NULL;
 288        }
 289        return single_release(ino, file);
 290}
 291
 292static int mtrr_seq_show(struct seq_file *seq, void *offset);
 293
 294static int mtrr_open(struct inode *inode, struct file *file)
 295{
 296        if (!mtrr_if) 
 297                return -EIO;
 298        if (!mtrr_if->get) 
 299                return -ENXIO; 
 300        return single_open(file, mtrr_seq_show, NULL);
 301}
 302
 303static struct file_operations mtrr_fops = {
 304        .owner   = THIS_MODULE,
 305        .open    = mtrr_open, 
 306        .read    = seq_read,
 307        .llseek  = seq_lseek,
 308        .write   = mtrr_write,
 309        .ioctl   = mtrr_ioctl,
 310        .release = mtrr_close,
 311};
 312
 313
 314static struct proc_dir_entry *proc_root_mtrr;
 315
 316
 317static int mtrr_seq_show(struct seq_file *seq, void *offset)
 318{
 319        char factor;
 320        int i, max, len;
 321        mtrr_type type;
 322        unsigned long base;
 323        unsigned int size;
 324
 325        len = 0;
 326        max = num_var_ranges;
 327        for (i = 0; i < max; i++) {
 328                mtrr_if->get(i, &base, &size, &type);
 329                if (size == 0)
 330                        usage_table[i] = 0;
 331                else {
 332                        if (size < (0x100000 >> PAGE_SHIFT)) {
 333                                /* less than 1MB */
 334                                factor = 'K';
 335                                size <<= PAGE_SHIFT - 10;
 336                        } else {
 337                                factor = 'M';
 338                                size >>= 20 - PAGE_SHIFT;
 339                        }
 340                        /* RED-PEN: base can be > 32bit */ 
 341                        len += seq_printf(seq, 
 342                                   "reg%02i: base=0x%05lx000 (%4liMB), size=%4i%cB: %s, count=%d\n",
 343                             i, base, base >> (20 - PAGE_SHIFT), size, factor,
 344                             mtrr_attrib_to_str(type), usage_table[i]);
 345                }
 346        }
 347        return 0;
 348}
 349
 350static int __init mtrr_if_init(void)
 351{
 352        struct cpuinfo_x86 *c = &boot_cpu_data;
 353
 354        if ((!cpu_has(c, X86_FEATURE_MTRR)) &&
 355            (!cpu_has(c, X86_FEATURE_K6_MTRR)) &&
 356            (!cpu_has(c, X86_FEATURE_CYRIX_ARR)) &&
 357            (!cpu_has(c, X86_FEATURE_CENTAUR_MCR)))
 358                return -ENODEV;
 359
 360        proc_root_mtrr =
 361            create_proc_entry("mtrr", S_IWUSR | S_IRUGO, &proc_root);
 362        if (proc_root_mtrr) {
 363                proc_root_mtrr->owner = THIS_MODULE;
 364                proc_root_mtrr->proc_fops = &mtrr_fops;
 365        }
 366        return 0;
 367}
 368
 369arch_initcall(mtrr_if_init);
 370#endif                  /*  CONFIG_PROC_FS  */
 371
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.