Subject: Re: cmos ram access?
To: None <current-users@netbsd.org>
From: Takahiro Kambe <taca@back-street.net>
List: current-users
Date: 03/28/2003 10:59:57
OK, Perry, Werner. I attached diff here.
- This diff is to 1.6.1_RC3 generated from our local CVS repogitry.
- sys/arch/i386/i386/machdep.c is completely extra one, notifying user
that it is now safe to power off.
- /dev/cmos provide read and write to BIOS NVRAM's 128 byte data.
When writing data,
* check sum for basic and extend BIOS data is calculated by
this driver.
* RTC clock information will not be changed.
* Writing wrong data cause reset all NVRAM's data or something
unexpected result. *CAUTION* !!
- /dev/bios simply provides read first 256 byte of BIOS ROM. This is
intended to identify different vendor or version of BIOS calculating
MD5 (or SHA1) value. 256 is experimental value enough to do it.
- These codes are "works for me" quality. Basic codes were written
and tested on FreeBSD 2.2.8 first and ported NetBSD 1.5 last year.
It was written as part of my real job.
- Those code are undeer BSD style license.
Since BIOS NVRAM's data is depends on vendor or version of BIOS, we
needed to check what version of BIOS was and created /dev/bios device.
In message <3E822A0A.B447E771@bit-1.de>
on Wed, 26 Mar 2003 23:30:34 +0100,
Werner Backes <werner@bit-1.de> wrote:
> is no production machine and I just want to do some testing with
> RTC alarm auto-wakeup.
One difficulty is such data exists as extended BIOS data and its
address(offset) might be vendor depend.
P.S.
If any question, please ask me. But I might forget why I wrote such
code fragment. :-)
--
Takahiro Kambe <taca@back-street.net>
Index: sys/arch/i386/conf/files.i386
===================================================================
RCS file: /usr/pkg/libdata/cvs/src/sys/arch/i386/conf/files.i386,v
retrieving revision 1.1.1.1
retrieving revision 1.1.1.1.2.1
diff -d -u -p -r1.1.1.1 -r1.1.1.1.2.1
--- sys/arch/i386/conf/files.i386 2003/02/24 02:25:26 1.1.1.1
+++ sys/arch/i386/conf/files.i386 2003/02/24 07:35:14 1.1.1.1.2.1
@@ -308,6 +308,13 @@ attach apm at mainbus
file arch/i386/i386/apm.c apm needs-count
file arch/i386/i386/apmcall.s apm
+device bios
+attach bios at isa
+file arch/i386/isa/bios.c bios needs-flag
+
+defpseudo cmos
+file arch/i386/isa/cmos.c cmos needs-flag
+
#
# Compatibility modules
#
Index: sys/arch/i386/i386/conf.c
===================================================================
RCS file: /usr/pkg/libdata/cvs/src/sys/arch/i386/i386/conf.c,v
retrieving revision 1.1.1.1
retrieving revision 1.1.1.1.2.1
diff -d -u -p -r1.1.1.1 -r1.1.1.1.2.1
--- sys/arch/i386/i386/conf.c 2003/02/24 02:25:27 1.1.1.1
+++ sys/arch/i386/i386/conf.c 2003/02/24 07:35:20 1.1.1.1.2.1
@@ -105,6 +105,20 @@ struct bdevsw bdevsw[] =
};
int nblkdev = sizeof(bdevsw) / sizeof(bdevsw[0]);
+/* open, close, read */
+#define cdev_bios_init(c,n) { \
+ dev_init(c,n,open), dev_init(c,n,close), dev_init(c,n,read), \
+ (dev_type_write((*))) enodev, (dev_type_ioctl((*))) enodev, \
+ (dev_type_stop((*))) enodev, 0, seltrue, \
+ (dev_type_mmap((*))) enodev }
+
+/* open, close, read, write */
+#define cdev_cmos_init(c,n) { \
+ dev_init(c,n,open), dev_init(c,n,close), dev_init(c,n,read), \
+ dev_init(c,n,write), (dev_type_ioctl((*))) enodev, \
+ (dev_type_stop((*))) enodev, 0, seltrue, \
+ (dev_type_mmap((*))) enodev }
+
#include <dev/sysmon/sysmonconf.h>
cdev_decl(sysmon);
@@ -195,6 +209,10 @@ cdev_decl(uscanner);
cdev_decl(vc_nb_);
#include "netsmb.h"
cdev_decl(nsmb_dev_);
+#include "bios.h"
+cdev_decl(bios);
+#include "cmos.h"
+cdev_decl(cmos);
#include "ipfilter.h"
#include "satlink.h"
@@ -296,8 +314,8 @@ struct cdevsw cdevsw[] =
cdev_lkm_dummy(), /* 30 */
cdev_lkm_dummy(), /* 31 */
cdev_lkm_dummy(), /* 32 */
- cdev_lkm_dummy(), /* 33 */
- cdev_lkm_dummy(), /* 34 */
+ cdev_bios_init(NBIOS,bios), /* 33: BIOS ROM */
+ cdev_cmos_init(NCMOS,cmos), /* 34: BIOS CMOS data */
cdev_mouse_init(NOMMS,mms), /* 35: Microsoft mouse */
cdev_mouse_init(NOLMS,lms), /* 36: Logitech mouse */
cdev_notdef(), /* 37: was: opms (PS/2 mouse) */
Index: sys/arch/i386/i386/machdep.c
===================================================================
RCS file: /usr/pkg/libdata/cvs/src/sys/arch/i386/i386/machdep.c,v
retrieving revision 1.1.1.1
retrieving revision 1.1.1.1.2.1
diff -d -u -p -r1.1.1.1 -r1.1.1.1.2.1
--- sys/arch/i386/i386/machdep.c 2003/02/24 02:25:27 1.1.1.1
+++ sys/arch/i386/i386/machdep.c 2003/02/24 07:35:20 1.1.1.1.2.1
@@ -2238,6 +2238,9 @@ cpu_reboot(howto, bootstr)
haltsys:
doshutdownhooks();
+ if ((howto & RB_HALT) == RB_HALT)
+ printf("\n\nYou can power off now.\n");
+
if ((howto & RB_POWERDOWN) == RB_POWERDOWN) {
#if NAPM > 0 && !defined(APM_NO_POWEROFF)
/* turn off, if we can. But try to turn disk off and
Index: sys/arch/i386/include/conf.h
===================================================================
RCS file: /usr/pkg/libdata/cvs/src/sys/arch/i386/include/conf.h,v
retrieving revision 1.1.1.1
retrieving revision 1.1.1.1.2.1
diff -d -u -p -r1.1.1.1 -r1.1.1.1.2.1
--- sys/arch/i386/include/conf.h 2003/02/24 02:25:28 1.1.1.1
+++ sys/arch/i386/include/conf.h 2003/02/24 07:35:23 1.1.1.1.2.1
@@ -50,3 +50,7 @@ cdev_decl(mms);
cdev_decl(lms);
cdev_decl(joy);
+
+cdev_decl(bios);
+
+cdev_decl(cmos);
Index: sys/arch/i386/isa/bios.c
===================================================================
RCS file: bios.c
diff -N bios.c
--- /dev/null Thu Mar 27 03:20:24 2003
+++ /tmp/cvs01693gw Thu Mar 27 21:29:19 2003
@@ -0,0 +1,189 @@
+/* $Id: bios.c,v 1.1.2.2 2003/03/26 06:53:24 taca Exp $ */
+
+/*
+ * Copyright (C) 2003 JONE System Co., Inc.
+ * All right reserved.
+ *
+ * Copyright (C) 1999, 2000, 2001, 2002 JEPRO Co., Ltd.
+ * All right 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.
+ * 3. Neither the name of JEPRO Co., Ltd. nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
+ *
+ */
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/select.h>
+#include <sys/proc.h>
+#include <sys/device.h>
+
+#include <machine/bus.h>
+#include <machine/conf.h>
+
+#include <dev/isa/isavar.h>
+
+#define BIOS_ID_OFFSET 0x1f80
+#define BIOS_BASE 0xfe000
+#define BIOS_SIZE 256
+
+struct bios_softc { /* driver status information */
+ struct device sc_dev;
+
+ int status;
+ int flag;
+#define BIOS_FREE 0
+#define BIOS_OPENED 1
+#define BIOS_READ 2
+ bus_space_tag_t memt; /* bus memory space identifier */
+ bus_space_handle_t memh; /* bus memory handle */
+
+ int size;
+ unsigned char *buf;
+};
+
+extern struct cfdriver bios_cd;
+
+#ifdef BIOS_DEBUG
+int bios_debug = 0;
+#endif
+
+int biosprobe __P((struct device *, struct cfdata *, void *));
+void biosattach __P((struct device *, struct device *, void *));
+
+struct cfattach bios_ca = {
+ sizeof(struct bios_softc), biosprobe, biosattach
+};
+
+int
+biosprobe(parent, match, aux)
+ struct device *parent;
+ struct cfdata *match;
+ void *aux;
+{
+ struct isa_attach_args *ia = aux;
+ bus_space_tag_t memt = ia->ia_memt;
+ bus_space_handle_t memh;
+ int id, rv;
+
+ if (bus_space_map(memt, BIOS_BASE, BIOS_SIZE, 0, &memh))
+ return 0;
+
+ id = bus_space_read_1(memt, memh, BIOS_ID_OFFSET);
+ rv = (id < 0xff && id >= 0xf8)? 1: 0;
+ bus_space_unmap(memt, memh, BIOS_SIZE);
+ if (rv) {
+ ia->ia_nio = 0;
+ ia->ia_iomem[0].ir_addr = BIOS_BASE;
+ ia->ia_iomem[0].ir_size = BIOS_SIZE;
+ }
+
+ return rv;
+}
+
+void
+biosattach(parent, self, aux)
+ struct device *parent, *self;
+ void *aux;
+{
+ struct bios_softc *sc = (void *)self;
+ struct isa_attach_args *ia = aux;
+ bus_space_tag_t memt = ia->ia_memt;
+ bus_space_handle_t memh;
+
+ printf("\n");
+
+ if (bus_space_map(memt, BIOS_BASE, BIOS_SIZE, 0, &memh)) {
+ printf("%s: can't map memory space\n", sc->sc_dev.dv_xname);
+ return;
+ }
+
+ sc->memt = memt;
+ sc->memh = memh;
+ sc->status = 0;
+ sc->flag = BIOS_FREE;
+ sc->size = BIOS_SIZE;
+ sc->buf = malloc(sc->size, M_DEVBUF, 0);
+}
+
+int
+biosopen(dev, flag, mode, p)
+ dev_t dev;
+ int flag;
+ int mode;
+ struct proc *p;
+{
+ int unit = minor(dev);
+ struct bios_softc *sc;
+
+ if (unit >= bios_cd.cd_ndevs)
+ return ENXIO;
+ sc = bios_cd.cd_devs[unit];
+ if (!sc)
+ return ENXIO;
+ if (sc->flag != BIOS_FREE)
+ return EBUSY;
+ sc->flag = BIOS_OPENED;
+
+ return 0;
+}
+
+int
+biosclose(dev, flag, mode, p)
+ dev_t dev;
+ int flag;
+ int mode;
+ struct proc *p;
+{
+ struct bios_softc *sc = bios_cd.cd_devs[minor(dev)];
+
+ sc->flag = BIOS_FREE;
+ return 0;
+}
+
+int
+biosread(dev, uio, flag)
+ dev_t dev;
+ struct uio *uio;
+ int flag;
+{
+ struct bios_softc *sc = bios_cd.cd_devs[minor(dev)];
+ int error = 0;
+
+ if (sc->flag == BIOS_READ)
+ return error;
+
+ if (sc->status == 0) {
+ bus_space_read_region_1(sc->memt, sc->memh, 0, sc->buf,
+ BIOS_SIZE);
+ sc->status++;
+ }
+
+ /* Copy the data to the user process. */
+ error = uiomove(sc->buf, sc->size, uio);
+ sc->flag = BIOS_READ;
+ return error;
+}
Index: sys/arch/i386/isa/cmos.c
===================================================================
RCS file: cmos.c
diff -N cmos.c
--- /dev/null Thu Mar 27 03:20:24 2003
+++ /tmp/cvs01693gx Thu Mar 27 21:29:19 2003
@@ -0,0 +1,267 @@
+/* $Id: cmos.c,v 1.1.2.2 2003/03/26 06:53:24 taca Exp $ */
+
+/*
+ * Copyright (C) 2003 JONE System Co., Inc.
+ * All right reserved.
+ *
+ * Copyright (C) 1999, 2000, 2001, 2002 JEPRO Co., Ltd.
+ * All right 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.
+ * 3. Neither the name of JEPRO Co., Ltd. nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
+ *
+ */
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/ioctl.h>
+#include <sys/proc.h>
+#include <sys/device.h>
+
+#include <machine/bus.h>
+#include <machine/intr.h>
+
+#include <dev/isa/isareg.h>
+#include <dev/isa/isavar.h>
+#include <dev/ic/mc146818reg.h>
+#include <i386/isa/nvram.h>
+
+#define CMOS_SUM 32
+#define CMOS_COUNTER 43
+#define CMOS_XSTART 50
+#define CMOS_XSUM 111
+
+#define NVRAM_SUMH (MC_NVRAM_START + CMOS_SUM)
+#define NVRAM_COUNTER (MC_NVRAM_START + CMOS_COUNTER)
+#define NVRAM_XSTART (MC_NVRAM_START + CMOS_XSTART)
+#define NVRAM_XSUMH (MC_NVRAM_START + CMOS_XSUM)
+
+#define CMOS_SIZE 128
+
+struct cmos_softc { /* driver status information */
+ int sc_state;
+#define CMOS_NONE 0
+#define CMOS_INITED 1
+#define CMOS_OPENED 2
+#define CMOS_READ 4
+#define CMOS_WROTE 8
+ unsigned char *sc_buf;
+} cmossoftc;
+
+#ifdef CMOS_DEBUG
+int cmos_debug = 0;
+#endif
+
+void cmosattach(int);
+int cmosopen(dev_t, int, int, struct proc *);
+int cmosclose(dev_t, int, int, struct proc *);
+int cmosread(dev_t, struct uio *, int);
+int cmoswrite(dev_t, struct uio *, int);
+static void cmossum(unsigned char *, int, int, int);
+#ifdef CMOS_DEBUG
+static void cmos_dump(unsigned char *);
+#endif
+
+extern __inline u_int mc146818_read(void *, u_int);
+extern __inline void mc146818_write(void *, u_int, u_int);
+
+void
+cmosattach(n)
+ int n;
+{
+ struct cmos_softc *sc = &cmossoftc;
+
+ printf("cmos: attached.\n");
+ sc->sc_state = CMOS_NONE;
+}
+
+int
+cmosopen(dev, flags, ifmt, p)
+ dev_t dev;
+ int flags, ifmt;
+ struct proc *p;
+{
+ struct cmos_softc *sc = &cmossoftc;
+ int error;
+
+ if ((error = suser(p->p_ucred, &p->p_acflag)))
+ return error;
+
+ if ((sc->sc_state & CMOS_INITED) != CMOS_INITED) {
+ cmossoftc.sc_buf = malloc(CMOS_SIZE, M_DEVBUF, M_WAITOK);
+ sc->sc_state = CMOS_INITED;
+ }
+ sc->sc_state |= CMOS_OPENED;
+#ifdef CMOS_DEBUG
+ printf("cmos: opened\n");
+#endif
+ return 0;
+}
+
+int
+cmosclose(dev, flags, ifmt, p)
+ dev_t dev;
+ int flags, ifmt;
+ struct proc *p;
+{
+ struct cmos_softc *sc = &cmossoftc;
+
+ sc->sc_state = CMOS_INITED;
+#ifdef CMOS_DEBUG
+ printf("cmos: closed\n");
+#endif
+ return 0;
+}
+
+int
+cmosread(dev, uio, ioflag)
+ dev_t dev;
+ struct uio *uio;
+ int ioflag;
+{
+ struct cmos_softc *sc = &cmossoftc;
+ int i, s;
+ unsigned char *p;
+ unsigned char c;
+ int error = 0;
+
+ if (sc->sc_state & CMOS_READ)
+ return (0);
+
+ if (uio->uio_resid < CMOS_SIZE)
+ return (EINVAL);
+
+#ifdef CMOS_DEBUG
+ printf("cmos: try to read to %d\n", CMOS_SIZE);
+#endif
+ p = sc->sc_buf;
+ s = splclock();
+ for (i = 0; i < CMOS_SIZE; i++) {
+ if (i >= MC_REGA && i <= MC_REGD)
+ c = 0;
+ else
+ c = mc146818_read(sc, i);
+ *p++ = c;
+ }
+ splx(s);
+
+ sc->sc_state |= CMOS_READ;
+ error = uiomove((caddr_t)sc->sc_buf, CMOS_SIZE, uio);
+ return (error);
+}
+
+int
+cmoswrite(dev, uio, ioflag)
+ dev_t dev;
+ struct uio *uio;
+ int ioflag;
+{
+ struct cmos_softc *sc = &cmossoftc;
+ int i, l;
+ int error = 0;
+ int s;
+
+ if (sc->sc_state & CMOS_WROTE)
+ return (0);
+
+ sc->sc_state |= CMOS_WROTE;
+ l = min(CMOS_SIZE, uio->uio_resid);
+ error = uiomove((caddr_t)sc->sc_buf, l, uio);
+#ifdef CMOS_DEBUG
+ printf("write %d\n", l);
+ if (cmos_debug) {
+ cmos_dump(sc->sc_buf);
+ }
+#endif
+ if (error)
+ return error;
+
+ cmossum(sc->sc_buf, NVRAM_DISKETTE, NVRAM_SUMH, CMOS_SUM);
+ cmossum(sc->sc_buf, NVRAM_XSTART, NVRAM_XSUMH, CMOS_XSUM);
+
+#ifdef CMOS_DEBUG
+ if (cmos_debug) {
+ cmos_dump(sc->sc_buf);
+ return (0);
+ }
+#endif
+ s = splclock();
+ for (i = NVRAM_DISKETTE; i < CMOS_SIZE; i++) {
+ if (i != NVRAM_COUNTER)
+ mc146818_write(sc, i, sc->sc_buf[i]);
+ }
+ splx(s);
+
+ return (error);
+}
+
+static void
+cmossum(p, from, to, offset)
+ unsigned char *p;
+ int from;
+ int to;
+ int offset;
+{
+ int i;
+ unsigned short u;
+
+#ifdef CMOS_DEBUG
+ printf("cmossum: from %d to %d and store %d\n", from, to, offset);
+#endif
+ u = 0;
+ offset += MC_NVRAM_START;
+ for (i = from; i < to; i++) {
+ u += p[i];
+ }
+ p[offset++] = (u / 256);
+ p[offset] = (u & 0xff);
+}
+
+#ifdef CMOS_DEBUG
+static void
+cmos_dump(p)
+ unsigned char *p;
+{
+ static char buf[80];
+ int i;
+ char *t;
+
+ for (i = 0; i < CMOS_SIZE; i++) {
+ if (i % 16 == 0) {
+ sprintf(buf, "%02x:", i);
+ t = strchr(buf, '\0');
+ }
+ sprintf(t, " %02x", p[i]);
+ t += 3;
+ if (i % 16 == 15) {
+ *t++ = '\n';
+ *t = '\0';
+ printf(buf);
+ }
+ }
+ printf("\n");
+}
+#endif