Add device to access and modify Open Firmware NVRAM settings in
PowerPC-based Apple's machines and small utility to do it from userland modelled after the similar utility in Darwin/OSX. Only tested on 1.25GHz G4 Mac Mini. MFC after: 1 month
This commit is contained in:
parent
78985e424a
commit
e5d34218fb
@ -56,6 +56,8 @@
|
||||
..
|
||||
ppbus
|
||||
..
|
||||
powermac_nvram
|
||||
..
|
||||
smbus
|
||||
..
|
||||
speaker
|
||||
|
@ -41,7 +41,7 @@ LDIRS= bsm cam geom net net80211 netatalk netatm netgraph netinet netinet6 \
|
||||
LSUBDIRS= cam/scsi \
|
||||
dev/acpica dev/an dev/bktr dev/firewire dev/hwpmc \
|
||||
dev/ic dev/iicbus ${_dev_ieee488} dev/lmc dev/ofw \
|
||||
dev/pbio dev/ppbus dev/smbus dev/speaker dev/usb dev/wi dev/utopia \
|
||||
dev/pbio ${_dev_powermac_nvram} dev/ppbus dev/smbus dev/speaker dev/usb dev/wi dev/utopia \
|
||||
fs/devfs fs/fdescfs fs/fifofs fs/msdosfs fs/ntfs fs/nullfs \
|
||||
${_fs_nwfs} fs/portalfs fs/procfs fs/smbfs fs/udf fs/umapfs \
|
||||
fs/unionfs \
|
||||
@ -55,6 +55,10 @@ LSUBDIRS= cam/scsi \
|
||||
security/mac_mls security/mac_partition \
|
||||
ufs/ffs ufs/ufs
|
||||
|
||||
.if ${MACHINE_ARCH} == "powerpc"
|
||||
_dev_powermac_nvram= dev/powermac_nvram
|
||||
.endif
|
||||
|
||||
.if ${MK_GPIB} != "no"
|
||||
_dev_ieee488= dev/ieee488
|
||||
.endif
|
||||
|
7
share/man/man4/man4.powerpc/Makefile
Normal file
7
share/man/man4/man4.powerpc/Makefile
Normal file
@ -0,0 +1,7 @@
|
||||
# $FreeBSD$
|
||||
|
||||
MAN= powermac_nvram.4
|
||||
|
||||
MANSUBDIR=/powerpc
|
||||
|
||||
.include <bsd.prog.mk>
|
58
share/man/man4/man4.powerpc/powermac_nvram.4
Normal file
58
share/man/man4/man4.powerpc/powermac_nvram.4
Normal file
@ -0,0 +1,58 @@
|
||||
.\"-
|
||||
.\" Copyright (c) 2006 Maxim Sobolev <sobomax@FreeBSD.org>
|
||||
.\" 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
|
||||
.Dt POWERMAC_NVRAM 4 powerpc
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm powermac_nvram
|
||||
.Nd "non-volatile RAM"
|
||||
.Sh SYNOPSIS
|
||||
.Cd "device powermac_nvram"
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Nm
|
||||
driver provides access to the Open Firmware configuration NVRAM
|
||||
available on the Apple PowerPC-based machines.
|
||||
.Sh SEE ALSO
|
||||
.Xr nvram 8 ,
|
||||
.Xr eeprom 8
|
||||
.Sh HISTORY
|
||||
The
|
||||
.Nm
|
||||
driver first appeared in
|
||||
.Fx 7.0 .
|
||||
.Sh AUTHORS
|
||||
The
|
||||
.Nm
|
||||
driver was written by
|
||||
.An Maxim Sobolev Aq sobomax@FreeBSD.org .
|
||||
.Sh BUGS
|
||||
Currently,
|
||||
.Nm
|
||||
driver only supports systems equipped with AMD flash part and is only
|
||||
tested on Apple G4-based Mac Mini machines.
|
@ -128,3 +128,5 @@ powerpc/psim/openpic_iobus.c optional psim
|
||||
powerpc/psim/uart_iobus.c optional uart psim
|
||||
|
||||
dev/scc/scc_bfe_macio.c optional scc powermac
|
||||
|
||||
dev/powermac_nvram/powermac_nvram.c optional powermac powermac_nvram
|
||||
|
423
sys/dev/powermac_nvram/powermac_nvram.c
Normal file
423
sys/dev/powermac_nvram/powermac_nvram.c
Normal file
@ -0,0 +1,423 @@
|
||||
/*
|
||||
* Copyright (c) 2006 Maxim Sobolev <sobomax@FreeBSD.org>
|
||||
* 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 <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/module.h>
|
||||
#include <sys/bus.h>
|
||||
#include <sys/conf.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/uio.h>
|
||||
|
||||
#include <dev/ofw/openfirm.h>
|
||||
#include <dev/ofw/ofw_pci.h>
|
||||
|
||||
#include <machine/bus.h>
|
||||
#include <machine/md_var.h>
|
||||
#include <machine/nexusvar.h>
|
||||
#include <machine/resource.h>
|
||||
|
||||
#include <sys/rman.h>
|
||||
|
||||
#include <powerpc/ofw/ofw_pci.h>
|
||||
#include <dev/powermac_nvram/powermac_nvramvar.h>
|
||||
|
||||
#include <vm/vm.h>
|
||||
#include <vm/pmap.h>
|
||||
|
||||
/*
|
||||
* 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, nexus, powermac_nvram_driver, powermac_nvram_devclass, 0, 0);
|
||||
|
||||
/*
|
||||
* Cdev methods.
|
||||
*/
|
||||
|
||||
#define NVRAM_UNIT(dev) minor(dev)
|
||||
#define NVRAM_SOFTC(unit) ((struct powermac_nvram_softc *) \
|
||||
devclass_get_softc(powermac_nvram_devclass, unit))
|
||||
|
||||
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)
|
||||
{
|
||||
char *type, *compatible;
|
||||
|
||||
type = nexus_get_device_type(dev);
|
||||
compatible = nexus_get_compatible(dev);
|
||||
|
||||
if (type == NULL || compatible == NULL)
|
||||
return ENXIO;
|
||||
|
||||
if (strcmp(type, "nvram") != 0 || strcmp(compatible, "amd-0137") != 0)
|
||||
return ENXIO;
|
||||
|
||||
device_set_desc(dev, "Apple NVRAM");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
powermac_nvram_attach(device_t dev)
|
||||
{
|
||||
struct powermac_nvram_softc *sc;
|
||||
phandle_t node;
|
||||
u_int32_t reg[2];
|
||||
int gen0, gen1;
|
||||
|
||||
node = nexus_get_node(dev);
|
||||
sc = device_get_softc(dev);
|
||||
|
||||
if (OF_getprop(node, "reg", reg, sizeof(reg)) < 8)
|
||||
return ENXIO;
|
||||
|
||||
sc->sc_dev = dev;
|
||||
sc->sc_node = node;
|
||||
|
||||
sc->sc_bank0 = (vm_offset_t)pmap_mapdev(reg[0], 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");
|
||||
|
||||
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);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
powermac_nvram_open(struct cdev *dev, int flags, int fmt, struct thread *td)
|
||||
{
|
||||
struct powermac_nvram_softc *sc;
|
||||
|
||||
sc = NVRAM_SOFTC(NVRAM_UNIT(dev));
|
||||
if (sc->sc_isopen)
|
||||
return EBUSY;
|
||||
sc->sc_isopen = 1;
|
||||
sc->sc_rpos = sc->sc_wpos = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
powermac_nvram_close(struct cdev *dev, int fflag, int devtype, struct thread *td)
|
||||
{
|
||||
struct powermac_nvram_softc *sc;
|
||||
struct core99_header *header;
|
||||
vm_offset_t bank;
|
||||
|
||||
sc = NVRAM_SOFTC(NVRAM_UNIT(dev));
|
||||
|
||||
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;
|
||||
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;
|
||||
return ENOSPC;
|
||||
}
|
||||
sc->sc_bank = bank;
|
||||
sc->sc_isopen = 0;
|
||||
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;
|
||||
|
||||
sc = NVRAM_SOFTC(NVRAM_UNIT(dev));
|
||||
|
||||
rv = 0;
|
||||
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;
|
||||
}
|
||||
}
|
||||
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;
|
||||
|
||||
sc = NVRAM_SOFTC(NVRAM_UNIT(dev));
|
||||
|
||||
if (sc->sc_wpos >= sizeof(sc->sc_data))
|
||||
return EINVAL;
|
||||
|
||||
rv = 0;
|
||||
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;
|
||||
}
|
||||
}
|
||||
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(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(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(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(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(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;
|
||||
}
|
68
sys/dev/powermac_nvram/powermac_nvramvar.h
Normal file
68
sys/dev/powermac_nvram/powermac_nvramvar.h
Normal file
@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright (c) 2006 Maxim Sobolev <sobomax@FreeBSD.org>
|
||||
* 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
|
||||
|
||||
#ifdef _KERNEL
|
||||
|
||||
struct powermac_nvram_softc {
|
||||
device_t sc_dev;
|
||||
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_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_ */
|
@ -190,6 +190,7 @@ SUBDIR= ${_3dfx} \
|
||||
plip \
|
||||
${_pmc} \
|
||||
portalfs \
|
||||
${_powermac_nvram} \
|
||||
ppbus \
|
||||
ppc \
|
||||
ppi \
|
||||
@ -521,6 +522,7 @@ _xe= xe
|
||||
_an= an
|
||||
_ath_hal= ath_hal
|
||||
_gem= gem
|
||||
_powermac_nvram= powermac_nvram
|
||||
_smbfs= smbfs
|
||||
.endif
|
||||
|
||||
|
8
sys/modules/powermac_nvram/Makefile
Normal file
8
sys/modules/powermac_nvram/Makefile
Normal file
@ -0,0 +1,8 @@
|
||||
# $FreeBSD$
|
||||
|
||||
.PATH: ${.CURDIR}/../../dev/powermac_nvram
|
||||
|
||||
KMOD= powermac_nvram
|
||||
SRCS= powermac_nvram.c powermac_nvramvar.h
|
||||
|
||||
.include <bsd.kmod.mk>
|
@ -145,6 +145,9 @@ device firewire # FireWire bus code
|
||||
device sbp # SCSI over FireWire (Requires scbus and da)
|
||||
device fwe # Ethernet over FireWire (non-standard!)
|
||||
|
||||
# Misc
|
||||
device powermac_nvram # Open Firmware configuration NVRAM
|
||||
|
||||
options KTR
|
||||
options KTR_COMPILE=0xffffffff
|
||||
#options KTR_MASK=KTR_SIG
|
||||
|
@ -110,6 +110,7 @@ SUBDIR= ac \
|
||||
nghook \
|
||||
nologin \
|
||||
ntp \
|
||||
${_nvram} \
|
||||
${_ofwdump} \
|
||||
${_pccard} \
|
||||
pciconf \
|
||||
@ -369,6 +370,7 @@ _zzz= zzz
|
||||
|
||||
.if ${MACHINE_ARCH} == "powerpc"
|
||||
_mount_smbfs= mount_smbfs
|
||||
_nvram= nvram
|
||||
.endif
|
||||
|
||||
.if ${MACHINE_ARCH} == "sparc64"
|
||||
|
8
usr.sbin/nvram/Makefile
Normal file
8
usr.sbin/nvram/Makefile
Normal file
@ -0,0 +1,8 @@
|
||||
# $FreeBSD$
|
||||
|
||||
PROG= nvram
|
||||
MAN= nvram.8
|
||||
|
||||
WARNS?= 6
|
||||
|
||||
.include <bsd.prog.mk>
|
119
usr.sbin/nvram/nvram.8
Normal file
119
usr.sbin/nvram/nvram.8
Normal file
@ -0,0 +1,119 @@
|
||||
.\"-
|
||||
.\" Copyright (c) 2006 Maxim Sobolev <sobomax@FreeBSD.org>
|
||||
.\" 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
|
||||
.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
|
||||
.Op Fl d Ar name
|
||||
.Op Ar name Ns = Ns Ar value
|
||||
.Ar ...
|
||||
.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"
|
||||
.Ed
|
||||
.Sh SEE ALSO
|
||||
.Xr powermac_nvram 4 ,
|
||||
.Xr eeprom 8
|
||||
.Sh HISTORY
|
||||
The
|
||||
.Nm
|
||||
utility first appeared in
|
||||
.Fx 7.0 .
|
||||
It is inspired by the
|
||||
Darwin/Mac OS X
|
||||
.Xr nvram 8
|
||||
utility.
|
||||
.Sh AUTHORS
|
||||
.An Maxim Sobolev Aq 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.
|
222
usr.sbin/nvram/nvram.c
Normal file
222
usr.sbin/nvram/nvram.c
Normal file
@ -0,0 +1,222 @@
|
||||
/*
|
||||
* Copyright (c) 2006 Maxim Sobolev <sobomax@FreeBSD.org>
|
||||
* 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 <sys/types.h>
|
||||
#include <sys/uio.h>
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <paths.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <dev/powermac_nvram/powermac_nvramvar.h>
|
||||
|
||||
#define DEVICE_NAME (_PATH_DEV "powermac_nvram")
|
||||
|
||||
static void usage(void);
|
||||
static int remove_var(uint8_t *, int, const char *);
|
||||
static int append_var(uint8_t *, int, const char *, const char *);
|
||||
|
||||
struct deletelist {
|
||||
char *name;
|
||||
struct deletelist *next;
|
||||
struct deletelist *last;
|
||||
};
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
int opt, dump, fd, res, i, size;
|
||||
uint8_t buf[NVRAM_SIZE], *cp, *common;
|
||||
struct chrp_header *header;
|
||||
struct deletelist *dl;
|
||||
|
||||
dump = 0;
|
||||
dl = NULL;
|
||||
|
||||
while((opt = getopt(argc, argv, "d:p")) != -1) {
|
||||
switch(opt) {
|
||||
case 'p':
|
||||
dump = 1;
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
if (dl == NULL) {
|
||||
dl = malloc(sizeof(*dl));
|
||||
if (dl == NULL)
|
||||
err(1, "malloc");
|
||||
bzero(dl, sizeof(*dl));
|
||||
dl->last = dl;
|
||||
} else {
|
||||
dl->last->next = malloc(sizeof(*dl));
|
||||
if (dl->last->next == NULL)
|
||||
err(1, "malloc");
|
||||
dl->last = dl->last->next;
|
||||
bzero(dl->last, sizeof(*dl));
|
||||
}
|
||||
dl->last->name = optarg;
|
||||
break;
|
||||
|
||||
default:
|
||||
usage();
|
||||
/* Not reached */
|
||||
}
|
||||
}
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
if (argc == 0 && dump == 0 && dl == NULL) {
|
||||
usage();
|
||||
/* Not reached */
|
||||
}
|
||||
|
||||
fd = open(DEVICE_NAME, O_RDWR);
|
||||
if (fd == -1)
|
||||
err(1, DEVICE_NAME);
|
||||
for (i = 0; i < (int)sizeof(buf);) {
|
||||
res = read(fd, buf + i, sizeof(buf) - i);
|
||||
if (res == -1 && errno != EINTR)
|
||||
err(1, DEVICE_NAME);
|
||||
if (res == 0)
|
||||
break;
|
||||
if (res > 0)
|
||||
i += res;
|
||||
}
|
||||
if (i != sizeof(buf))
|
||||
errx(1, "%s: short read", DEVICE_NAME);
|
||||
|
||||
/* Locate common block */
|
||||
size = 0;
|
||||
for (cp = buf; cp < buf + sizeof(buf); cp += size) {
|
||||
header = (struct chrp_header *)cp;
|
||||
size = header->length * 0x10;
|
||||
if (strncmp(header->name, "common", 7) == 0)
|
||||
break;
|
||||
}
|
||||
if (cp >= buf + sizeof(buf) || size <= (int)sizeof(struct chrp_header))
|
||||
errx(1, "%s: no common block", DEVICE_NAME);
|
||||
common = cp + sizeof(struct chrp_header);
|
||||
size -= sizeof(struct chrp_header);
|
||||
|
||||
if (dump != 0) {
|
||||
while (size > 0) {
|
||||
i = strlen(common) + 1;
|
||||
if (i == 1)
|
||||
break;
|
||||
printf("%s\n", common);
|
||||
size -= i;
|
||||
common += i;
|
||||
}
|
||||
exit(0);
|
||||
}
|
||||
|
||||
for (;dl != NULL; dl = dl->next) {
|
||||
if (remove_var(common, size, dl->name) == 0)
|
||||
warnx("%s: no such variable", dl->name);
|
||||
}
|
||||
|
||||
for (; argc > 0; argc--, argv++) {
|
||||
cp = strchr(*argv, '=');
|
||||
if (cp == NULL)
|
||||
errx(1, "%s: invalid argument", *argv);
|
||||
cp[0] = '\0';
|
||||
cp++;
|
||||
remove_var(common, size, *argv);
|
||||
if (append_var(common, size, *argv, cp) == -1)
|
||||
errx(1, "%s: error setting variable", *argv);
|
||||
}
|
||||
|
||||
for (i = 0; i < (int)sizeof(buf);) {
|
||||
res = write(fd, buf + i, sizeof(buf) - i);
|
||||
if (res == -1 && errno != EINTR)
|
||||
err(1, DEVICE_NAME);
|
||||
if (res == 0)
|
||||
break;
|
||||
if (res > 0)
|
||||
i += res;
|
||||
}
|
||||
if (i != sizeof(buf))
|
||||
errx(1, "%s: short write", DEVICE_NAME);
|
||||
if (close(fd) == -1)
|
||||
err(1, DEVICE_NAME);
|
||||
|
||||
exit(0);
|
||||
}
|
||||
|
||||
static void
|
||||
usage(void)
|
||||
{
|
||||
|
||||
fprintf(stderr, "usage: nvram [-p] | [-d name ...] [name=value ...]\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static int
|
||||
remove_var(uint8_t *buf, int len, const char *var_name)
|
||||
{
|
||||
int nremoved, i, name_len;
|
||||
|
||||
nremoved = 0;
|
||||
name_len = strlen(var_name);
|
||||
while (len > 0) {
|
||||
i = strlen(buf) + 1;
|
||||
if (i == 1)
|
||||
break;
|
||||
if (strncmp(buf, var_name, name_len) == 0 && buf[name_len] == '=') {
|
||||
memmove(buf, buf + i, len - i);
|
||||
memset(buf + len - i, '\0', i);
|
||||
nremoved += 1;
|
||||
continue;
|
||||
}
|
||||
len -= i;
|
||||
buf += i;
|
||||
}
|
||||
return nremoved;
|
||||
}
|
||||
|
||||
static int
|
||||
append_var(uint8_t *buf, int len, const char *var_name, const char *var_value)
|
||||
{
|
||||
int i, append_len;
|
||||
|
||||
while (len > 0) {
|
||||
i = strlen(buf) + 1;
|
||||
if (i == 1)
|
||||
break;
|
||||
len -= i;
|
||||
buf += i;
|
||||
}
|
||||
append_len = strlen(var_name) + strlen(var_value) + 2;
|
||||
if (len < append_len)
|
||||
return -1;
|
||||
sprintf(buf, "%s=%s", var_name, var_value);
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue
Block a user