cregit-Linux how code gets into the kernel

Release 4.14 arch/x86/kernel/cpu/mtrr/if.c

// SPDX-License-Identifier: GPL-2.0
#include <linux/capability.h>
#include <linux/seq_file.h>
#include <linux/uaccess.h>
#include <linux/proc_fs.h>
#include <linux/ctype.h>
#include <linux/string.h>
#include <linux/slab.h>
#include <linux/init.h>


#define LINE_SIZE 80

#include <asm/mtrr.h>

#include "mtrr.h"


#define FILE_FCOUNT(f) (((struct seq_file *)((f)->private_data))->private)


static const char *const mtrr_strings[MTRR_NUM_TYPES] =
{
	"uncachable",		/* 0 */
	"write-combining",	/* 1 */
	"?",			/* 2 */
	"?",			/* 3 */
	"write-through",	/* 4 */
	"write-protect",	/* 5 */
	"write-back",		/* 6 */
};


const char *mtrr_attrib_to_str(int x) { return (x <= 6) ? mtrr_strings[x] : "?"; }

Contributors

PersonTokensPropCommitsCommitProp
Andrew Morton2395.83%150.00%
Jan Beulich14.17%150.00%
Total24100.00%2100.00%

#ifdef CONFIG_PROC_FS
static int mtrr_file_add(unsigned long base, unsigned long size, unsigned int type, bool increment, struct file *file, int page) { unsigned int *fcount = FILE_FCOUNT(file); int reg, max; max = num_var_ranges; if (fcount == NULL) { fcount = kzalloc(max * sizeof *fcount, GFP_KERNEL); if (!fcount) return -ENOMEM; FILE_FCOUNT(file) = fcount; } if (!page) { if ((base & (PAGE_SIZE - 1)) || (size & (PAGE_SIZE - 1))) return -EINVAL; base >>= PAGE_SHIFT; size >>= PAGE_SHIFT; } reg = mtrr_add_page(base, size, type, true); if (reg >= 0) ++fcount[reg]; return reg; }

Contributors

PersonTokensPropCommitsCommitProp
Dave Jones13587.66%116.67%
Andi Kleen63.90%116.67%
Linus Torvalds53.25%116.67%
Jaswinder Singh Rajput53.25%116.67%
Paul Jimenez21.30%116.67%
Burman Yan10.65%116.67%
Total154100.00%6100.00%


static int mtrr_file_del(unsigned long base, unsigned long size, struct file *file, int page) { unsigned int *fcount = FILE_FCOUNT(file); int reg; if (!page) { if ((base & (PAGE_SIZE - 1)) || (size & (PAGE_SIZE - 1))) return -EINVAL; base >>= PAGE_SHIFT; size >>= PAGE_SHIFT; } reg = mtrr_del_page(-1, base, size); if (reg < 0) return reg; if (fcount == NULL) return reg; if (fcount[reg] < 1) return -EINVAL; --fcount[reg]; return reg; }

Contributors

PersonTokensPropCommitsCommitProp
Dave Jones12295.31%133.33%
Andrew Morton32.34%133.33%
Jaswinder Singh Rajput32.34%133.33%
Total128100.00%3100.00%

/* * seq_file can seek but we ignore it. * * Format of control line: * "base=%Lx size=%Lx type=%s" or "disable=%d" */
static ssize_t mtrr_write(struct file *file, const char __user *buf, size_t len, loff_t * ppos) { int i, err; unsigned long reg; unsigned long long base, size; char *ptr; char line[LINE_SIZE]; int length; size_t linelen; if (!capable(CAP_SYS_ADMIN)) return -EPERM; memset(line, 0, LINE_SIZE); length = len; length--; if (length > LINE_SIZE - 1) length = LINE_SIZE - 1; if (length < 0) return -EINVAL; if (copy_from_user(line, buf, length)) return -EFAULT; linelen = strlen(line); ptr = line + linelen - 1; if (linelen && *ptr == '\n') *ptr = '\0'; if (!strncmp(line, "disable=", 8)) { reg = simple_strtoul(line + 8, &ptr, 0); err = mtrr_del_page(reg, 0, 0); if (err < 0) return err; return len; } if (strncmp(line, "base=", 5)) return -EINVAL; base = simple_strtoull(line + 5, &ptr, 0); ptr = skip_spaces(ptr); if (strncmp(ptr, "size=", 5)) return -EINVAL; size = simple_strtoull(ptr + 5, &ptr, 0); if ((base & 0xfff) || (size & 0xfff)) return -EINVAL; ptr = skip_spaces(ptr); if (strncmp(ptr, "type=", 5)) return -EINVAL; ptr = skip_spaces(ptr + 5); for (i = 0; i < MTRR_NUM_TYPES; ++i) { if (strcmp(ptr, mtrr_strings[i])) continue; base >>= PAGE_SHIFT; size >>= PAGE_SHIFT; err = mtrr_add_page((unsigned long)base, (unsigned long)size, i, true); if (err < 0) return err; return len; } return -EINVAL; }

Contributors

PersonTokensPropCommitsCommitProp
Dave Jones32483.08%112.50%
Arjan van de Ven276.92%112.50%
Randy Dunlap123.08%112.50%
Andi Kleen123.08%112.50%
André Goddard Rosa102.56%112.50%
Joe Perches30.77%112.50%
Paul Jimenez10.26%112.50%
Linus Torvalds10.26%112.50%
Total390100.00%8100.00%


static long mtrr_ioctl(struct file *file, unsigned int cmd, unsigned long __arg) { int err = 0; mtrr_type type; unsigned long base; unsigned long size; struct mtrr_sentry sentry; struct mtrr_gentry gentry; void __user *arg = (void __user *) __arg; switch (cmd) { case MTRRIOC_ADD_ENTRY: case MTRRIOC_SET_ENTRY: case MTRRIOC_DEL_ENTRY: case MTRRIOC_KILL_ENTRY: case MTRRIOC_ADD_PAGE_ENTRY: case MTRRIOC_SET_PAGE_ENTRY: case MTRRIOC_DEL_PAGE_ENTRY: case MTRRIOC_KILL_PAGE_ENTRY: if (copy_from_user(&sentry, arg, sizeof sentry)) return -EFAULT; break; case MTRRIOC_GET_ENTRY: case MTRRIOC_GET_PAGE_ENTRY: if (copy_from_user(&gentry, arg, sizeof gentry)) return -EFAULT; break; #ifdef CONFIG_COMPAT case MTRRIOC32_ADD_ENTRY: case MTRRIOC32_SET_ENTRY: case MTRRIOC32_DEL_ENTRY: case MTRRIOC32_KILL_ENTRY: case MTRRIOC32_ADD_PAGE_ENTRY: case MTRRIOC32_SET_PAGE_ENTRY: case MTRRIOC32_DEL_PAGE_ENTRY: case MTRRIOC32_KILL_PAGE_ENTRY: { struct mtrr_sentry32 __user *s32; s32 = (struct mtrr_sentry32 __user *)__arg; err = get_user(sentry.base, &s32->base); err |= get_user(sentry.size, &s32->size); err |= get_user(sentry.type, &s32->type); if (err) return err; break; } case MTRRIOC32_GET_ENTRY: case MTRRIOC32_GET_PAGE_ENTRY: { struct mtrr_gentry32 __user *g32; g32 = (struct mtrr_gentry32 __user *)__arg; err = get_user(gentry.regnum, &g32->regnum); err |= get_user(gentry.base, &g32->base); err |= get_user(gentry.size, &g32->size); err |= get_user(gentry.type, &g32->type); if (err) return err; break; } #endif } switch (cmd) { default: return -ENOTTY; case MTRRIOC_ADD_ENTRY: #ifdef CONFIG_COMPAT case MTRRIOC32_ADD_ENTRY: #endif if (!capable(CAP_SYS_ADMIN)) return -EPERM; err = mtrr_file_add(sentry.base, sentry.size, sentry.type, true, file, 0); break; case MTRRIOC_SET_ENTRY: #ifdef CONFIG_COMPAT case MTRRIOC32_SET_ENTRY: #endif if (!capable(CAP_SYS_ADMIN)) return -EPERM; err = mtrr_add(sentry.base, sentry.size, sentry.type, false); break; case MTRRIOC_DEL_ENTRY: #ifdef CONFIG_COMPAT case MTRRIOC32_DEL_ENTRY: #endif if (!capable(CAP_SYS_ADMIN)) return -EPERM; err = mtrr_file_del(sentry.base, sentry.size, file, 0); break; case MTRRIOC_KILL_ENTRY: #ifdef CONFIG_COMPAT case MTRRIOC32_KILL_ENTRY: #endif if (!capable(CAP_SYS_ADMIN)) return -EPERM; err = mtrr_del(-1, sentry.base, sentry.size); break; case MTRRIOC_GET_ENTRY: #ifdef CONFIG_COMPAT case MTRRIOC32_GET_ENTRY: #endif if (gentry.regnum >= num_var_ranges) return -EINVAL; mtrr_if->get(gentry.regnum, &base, &size, &type); /* Hide entries that go above 4GB */ if (base + size - 1 >= (1UL << (8 * sizeof(gentry.size) - PAGE_SHIFT)) || size >= (1UL << (8 * sizeof(gentry.size) - PAGE_SHIFT))) gentry.base = gentry.size = gentry.type = 0; else { gentry.base = base << PAGE_SHIFT; gentry.size = size << PAGE_SHIFT; gentry.type = type; } break; case MTRRIOC_ADD_PAGE_ENTRY: #ifdef CONFIG_COMPAT case MTRRIOC32_ADD_PAGE_ENTRY: #endif if (!capable(CAP_SYS_ADMIN)) return -EPERM; err = mtrr_file_add(sentry.base, sentry.size, sentry.type, true, file, 1); break; case MTRRIOC_SET_PAGE_ENTRY: #ifdef CONFIG_COMPAT case MTRRIOC32_SET_PAGE_ENTRY: #endif if (!capable(CAP_SYS_ADMIN)) return -EPERM; err = mtrr_add_page(sentry.base, sentry.size, sentry.type, false); break; case MTRRIOC_DEL_PAGE_ENTRY: #ifdef CONFIG_COMPAT case MTRRIOC32_DEL_PAGE_ENTRY: #endif if (!capable(CAP_SYS_ADMIN)) return -EPERM; err = mtrr_file_del(sentry.base, sentry.size, file, 1); break; case MTRRIOC_KILL_PAGE_ENTRY: #ifdef CONFIG_COMPAT case MTRRIOC32_KILL_PAGE_ENTRY: #endif if (!capable(CAP_SYS_ADMIN)) return -EPERM; err = mtrr_del_page(-1, sentry.base, sentry.size); break; case MTRRIOC_GET_PAGE_ENTRY: #ifdef CONFIG_COMPAT case MTRRIOC32_GET_PAGE_ENTRY: #endif if (gentry.regnum >= num_var_ranges) return -EINVAL; mtrr_if->get(gentry.regnum, &base, &size, &type); /* Hide entries that would overflow */ if (size != (__typeof__(gentry.size))size) gentry.base = gentry.size = gentry.type = 0; else { gentry.base = base; gentry.size = size; gentry.type = type; } break; } if (err) return err; switch (cmd) { case MTRRIOC_GET_ENTRY: case MTRRIOC_GET_PAGE_ENTRY: if (copy_to_user(arg, &gentry, sizeof gentry)) err = -EFAULT; break; #ifdef CONFIG_COMPAT case MTRRIOC32_GET_ENTRY: case MTRRIOC32_GET_PAGE_ENTRY: { struct mtrr_gentry32 __user *g32; g32 = (struct mtrr_gentry32 __user *)__arg; err = put_user(gentry.base, &g32->base); err |= put_user(gentry.size, &g32->size); err |= put_user(gentry.regnum, &g32->regnum); err |= put_user(gentry.type, &g32->type); break; } #endif } return err; }

Contributors

PersonTokensPropCommitsCommitProp
Dave Jones46345.84%112.50%
Brian Gerst34834.46%112.50%
Giuliano Procida807.92%112.50%
Jan Beulich777.62%112.50%
H. Peter Anvin131.29%112.50%
Linus Torvalds131.29%112.50%
Jaswinder Singh Rajput121.19%112.50%
Paul Jimenez40.40%112.50%
Total1010100.00%8100.00%


static int mtrr_close(struct inode *ino, struct file *file) { unsigned int *fcount = FILE_FCOUNT(file); int i, max; if (fcount != NULL) { max = num_var_ranges; for (i = 0; i < max; ++i) { while (fcount[i] > 0) { mtrr_del(i, 0, 0); --fcount[i]; } } kfree(fcount); FILE_FCOUNT(file) = NULL; } return single_release(ino, file); }

Contributors

PersonTokensPropCommitsCommitProp
Dave Jones8278.85%133.33%
Andi Kleen1716.35%133.33%
Jaswinder Singh Rajput54.81%133.33%
Total104100.00%3100.00%

static int mtrr_seq_show(struct seq_file *seq, void *offset);
static int mtrr_open(struct inode *inode, struct file *file) { if (!mtrr_if) return -EIO; if (!mtrr_if->get) return -ENXIO; return single_open(file, mtrr_seq_show, NULL); }

Contributors

PersonTokensPropCommitsCommitProp
Andi Kleen4495.65%150.00%
Dave Jones24.35%150.00%
Total46100.00%2100.00%

static const struct file_operations mtrr_fops = { .owner = THIS_MODULE, .open = mtrr_open, .read = seq_read, .llseek = seq_lseek, .write = mtrr_write, .unlocked_ioctl = mtrr_ioctl, .compat_ioctl = mtrr_ioctl, .release = mtrr_close, };
static int mtrr_seq_show(struct seq_file *seq, void *offset) { char factor; int i, max; mtrr_type type; unsigned long base, size; max = num_var_ranges; for (i = 0; i < max; i++) { mtrr_if->get(i, &base, &size, &type); if (size == 0) { mtrr_usage_table[i] = 0; continue; } if (size < (0x100000 >> PAGE_SHIFT)) { /* less than 1MB */ factor = 'K'; size <<= PAGE_SHIFT - 10; } else { factor = 'M'; size >>= 20 - PAGE_SHIFT; } /* Base can be > 32bit */ seq_printf(seq, "reg%02i: base=0x%06lx000 (%5luMB), size=%5lu%cB, count=%d: %s\n", i, base, base >> (20 - PAGE_SHIFT), size, factor, mtrr_usage_table[i], mtrr_attrib_to_str(type)); } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Dave Jones12882.05%114.29%
Andi Kleen159.62%114.29%
J. A. Magallon53.21%114.29%
Jaswinder Singh Rajput42.56%114.29%
Jesse Barnes21.28%114.29%
Jan Beulich10.64%114.29%
Joe Perches10.64%114.29%
Total156100.00%7100.00%


static int __init mtrr_if_init(void) { struct cpuinfo_x86 *c = &boot_cpu_data; if ((!cpu_has(c, X86_FEATURE_MTRR)) && (!cpu_has(c, X86_FEATURE_K6_MTRR)) && (!cpu_has(c, X86_FEATURE_CYRIX_ARR)) && (!cpu_has(c, X86_FEATURE_CENTAUR_MCR))) return -ENODEV; proc_create("mtrr", S_IWUSR | S_IRUGO, NULL, &mtrr_fops); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Dave Jones7593.75%250.00%
Alexey Dobriyan56.25%250.00%
Total80100.00%4100.00%

arch_initcall(mtrr_if_init); #endif /* CONFIG_PROC_FS */

Overall Contributors

PersonTokensPropCommitsCommitProp
Dave Jones138261.64%27.14%
Brian Gerst35415.79%13.57%
Andi Kleen1165.17%13.57%
Jan Beulich813.61%13.57%
Giuliano Procida803.57%13.57%
Andrew Morton783.48%310.71%
Jaswinder Singh Rajput361.61%13.57%
Arjan van de Ven281.25%27.14%
Linus Torvalds190.85%27.14%
Randy Dunlap140.62%27.14%
André Goddard Rosa130.58%13.57%
H. Peter Anvin130.58%13.57%
Paul Jimenez70.31%13.57%
J. A. Magallon50.22%13.57%
Alexey Dobriyan50.22%27.14%
Joe Perches40.18%27.14%
Tejun Heo30.13%13.57%
Jesse Barnes20.09%13.57%
Burman Yan10.04%13.57%
Greg Kroah-Hartman10.04%13.57%
Total2242100.00%28100.00%
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with cregit.