Index: head/share/man/man4/man4.powerpc/powermac_nvram.4 =================================================================== --- head/share/man/man4/man4.powerpc/powermac_nvram.4 (revision 362405) +++ head/share/man/man4/man4.powerpc/powermac_nvram.4 (revision 362406) @@ -1,65 +1,67 @@ .\"- .\" Copyright (c) 2006 Maxim Sobolev .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR .\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE .\" DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, .\" INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES .\" (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR .\" SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, .\" STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN .\" ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE .\" POSSIBILITY OF SUCH DAMAGE. .\" .\" $FreeBSD$ .\" -.Dd September 5, 2010 +.Dd June 19, 2020 .Dt POWERMAC_NVRAM 4 powerpc .Os .Sh NAME .Nm powermac_nvram .Nd "non-volatile RAM" .Sh SYNOPSIS To compile this driver into the kernel, place the following line in your kernel configuration file: .Bd -ragged -offset indent .Cd "device powermac_nvram" .Ed .Pp Alternatively, to load the driver as a module at boot time, place the following line in .Xr loader.conf 5 : .Bd -literal -offset indent powermac_nvram_load="YES" .Ed .Sh DESCRIPTION The .Nm driver provides access to the Open Firmware configuration NVRAM available on the Apple PowerPC-based machines. +.Pp +This driver currently supports "Core99" machines containing a Sharp, Micron, +or AMD NVRAM. .Sh SEE ALSO -.Xr eeprom 8 , .Xr nvram 8 .Sh HISTORY The .Nm driver first appeared in .Fx 7.0 . .Sh AUTHORS The .Nm driver was written by .An Maxim Sobolev Aq Mt sobomax@FreeBSD.org . Index: head/sys/dev/powermac_nvram/powermac_nvram.c =================================================================== --- head/sys/dev/powermac_nvram/powermac_nvram.c (revision 362405) +++ head/sys/dev/powermac_nvram/powermac_nvram.c (revision 362406) @@ -1,519 +1,546 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2006 Maxim Sobolev * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD$ */ #include #include #include #include #include #include +#include +#include #include #include #include #include #include #include #include #include #include #include #include #include /* * Device interface. */ static int powermac_nvram_probe(device_t); static int powermac_nvram_attach(device_t); static int powermac_nvram_detach(device_t); /* Helper functions */ static int powermac_nvram_check(void *data); static int chrp_checksum(int sum, uint8_t *, uint8_t *); static uint32_t adler_checksum(uint8_t *, int); static int erase_bank(device_t, uint8_t *); static int write_bank(device_t, uint8_t *, uint8_t *); /* * Driver methods. */ static device_method_t powermac_nvram_methods[] = { /* Device interface */ DEVMETHOD(device_probe, powermac_nvram_probe), DEVMETHOD(device_attach, powermac_nvram_attach), DEVMETHOD(device_detach, powermac_nvram_detach), { 0, 0 } }; static driver_t powermac_nvram_driver = { "powermac_nvram", powermac_nvram_methods, sizeof(struct powermac_nvram_softc) }; static devclass_t powermac_nvram_devclass; DRIVER_MODULE(powermac_nvram, ofwbus, powermac_nvram_driver, powermac_nvram_devclass, 0, 0); /* * Cdev methods. */ static d_open_t powermac_nvram_open; static d_close_t powermac_nvram_close; static d_read_t powermac_nvram_read; static d_write_t powermac_nvram_write; static struct cdevsw powermac_nvram_cdevsw = { .d_version = D_VERSION, - .d_flags = D_NEEDGIANT, .d_open = powermac_nvram_open, .d_close = powermac_nvram_close, .d_read = powermac_nvram_read, .d_write = powermac_nvram_write, .d_name = "powermac_nvram", }; static int powermac_nvram_probe(device_t dev) { const char *type, *compatible; type = ofw_bus_get_type(dev); compatible = ofw_bus_get_compat(dev); if (type == NULL || compatible == NULL) return ENXIO; if (strcmp(type, "nvram") != 0) return ENXIO; if (strcmp(compatible, "amd-0137") != 0 && !ofw_bus_is_compatible(dev, "nvram,flash")) return ENXIO; device_set_desc(dev, "Apple NVRAM"); return 0; } static int powermac_nvram_attach(device_t dev) { struct powermac_nvram_softc *sc; const char *compatible; phandle_t node; u_int32_t reg[3]; int gen0, gen1, i; node = ofw_bus_get_node(dev); sc = device_get_softc(dev); if ((i = OF_getprop(node, "reg", reg, sizeof(reg))) < 8) return ENXIO; sc->sc_dev = dev; sc->sc_node = node; compatible = ofw_bus_get_compat(dev); if (strcmp(compatible, "amd-0137") == 0) sc->sc_type = FLASH_TYPE_AMD; else sc->sc_type = FLASH_TYPE_SM; /* * Find which byte of reg corresponds to the 32-bit physical address. * We should probably read #address-cells from /chosen instead. */ i = (i/4) - 2; sc->sc_bank0 = (vm_offset_t)pmap_mapdev(reg[i], NVRAM_SIZE * 2); sc->sc_bank1 = sc->sc_bank0 + NVRAM_SIZE; gen0 = powermac_nvram_check((void *)sc->sc_bank0); gen1 = powermac_nvram_check((void *)sc->sc_bank1); if (gen0 == -1 && gen1 == -1) { if ((void *)sc->sc_bank0 != NULL) pmap_unmapdev(sc->sc_bank0, NVRAM_SIZE * 2); device_printf(dev, "both banks appear to be corrupt\n"); return ENXIO; } device_printf(dev, "bank0 generation %d, bank1 generation %d\n", gen0, gen1); sc->sc_bank = (gen0 > gen1) ? sc->sc_bank0 : sc->sc_bank1; bcopy((void *)sc->sc_bank, (void *)sc->sc_data, NVRAM_SIZE); sc->sc_cdev = make_dev(&powermac_nvram_cdevsw, 0, 0, 0, 0600, "powermac_nvram"); sc->sc_cdev->si_drv1 = sc; + sx_init(&sc->sc_lock, "powermac_nvram"); + return 0; } static int powermac_nvram_detach(device_t dev) { struct powermac_nvram_softc *sc; sc = device_get_softc(dev); if ((void *)sc->sc_bank0 != NULL) pmap_unmapdev(sc->sc_bank0, NVRAM_SIZE * 2); if (sc->sc_cdev != NULL) destroy_dev(sc->sc_cdev); + + sx_destroy(&sc->sc_lock); return 0; } static int powermac_nvram_open(struct cdev *dev, int flags, int fmt, struct thread *td) { struct powermac_nvram_softc *sc = dev->si_drv1; + int err; + err = 0; + sx_xlock(&sc->sc_lock); if (sc->sc_isopen) - return EBUSY; - sc->sc_isopen = 1; + err = EBUSY; + else + sc->sc_isopen = 1; sc->sc_rpos = sc->sc_wpos = 0; + sx_xunlock(&sc->sc_lock); + return 0; } static int powermac_nvram_close(struct cdev *dev, int fflag, int devtype, struct thread *td) { struct powermac_nvram_softc *sc = dev->si_drv1; struct core99_header *header; vm_offset_t bank; + sx_xlock(&sc->sc_lock); if (sc->sc_wpos != sizeof(sc->sc_data)) { /* Short write, restore in-memory copy */ bcopy((void *)sc->sc_bank, (void *)sc->sc_data, NVRAM_SIZE); sc->sc_isopen = 0; + sx_xunlock(&sc->sc_lock); return 0; } header = (struct core99_header *)sc->sc_data; header->generation = ((struct core99_header *)sc->sc_bank)->generation; header->generation++; header->chrp_header.signature = CORE99_SIGNATURE; header->adler_checksum = adler_checksum((uint8_t *)&(header->generation), NVRAM_SIZE - offsetof(struct core99_header, generation)); header->chrp_header.chrp_checksum = chrp_checksum(header->chrp_header.signature, (uint8_t *)&(header->chrp_header.length), (uint8_t *)&(header->adler_checksum)); bank = (sc->sc_bank == sc->sc_bank0) ? sc->sc_bank1 : sc->sc_bank0; if (erase_bank(sc->sc_dev, (uint8_t *)bank) != 0 || write_bank(sc->sc_dev, (uint8_t *)bank, sc->sc_data) != 0) { sc->sc_isopen = 0; + sx_xunlock(&sc->sc_lock); return ENOSPC; } sc->sc_bank = bank; sc->sc_isopen = 0; + sx_xunlock(&sc->sc_lock); return 0; } static int powermac_nvram_read(struct cdev *dev, struct uio *uio, int ioflag) { int rv, amnt, data_available; struct powermac_nvram_softc *sc = dev->si_drv1; rv = 0; + + sx_xlock(&sc->sc_lock); while (uio->uio_resid > 0) { data_available = sizeof(sc->sc_data) - sc->sc_rpos; if (data_available > 0) { amnt = MIN(uio->uio_resid, data_available); rv = uiomove((void *)(sc->sc_data + sc->sc_rpos), amnt, uio); if (rv != 0) break; sc->sc_rpos += amnt; } else { break; } } + sx_xunlock(&sc->sc_lock); + return rv; } static int powermac_nvram_write(struct cdev *dev, struct uio *uio, int ioflag) { int rv, amnt, data_available; struct powermac_nvram_softc *sc = dev->si_drv1; if (sc->sc_wpos >= sizeof(sc->sc_data)) return EINVAL; rv = 0; + + sx_xlock(&sc->sc_lock); while (uio->uio_resid > 0) { data_available = sizeof(sc->sc_data) - sc->sc_wpos; if (data_available > 0) { amnt = MIN(uio->uio_resid, data_available); rv = uiomove((void *)(sc->sc_data + sc->sc_wpos), amnt, uio); if (rv != 0) break; sc->sc_wpos += amnt; } else { break; } } + sx_xunlock(&sc->sc_lock); + return rv; } static int powermac_nvram_check(void *data) { struct core99_header *header; header = (struct core99_header *)data; if (header->chrp_header.signature != CORE99_SIGNATURE) return -1; if (header->chrp_header.chrp_checksum != chrp_checksum(header->chrp_header.signature, (uint8_t *)&(header->chrp_header.length), (uint8_t *)&(header->adler_checksum))) return -1; if (header->adler_checksum != adler_checksum((uint8_t *)&(header->generation), NVRAM_SIZE - offsetof(struct core99_header, generation))) return -1; return header->generation; } static int chrp_checksum(int sum, uint8_t *data, uint8_t *end) { for (; data < end; data++) sum += data[0]; while (sum > 0xff) sum = (sum & 0xff) + (sum >> 8); return sum; } static uint32_t adler_checksum(uint8_t *data, int len) { uint32_t low, high; int i; low = 1; high = 0; for (i = 0; i < len; i++) { if ((i % 5000) == 0) { high %= 65521UL; high %= 65521UL; } low += data[i]; high += low; } low %= 65521UL; high %= 65521UL; return (high << 16) | low; } #define OUTB_DELAY(a, v) outb(a, v); DELAY(1); static int wait_operation_complete_amd(uint8_t *bank) { int i; for (i = 1000000; i != 0; i--) if ((inb(bank) ^ inb(bank)) == 0) return 0; return -1; } static int erase_bank_amd(device_t dev, uint8_t *bank) { unsigned int i; /* Unlock 1 */ OUTB_DELAY(bank + 0x555, 0xaa); /* Unlock 2 */ OUTB_DELAY(bank + 0x2aa, 0x55); /* Sector-Erase */ OUTB_DELAY(bank + 0x555, 0x80); OUTB_DELAY(bank + 0x555, 0xaa); OUTB_DELAY(bank + 0x2aa, 0x55); OUTB_DELAY(bank, 0x30); if (wait_operation_complete_amd(bank) != 0) { device_printf(dev, "flash erase timeout\n"); return -1; } /* Reset */ OUTB_DELAY(bank, 0xf0); for (i = 0; i < NVRAM_SIZE; i++) { if (bank[i] != 0xff) { device_printf(dev, "flash erase has failed\n"); return -1; } } return 0; } static int write_bank_amd(device_t dev, uint8_t *bank, uint8_t *data) { unsigned int i; for (i = 0; i < NVRAM_SIZE; i++) { /* Unlock 1 */ OUTB_DELAY(bank + 0x555, 0xaa); /* Unlock 2 */ OUTB_DELAY(bank + 0x2aa, 0x55); /* Write single word */ OUTB_DELAY(bank + 0x555, 0xa0); OUTB_DELAY(bank + i, data[i]); if (wait_operation_complete_amd(bank) != 0) { device_printf(dev, "flash write timeout\n"); return -1; } } /* Reset */ OUTB_DELAY(bank, 0xf0); for (i = 0; i < NVRAM_SIZE; i++) { if (bank[i] != data[i]) { device_printf(dev, "flash write has failed\n"); return -1; } } return 0; } static int wait_operation_complete_sm(uint8_t *bank) { int i; for (i = 1000000; i != 0; i--) { outb(bank, SM_FLASH_CMD_READ_STATUS); if (inb(bank) & SM_FLASH_STATUS_DONE) return (0); } return (-1); } static int erase_bank_sm(device_t dev, uint8_t *bank) { unsigned int i; outb(bank, SM_FLASH_CMD_ERASE_SETUP); outb(bank, SM_FLASH_CMD_ERASE_CONFIRM); if (wait_operation_complete_sm(bank) != 0) { device_printf(dev, "flash erase timeout\n"); return (-1); } outb(bank, SM_FLASH_CMD_CLEAR_STATUS); outb(bank, SM_FLASH_CMD_RESET); for (i = 0; i < NVRAM_SIZE; i++) { if (bank[i] != 0xff) { device_printf(dev, "flash write has failed\n"); return (-1); } } return (0); } static int write_bank_sm(device_t dev, uint8_t *bank, uint8_t *data) { unsigned int i; for (i = 0; i < NVRAM_SIZE; i++) { OUTB_DELAY(bank + i, SM_FLASH_CMD_WRITE_SETUP); outb(bank + i, data[i]); if (wait_operation_complete_sm(bank) != 0) { device_printf(dev, "flash write error/timeout\n"); break; } } outb(bank, SM_FLASH_CMD_CLEAR_STATUS); outb(bank, SM_FLASH_CMD_RESET); for (i = 0; i < NVRAM_SIZE; i++) { if (bank[i] != data[i]) { device_printf(dev, "flash write has failed\n"); return (-1); } } return (0); } static int erase_bank(device_t dev, uint8_t *bank) { struct powermac_nvram_softc *sc; sc = device_get_softc(dev); + + sx_assert(&sc->sc_lock, SA_XLOCKED); if (sc->sc_type == FLASH_TYPE_AMD) return (erase_bank_amd(dev, bank)); else return (erase_bank_sm(dev, bank)); } static int write_bank(device_t dev, uint8_t *bank, uint8_t *data) { struct powermac_nvram_softc *sc; sc = device_get_softc(dev); + + sx_assert(&sc->sc_lock, SA_XLOCKED); if (sc->sc_type == FLASH_TYPE_AMD) return (write_bank_amd(dev, bank, data)); else return (write_bank_sm(dev, bank, data)); } Index: head/sys/dev/powermac_nvram/powermac_nvramvar.h =================================================================== --- head/sys/dev/powermac_nvram/powermac_nvramvar.h (revision 362405) +++ head/sys/dev/powermac_nvram/powermac_nvramvar.h (revision 362406) @@ -1,83 +1,84 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2006 Maxim Sobolev * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD$ */ #ifndef _POWERPC_POWERMAC_POWERMAC_NVRAMVAR_H_ #define _POWERPC_POWERMAC_POWERMAC_NVRAMVAR_H_ #define NVRAM_SIZE 0x2000 #define CORE99_SIGNATURE 0x5a #define SM_FLASH_CMD_ERASE_CONFIRM 0xd0 #define SM_FLASH_CMD_ERASE_SETUP 0x20 #define SM_FLASH_CMD_RESET 0xff #define SM_FLASH_CMD_WRITE_SETUP 0x40 #define SM_FLASH_CMD_CLEAR_STATUS 0x50 #define SM_FLASH_CMD_READ_STATUS 0x70 #define SM_FLASH_STATUS_DONE 0x80 #define SM_FLASH_STATUS_ERR 0x38 #ifdef _KERNEL struct powermac_nvram_softc { device_t sc_dev; + struct sx sc_lock; phandle_t sc_node; vm_offset_t sc_bank; vm_offset_t sc_bank0; vm_offset_t sc_bank1; uint8_t sc_data[NVRAM_SIZE]; struct cdev * sc_cdev; int sc_type; #define FLASH_TYPE_SM 0 #define FLASH_TYPE_AMD 1 int sc_isopen; int sc_rpos; int sc_wpos; }; #endif /* _KERNEL */ struct chrp_header { uint8_t signature; uint8_t chrp_checksum; uint16_t length; char name[12]; }; struct core99_header { struct chrp_header chrp_header; uint32_t adler_checksum; uint32_t generation; uint32_t reserved[2]; }; #endif /* _POWERPC_POWERMAC_POWERMAC_NVRAMVAR_H_ */ Index: head/usr.sbin/nvram/nvram.8 =================================================================== --- head/usr.sbin/nvram/nvram.8 (revision 362405) +++ head/usr.sbin/nvram/nvram.8 (revision 362406) @@ -1,118 +1,112 @@ .\"- .\" Copyright (c) 2006 Maxim Sobolev .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR .\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE .\" DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, .\" INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES .\" (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR .\" SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, .\" STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN .\" ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE .\" POSSIBILITY OF SUCH DAMAGE. .\" .\" $FreeBSD$ .\" -.Dd August 1, 2006 +.Dd June 19, 2020 .Dt NVRAM 8 powerpc .Os .Sh NAME .Nm nvram .Nd "display or modify contents of the EEPROM or NVRAM" .Sh SYNOPSIS .Nm .Fl p .Nm .Oo Fl d Ar name Oc Ar ... .Op Ar name Ns = Ns Ar value ... .Sh DESCRIPTION The .Nm utility provides an interface for displaying and changing the system's configuration variables contained in EEPROM or NVRAM. In the first synopsis form, all available configuration variables and their current values are printed. In the second form, the variable selected by .Ar name is either removed or its value is changed to the .Ar value following by .Ql = sign. .Pp The following options are available: .Bl -tag -width indent .It Fl d Ar name Delete the variable selected by .Ar name from the EEPROM or NVRAM. The .Fl d flag can be specified multiple times, in which case multiple variables will be removed. .It Fl p Print all available configuration variables and their current values. .El .Sh EXAMPLES Print all available configuration variables and their current values: .Pp .Dl "nvram -p" .Pp Remove the variable named .Va local-mac-address? : .Pp .Dl "nvram -d local-mac-address\e?" .Pp Set the value of the .Va local-mac-address? variable to .Dq Li true : .Pp .Dl "nvram local-mac-address\e?=true" .Pp Note that the .Ql \e in the above examples is used to keep the shell from interpreting the .Ql \&? . .Pp Remove variables named .Va foo and .Va bar and set variable named .Va baz to .Dq Li 100 : .Pp .Dl "nvram -d foo -d bar baz=100" .Sh SEE ALSO -.Xr powermac_nvram 4 , -.Xr eeprom 8 +.Xr powermac_nvram 4 .Sh HISTORY The .Nm utility first appeared in .Fx 7.0 . It is inspired by the Darwin/Mac OS X .Nm utility. .Sh AUTHORS .An Maxim Sobolev Aq Mt sobomax@FreeBSD.org -.Sh BUGS -Currently, -.Nm -only supports systems equipped with AMD flash and is only tested on Apple -G4-based Mac Mini machines.