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