1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2010 Aleksandr Rybalko.
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 AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28 
29 /*
30  * Pseudo driver to copy the NVRAM settings from various sources
31  * into the kernel environment.
32  *
33  * Drivers (such as ethernet devices) can then use environment
34  * variables to set default parameters.
35  */
36 
37 #include <sys/cdefs.h>
38 __FBSDID("$FreeBSD: stable/12/sys/dev/nvram2env/nvram2env.c 326255 2017-11-27 14:52:40Z pfg $");
39 
40 #include <sys/param.h>
41 #include <sys/systm.h>
42 #include <sys/bus.h>
43 #include <sys/endian.h>
44 #include <sys/kernel.h>
45 #include <sys/module.h>
46 #include <sys/rman.h>
47 #include <sys/malloc.h>
48 
49 #include <machine/bus.h>
50 
51 #include "nvram2env.h"
52 
53 static void
nvram2env_identify(driver_t * drv,device_t parent)54 nvram2env_identify(driver_t * drv, device_t parent)
55 {
56 	int i, ivar;
57 
58 	for (i = 0; !resource_int_value("nvram", i, "base", &ivar); i++)
59 		BUS_ADD_CHILD(parent, 0, "nvram2env", i);
60 }
61 
62 int
nvram2env_probe(device_t dev)63 nvram2env_probe(device_t dev)
64 {
65 	uint32_t i, ivar, sig;
66 	struct nvram2env_softc * sc = device_get_softc(dev);
67 
68 	/*
69 	 * Please ensure that your implementation of NVRAM->ENV specifies
70 	 * bus tag
71 	 */
72 	if (sc->bst == NULL)
73 		return (ENXIO);
74 
75 	if (sc->sig == 0)
76 		if (resource_int_value("nvram", device_get_unit(dev), "sig",
77 		    &sc->sig) != 0 || sc->sig == 0)
78 			sc->sig = CFE_NVRAM_SIGNATURE;
79 
80 	if (sc->maxsize == 0)
81 		if (resource_int_value("nvram", device_get_unit(dev), "maxsize",
82 		    &sc->maxsize) != 0 || sc->maxsize == 0)
83 			sc->maxsize = NVRAM_MAX_SIZE;
84 
85 	if (sc->flags == 0)
86 		if (resource_int_value("nvram", device_get_unit(dev), "flags",
87 		    &sc->flags) != 0 || sc->flags == 0)
88 			sc->flags = NVRAM_FLAGS_GENERIC;
89 
90 
91 	for (i = 0; i < 2; i ++)
92 	{
93 		switch (i) {
94 		case 0:
95 			break;
96 		case 1:
97 		case 2:
98 			if (resource_int_value("nvram", device_get_unit(dev),
99 			    (i == 1) ? "base" : "fallbackbase", &ivar) != 0 ||
100 			    ivar == 0)
101 				continue;
102 
103 			sc->addr = ivar;
104 			break;
105 		default:
106 			break;
107 		}
108 
109 		if (sc->addr == 0)
110 			continue;
111 
112 		if (bootverbose)
113 			device_printf(dev, "base=0x%08x sig=0x%08x "
114 			    "maxsize=0x%08x flags=0x%08x\n",
115 			    sc->addr, sc->sig, sc->maxsize, sc->flags);
116 
117 		if (bus_space_map(sc->bst, sc->addr, sc->maxsize, 0,
118 		    &sc->bsh) != 0)
119 			continue;
120 
121 		sig = bus_space_read_4(sc->bst, sc->bsh, 0);
122 		if ( sig == sc->sig /*FLSH*/)
123 		{
124 			device_printf(dev, "Found NVRAM at %#x\n",
125 			    (uint32_t)ivar);
126 			sc->need_swap = 0;
127 			goto unmap_done;
128 		}
129 		else if ( htole32(sig) == sc->sig /*HSLF*/)
130 		{
131 			device_printf(dev, "Found NVRAM at %#x\n",
132 			    (uint32_t)ivar);
133 			sc->need_swap = 1;
134 			goto unmap_done;
135 		} else if (sc->flags & NVRAM_FLAGS_UBOOT) {
136 			device_printf(dev, "Use NVRAM at %#x\n",
137 			    (uint32_t)ivar);
138 			sc->crc = sig;
139 			goto unmap_done;
140 		}
141 		bus_space_unmap(sc->bst, sc->bsh, NVRAM_MAX_SIZE);
142 	}
143 	sc->bst = 0;
144 	sc->bsh = 0;
145 	sc->addr = 0;
146 	return (ENXIO);
147 
148 unmap_done:
149 	bus_space_unmap(sc->bst, sc->bsh, NVRAM_MAX_SIZE);
150 	device_set_desc(dev, "NVRAM to ENV pseudo-device");
151 	return (BUS_PROBE_SPECIFIC);
152 
153 }
154 
read_4(struct nvram2env_softc * sc,int offset)155 static uint32_t read_4(struct nvram2env_softc * sc, int offset)
156 {
157 	if (sc->need_swap)
158 		return (bswap32(bus_space_read_4(sc->bst, sc->bsh, offset)));
159 	else
160 		return (bus_space_read_4(sc->bst, sc->bsh, offset));
161 }
162 
163 
164 int
nvram2env_attach(device_t dev)165 nvram2env_attach(device_t dev)
166 {
167 	struct nvram2env_softc 	*sc;
168 	struct nvram 		*nv;
169 	char *pair, *value, *assign;
170 	uint32_t sig, size, i, *tmp;
171 
172 	sc = device_get_softc(dev);
173 
174 	if (sc->bst == 0 || sc->addr == 0)
175 		return (ENXIO);
176 
177 	if (bus_space_map(sc->bst, sc->addr, NVRAM_MAX_SIZE, 0,
178 		&sc->bsh) != 0)
179 		return (ENXIO);
180 
181 	sig  = read_4(sc, 0);
182 	size = read_4(sc, 4);
183 
184 	if (bootverbose)
185 		device_printf(dev, " size=0x%05x maxsize=0x%05x\n", size,
186 				sc->maxsize);
187 
188 	size = (size > sc->maxsize)?sc->maxsize:size;
189 
190 
191 	if (sig == sc->sig || (sc->flags & NVRAM_FLAGS_UBOOT))
192 	{
193 
194 		/* align size to 32bit size*/
195 		size += 3;
196 		size &= ~3;
197 
198 		nv = malloc(size, M_DEVBUF, M_WAITOK | M_ZERO);
199 		if (!nv)
200 			return (ENOMEM);
201 		/* set tmp pointer to begin of NVRAM */
202 		tmp = (uint32_t *) nv;
203 
204 		/* use read_4 to swap bytes if it's required */
205 		for (i = 0; i < size; i += 4) {
206 			*tmp = read_4(sc, i);
207 			tmp++;
208 		}
209 		/* now tmp pointer is end of NVRAM */
210 
211 		if (sc->flags & NVRAM_FLAGS_BROADCOM) {
212 			device_printf(dev, "sig = %#x\n",  nv->sig);
213 			device_printf(dev, "size = %#x\n", nv->size);
214 		}
215 
216 		if (!(sc->flags & NVRAM_FLAGS_NOCHECK)) {
217 			/* TODO: need checksum verification */
218 		}
219 
220 		if (sc->flags & NVRAM_FLAGS_GENERIC)
221 			pair = (char*)nv+4;
222 		if (sc->flags & NVRAM_FLAGS_UBOOT)
223 			pair = (char*)nv+4;
224 		else if (sc->flags & NVRAM_FLAGS_BROADCOM)
225 			pair = (char*)nv+20;
226 		else
227 			pair = (char*)nv+4;
228 
229 		/* iterate over buffer till end. tmp points to end of NVRAM */
230 		for ( ; pair < (char*)tmp;
231 		    pair += strlen(pair) + strlen(value) + 2 ) {
232 
233 			if (!pair || (strlen(pair) == 0))
234 				break;
235 
236 			/* hint.nvram.0. */
237 			assign = strchr(pair,'=');
238 			assign[0] = '\0';
239 			value = assign+1;
240 
241 			if (bootverbose)
242 				printf("ENV[%p]: %s=%s\n",
243 				    (void*)((char*)pair - (char*)nv),
244 				    pair, value);
245 
246 			kern_setenv(pair, value);
247 
248 			if (strcasecmp(pair, "WAN_MAC_ADDR") == 0) {
249 				/* Alias for MAC address of eth0 */
250 				if (bootverbose)
251 					printf("ENV: aliasing "
252 					    "WAN_MAC_ADDR to ethaddr"
253 					    " = %s\n",  value);
254 				kern_setenv("ethaddr", value);
255 			}
256 			else if (strcasecmp(pair, "LAN_MAC_ADDR") == 0){
257 				/* Alias for MAC address of eth1 */
258 				if (bootverbose)
259 					printf("ENV: aliasing "
260 					    "LAN_MAC_ADDR to eth1addr"
261 					    " = %s\n",  value);
262 				kern_setenv("eth1addr", value);
263 			}
264 
265 			if (strcmp(pair, "bootverbose") == 0)
266 				bootverbose = strtoul(value, 0, 0);
267 			if (strcmp(pair, "boothowto"  ) == 0)
268 				boothowto   = strtoul(value, 0, 0);
269 
270 		}
271 		free(nv, M_DEVBUF);
272 	}
273 
274 	bus_space_unmap(sc->bst, sc->bsh, NVRAM_MAX_SIZE);
275 
276 	return (0);
277 }
278 
279 static device_method_t nvram2env_methods[] = {
280 	/* Device interface */
281 	DEVMETHOD(device_identify, 	nvram2env_identify),
282 	DEVMETHOD(device_probe,		nvram2env_probe),
283 	DEVMETHOD(device_attach,	nvram2env_attach),
284 
285 	DEVMETHOD_END
286 };
287 
288 driver_t nvram2env_driver = {
289 	"nvram2env",
290 	nvram2env_methods,
291 	sizeof(struct nvram2env_softc),
292 };
293 
294 devclass_t nvram2env_devclass;
295