linux/drivers/char/nvram.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * CMOS/NV-RAM driver for Linux
   4 *
   5 * Copyright (C) 1997 Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de>
   6 * idea by and with help from Richard Jelinek <rj@suse.de>
   7 * Portions copyright (c) 2001,2002 Sun Microsystems (thockin@sun.com)
   8 *
   9 * This driver allows you to access the contents of the non-volatile memory in
  10 * the mc146818rtc.h real-time clock. This chip is built into all PCs and into
  11 * many Atari machines. In the former it's called "CMOS-RAM", in the latter
  12 * "NVRAM" (NV stands for non-volatile).
  13 *
  14 * The data are supplied as a (seekable) character device, /dev/nvram. The
  15 * size of this file is dependent on the controller.  The usual size is 114,
  16 * the number of freely available bytes in the memory (i.e., not used by the
  17 * RTC itself).
  18 *
  19 * Checksums over the NVRAM contents are managed by this driver. In case of a
  20 * bad checksum, reads and writes return -EIO. The checksum can be initialized
  21 * to a sane state either by ioctl(NVRAM_INIT) (clear whole NVRAM) or
  22 * ioctl(NVRAM_SETCKS) (doesn't change contents, just makes checksum valid
  23 * again; use with care!)
  24 *
  25 *      1.1     Cesar Barros: SMP locking fixes
  26 *              added changelog
  27 *      1.2     Erik Gilling: Cobalt Networks support
  28 *              Tim Hockin: general cleanup, Cobalt support
  29 *      1.3     Wim Van Sebroeck: convert PRINT_PROC to seq_file
  30 */
  31
  32#define NVRAM_VERSION   "1.3"
  33
  34#include <linux/module.h>
  35#include <linux/nvram.h>
  36#include <linux/types.h>
  37#include <linux/errno.h>
  38#include <linux/miscdevice.h>
  39#include <linux/ioport.h>
  40#include <linux/fcntl.h>
  41#include <linux/mc146818rtc.h>
  42#include <linux/init.h>
  43#include <linux/proc_fs.h>
  44#include <linux/seq_file.h>
  45#include <linux/slab.h>
  46#include <linux/spinlock.h>
  47#include <linux/io.h>
  48#include <linux/uaccess.h>
  49#include <linux/mutex.h>
  50#include <linux/pagemap.h>
  51
  52#ifdef CONFIG_PPC
  53#include <asm/nvram.h>
  54#endif
  55
  56static DEFINE_MUTEX(nvram_mutex);
  57static DEFINE_SPINLOCK(nvram_state_lock);
  58static int nvram_open_cnt;      /* #times opened */
  59static int nvram_open_mode;     /* special open modes */
  60static ssize_t nvram_size;
  61#define NVRAM_WRITE             1 /* opened for writing (exclusive) */
  62#define NVRAM_EXCL              2 /* opened with O_EXCL */
  63
  64#ifdef CONFIG_X86
  65/*
  66 * These functions are provided to be called internally or by other parts of
  67 * the kernel. It's up to the caller to ensure correct checksum before reading
  68 * or after writing (needs to be done only once).
  69 *
  70 * It is worth noting that these functions all access bytes of general
  71 * purpose memory in the NVRAM - that is to say, they all add the
  72 * NVRAM_FIRST_BYTE offset.  Pass them offsets into NVRAM as if you did not
  73 * know about the RTC cruft.
  74 */
  75
  76#define NVRAM_BYTES             (128 - NVRAM_FIRST_BYTE)
  77
  78/* Note that *all* calls to CMOS_READ and CMOS_WRITE must be done with
  79 * rtc_lock held. Due to the index-port/data-port design of the RTC, we
  80 * don't want two different things trying to get to it at once. (e.g. the
  81 * periodic 11 min sync from kernel/time/ntp.c vs. this driver.)
  82 */
  83
  84static unsigned char __nvram_read_byte(int i)
  85{
  86        return CMOS_READ(NVRAM_FIRST_BYTE + i);
  87}
  88
  89static unsigned char pc_nvram_read_byte(int i)
  90{
  91        unsigned long flags;
  92        unsigned char c;
  93
  94        spin_lock_irqsave(&rtc_lock, flags);
  95        c = __nvram_read_byte(i);
  96        spin_unlock_irqrestore(&rtc_lock, flags);
  97        return c;
  98}
  99
 100/* This races nicely with trying to read with checksum checking (nvram_read) */
 101static void __nvram_write_byte(unsigned char c, int i)
 102{
 103        CMOS_WRITE(c, NVRAM_FIRST_BYTE + i);
 104}
 105
 106static void pc_nvram_write_byte(unsigned char c, int i)
 107{
 108        unsigned long flags;
 109
 110        spin_lock_irqsave(&rtc_lock, flags);
 111        __nvram_write_byte(c, i);
 112        spin_unlock_irqrestore(&rtc_lock, flags);
 113}
 114
 115/* On PCs, the checksum is built only over bytes 2..31 */
 116#define PC_CKS_RANGE_START      2
 117#define PC_CKS_RANGE_END        31
 118#define PC_CKS_LOC              32
 119
 120static int __nvram_check_checksum(void)
 121{
 122        int i;
 123        unsigned short sum = 0;
 124        unsigned short expect;
 125
 126        for (i = PC_CKS_RANGE_START; i <= PC_CKS_RANGE_END; ++i)
 127                sum += __nvram_read_byte(i);
 128        expect = __nvram_read_byte(PC_CKS_LOC)<<8 |
 129            __nvram_read_byte(PC_CKS_LOC+1);
 130        return (sum & 0xffff) == expect;
 131}
 132
 133static void __nvram_set_checksum(void)
 134{
 135        int i;
 136        unsigned short sum = 0;
 137
 138        for (i = PC_CKS_RANGE_START; i <= PC_CKS_RANGE_END; ++i)
 139                sum += __nvram_read_byte(i);
 140        __nvram_write_byte(sum >> 8, PC_CKS_LOC);
 141        __nvram_write_byte(sum & 0xff, PC_CKS_LOC + 1);
 142}
 143
 144static long pc_nvram_set_checksum(void)
 145{
 146        spin_lock_irq(&rtc_lock);
 147        __nvram_set_checksum();
 148        spin_unlock_irq(&rtc_lock);
 149        return 0;
 150}
 151
 152static long pc_nvram_initialize(void)
 153{
 154        ssize_t i;
 155
 156        spin_lock_irq(&rtc_lock);
 157        for (i = 0; i < NVRAM_BYTES; ++i)
 158                __nvram_write_byte(0, i);
 159        __nvram_set_checksum();
 160        spin_unlock_irq(&rtc_lock);
 161        return 0;
 162}
 163
 164static ssize_t pc_nvram_get_size(void)
 165{
 166        return NVRAM_BYTES;
 167}
 168
 169static ssize_t pc_nvram_read(char *buf, size_t count, loff_t *ppos)
 170{
 171        char *p = buf;
 172        loff_t i;
 173
 174        spin_lock_irq(&rtc_lock);
 175        if (!__nvram_check_checksum()) {
 176                spin_unlock_irq(&rtc_lock);
 177                return -EIO;
 178        }
 179        for (i = *ppos; count > 0 && i < NVRAM_BYTES; --count, ++i, ++p)
 180                *p = __nvram_read_byte(i);
 181        spin_unlock_irq(&rtc_lock);
 182
 183        *ppos = i;
 184        return p - buf;
 185}
 186
 187static ssize_t pc_nvram_write(char *buf, size_t count, loff_t *ppos)
 188{
 189        char *p = buf;
 190        loff_t i;
 191
 192        spin_lock_irq(&rtc_lock);
 193        if (!__nvram_check_checksum()) {
 194                spin_unlock_irq(&rtc_lock);
 195                return -EIO;
 196        }
 197        for (i = *ppos; count > 0 && i < NVRAM_BYTES; --count, ++i, ++p)
 198                __nvram_write_byte(*p, i);
 199        __nvram_set_checksum();
 200        spin_unlock_irq(&rtc_lock);
 201
 202        *ppos = i;
 203        return p - buf;
 204}
 205
 206const struct nvram_ops arch_nvram_ops = {
 207        .read           = pc_nvram_read,
 208        .write          = pc_nvram_write,
 209        .read_byte      = pc_nvram_read_byte,
 210        .write_byte     = pc_nvram_write_byte,
 211        .get_size       = pc_nvram_get_size,
 212        .set_checksum   = pc_nvram_set_checksum,
 213        .initialize     = pc_nvram_initialize,
 214};
 215EXPORT_SYMBOL(arch_nvram_ops);
 216#endif /* CONFIG_X86 */
 217
 218/*
 219 * The are the file operation function for user access to /dev/nvram
 220 */
 221
 222static loff_t nvram_misc_llseek(struct file *file, loff_t offset, int origin)
 223{
 224        return generic_file_llseek_size(file, offset, origin, MAX_LFS_FILESIZE,
 225                                        nvram_size);
 226}
 227
 228static ssize_t nvram_misc_read(struct file *file, char __user *buf,
 229                               size_t count, loff_t *ppos)
 230{
 231        char *tmp;
 232        ssize_t ret;
 233
 234
 235        if (*ppos >= nvram_size)
 236                return 0;
 237
 238        count = min_t(size_t, count, nvram_size - *ppos);
 239        count = min_t(size_t, count, PAGE_SIZE);
 240
 241        tmp = kmalloc(count, GFP_KERNEL);
 242        if (!tmp)
 243                return -ENOMEM;
 244
 245        ret = nvram_read(tmp, count, ppos);
 246        if (ret <= 0)
 247                goto out;
 248
 249        if (copy_to_user(buf, tmp, ret)) {
 250                *ppos -= ret;
 251                ret = -EFAULT;
 252        }
 253
 254out:
 255        kfree(tmp);
 256        return ret;
 257}
 258
 259static ssize_t nvram_misc_write(struct file *file, const char __user *buf,
 260                                size_t count, loff_t *ppos)
 261{
 262        char *tmp;
 263        ssize_t ret;
 264
 265        if (*ppos >= nvram_size)
 266                return 0;
 267
 268        count = min_t(size_t, count, nvram_size - *ppos);
 269        count = min_t(size_t, count, PAGE_SIZE);
 270
 271        tmp = memdup_user(buf, count);
 272        if (IS_ERR(tmp))
 273                return PTR_ERR(tmp);
 274
 275        ret = nvram_write(tmp, count, ppos);
 276        kfree(tmp);
 277        return ret;
 278}
 279
 280static long nvram_misc_ioctl(struct file *file, unsigned int cmd,
 281                             unsigned long arg)
 282{
 283        long ret = -ENOTTY;
 284
 285        switch (cmd) {
 286#ifdef CONFIG_PPC
 287        case OBSOLETE_PMAC_NVRAM_GET_OFFSET:
 288                pr_warn("nvram: Using obsolete PMAC_NVRAM_GET_OFFSET ioctl\n");
 289                fallthrough;
 290        case IOC_NVRAM_GET_OFFSET:
 291                ret = -EINVAL;
 292#ifdef CONFIG_PPC_PMAC
 293                if (machine_is(powermac)) {
 294                        int part, offset;
 295
 296                        if (copy_from_user(&part, (void __user *)arg,
 297                                           sizeof(part)) != 0)
 298                                return -EFAULT;
 299                        if (part < pmac_nvram_OF || part > pmac_nvram_NR)
 300                                return -EINVAL;
 301                        offset = pmac_get_partition(part);
 302                        if (offset < 0)
 303                                return -EINVAL;
 304                        if (copy_to_user((void __user *)arg,
 305                                         &offset, sizeof(offset)) != 0)
 306                                return -EFAULT;
 307                        ret = 0;
 308                }
 309#endif
 310                break;
 311#ifdef CONFIG_PPC32
 312        case IOC_NVRAM_SYNC:
 313                if (ppc_md.nvram_sync != NULL) {
 314                        mutex_lock(&nvram_mutex);
 315                        ppc_md.nvram_sync();
 316                        mutex_unlock(&nvram_mutex);
 317                }
 318                ret = 0;
 319                break;
 320#endif
 321#elif defined(CONFIG_X86) || defined(CONFIG_M68K)
 322        case NVRAM_INIT:
 323                /* initialize NVRAM contents and checksum */
 324                if (!capable(CAP_SYS_ADMIN))
 325                        return -EACCES;
 326
 327                if (arch_nvram_ops.initialize != NULL) {
 328                        mutex_lock(&nvram_mutex);
 329                        ret = arch_nvram_ops.initialize();
 330                        mutex_unlock(&nvram_mutex);
 331                }
 332                break;
 333        case NVRAM_SETCKS:
 334                /* just set checksum, contents unchanged (maybe useful after
 335                 * checksum garbaged somehow...) */
 336                if (!capable(CAP_SYS_ADMIN))
 337                        return -EACCES;
 338
 339                if (arch_nvram_ops.set_checksum != NULL) {
 340                        mutex_lock(&nvram_mutex);
 341                        ret = arch_nvram_ops.set_checksum();
 342                        mutex_unlock(&nvram_mutex);
 343                }
 344                break;
 345#endif /* CONFIG_X86 || CONFIG_M68K */
 346        }
 347        return ret;
 348}
 349
 350static int nvram_misc_open(struct inode *inode, struct file *file)
 351{
 352        spin_lock(&nvram_state_lock);
 353
 354        /* Prevent multiple readers/writers if desired. */
 355        if ((nvram_open_cnt && (file->f_flags & O_EXCL)) ||
 356            (nvram_open_mode & NVRAM_EXCL)) {
 357                spin_unlock(&nvram_state_lock);
 358                return -EBUSY;
 359        }
 360
 361#if defined(CONFIG_X86) || defined(CONFIG_M68K)
 362        /* Prevent multiple writers if the set_checksum ioctl is implemented. */
 363        if ((arch_nvram_ops.set_checksum != NULL) &&
 364            (file->f_mode & FMODE_WRITE) && (nvram_open_mode & NVRAM_WRITE)) {
 365                spin_unlock(&nvram_state_lock);
 366                return -EBUSY;
 367        }
 368#endif
 369
 370        if (file->f_flags & O_EXCL)
 371                nvram_open_mode |= NVRAM_EXCL;
 372        if (file->f_mode & FMODE_WRITE)
 373                nvram_open_mode |= NVRAM_WRITE;
 374        nvram_open_cnt++;
 375
 376        spin_unlock(&nvram_state_lock);
 377
 378        return 0;
 379}
 380
 381static int nvram_misc_release(struct inode *inode, struct file *file)
 382{
 383        spin_lock(&nvram_state_lock);
 384
 385        nvram_open_cnt--;
 386
 387        /* if only one instance is open, clear the EXCL bit */
 388        if (nvram_open_mode & NVRAM_EXCL)
 389                nvram_open_mode &= ~NVRAM_EXCL;
 390        if (file->f_mode & FMODE_WRITE)
 391                nvram_open_mode &= ~NVRAM_WRITE;
 392
 393        spin_unlock(&nvram_state_lock);
 394
 395        return 0;
 396}
 397
 398#if defined(CONFIG_X86) && defined(CONFIG_PROC_FS)
 399static const char * const floppy_types[] = {
 400        "none", "5.25'' 360k", "5.25'' 1.2M", "3.5'' 720k", "3.5'' 1.44M",
 401        "3.5'' 2.88M", "3.5'' 2.88M"
 402};
 403
 404static const char * const gfx_types[] = {
 405        "EGA, VGA, ... (with BIOS)",
 406        "CGA (40 cols)",
 407        "CGA (80 cols)",
 408        "monochrome",
 409};
 410
 411static void pc_nvram_proc_read(unsigned char *nvram, struct seq_file *seq,
 412                               void *offset)
 413{
 414        int checksum;
 415        int type;
 416
 417        spin_lock_irq(&rtc_lock);
 418        checksum = __nvram_check_checksum();
 419        spin_unlock_irq(&rtc_lock);
 420
 421        seq_printf(seq, "Checksum status: %svalid\n", checksum ? "" : "not ");
 422
 423        seq_printf(seq, "# floppies     : %d\n",
 424            (nvram[6] & 1) ? (nvram[6] >> 6) + 1 : 0);
 425        seq_printf(seq, "Floppy 0 type  : ");
 426        type = nvram[2] >> 4;
 427        if (type < ARRAY_SIZE(floppy_types))
 428                seq_printf(seq, "%s\n", floppy_types[type]);
 429        else
 430                seq_printf(seq, "%d (unknown)\n", type);
 431        seq_printf(seq, "Floppy 1 type  : ");
 432        type = nvram[2] & 0x0f;
 433        if (type < ARRAY_SIZE(floppy_types))
 434                seq_printf(seq, "%s\n", floppy_types[type]);
 435        else
 436                seq_printf(seq, "%d (unknown)\n", type);
 437
 438        seq_printf(seq, "HD 0 type      : ");
 439        type = nvram[4] >> 4;
 440        if (type)
 441                seq_printf(seq, "%02x\n", type == 0x0f ? nvram[11] : type);
 442        else
 443                seq_printf(seq, "none\n");
 444
 445        seq_printf(seq, "HD 1 type      : ");
 446        type = nvram[4] & 0x0f;
 447        if (type)
 448                seq_printf(seq, "%02x\n", type == 0x0f ? nvram[12] : type);
 449        else
 450                seq_printf(seq, "none\n");
 451
 452        seq_printf(seq, "HD type 48 data: %d/%d/%d C/H/S, precomp %d, lz %d\n",
 453            nvram[18] | (nvram[19] << 8),
 454            nvram[20], nvram[25],
 455            nvram[21] | (nvram[22] << 8), nvram[23] | (nvram[24] << 8));
 456        seq_printf(seq, "HD type 49 data: %d/%d/%d C/H/S, precomp %d, lz %d\n",
 457            nvram[39] | (nvram[40] << 8),
 458            nvram[41], nvram[46],
 459            nvram[42] | (nvram[43] << 8), nvram[44] | (nvram[45] << 8));
 460
 461        seq_printf(seq, "DOS base memory: %d kB\n", nvram[7] | (nvram[8] << 8));
 462        seq_printf(seq, "Extended memory: %d kB (configured), %d kB (tested)\n",
 463            nvram[9] | (nvram[10] << 8), nvram[34] | (nvram[35] << 8));
 464
 465        seq_printf(seq, "Gfx adapter    : %s\n",
 466            gfx_types[(nvram[6] >> 4) & 3]);
 467
 468        seq_printf(seq, "FPU            : %sinstalled\n",
 469            (nvram[6] & 2) ? "" : "not ");
 470
 471        return;
 472}
 473
 474static int nvram_proc_read(struct seq_file *seq, void *offset)
 475{
 476        unsigned char contents[NVRAM_BYTES];
 477        int i = 0;
 478
 479        spin_lock_irq(&rtc_lock);
 480        for (i = 0; i < NVRAM_BYTES; ++i)
 481                contents[i] = __nvram_read_byte(i);
 482        spin_unlock_irq(&rtc_lock);
 483
 484        pc_nvram_proc_read(contents, seq, offset);
 485
 486        return 0;
 487}
 488#endif /* CONFIG_X86 && CONFIG_PROC_FS */
 489
 490static const struct file_operations nvram_misc_fops = {
 491        .owner          = THIS_MODULE,
 492        .llseek         = nvram_misc_llseek,
 493        .read           = nvram_misc_read,
 494        .write          = nvram_misc_write,
 495        .unlocked_ioctl = nvram_misc_ioctl,
 496        .open           = nvram_misc_open,
 497        .release        = nvram_misc_release,
 498};
 499
 500static struct miscdevice nvram_misc = {
 501        NVRAM_MINOR,
 502        "nvram",
 503        &nvram_misc_fops,
 504};
 505
 506static int __init nvram_module_init(void)
 507{
 508        int ret;
 509
 510        nvram_size = nvram_get_size();
 511        if (nvram_size < 0)
 512                return nvram_size;
 513
 514        ret = misc_register(&nvram_misc);
 515        if (ret) {
 516                pr_err("nvram: can't misc_register on minor=%d\n", NVRAM_MINOR);
 517                return ret;
 518        }
 519
 520#if defined(CONFIG_X86) && defined(CONFIG_PROC_FS)
 521        if (!proc_create_single("driver/nvram", 0, NULL, nvram_proc_read)) {
 522                pr_err("nvram: can't create /proc/driver/nvram\n");
 523                misc_deregister(&nvram_misc);
 524                return -ENOMEM;
 525        }
 526#endif
 527
 528        pr_info("Non-volatile memory driver v" NVRAM_VERSION "\n");
 529        return 0;
 530}
 531
 532static void __exit nvram_module_exit(void)
 533{
 534#if defined(CONFIG_X86) && defined(CONFIG_PROC_FS)
 535        remove_proc_entry("driver/nvram", NULL);
 536#endif
 537        misc_deregister(&nvram_misc);
 538}
 539
 540module_init(nvram_module_init);
 541module_exit(nvram_module_exit);
 542
 543MODULE_LICENSE("GPL");
 544MODULE_ALIAS_MISCDEV(NVRAM_MINOR);
 545MODULE_ALIAS("devname:nvram");
 546