📄 mtrr.c
字号:
if ( (base < lbase) && (base + size <= lbase) ) continue; /* At this point we know there is some kind of overlap/enclosure */ if ( (base < lbase) || (base + size > lbase + lsize) ) { up(&main_lock); printk (KERN_WARNING "mtrr: 0x%lx000,0x%lx000 overlaps existing" " 0x%lx000,0x%lx000\n", base, size, lbase, lsize); return -EINVAL; } /* New region is enclosed by an existing region */ if (ltype != type) { if (type == MTRR_TYPE_UNCACHABLE) continue; up(&main_lock); printk ( "mtrr: type mismatch for %lx000,%lx000 old: %s new: %s\n", base, size, attrib_to_str (ltype), attrib_to_str (type) ); return -EINVAL; } if (increment) ++usage_table[i]; compute_ascii (); up(&main_lock); return i; } /* Search for an empty MTRR */ i = (*get_free_region) (base, size); if (i < 0) { up(&main_lock); printk ("mtrr: no more MTRRs available\n"); return i; } set_mtrr (i, base, size, type); usage_table[i] = 1; compute_ascii (); up(&main_lock); return i;} /* End Function mtrr_add_page *//** * mtrr_add - Add a memory type region * @base: Physical base address of region * @size: Physical size of region * @type: Type of MTRR desired * @increment: If this is true do usage counting on the region * * Memory type region registers control the caching on newer Intel and * non Intel processors. This function allows drivers to request an * MTRR is added. The details and hardware specifics of each processor's * implementation are hidden from the caller, but nevertheless the * caller should expect to need to provide a power of two size on an * equivalent power of two boundary. * * If the region cannot be added either because all regions are in use * or the CPU cannot support it a negative value is returned. On success * the register number for this entry is returned, but should be treated * as a cookie only. * * On a multiprocessor machine the changes are made to all processors. * This is required on x86 by the Intel processors. * * The available types are * * %MTRR_TYPE_UNCACHEABLE - No caching * * %MTRR_TYPE_WRITEBACK - Write data back in bursts whenever * * %MTRR_TYPE_WRCOMB - Write data back soon but allow bursts * * %MTRR_TYPE_WRTHROUGH - Cache reads but not writes * * BUGS: Needs a quiet flag for the cases where drivers do not mind * failures and do not wish system log messages to be sent. */int mtrr_add(unsigned long base, unsigned long size, unsigned int type, char increment){/* [SUMMARY] Add an MTRR entry. <base> The starting (base) address of the region. <size> The size (in bytes) of the region. <type> The type of the new region. <increment> If true and the region already exists, the usage count will be incremented. [RETURNS] The MTRR register on success, else a negative number indicating the error code.*/ if ( (base & (PAGE_SIZE - 1)) || (size & (PAGE_SIZE - 1)) ) { printk ("mtrr: size and base must be multiples of 4 kiB\n"); printk ("mtrr: size: 0x%lx base: 0x%lx\n", size, base); return -EINVAL; } return mtrr_add_page(base >> PAGE_SHIFT, size >> PAGE_SHIFT, type, increment);} /* End Function mtrr_add *//** * mtrr_del_page - delete a memory type region * @reg: Register returned by mtrr_add * @base: Physical base address * @size: Size of region * * If register is supplied then base and size are ignored. This is * how drivers should call it. * * Releases an MTRR region. If the usage count drops to zero the * register is freed and the region returns to default state. * On success the register is returned, on failure a negative error * code. */ int mtrr_del_page (int reg, unsigned long base, unsigned long size)/* [SUMMARY] Delete MTRR/decrement usage count. <reg> The register. If this is less than 0 then <<base>> and <<size>> must be supplied. <base> The base address of the region. This is ignored if <<reg>> is >= 0. <size> The size of the region. This is ignored if <<reg>> is >= 0. [RETURNS] The register on success, else a negative number indicating the error code. [NOTE] This routine uses a spinlock.*/{ int i, max; mtrr_type ltype; unsigned long lbase, lsize; if ( mtrr_if == MTRR_IF_NONE ) return -ENXIO; max = get_num_var_ranges (); down (&main_lock); if (reg < 0) { /* Search for existing MTRR */ for (i = 0; i < max; ++i) { (*get_mtrr) (i, &lbase, &lsize, <ype); if (lbase == base && lsize == size) { reg = i; break; } } if (reg < 0) { up(&main_lock); printk ("mtrr: no MTRR for %lx000,%lx000 found\n", base, size); return -EINVAL; } } if (reg >= max) { up (&main_lock); printk ("mtrr: register: %d too big\n", reg); return -EINVAL; } if ( mtrr_if == MTRR_IF_CYRIX_ARR ) { if ( (reg == 3) && arr3_protected ) { up (&main_lock); printk ("mtrr: ARR3 cannot be changed\n"); return -EINVAL; } } (*get_mtrr) (reg, &lbase, &lsize, <ype); if (lsize < 1) { up (&main_lock); printk ("mtrr: MTRR %d not used\n", reg); return -EINVAL; } if (usage_table[reg] < 1) { up (&main_lock); printk ("mtrr: reg: %d has count=0\n", reg); return -EINVAL; } if (--usage_table[reg] < 1) set_mtrr (reg, 0, 0, 0); compute_ascii (); up (&main_lock); return reg;} /* End Function mtrr_del_page *//** * mtrr_del - delete a memory type region * @reg: Register returned by mtrr_add * @base: Physical base address * @size: Size of region * * If register is supplied then base and size are ignored. This is * how drivers should call it. * * Releases an MTRR region. If the usage count drops to zero the * register is freed and the region returns to default state. * On success the register is returned, on failure a negative error * code. */ int mtrr_del (int reg, unsigned long base, unsigned long size)/* [SUMMARY] Delete MTRR/decrement usage count. <reg> The register. If this is less than 0 then <<base>> and <<size>> must be supplied. <base> The base address of the region. This is ignored if <<reg>> is >= 0. <size> The size of the region. This is ignored if <<reg>> is >= 0. [RETURNS] The register on success, else a negative number indicating the error code.*/{ if ( (base & (PAGE_SIZE - 1)) || (size & (PAGE_SIZE - 1)) ) { printk ("mtrr: size and base must be multiples of 4 kiB\n"); printk ("mtrr: size: 0x%lx base: 0x%lx\n", size, base); return -EINVAL; } return mtrr_del_page(reg, base >> PAGE_SHIFT, size >> PAGE_SHIFT);}#ifdef USERSPACE_INTERFACEstatic int mtrr_file_add (unsigned long base, unsigned long size, unsigned int type, char increment, struct file *file, int page){ int reg, max; unsigned int *fcount = file->private_data; max = get_num_var_ranges (); if (fcount == NULL) { if ( ( fcount = kmalloc (max * sizeof *fcount, GFP_KERNEL) ) == NULL ) { printk ("mtrr: could not allocate\n"); return -ENOMEM; } memset (fcount, 0, max * sizeof *fcount); file->private_data = fcount; } if (!page) { if ( (base & (PAGE_SIZE - 1)) || (size & (PAGE_SIZE - 1)) ) { printk ("mtrr: size and base must be multiples of 4 kiB\n"); printk ("mtrr: size: 0x%lx base: 0x%lx\n", size, base); return -EINVAL; } base >>= PAGE_SHIFT; size >>= PAGE_SHIFT; } reg = mtrr_add_page (base, size, type, 1); if (reg >= 0) ++fcount[reg]; return reg;} /* End Function mtrr_file_add */static int mtrr_file_del (unsigned long base, unsigned long 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 ("mtrr: size and base must be multiples of 4 kiB\n"); printk ("mtrr: size: 0x%lx 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;} /* End Function mtrr_file_del */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;} /* End Function mtrr_read */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; unsigned long reg; unsigned long long base, size; char *ptr; char line[LINE_SIZE]; if ( !suser () ) 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 ("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 ("mtrr: no \"size=\" in line: \"%s\"\n", line); return -EINVAL; } size = simple_strtoull (ptr + 5, &ptr, 0); if ( (base & 0xfff) || (size & 0xfff) ) { printk ("mtrr: size and base must be multiples of 4 kiB\n"); printk ("mtrr: size: 0x%Lx base: 0x%Lx\n", size, base); return -EINVAL; } for (; isspace (*ptr); ++ptr); if ( strncmp (ptr, "type=", 5) ) { printk ("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 ((unsigned long)base, (unsigned long)size, i, 1); if (err < 0) return err; return len; } printk ("mtrr: illegal type: \"%s\"\n", ptr); return -EINVAL;} /* End Function mtrr_write */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 ( !suser () ) return -EPERM; if ( copy_from_user (&sentry, (void *) arg, sizeof sentry) ) return -EFAULT; err = mtrr_file_add (sentry.base, sentry.size, sentry.type, 1, file, 0); if (err < 0) return err; break; case MTRRIOC_SET_ENTRY: if ( !suser () ) 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 ( !suser () ) 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 ( !suser () ) 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, &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 ( !suser () ) return -EPERM; if ( copy_from_user (&sentry, (void *) arg, sizeof sentry) ) return -EFAULT; err = mtrr_file_add (sentry.base, sentry.size, sentry.type, 1, file, 1); if (err < 0) return err;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -