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: