📄 mtrr.c
字号:
base >>= PAGE_SHIFT; size >>= PAGE_SHIFT; } reg = mtrr_add_page (base, size, type, 1); if (reg >= 0) ++fcount[reg]; return reg;}static int mtrr_file_del (u64 base, u32 size, struct file *file, int page){ int reg; unsigned int *fcount = file->private_data; if (!page) { if ((base & (PAGE_SIZE - 1)) || (size & (PAGE_SIZE - 1))) { printk (KERN_INFO "mtrr: size and base must be multiples of 4 kiB\n"); printk (KERN_INFO "mtrr: size: 0x%x base: 0x%Lx\n", size, base); 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;}static ssize_t mtrr_read (struct file *file, char *buf, size_t len, loff_t * ppos){ if (*ppos >= ascii_buf_bytes) return 0; if (*ppos + len > ascii_buf_bytes) len = ascii_buf_bytes - *ppos; if (copy_to_user (buf, ascii_buffer + *ppos, len)) return -EFAULT; *ppos += len; return len;}static ssize_t mtrr_write (struct file *file, const char *buf, size_t len, loff_t * ppos)/* Format of control line: "base=%Lx size=%Lx type=%s" OR: "disable=%d"*/{ int i, err, reg; u64 base; u32 size; char *ptr; char line[LINE_SIZE]; if (!capable(CAP_SYS_ADMIN)) return -EPERM; /* Can't seek (pwrite) on this device */ if (ppos != &file->f_pos) return -ESPIPE; memset (line, 0, LINE_SIZE); if (len > LINE_SIZE) len = LINE_SIZE; if (copy_from_user (line, buf, len - 1)) return -EFAULT; ptr = line + strlen (line) - 1; if (*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)) { printk (KERN_INFO "mtrr: no \"base=\" in line: \"%s\"\n", line); return -EINVAL; } base = simple_strtoull (line + 5, &ptr, 0); for (; isspace (*ptr); ++ptr) ; if (strncmp (ptr, "size=", 5)) { printk (KERN_INFO "mtrr: no \"size=\" in line: \"%s\"\n", line); return -EINVAL; } size = simple_strtoull (ptr + 5, &ptr, 0); if ((base & 0xfff) || (size & 0xfff)) { printk (KERN_INFO "mtrr: size and base must be multiples of 4 kiB\n"); printk (KERN_INFO "mtrr: size: 0x%x base: 0x%Lx\n", size, base); return -EINVAL; } for (; isspace (*ptr); ++ptr) ; if (strncmp (ptr, "type=", 5)) { printk (KERN_INFO "mtrr: no \"type=\" in line: \"%s\"\n", line); return -EINVAL; } ptr += 5; for (; isspace (*ptr); ++ptr) ; 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 ((u64) base, size, i, 1); if (err < 0) return err; return len; } printk (KERN_INFO "mtrr: illegal type: \"%s\"\n", ptr); return -EINVAL;}static int mtrr_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg){ int err; mtrr_type type; struct mtrr_sentry sentry; struct mtrr_gentry gentry; switch (cmd) { default: return -ENOIOCTLCMD; case MTRRIOC_ADD_ENTRY: if (!capable(CAP_SYS_ADMIN)) return -EPERM; if (copy_from_user (&sentry, (void *) arg, sizeof sentry)) return -EFAULT; err = mtrr_file_add (sentry.base, sentry.size, sentry.type, file, 0); if (err < 0) return err; break; case MTRRIOC_SET_ENTRY: if (!capable(CAP_SYS_ADMIN)) return -EPERM; if (copy_from_user (&sentry, (void *) arg, sizeof sentry)) return -EFAULT; err = mtrr_add (sentry.base, sentry.size, sentry.type, 0); if (err < 0) return err; break; case MTRRIOC_DEL_ENTRY: if (!capable(CAP_SYS_ADMIN)) return -EPERM; if (copy_from_user (&sentry, (void *) arg, sizeof sentry)) return -EFAULT; err = mtrr_file_del (sentry.base, sentry.size, file, 0); if (err < 0) return err; break; case MTRRIOC_KILL_ENTRY: if (!capable(CAP_SYS_ADMIN)) return -EPERM; if (copy_from_user (&sentry, (void *) arg, sizeof sentry)) return -EFAULT; err = mtrr_del (-1, sentry.base, sentry.size); if (err < 0) return err; break; case MTRRIOC_GET_ENTRY: if (copy_from_user (&gentry, (void *) arg, sizeof gentry)) return -EFAULT; if (gentry.regnum >= get_num_var_ranges ()) return -EINVAL; get_mtrr (gentry.regnum, (u64*) &gentry.base, &gentry.size, &type); /* Hide entries that go above 4GB */ if (gentry.base + gentry.size > 0x100000 || gentry.size == 0x100000) gentry.base = gentry.size = gentry.type = 0; else { gentry.base <<= PAGE_SHIFT; gentry.size <<= PAGE_SHIFT; gentry.type = type; } if (copy_to_user ((void *) arg, &gentry, sizeof gentry)) return -EFAULT; break; case MTRRIOC_ADD_PAGE_ENTRY: if (!capable(CAP_SYS_ADMIN)) return -EPERM; if (copy_from_user (&sentry, (void *) arg, sizeof sentry)) return -EFAULT; err = mtrr_file_add (sentry.base, sentry.size, sentry.type, file, 1); if (err < 0) return err; break; case MTRRIOC_SET_PAGE_ENTRY: if (!capable(CAP_SYS_ADMIN)) return -EPERM; if (copy_from_user (&sentry, (void *) arg, sizeof sentry)) return -EFAULT; err = mtrr_add_page (sentry.base, sentry.size, sentry.type, 0); if (err < 0) return err; break; case MTRRIOC_DEL_PAGE_ENTRY: if (!capable(CAP_SYS_ADMIN)) return -EPERM; if (copy_from_user (&sentry, (void *) arg, sizeof sentry)) return -EFAULT; err = mtrr_file_del (sentry.base, sentry.size, file, 1); if (err < 0) return err; break; case MTRRIOC_KILL_PAGE_ENTRY: if (!capable(CAP_SYS_ADMIN)) return -EPERM; if (copy_from_user (&sentry, (void *) arg, sizeof sentry)) return -EFAULT; err = mtrr_del_page (-1, sentry.base, sentry.size); if (err < 0) return err; break; case MTRRIOC_GET_PAGE_ENTRY: if (copy_from_user (&gentry, (void *) arg, sizeof gentry)) return -EFAULT; if (gentry.regnum >= get_num_var_ranges ()) return -EINVAL; get_mtrr (gentry.regnum, (u64*) &gentry.base, &gentry.size, &type); gentry.type = type; if (copy_to_user ((void *) arg, &gentry, sizeof gentry)) return -EFAULT; break; } return 0;}static int mtrr_close (struct inode *ino, struct file *file){ int i, max; unsigned int *fcount = file->private_data; if (fcount == NULL) return 0; lock_kernel (); max = get_num_var_ranges (); for (i = 0; i < max; ++i) { while (fcount[i] > 0) { if (mtrr_del (i, 0, 0) < 0) printk ("mtrr: reg %d not used\n", i); --fcount[i]; } } unlock_kernel (); kfree (fcount); file->private_data = NULL; return 0;}static struct file_operations mtrr_fops = { owner: THIS_MODULE, read: mtrr_read, write: mtrr_write, ioctl: mtrr_ioctl, release:mtrr_close,};#ifdef CONFIG_PROC_FSstatic struct proc_dir_entry *proc_root_mtrr;#endifstatic devfs_handle_t devfs_handle;static void compute_ascii (void){ char factor; int i, max; mtrr_type type; u64 base; u32 size; ascii_buf_bytes = 0; max = get_num_var_ranges (); for (i = 0; i < max; i++) { get_mtrr (i, &base, &size, &type); if (size == 0) usage_table[i] = 0; else { if (size < (0x100000 >> PAGE_SHIFT)) { /* less than 1MB */ factor = 'K'; size <<= PAGE_SHIFT - 10; } else { factor = 'M'; size >>= 20 - PAGE_SHIFT; } sprintf (ascii_buffer + ascii_buf_bytes, "reg%02i: base=0x%05Lx000 (%4iMB), size=%4i%cB: %s, count=%d\n", i, base, (u32) base >> (20 - PAGE_SHIFT), size, factor, attrib_to_str (type), usage_table[i]); ascii_buf_bytes += strlen (ascii_buffer + ascii_buf_bytes); } } devfs_set_file_size (devfs_handle, ascii_buf_bytes);#ifdef CONFIG_PROC_FS if (proc_root_mtrr) proc_root_mtrr->size = ascii_buf_bytes;#endif}#endif /* USERSPACE_INTERFACE */EXPORT_SYMBOL (mtrr_add);EXPORT_SYMBOL (mtrr_del);static void __init mtrr_setup (void){ printk ("mtrr: v%s)\n", MTRR_VERSION); if (test_bit (X86_FEATURE_MTRR, boot_cpu_data.x86_capability)) { /* Query the width (in bits) of the physical addressable memory on the Hammer family. */ if ((cpuid_eax (0x80000000) >= 0x80000008)) { u32 phys_addr; phys_addr = cpuid_eax (0x80000008) & 0xff; size_or_mask = ~((1L << phys_addr) - 1); /* * top bits MBZ as its beyond the addressable range. * bottom bits MBZ as we don't care about lower 12 bits of addr. */ size_and_mask = (~size_or_mask) & 0x000ffffffffff000L; } }}#ifdef CONFIG_SMPstatic volatile u32 smp_changes_mask __initdata = 0;static struct mtrr_state smp_mtrr_state __initdata = { 0, 0 };void __init mtrr_init_boot_cpu (void){ mtrr_setup(); get_mtrr_state (&smp_mtrr_state);}void __init mtrr_init_secondary_cpu (void){ u64 mask; int count; struct set_mtrr_context ctxt; /* Note that this is not ideal, since the cache is only flushed/disabled for this CPU while the MTRRs are changed, but changing this requires more invasive changes to the way the kernel boots */ set_mtrr_prepare (&ctxt); mask = set_mtrr_state (&smp_mtrr_state, &ctxt); set_mtrr_done (&ctxt); /* Use the atomic bitops to update the global mask */ for (count = 0; count < sizeof mask * 8; ++count) { if (mask & 0x01) set_bit (count, &smp_changes_mask); mask >>= 1; }}#endif /* CONFIG_SMP */int __init mtrr_init (void){#ifdef CONFIG_SMP /* mtrr_setup() should already have been called from mtrr_init_boot_cpu() */ finalize_mtrr_state (&smp_mtrr_state); mtrr_state_warn (smp_changes_mask);#else mtrr_setup();#endif#ifdef CONFIG_PROC_FS proc_root_mtrr = create_proc_entry ("mtrr", S_IWUSR | S_IRUGO, &proc_root); if (proc_root_mtrr) { proc_root_mtrr->owner = THIS_MODULE; proc_root_mtrr->proc_fops = &mtrr_fops; }#endif#ifdef CONFIG_DEVFS_FS devfs_handle = devfs_register (NULL, "cpu/mtrr", DEVFS_FL_DEFAULT, 0, 0, S_IFREG | S_IRUGO | S_IWUSR, &mtrr_fops, NULL);#endif init_table (); return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -