diff options
author | peter <peter@FreeBSD.org> | 2007-06-15 22:58:14 +0000 |
---|---|---|
committer | peter <peter@FreeBSD.org> | 2007-06-15 22:58:14 +0000 |
commit | 7d427641bffb8a59a5be2e9fe2eb297d89427dbb (patch) | |
tree | db3f86f1334e5f32597017085e6ae74e05a50e6b /sys | |
parent | d8964f8dc1a663e91dd1685e88682de1f9b9f242 (diff) | |
download | FreeBSD-src-7d427641bffb8a59a5be2e9fe2eb297d89427dbb.zip FreeBSD-src-7d427641bffb8a59a5be2e9fe2eb297d89427dbb.tar.gz |
Prototype (but functional) Linux-ish /dev/nvram interface to the extra
114 bytes of cmos ram in the PC clock chip. The big difference between
this and the Linux version is that we do not recalculate the checksums
for bytes 16..31.
We use this at work when cloning identical machines - we can copy the
bios settings as well. Reading /dev/nvram gives 114 bytes of data but
you can seek/read/write whichever bytes you like.
Yes, this is a "foot, gun, fire!" type of device.
Diffstat (limited to 'sys')
-rw-r--r-- | sys/amd64/isa/clock.c | 99 | ||||
-rw-r--r-- | sys/i386/isa/clock.c | 99 | ||||
-rw-r--r-- | sys/isa/atrtc.c | 99 |
3 files changed, 297 insertions, 0 deletions
diff --git a/sys/amd64/isa/clock.c b/sys/amd64/isa/clock.c index 4efe73a..0ef295b 100644 --- a/sys/amd64/isa/clock.c +++ b/sys/amd64/isa/clock.c @@ -53,12 +53,15 @@ __FBSDID("$FreeBSD$"); #include <sys/systm.h> #include <sys/bus.h> #include <sys/clock.h> +#include <sys/conf.h> +#include <sys/fcntl.h> #include <sys/lock.h> #include <sys/kdb.h> #include <sys/mutex.h> #include <sys/proc.h> #include <sys/time.h> #include <sys/timetc.h> +#include <sys/uio.h> #include <sys/kernel.h> #include <sys/limits.h> #include <sys/module.h> @@ -931,4 +934,100 @@ static devclass_t attimer_devclass; DRIVER_MODULE(attimer, isa, attimer_driver, attimer_devclass, 0, 0); DRIVER_MODULE(attimer, acpi, attimer_driver, attimer_devclass, 0, 0); + +/* + * Linux-style /dev/nvram driver + * + * cmos ram starts at bytes 14 through 128, for a total of 114 bytes. + * bytes 16 through 31 are checksummed at byte 32. + * Unlike Linux, you have to take care of the checksums yourself. + * The driver exposes byte 14 as file offset 0. + */ + +#define NVRAM_FIRST RTC_DIAG /* 14 */ +#define NVRAM_LAST 128 + +static d_open_t nvram_open; +static d_read_t nvram_read; +static d_write_t nvram_write; + +static struct cdev *nvram_dev; + +static struct cdevsw nvram_cdevsw = { + .d_version = D_VERSION, + .d_flags = D_NEEDGIANT, + .d_open = nvram_open, + .d_read = nvram_read, + .d_write = nvram_write, + .d_name = "nvram", +}; + +static int +nvram_open(struct cdev *dev __unused, int flags, int fmt __unused, + struct thread *td) +{ + int error = 0; + + if (flags & FWRITE) + error = securelevel_gt(td->td_ucred, 0); + + return (error); +} + +static int +nvram_read(struct cdev *dev, struct uio *uio, int flags) +{ + int nv_off; + u_char v; + int error = 0; + + while (uio->uio_resid > 0 && error == 0) { + nv_off = uio->uio_offset + NVRAM_FIRST; + if (nv_off < NVRAM_FIRST || nv_off >= NVRAM_LAST) + return (0); /* Signal EOF */ + /* Single byte at a time */ + v = rtcin(nv_off); + error = uiomove(&v, 1, uio); + } + return (error); + +} + +static int +nvram_write(struct cdev *dev, struct uio *uio, int flags) +{ + int nv_off; + u_char v; + int error = 0; + + while (uio->uio_resid > 0 && error == 0) { + nv_off = uio->uio_offset + NVRAM_FIRST; + if (nv_off < NVRAM_FIRST || nv_off >= NVRAM_LAST) + return (0); /* Signal EOF */ + /* Single byte at a time */ + error = uiomove(&v, 1, uio); + writertc(nv_off, v); + } + return (error); +} + +static int +nvram_modevent(module_t mod __unused, int type, void *data __unused) +{ + switch (type) { + case MOD_LOAD: + nvram_dev = make_dev(&nvram_cdevsw, 0, + UID_ROOT, GID_KMEM, 0640, "nvram"); + break; + case MOD_UNLOAD: + case MOD_SHUTDOWN: + destroy_dev(nvram_dev); + break; + default: + return (EOPNOTSUPP); + } + return (0); +} +DEV_MODULE(nvram, nvram_modevent, NULL); + #endif /* DEV_ISA */ diff --git a/sys/i386/isa/clock.c b/sys/i386/isa/clock.c index 62c5764..f8e1c4e 100644 --- a/sys/i386/isa/clock.c +++ b/sys/i386/isa/clock.c @@ -56,12 +56,15 @@ __FBSDID("$FreeBSD$"); #include <sys/systm.h> #include <sys/bus.h> #include <sys/clock.h> +#include <sys/conf.h> +#include <sys/fcntl.h> #include <sys/lock.h> #include <sys/kdb.h> #include <sys/mutex.h> #include <sys/proc.h> #include <sys/time.h> #include <sys/timetc.h> +#include <sys/uio.h> #include <sys/kernel.h> #include <sys/limits.h> #include <sys/module.h> @@ -930,4 +933,100 @@ static devclass_t attimer_devclass; DRIVER_MODULE(attimer, isa, attimer_driver, attimer_devclass, 0, 0); DRIVER_MODULE(attimer, acpi, attimer_driver, attimer_devclass, 0, 0); + +/* + * Linux-style /dev/nvram driver + * + * cmos ram starts at bytes 14 through 128, for a total of 114 bytes. + * bytes 16 through 31 are checksummed at byte 32. + * Unlike Linux, you have to take care of the checksums yourself. + * The driver exposes byte 14 as file offset 0. + */ + +#define NVRAM_FIRST RTC_DIAG /* 14 */ +#define NVRAM_LAST 128 + +static d_open_t nvram_open; +static d_read_t nvram_read; +static d_write_t nvram_write; + +static struct cdev *nvram_dev; + +static struct cdevsw nvram_cdevsw = { + .d_version = D_VERSION, + .d_flags = D_NEEDGIANT, + .d_open = nvram_open, + .d_read = nvram_read, + .d_write = nvram_write, + .d_name = "nvram", +}; + +static int +nvram_open(struct cdev *dev __unused, int flags, int fmt __unused, + struct thread *td) +{ + int error = 0; + + if (flags & FWRITE) + error = securelevel_gt(td->td_ucred, 0); + + return (error); +} + +static int +nvram_read(struct cdev *dev, struct uio *uio, int flags) +{ + int nv_off; + u_char v; + int error = 0; + + while (uio->uio_resid > 0 && error == 0) { + nv_off = uio->uio_offset + NVRAM_FIRST; + if (nv_off < NVRAM_FIRST || nv_off >= NVRAM_LAST) + return (0); /* Signal EOF */ + /* Single byte at a time */ + v = rtcin(nv_off); + error = uiomove(&v, 1, uio); + } + return (error); + +} + +static int +nvram_write(struct cdev *dev, struct uio *uio, int flags) +{ + int nv_off; + u_char v; + int error = 0; + + while (uio->uio_resid > 0 && error == 0) { + nv_off = uio->uio_offset + NVRAM_FIRST; + if (nv_off < NVRAM_FIRST || nv_off >= NVRAM_LAST) + return (0); /* Signal EOF */ + /* Single byte at a time */ + error = uiomove(&v, 1, uio); + writertc(nv_off, v); + } + return (error); +} + +static int +nvram_modevent(module_t mod __unused, int type, void *data __unused) +{ + switch (type) { + case MOD_LOAD: + nvram_dev = make_dev(&nvram_cdevsw, 0, + UID_ROOT, GID_KMEM, 0640, "nvram"); + break; + case MOD_UNLOAD: + case MOD_SHUTDOWN: + destroy_dev(nvram_dev); + break; + default: + return (EOPNOTSUPP); + } + return (0); +} +DEV_MODULE(nvram, nvram_modevent, NULL); + #endif /* DEV_ISA */ diff --git a/sys/isa/atrtc.c b/sys/isa/atrtc.c index 62c5764..f8e1c4e 100644 --- a/sys/isa/atrtc.c +++ b/sys/isa/atrtc.c @@ -56,12 +56,15 @@ __FBSDID("$FreeBSD$"); #include <sys/systm.h> #include <sys/bus.h> #include <sys/clock.h> +#include <sys/conf.h> +#include <sys/fcntl.h> #include <sys/lock.h> #include <sys/kdb.h> #include <sys/mutex.h> #include <sys/proc.h> #include <sys/time.h> #include <sys/timetc.h> +#include <sys/uio.h> #include <sys/kernel.h> #include <sys/limits.h> #include <sys/module.h> @@ -930,4 +933,100 @@ static devclass_t attimer_devclass; DRIVER_MODULE(attimer, isa, attimer_driver, attimer_devclass, 0, 0); DRIVER_MODULE(attimer, acpi, attimer_driver, attimer_devclass, 0, 0); + +/* + * Linux-style /dev/nvram driver + * + * cmos ram starts at bytes 14 through 128, for a total of 114 bytes. + * bytes 16 through 31 are checksummed at byte 32. + * Unlike Linux, you have to take care of the checksums yourself. + * The driver exposes byte 14 as file offset 0. + */ + +#define NVRAM_FIRST RTC_DIAG /* 14 */ +#define NVRAM_LAST 128 + +static d_open_t nvram_open; +static d_read_t nvram_read; +static d_write_t nvram_write; + +static struct cdev *nvram_dev; + +static struct cdevsw nvram_cdevsw = { + .d_version = D_VERSION, + .d_flags = D_NEEDGIANT, + .d_open = nvram_open, + .d_read = nvram_read, + .d_write = nvram_write, + .d_name = "nvram", +}; + +static int +nvram_open(struct cdev *dev __unused, int flags, int fmt __unused, + struct thread *td) +{ + int error = 0; + + if (flags & FWRITE) + error = securelevel_gt(td->td_ucred, 0); + + return (error); +} + +static int +nvram_read(struct cdev *dev, struct uio *uio, int flags) +{ + int nv_off; + u_char v; + int error = 0; + + while (uio->uio_resid > 0 && error == 0) { + nv_off = uio->uio_offset + NVRAM_FIRST; + if (nv_off < NVRAM_FIRST || nv_off >= NVRAM_LAST) + return (0); /* Signal EOF */ + /* Single byte at a time */ + v = rtcin(nv_off); + error = uiomove(&v, 1, uio); + } + return (error); + +} + +static int +nvram_write(struct cdev *dev, struct uio *uio, int flags) +{ + int nv_off; + u_char v; + int error = 0; + + while (uio->uio_resid > 0 && error == 0) { + nv_off = uio->uio_offset + NVRAM_FIRST; + if (nv_off < NVRAM_FIRST || nv_off >= NVRAM_LAST) + return (0); /* Signal EOF */ + /* Single byte at a time */ + error = uiomove(&v, 1, uio); + writertc(nv_off, v); + } + return (error); +} + +static int +nvram_modevent(module_t mod __unused, int type, void *data __unused) +{ + switch (type) { + case MOD_LOAD: + nvram_dev = make_dev(&nvram_cdevsw, 0, + UID_ROOT, GID_KMEM, 0640, "nvram"); + break; + case MOD_UNLOAD: + case MOD_SHUTDOWN: + destroy_dev(nvram_dev); + break; + default: + return (EOPNOTSUPP); + } + return (0); +} +DEV_MODULE(nvram, nvram_modevent, NULL); + #endif /* DEV_ISA */ |