1 /* $OpenBSD: nvram.c,v 1.7 2023/01/30 10:49:05 jsg Exp $ */
2
3 /*
4 * Copyright (c) 2004 Joshua Stein <jcs@openbsd.org>
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28 #include <sys/param.h>
29 #include <sys/systm.h>
30 #include <sys/uio.h>
31 #include <sys/fcntl.h>
32
33 #include <dev/ic/mc146818reg.h>
34
35 /* checksum is calculated over bytes 2 to 31 and stored in byte 32 */
36 #define NVRAM_CSUM_START (MC_NVRAM_START + 2)
37 #define NVRAM_CSUM_END (MC_NVRAM_START + 31)
38 #define NVRAM_CSUM_LOC (MC_NVRAM_START + 32)
39
40 #define NVRAM_SIZE (128 - MC_NVRAM_START)
41
42 /* #define NVRAM_DEBUG 1 */
43
44 void nvramattach(int);
45
46 int nvramopen(dev_t dev, int flag, int mode, struct proc *p);
47 int nvramclose(dev_t dev, int flag, int mode, struct proc *p);
48 int nvramread(dev_t dev, struct uio *uio, int flags);
49
50 int nvram_csum_valid(void);
51 int nvram_get_byte(int byteno);
52
53 static int nvram_initialized;
54
55 void
nvramattach(int num)56 nvramattach(int num)
57 {
58 if (num > 1)
59 return;
60
61 if (nvram_initialized || nvram_csum_valid()) {
62 #ifdef NVRAM_DEBUG
63 printf("nvram: initialized\n");
64 #endif
65 nvram_initialized = 1;
66 } else
67 printf("nvram: invalid checksum\n");
68 }
69
70 int
nvramopen(dev_t dev,int flag,int mode,struct proc * p)71 nvramopen(dev_t dev, int flag, int mode, struct proc *p)
72 {
73 /* TODO: re-calc checksum on every open? */
74
75 if ((minor(dev) != 0) || (!nvram_initialized))
76 return (ENXIO);
77
78 if ((flag & FWRITE))
79 return (EPERM);
80
81 return (0);
82 }
83
84 int
nvramclose(dev_t dev,int flag,int mode,struct proc * p)85 nvramclose(dev_t dev, int flag, int mode, struct proc *p)
86 {
87 return (0);
88 }
89
90 int
nvramread(dev_t dev,struct uio * uio,int flags)91 nvramread(dev_t dev, struct uio *uio, int flags)
92 {
93 u_char buf[NVRAM_SIZE];
94 off_t pos = uio->uio_offset;
95 u_char *tmp;
96 size_t count = ulmin(sizeof(buf), uio->uio_resid);
97 int ret;
98
99 if (!nvram_initialized)
100 return (ENXIO);
101
102 if (uio->uio_offset < 0)
103 return (EINVAL);
104
105 if (uio->uio_resid == 0)
106 return (0);
107
108 #ifdef NVRAM_DEBUG
109 printf("attempting to read %zu bytes at offset %lld\n", count, pos);
110 #endif
111
112 for (tmp = buf; count-- > 0 && pos < NVRAM_SIZE; ++pos, ++tmp)
113 *tmp = nvram_get_byte(pos);
114
115 #ifdef NVRAM_DEBUG
116 printf("nvramread read %td bytes (%s)\n", (tmp - buf), tmp);
117 #endif
118
119 ret = uiomove(buf, (tmp - buf), uio);
120
121 uio->uio_offset += uio->uio_resid;
122
123 return (ret);
124 }
125
126 int
nvram_get_byte(int byteno)127 nvram_get_byte(int byteno)
128 {
129 if (!nvram_initialized)
130 return (ENXIO);
131
132 return (mc146818_read(NULL, byteno + MC_NVRAM_START) & 0xff);
133 }
134
135 int
nvram_csum_valid(void)136 nvram_csum_valid(void)
137 {
138 u_short csum = 0;
139 u_short csumexpect;
140 int nreg;
141
142 for (nreg = NVRAM_CSUM_START; nreg <= NVRAM_CSUM_END; nreg++)
143 csum += mc146818_read(NULL, nreg);
144
145 csumexpect = mc146818_read(NULL, NVRAM_CSUM_LOC) << 8 |
146 mc146818_read(NULL, NVRAM_CSUM_LOC + 1);
147
148 #ifdef NVRAM_DEBUG
149 printf("nvram: checksum is %x, expecting %x\n", (csum & 0xffff),
150 csumexpect);
151 #endif
152
153 return ((csum & 0xffff) == csumexpect);
154 }
155