xref: /openbsd-src/sys/arch/i386/i386/nvram.c (revision f4e7063748a2ac72b2bab4389c0a7efc72d82189)
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