]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/nvram/nvram.c
Merge from vendor/bind9/dist as of the 9.4.2-P1 import, including
[FreeBSD/FreeBSD.git] / sys / dev / nvram / nvram.c
1 /*-
2  * Copyright (c) 2007 Peter Wemm
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  * $FreeBSD$
27  */
28
29 #include <sys/param.h>
30 #include <sys/systm.h>
31 #include <sys/kernel.h>
32 #include <sys/conf.h>
33 #include <sys/fcntl.h>
34 #include <sys/proc.h>
35 #include <sys/uio.h>
36 #include <sys/module.h>
37
38 #include <isa/rtc.h>
39
40 /*
41  * Linux-style /dev/nvram driver
42  *
43  * cmos ram starts at bytes 14 through 128, for a total of 114 bytes.
44  * The driver exposes byte 14 as file offset 0.
45  *
46  * Offsets 2 through 31 are checksummed at offset 32, 33.
47  * In order to avoid the possibility of making the machine unbootable at the
48  * bios level (press F1 to continue!), we refuse to allow writes if we do
49  * not see a pre-existing valid checksum.  If the existing sum is invalid,
50  * then presumably we do not know how to make a sum that the bios will accept.
51  */
52
53 #define NVRAM_FIRST     RTC_DIAG        /* 14 */
54 #define NVRAM_LAST      128
55
56 #define CKSUM_FIRST     2
57 #define CKSUM_LAST      31
58 #define CKSUM_MSB       32
59 #define CKSUM_LSB       33
60
61 static d_open_t         nvram_open;
62 static d_read_t         nvram_read;
63 static d_write_t        nvram_write;
64
65 static struct cdev *nvram_dev;
66
67 static struct cdevsw nvram_cdevsw = {
68         .d_version =    D_VERSION,
69         .d_flags =      D_NEEDGIANT,
70         .d_open =       nvram_open,
71         .d_read =       nvram_read,
72         .d_write =      nvram_write,
73         .d_name =       "nvram",
74 };
75
76 static int
77 nvram_open(struct cdev *dev __unused, int flags, int fmt __unused,
78     struct thread *td)
79 {
80         int error = 0;
81
82         if (flags & FWRITE)
83                 error = securelevel_gt(td->td_ucred, 0);
84
85         return (error);
86 }
87
88 static int
89 nvram_read(struct cdev *dev, struct uio *uio, int flags)
90 {
91         int nv_off;
92         u_char v;
93         int error = 0;
94
95         while (uio->uio_resid > 0 && error == 0) {
96                 nv_off = uio->uio_offset + NVRAM_FIRST;
97                 if (nv_off < NVRAM_FIRST || nv_off >= NVRAM_LAST)
98                         return (0);     /* Signal EOF */
99                 /* Single byte at a time */
100                 v = rtcin(nv_off);
101                 error = uiomove(&v, 1, uio);
102         }
103         return (error);
104
105 }
106
107 static int
108 nvram_write(struct cdev *dev, struct uio *uio, int flags)
109 {
110         int nv_off;
111         u_char v;
112         int error = 0;
113         int i;
114         uint16_t sum;
115
116         /* Assert that we understand the existing checksum first!  */
117         sum = rtcin(NVRAM_FIRST + CKSUM_MSB) << 8 |
118               rtcin(NVRAM_FIRST + CKSUM_LSB);
119         for (i = CKSUM_FIRST; i <= CKSUM_LAST; i++)
120                 sum -= rtcin(NVRAM_FIRST + i);
121         if (sum != 0)
122                 return (EIO);
123         /* Bring in user data and write */
124         while (uio->uio_resid > 0 && error == 0) {
125                 nv_off = uio->uio_offset + NVRAM_FIRST;
126                 if (nv_off < NVRAM_FIRST || nv_off >= NVRAM_LAST)
127                         return (0);     /* Signal EOF */
128                 /* Single byte at a time */
129                 error = uiomove(&v, 1, uio);
130                 writertc(nv_off, v);
131         }
132         /* Recalculate checksum afterwards */
133         sum = 0;
134         for (i = CKSUM_FIRST; i <= CKSUM_LAST; i++)
135                 sum += rtcin(NVRAM_FIRST + i);
136         writertc(NVRAM_FIRST + CKSUM_MSB, sum >> 8);
137         writertc(NVRAM_FIRST + CKSUM_LSB, sum);
138         return (error);
139 }
140
141 static int
142 nvram_modevent(module_t mod __unused, int type, void *data __unused)
143 {
144         switch (type) {
145         case MOD_LOAD:
146                 nvram_dev = make_dev(&nvram_cdevsw, 0,
147                     UID_ROOT, GID_KMEM, 0640, "nvram");
148                 break;
149         case MOD_UNLOAD:
150         case MOD_SHUTDOWN:
151                 destroy_dev(nvram_dev);
152                 break;
153         default:
154                 return (EOPNOTSUPP);
155         }
156         return (0);
157 }
158 DEV_MODULE(nvram, nvram_modevent, NULL);