Subject: kern/23825: x1226 (i2c) broken
To: None <gnats-bugs@gnats.NetBSD.org>
From: None <kiyohara@kk.iij4u.or.jp>
List: netbsd-bugs
Date: 12/21/2003 15:16:58
>Number:         23825
>Category:       kern
>Synopsis:       x1226 (i2c) broken
>Confidential:   no
>Severity:       critical
>Priority:       high
>Responsible:    kern-bug-people
>State:          open
>Class:          change-request
>Submitter-Id:   net
>Arrival-Date:   Sun Dec 21 15:17:00 UTC 2003
>Closed-Date:
>Last-Modified:
>Originator:     KIYOHARA Takashi
>Release:        1.6ZG
>Organization:
>Environment:
NetBSD evbppc.fool 1.6ZG NetBSD 1.6ZG (OPENBLOCKS266) #0: Sun Dec 21 12:58:20 JST 2003  lance@highpriestess.fool:/sys/arch/evbppc/compile/OPENBLOCKS266 evbppc
>Description:
sys/dev/i2c/x1226{.c,reg.h}  broken.

  1. read/write overflow to array size.
  2. abnormal master addressing


1 is in xrtc_clock_{read,write}(). variable bcd[] declarated size from the macro X1226_REG_RTC_SIZE. bcd is readed/writed RTC, from sec to y2k, size is 8. but defined number 7 the macro X1226_REG_RTC_SIZE from x1226reg.h. OK ?

2. is abnormal addressing. the x1226 is big endian for master address.
little endian currently.
>How-To-Repeat:

>Fix:
Index: x1226.c
===================================================================
RCS file: /cvsroot/src/sys/dev/i2c/x1226.c,v
retrieving revision 1.1
diff -c -r1.1 x1226.c
*** x1226.c     2003/10/06 18:02:02     1.1
--- x1226.c     2003/12/21 13:03:30
***************
*** 176,183 ****

        while (uio->uio_resid && uio->uio_offset < X1226_NVRAM_SIZE) {
                addr = (int)uio->uio_offset + X1226_NVRAM_START;
!               cmdbuf[0] = addr && 0xff;
!               cmdbuf[1] = (addr >> 8) && 0xff;
                if ((error = iic_exec(sc->sc_tag,
                        I2C_OP_READ_WITH_STOP,
                        sc->sc_address, cmdbuf, 2, &ch, 1, 0)) != 0) {
--- 176,183 ----

        while (uio->uio_resid && uio->uio_offset < X1226_NVRAM_SIZE) {
                addr = (int)uio->uio_offset + X1226_NVRAM_START;
!               cmdbuf[0] = (addr >> 8) && 0xff;
!               cmdbuf[1] = addr && 0xff;
                if ((error = iic_exec(sc->sc_tag,
                        I2C_OP_READ_WITH_STOP,
                        sc->sc_address, cmdbuf, 2, &ch, 1, 0)) != 0) {
***************
*** 216,223 ****

        while (uio->uio_resid && uio->uio_offset < X1226_NVRAM_SIZE) {
                addr = (int)uio->uio_offset + X1226_NVRAM_START;
!               cmdbuf[0] = addr && 0xff;
!               cmdbuf[1] = (addr >> 8) && 0xff;
                if ((error = uiomove(&cmdbuf[2], 1, uio)) != 0) {
                        break;
                }
--- 216,223 ----

        while (uio->uio_resid && uio->uio_offset < X1226_NVRAM_SIZE) {
                addr = (int)uio->uio_offset + X1226_NVRAM_START;
!               cmdbuf[0] = (addr >> 8) && 0xff;
!               cmdbuf[1] = addr && 0xff;
                if ((error = uiomove(&cmdbuf[2], 1, uio)) != 0) {
                        break;
                }
***************
*** 300,307 ****
        /* Read each RTC register in order */
        for (i = 0 ; i < X1226_REG_RTC_SIZE ; i++) {
                int addr = i + X1226_REG_RTC_BASE;
!               cmdbuf[0] = addr & 0xff;
!               cmdbuf[1] = (addr >> 8) & 0xff;

                if (iic_exec(sc->sc_tag,
                        I2C_OP_READ_WITH_STOP,
--- 300,307 ----
        /* Read each RTC register in order */
        for (i = 0 ; i < X1226_REG_RTC_SIZE ; i++) {
                int addr = i + X1226_REG_RTC_BASE;
!               cmdbuf[0] = (addr >> 8) & 0xff;
!               cmdbuf[1] = addr & 0xff;

                if (iic_exec(sc->sc_tag,
                        I2C_OP_READ_WITH_STOP,
***************
*** 334,339 ****
--- 334,341 ----
                dt->dt_hour = FROMBCD(bcd[X1226_REG_HR - X1226_REG_RTC_BASE]
                        & X1226_REG_HR24_MASK);
        }
+       dt->dt_wday = FROMBCD(bcd[X1226_REG_DW - X1226_REG_RTC_BASE]
+                       & X1226_REG_DT_MASK);
        dt->dt_day = FROMBCD(bcd[X1226_REG_DT - X1226_REG_RTC_BASE]
                        & X1226_REG_DT_MASK);
        dt->dt_mon = FROMBCD(bcd[X1226_REG_MO - X1226_REG_RTC_BASE]
***************
*** 373,380 ****

        /* Unlock register: Write Enable Latch */
        addr = X1226_REG_SR;
!       cmdbuf[0] = (addr & 0xff);
!       cmdbuf[1] = ((addr >> 8) & 0xff);
        cmdbuf[2] = X1226_FLAG_SR_WEL;
        if (iic_exec(sc->sc_tag,
                I2C_OP_WRITE_WITH_STOP,
--- 375,382 ----

        /* Unlock register: Write Enable Latch */
        addr = X1226_REG_SR;
!       cmdbuf[0] = ((addr >> 8) & 0xff);
!       cmdbuf[1] = (addr & 0xff);
        cmdbuf[2] = X1226_FLAG_SR_WEL;
        if (iic_exec(sc->sc_tag,
                I2C_OP_WRITE_WITH_STOP,
***************
*** 388,395 ****

        /* Unlock register: Register Write Enable Latch */
        addr = X1226_REG_SR;
!       cmdbuf[0] = (addr & 0xff);
!       cmdbuf[1] = ((addr >> 8) & 0xff);
        cmdbuf[2] = X1226_FLAG_SR_RWEL;
        if (iic_exec(sc->sc_tag,
                I2C_OP_WRITE_WITH_STOP,
--- 390,397 ----

        /* Unlock register: Register Write Enable Latch */
        addr = X1226_REG_SR;
!       cmdbuf[0] = ((addr >> 8) & 0xff);
!       cmdbuf[1] = (addr & 0xff);
        cmdbuf[2] = X1226_FLAG_SR_RWEL;
        if (iic_exec(sc->sc_tag,
                I2C_OP_WRITE_WITH_STOP,
***************
*** 404,411 ****
        /* Write each RTC register in reverse order */
        for (i = (X1226_REG_RTC_SIZE - 1) ; i >= 0; i--) {
                int addr = i + X1226_REG_RTC_BASE;
!               cmdbuf[0] = (addr & 0xff);
!               cmdbuf[1] = ((addr >> 8) & 0xff);
                if (iic_exec(sc->sc_tag,
                        I2C_OP_WRITE_WITH_STOP,
                        sc->sc_address, cmdbuf, 2,
--- 406,413 ----
        /* Write each RTC register in reverse order */
        for (i = (X1226_REG_RTC_SIZE - 1) ; i >= 0; i--) {
                int addr = i + X1226_REG_RTC_BASE;
!               cmdbuf[0] = ((addr >> 8) & 0xff);
!               cmdbuf[1] = (addr & 0xff);
                if (iic_exec(sc->sc_tag,
                        I2C_OP_WRITE_WITH_STOP,
                        sc->sc_address, cmdbuf, 2,
***************
*** 413,420 ****

                        /* Lock register: WEL/RWEL off */
                        addr = X1226_REG_SR;
!                       cmdbuf[0] = (addr & 0xff);
!                       cmdbuf[1] = ((addr >> 8) & 0xff);
                        cmdbuf[2] = 0;
                        iic_exec(sc->sc_tag,
                                I2C_OP_WRITE_WITH_STOP,
--- 415,422 ----

                        /* Lock register: WEL/RWEL off */
                        addr = X1226_REG_SR;
!                       cmdbuf[0] = ((addr >> 8) & 0xff);
!                       cmdbuf[1] = (addr & 0xff);
                        cmdbuf[2] = 0;
                        iic_exec(sc->sc_tag,
                                I2C_OP_WRITE_WITH_STOP,
***************
*** 430,438 ****

        /* Lock register: WEL/RWEL off */
        addr = X1226_REG_SR;
!       cmdbuf[0] = (addr & 0xff);
!       cmdbuf[1] = ((addr >> 8) & 0xff);
!       cmdbuf[2] = X1226_FLAG_SR_WEL;
        if (iic_exec(sc->sc_tag,
                I2C_OP_WRITE_WITH_STOP,
                sc->sc_address, cmdbuf, 2, &cmdbuf[2], 1, 0) != 0) {
--- 432,440 ----

        /* Lock register: WEL/RWEL off */
        addr = X1226_REG_SR;
!       cmdbuf[0] = ((addr >> 8) & 0xff);
!       cmdbuf[1] = (addr & 0xff);
!       cmdbuf[2] = 0;
        if (iic_exec(sc->sc_tag,
                I2C_OP_WRITE_WITH_STOP,
                sc->sc_address, cmdbuf, 2, &cmdbuf[2], 1, 0) != 0) {
Index: x1226reg.h
===================================================================
RCS file: /cvsroot/src/sys/dev/i2c/x1226reg.h,v
retrieving revision 1.1
diff -c -r1.1 x1226reg.h
*** x1226reg.h  2003/10/06 18:02:02     1.1
--- x1226reg.h  2003/12/21 13:03:30
***************
*** 64,70 ****
  #define       X1226_REG_MN            0x31    /* bcd inute (0-59) */
  #define       X1226_REG_SC            0x30    /* bcd econd (0-59) */
  #define       X1226_REG_RTC_BASE      0x30
! #define       X1226_REG_RTC_SIZE      (X1226_REG_Y2K - X1226_REG_RTC_BASE)
  /* Watchdog RTC registers mask */
  #define       X1226_REG_Y2K_MASK      0x39
  #define       X1226_REG_DW_MASK       0x07
--- 64,70 ----
  #define       X1226_REG_MN            0x31    /* bcd inute (0-59) */
  #define       X1226_REG_SC            0x30    /* bcd econd (0-59) */
  #define       X1226_REG_RTC_BASE      0x30
! #define       X1226_REG_RTC_SIZE      (X1226_REG_Y2K - X1226_REG_RTC_BASE) + \
1
  /* Watchdog RTC registers mask */
  #define       X1226_REG_Y2K_MASK      0x39
  #define       X1226_REG_DW_MASK       0x07

>Release-Note:
>Audit-Trail:
>Unformatted: