Subject: port-sparc/1427: eeprom_uio() attempts bad access to EEPROM
To: None <gnats-bugs@gnats.netbsd.org>
From: Jason R. Thorpe <thorpej@SJ.Xenotropic.COM>
List: netbsd-bugs
Date: 08/31/1995 16:25:54
>Number: 1427
>Category: port-sparc
>Synopsis: eeprom_uio() attempts bad access to EEPROM
>Confidential: no
>Severity: serious
>Priority: high
>Responsible: gnats-admin (GNATS administrator)
>State: open
>Class: sw-bug
>Submitter-Id: net
>Arrival-Date: Thu Aug 31 19:35:02 1995
>Last-Modified:
>Originator:
>Organization:
Just me and my collection of obsolete computer gear(s).
>Release: -current Aug 27 1995
>Environment:
System: NetBSD bigsby 1.0A NetBSD 1.0A (BIGSBY) #57: Thu Aug 31 09:53:30 PDT 1995 thorpej@bigsby:/tmp_mnt/basalt/work/netbsd/src/sys/arch/sparc/compile/BIGSBY sparc
>Description:
Apparently, the Sun 4 EEPROM is picky about how it's accessed.
Experience has shown me that byte-at-a-time access is all that's
permitted at all locations within EEPROM space.
This poses a problem given that copyout() (by calling bcopy()) will
attempt long-word access of the EEPROM, causing the user process
to receive an EFAULT.
Note that this problem does not exist on writes, since writes
are written into a temporary buffer already, and only differing
bytes are written to the EEPROM, for the sake of saving hardware
wear-and-tear.
Unfortunately, at the time I wrote the eeprom(8) program, I had
to rely on others to tell me that the EEPROM-related changes
worked on the Sun 4, as my 4/260 was having hardware problems.
*sigh* I was only able to test it first-hand on OpenProm Sparcs
and a Sun 3/60.
>How-To-Repeat:
Run `/usr/sbin/eeprom'. You'll get:
eeprom: read: Bad address
eeprom: can't read field `eeprom contents'
>Fix:
The patch to clock.c below fixes the problem by doing a
byte-by-byte copy of the meaningful EEPROM contents into a
temporary buffer, which is then passed to uiomove().
Index: clock.c
===================================================================
RCS file: /usr/og/devsrc/netbsd/src/sys/arch/sparc/sparc/clock.c,v
retrieving revision 1.2
diff -c -r1.2 clock.c
*** clock.c 1995/08/27 23:33:09 1.2
--- clock.c 1995/08/31 17:02:20
***************
*** 1047,1054 ****
#if defined(SUN4)
int error;
int off; /* NOT off_t */
! u_int cnt;
! caddr_t va;
caddr_t buf = NULL;
if (cputyp != CPU_SUN4)
--- 1047,1053 ----
#if defined(SUN4)
int error;
int off; /* NOT off_t */
! u_int cnt, bcnt;
caddr_t buf = NULL;
if (cputyp != CPU_SUN4)
***************
*** 1070,1087 ****
goto out;
}
! va = eeprom_va;
! if (uio->uio_rw != UIO_READ) {
! /* Write requires a temporary buffer. */
! buf = malloc(EEPROM_SIZE, M_DEVBUF, M_WAITOK);
! if (buf == NULL) {
! error = EAGAIN;
! goto out;
! }
! va = buf;
}
! if ((error = uiomove(va + off, (int)cnt, uio)) != 0)
goto out;
if (uio->uio_rw != UIO_READ)
--- 1069,1091 ----
goto out;
}
! /*
! * The EEPROM can only be accessed one byte at a time, yet
! * uiomove() will attempt long-word access. To circumvent
! * this, we byte-by-byte copy the eeprom contents into a
! * temporary buffer.
! */
! buf = malloc(EEPROM_SIZE, M_DEVBUF, M_WAITOK);
! if (buf == NULL) {
! error = EAGAIN;
! goto out;
}
! if (uio->uio_rw == UIO_READ)
! for (bcnt = 0; bcnt < EEPROM_SIZE; ++bcnt)
! *(char *)(buf + bcnt) = *(char *)(eeprom_va + bcnt);
!
! if ((error = uiomove(buf + off, (int)cnt, uio)) != 0)
goto out;
if (uio->uio_rw != UIO_READ)
>Audit-Trail:
>Unformatted: