> From: Henri Kemppainen <ducl...@guu.fi>
> Date: Tue, 21 May 2013 10:50:19 +0300 (EEST)
> 
> > +   if (blen > aml_intlen) {
> > +           if (mode == ACPI_IOREAD) {
> > +                   /* Read from a large field: create buffer */
> > +                   _aml_setvalue(val, AML_OBJTYPE_BUFFER,
> > +                       (blen + 7) << 3, 0);
>                                      ^^^^^^
> 
> It looks like a bit count is being converted to bytes.  Shouldn't
> this be a right shift?

Good catch!

Here's a new diff.  That bug is in a codepath that will probably never
be executed by real-world AML.  So there is no real need to retest if
you already did.  But if you have yet to start your testing, please
use this diff instead.

Thanks,

Mark


Index: dsdt.c
===================================================================
RCS file: /cvs/src/sys/dev/acpi/dsdt.c,v
retrieving revision 1.200
diff -u -p -r1.200 dsdt.c
--- dsdt.c      10 Apr 2013 01:35:55 -0000      1.200
+++ dsdt.c      21 May 2013 08:21:17 -0000
@@ -2221,8 +2221,9 @@ aml_evalhid(struct aml_node *node, struc
        return (0);
 }
 
-void aml_rwfield(struct aml_value *, int, int, struct aml_value *, int);
 void aml_rwgas(struct aml_value *, int, int, struct aml_value *, int, int);
+void aml_rwindexfield(struct aml_value *, struct aml_value *val, int);
+void aml_rwfield(struct aml_value *, int, int, struct aml_value *, int);
 
 /* Get PCI address for opregion objects */
 int
@@ -2341,6 +2342,81 @@ aml_rwgas(struct aml_value *rgn, int bpo
        aml_freevalue(&tmp);
 }
 
+
+void
+aml_rwindexfield(struct aml_value *fld, struct aml_value *val, int mode)
+{
+       struct aml_value tmp, *ref1, *ref2;
+       void *tbit, *vbit;
+       int vpos, bpos, blen;
+       int indexval;
+       int sz, len;
+
+       ref2 = fld->v_field.ref2;
+       ref1 = fld->v_field.ref1;
+       bpos = fld->v_field.bitpos;
+       blen = fld->v_field.bitlen;
+
+       memset(&tmp, 0, sizeof(tmp));
+       tmp.refcnt = 99;
+
+       /* Get field access size */
+       switch (AML_FIELD_ACCESS(fld->v_field.flags)) {
+       case AML_FIELD_WORDACC:
+               sz = 2;
+               break;
+       case AML_FIELD_DWORDACC:
+               sz = 4;
+               break;
+       case AML_FIELD_QWORDACC:
+               sz = 8;
+               break;
+       default:
+               sz = 1;
+               break;
+       }
+
+       if (blen > aml_intlen) {
+               if (mode == ACPI_IOREAD) {
+                       /* Read from a large field: create buffer */
+                       _aml_setvalue(val, AML_OBJTYPE_BUFFER,
+                           (blen + 7) >> 3, 0);
+               }
+               vbit = val->v_buffer;
+       } else {
+               if (mode == ACPI_IOREAD) {
+                       /* Read from a short field: initialize integer */
+                       _aml_setvalue(val, AML_OBJTYPE_INTEGER, 0, 0);
+               }
+               vbit = &val->v_integer;
+       }
+       tbit = &tmp.v_integer;
+       vpos = 0;
+
+       indexval = (bpos >> 3) & ~(sz - 1);
+       bpos = bpos - (indexval << 3);
+
+       while (blen > 0) {
+               len = min(blen, (sz << 3) - bpos);
+
+               /* Write index register */
+               _aml_setvalue(&tmp, AML_OBJTYPE_INTEGER, indexval, 0);
+               aml_rwfield(ref2, 0, aml_intlen, &tmp, ACPI_IOWRITE);
+               indexval += sz;
+
+               /* Read/write data register */
+               _aml_setvalue(&tmp, AML_OBJTYPE_INTEGER, 0, 0);
+               if (mode == ACPI_IOWRITE)
+                       aml_bufcpy(tbit, 0, vbit, vpos, len);
+               aml_rwfield(ref1, bpos, len, &tmp, mode);
+               if (mode == ACPI_IOREAD)
+                       aml_bufcpy(vbit, vpos, tbit, 0, len);
+               vpos += len;
+               blen -= len;
+               bpos = 0;
+       }
+}
+
 void
 aml_rwfield(struct aml_value *fld, int bpos, int blen, struct aml_value *val,
     int mode)
@@ -2356,10 +2432,7 @@ aml_rwfield(struct aml_value *fld, int b
        memset(&tmp, 0, sizeof(tmp));
        aml_addref(&tmp, "fld.write");
        if (fld->v_field.type == AMLOP_INDEXFIELD) {
-               _aml_setvalue(&tmp, AML_OBJTYPE_INTEGER, fld->v_field.ref3, 0);
-               aml_rwfield(ref2, 0, aml_intlen, &tmp, ACPI_IOWRITE);
-               aml_rwfield(ref1, fld->v_field.bitpos, fld->v_field.bitlen,
-                   val, mode);
+               aml_rwindexfield(fld, val, mode);
        } else if (fld->v_field.type == AMLOP_BANKFIELD) {
                _aml_setvalue(&tmp, AML_OBJTYPE_INTEGER, fld->v_field.ref3, 0);
                aml_rwfield(ref2, 0, aml_intlen, &tmp, ACPI_IOWRITE);
@@ -2414,10 +2487,6 @@ aml_createfield(struct aml_value *field,
            opcode == AMLOP_BANKFIELD) ?
            AML_OBJTYPE_FIELDUNIT :
            AML_OBJTYPE_BUFFERFIELD;
-       if (opcode == AMLOP_INDEXFIELD) {
-               indexval = bpos >> 3;
-               bpos &= 7;
-       }
 
        if (field->type == AML_OBJTYPE_BUFFERFIELD &&
            data->type != AML_OBJTYPE_BUFFER)

Reply via email to