nvram2env.c revision 299034
1/*- 2 * Copyright (c) 2010 Aleksandr Rybalko. 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 27/* 28 * Pseudo driver to copy the NVRAM settings from various sources 29 * into the kernel environment. 30 * 31 * Drivers (such as ethernet devices) can then use environment 32 * variables to set default parameters. 33 */ 34 35#include <sys/cdefs.h> 36__FBSDID("$FreeBSD: head/sys/dev/nvram2env/nvram2env.c 299034 2016-05-04 01:56:37Z kan $"); 37 38#include <sys/param.h> 39#include <sys/systm.h> 40#include <sys/bus.h> 41#include <sys/endian.h> 42#include <sys/kernel.h> 43#include <sys/module.h> 44#include <sys/rman.h> 45#include <sys/malloc.h> 46 47#include <machine/bus.h> 48 49#include <dev/siba/siba_ids.h> 50#include <dev/siba/sibareg.h> 51#include <dev/siba/sibavar.h> 52 53#define nvram2env_read_1(sc, reg) \ 54 bus_space_read_1((sc)->sc_bt, (sc)->sc_bh,(reg)) 55 56#define nvram2env_read_2(sc, reg) \ 57 bus_space_read_2((sc)->sc_bt, (sc)->sc_bh,(reg)) 58 59#define nvram2env_read_4(sc, reg) \ 60 bus_space_read_4((sc)->sc_bt, (sc)->sc_bh,(reg)) 61 62#define nvram2env_write_1(sc, reg, val) \ 63 bus_space_write_1((sc)->sc_bt, (sc)->sc_bh, \ 64 (reg), (val)) 65 66#define nvram2env_write_2(sc, reg, val) \ 67 bus_space_write_2((sc)->sc_bt, (sc)->sc_bh, \ 68 (reg), (val)) 69 70#define nvram2env_write_4(sc, reg, val) \ 71 bus_space_write_4((sc)->sc_bt, (sc)->sc_bh, \ 72 (reg), (val)) 73 74struct nvram2env_softc { 75 bus_space_tag_t bst; 76 bus_space_handle_t bsh; 77 bus_addr_t addr; 78 int need_swap; 79 uint32_t sig; 80 uint32_t flags; 81#define NVRAM_FLAGS_NOCHECK 0x0001 /* Do not check(CRC or somthing else)*/ 82#define NVRAM_FLAGS_GENERIC 0x0002 /* Format Generic, skip 4b and read */ 83#define NVRAM_FLAGS_BROADCOM 0x0004 /* Format Broadcom, use struct nvram */ 84#define NVRAM_FLAGS_UBOOT 0x0008 /* Format Generic, skip 4b of CRC and read */ 85 uint32_t maxsize; 86 uint32_t crc; 87}; 88 89static int nvram2env_attach(device_t); 90static int nvram2env_probe(device_t); 91 92#define NVRAM_MAX_SIZE 0x10000 93 94static void 95nvram2env_identify(driver_t * drv, device_t parent) 96{ 97 int i, ivar; 98 99 for (i = 0; !resource_int_value("nvram", i, "base", &ivar); i++) 100 BUS_ADD_CHILD(parent, 0, "nvram2env", i); 101} 102 103static int 104nvram2env_probe(device_t dev) 105{ 106 uint32_t i, ivar, sig; 107 struct nvram2env_softc * sc = device_get_softc(dev); 108 sc->bst = mips_bus_space_generic; 109 110 if (resource_int_value("nvram", device_get_unit(dev), "sig", 111 &sc->sig) != 0 || sc->sig == 0) 112 sc->sig = 0x48534c46; 113 114 if (resource_int_value("nvram", device_get_unit(dev), "maxsize", 115 &sc->maxsize) != 0 || sc->maxsize == 0) 116 sc->maxsize = NVRAM_MAX_SIZE; 117 118 if (resource_int_value("nvram", device_get_unit(dev), "flags", 119 &sc->flags) != 0 || sc->flags == 0) 120 sc->flags = NVRAM_FLAGS_GENERIC; 121 122 123 for (i = 0; i < 2; i ++) 124 { 125 if (resource_int_value("nvram", device_get_unit(dev), 126 (!i)?"base":"fallbackbase", &ivar) != 0 || 127 ivar == 0) 128 continue; 129 130 sc->addr = ivar; 131 132 if (bootverbose) 133 device_printf(dev, "base=0x%08x sig=0x%08x " 134 "maxsize=0x%08x flags=0x%08x\n", 135 sc->addr, sc->sig, sc->maxsize, sc->flags); 136 137 if (bus_space_map(sc->bst, sc->addr, sc->maxsize, 0, 138 &sc->bsh) != 0) 139 continue; 140 141 sig = bus_space_read_4(sc->bst, sc->bsh, 0); 142 if ( sig == sc->sig /*FLSH*/) 143 { 144 device_printf(dev, "Found NVRAM at %#x\n", 145 (uint32_t)ivar); 146 sc->need_swap = 0; 147 goto unmap_done; 148 } 149 else if ( htole32(sig) == sc->sig /*HSLF*/) 150 { 151 device_printf(dev, "Found NVRAM at %#x\n", 152 (uint32_t)ivar); 153 sc->need_swap = 1; 154 goto unmap_done; 155 } else if (sc->flags & NVRAM_FLAGS_UBOOT) { 156 device_printf(dev, "Use NVRAM at %#x\n", 157 (uint32_t)ivar); 158 sc->crc = sig; 159 goto unmap_done; 160 } 161 bus_space_unmap(sc->bst, sc->bsh, NVRAM_MAX_SIZE); 162 } 163 sc->bst = 0; 164 sc->bsh = 0; 165 sc->addr = 0; 166 return (ENXIO); 167 168unmap_done: 169 bus_space_unmap(sc->bst, sc->bsh, NVRAM_MAX_SIZE); 170 device_set_desc(dev, "NVRAM to ENV pseudo-device"); 171 return (BUS_PROBE_SPECIFIC); 172 173} 174 175struct nvram { 176 u_int32_t sig; 177 u_int32_t size; 178 u_int32_t unknown1; 179 u_int32_t unknown2; 180 u_int32_t unknown3; 181 char data[]; 182}; 183 184static uint32_t read_4(struct nvram2env_softc * sc, int offset) 185{ 186 if (sc->need_swap) 187 return (bswap32(bus_space_read_4(sc->bst, sc->bsh, offset))); 188 else 189 return (bus_space_read_4(sc->bst, sc->bsh, offset)); 190} 191 192 193static int 194nvram2env_attach(device_t dev) 195{ 196 struct nvram2env_softc * sc = device_get_softc(dev); 197 struct nvram * nv; 198 char *pair, *value, *assign; 199 uint32_t sig, size, i; 200 201 if (sc->bst == 0 || sc->addr == 0) 202 return (ENXIO); 203 204 if (bus_space_map(sc->bst, sc->addr, NVRAM_MAX_SIZE, 0, 205 &sc->bsh) != 0) 206 return (ENXIO); 207 208 sig = read_4(sc, 0); 209 size = read_4(sc, 4); 210#if 1 211 if (bootverbose) 212 device_printf(dev, " size=0x%05x maxsize=0x%05x\n", size, sc->maxsize); 213#endif 214 size = (size > sc->maxsize)?sc->maxsize:size; 215 216 217 if (sig == sc->sig || (sc->flags & NVRAM_FLAGS_UBOOT)) 218 { 219 220 /* align and shift size to 32bit size*/ 221 size += 3; 222 size >>= 2; 223 224 nv = malloc(size<<2, M_DEVBUF, M_WAITOK | M_ZERO); 225 if (!nv) 226 return (ENOMEM); 227 228 for (i = 0; i < size; i ++) 229 ((uint32_t *)nv)[i] = read_4(sc, i<<2); 230 231 if (sc->flags & NVRAM_FLAGS_BROADCOM) { 232 device_printf(dev, "sig = %#x\n", nv->sig); 233 device_printf(dev, "size = %#x\n", nv->size); 234 } 235 236 if (!(sc->flags & NVRAM_FLAGS_NOCHECK)) { 237 /* TODO: need checksum verification */ 238 } 239 240 if (sc->flags & NVRAM_FLAGS_GENERIC) 241 pair = (char*)nv+4; 242 if (sc->flags & NVRAM_FLAGS_UBOOT) 243 pair = (char*)nv+4; 244 else if (sc->flags & NVRAM_FLAGS_BROADCOM) 245 pair = (char*)nv+20; 246 else 247 pair = (char*)nv+4; 248 249 for ( ; 250 (u_int32_t)pair < ((u_int32_t)nv + size - 4); 251 pair = pair + strlen(pair) + 1 + strlen(value) + 1 ) { 252 253 if (pair && strlen(pair)) { 254 255#if 0 256 printf("ENV: %s\n", pair); 257#endif 258 /* hint.nvram.0. */ 259 assign = strchr(pair,'='); 260 assign[0] = '\0'; 261 value = assign+1; 262#if 1 263 if (bootverbose) 264 printf("ENV: %s=%s\n", pair, value); 265#endif 266 kern_setenv(pair, value); 267 268 if (strcasecmp(pair, "WAN_MAC_ADDR") == 0) { 269 /* Alias for MAC address of eth0 */ 270 if (bootverbose) 271 printf("ENV: aliasing " 272 "WAN_MAC_ADDR to ethaddr" 273 " = %s\n", value); 274 kern_setenv("ethaddr", value); 275 } 276 else if (strcasecmp(pair, "LAN_MAC_ADDR") == 0){ 277 /* Alias for MAC address of eth1 */ 278 if (bootverbose) 279 printf("ENV: aliasing " 280 "LAN_MAC_ADDR to eth1addr" 281 " = %s\n", value); 282 kern_setenv("eth1addr", value); 283 } 284 285 if (strcmp(pair, "bootverbose") == 0) 286 bootverbose = strtoul(value, 0, 0); 287 if (strcmp(pair, "boothowto" ) == 0) 288 boothowto = strtoul(value, 0, 0); 289 } 290 else 291 break; 292 } 293 free(nv, M_DEVBUF); 294 } 295 296 bus_space_unmap(sc->bst, sc->bsh, NVRAM_MAX_SIZE); 297 298 return (0); 299} 300 301static device_method_t nvram2env_methods[] = { 302 /* Device interface */ 303 DEVMETHOD(device_identify, nvram2env_identify), 304 DEVMETHOD(device_probe, nvram2env_probe), 305 DEVMETHOD(device_attach, nvram2env_attach), 306 307 DEVMETHOD_END 308}; 309 310static driver_t nvram2env_driver = { 311 "nvram2env", 312 nvram2env_methods, 313 sizeof(struct nvram2env_softc), 314}; 315static devclass_t nvram2env_devclass; 316 317DRIVER_MODULE(nvram2env, nexus, nvram2env_driver, nvram2env_devclass, 0, 0); 318 319