On December 12, 2019 4:42:18 AM GMT+08:00, K Staring <q...@quickdekay.net> 
wrote:
>Hi,
>
>Another one.. While using acpi_call to disable the dGPU on my Dell XPS
>9560,
>I experienced a crash. FreeBSD had fixed this exact crash some months
>prior;
>included is a patch which imports the fix.
>
>
>Regards,
>
>Khamba
>
>
>--- a/sys/dev/acpica/acpi.c
>+++ b/sys/dev/acpica/acpi.c
>@@ -300,7 +300,7 @@ SYSCTL_INT(_debug_acpi, OID_AUTO, do_powerstate,
>CTLFLAG_RW,
> TUNABLE_INT("debug.acpi.quirks", &acpi_quirks);
> 
> /* Allow to call ACPI methods from userland. */
>-static int acpi_allow_mcall;
>+static int acpi_allow_mcall = 0;
> TUNABLE_INT("debug.acpi.allow_method_calls", &acpi_allow_mcall);
> 
> static int acpi_susp_bounce;
>@@ -3230,6 +3230,136 @@ acpiclose(struct dev_close_args *ap)
>     return (0);
> }
> 
>+//--------------------------------------------------------------------------
>+void acpi_call_fixup_pointers(ACPI_OBJECT *p, UINT8 *orig);
>+
>+static void
>+free_acpi_object_list(ACPI_OBJECT_LIST *list)
>+{
>+      for (int i = 0; i < list->Count; i++) {
>+              switch (list->Pointer[i].Type) {
>+              case ACPI_TYPE_STRING:
>+                      AcpiOsFree(list->Pointer[i].String.Pointer);
>+                      break;
>+              case ACPI_TYPE_BUFFER:
>+                      AcpiOsFree(list->Pointer[i].Buffer.Pointer);
>+                      break;
>+              default:
>+                      break;
>+              }
>+      }
>+      AcpiOsFree(list);
>+}
>+
>+static ACPI_OBJECT_LIST *
>+copyin_acpi_object_list(ACPI_OBJECT_LIST *src)
>+{
>+      ACPI_OBJECT_LIST *dest;
>+      bool failed;
>+
>+      if (src->Count > 7)
>+              return NULL;
>+
>+      dest = AcpiOsAllocate(sizeof(ACPI_OBJECT_LIST) + sizeof(ACPI_OBJECT)
>* src->Count);
>+      if (!dest)
>+              return NULL;
>+
>+      dest->Count = src->Count;
>+      dest->Pointer = (ACPI_OBJECT *)(dest + 1);
>+      if (copyin(src->Pointer, dest->Pointer, sizeof(ACPI_OBJECT) *
>dest->Count)) {
>+              AcpiOsFree(dest);
>+              return NULL;
>+      }
>+
>+      failed = false;
>+
>+      for (int i = 0; i < dest->Count; i++) {
>+              switch (dest->Pointer[i].Type) {
>+              case ACPI_TYPE_INTEGER:
>+                      break;
>+              case ACPI_TYPE_STRING: {
>+                      void *v = 
>AcpiOsAllocate(dest->Pointer[i].String.Length);
>+                      if (!v || copyin(dest->Pointer[i].String.Pointer, v,
>dest->Pointer[i].String.Length))
>+                              failed = true;
>+                      dest->Pointer[i].String.Pointer = v;
>+                      break;
>+              }
>+              case ACPI_TYPE_BUFFER: {
>+                      void *v = 
>AcpiOsAllocate(dest->Pointer[i].Buffer.Length);
>+                      if (!v || copyin(dest->Pointer[i].Buffer.Pointer, v,
>dest->Pointer[i].Buffer.Length))
>+                              failed = true;
>+                      dest->Pointer[i].String.Pointer = v;
>+                      break;
>+              }
>+              default:
>+                      failed = true;
>+                      break;
>+              }
>+      }
>+
>+      if (failed) {
>+              free_acpi_object_list(dest);
>+              dest = NULL;
>+      }
>+
>+      return dest;
>+}
>+
>+static int
>+acpi_call_ioctl(caddr_t addr)
>+{
>+      struct acpi_mcall_ioctl_arg *params;
>+      ACPI_OBJECT_LIST        *args;
>+      ACPI_BUFFER     result;
>+      char            path[256];
>+
>+      result.Length = ACPI_ALLOCATE_BUFFER;
>+      result.Pointer = NULL;
>+
>+      params = (struct acpi_mcall_ioctl_arg*)addr;
>+      args = copyin_acpi_object_list(&params->args);
>+      if (!args)
>+              return EINVAL;
>+      if (copyinstr(params->path, path, sizeof(path), NULL))
>+                      return EINVAL;
>+      params->retval = AcpiEvaluateObject(NULL, path, args, &result);
>+      if (ACPI_SUCCESS(params->retval))
>+      {
>+              if (result.Pointer != NULL)
>+              {
>+                      if (params->result.Pointer != NULL)
>+                      {       
>+                              params->result.Length = 
>min(params->result.Length, result.Length);
>+                              if (result.Length >= sizeof(ACPI_OBJECT))
>+                                      
>acpi_call_fixup_pointers((ACPI_OBJECT*)result.Pointer,
>params->result.Pointer);
>+                              copyout(result.Pointer, params->result.Pointer,
>+                                              params->result.Length);
>+                              params->reslen = result.Length;
>+                      }
>+                      AcpiOsFree(result.Pointer);
>+              }
>+      }
>+      free_acpi_object_list(args);
>+
>+      return (0);
>+}
>+
>+void
>+acpi_call_fixup_pointers(ACPI_OBJECT *p, UINT8 *dest)
>+{
>+      switch (p->Type)
>+      {
>+      case ACPI_TYPE_STRING:
>+              p->String.Pointer += dest - (UINT8*)p;
>+              break;
>+      case ACPI_TYPE_BUFFER:
>+              p->Buffer.Pointer += dest - (UINT8*)p;
>+              break;
>+      }
>+}
>+
>+//--------------------------------------------------------------------------
>+
> static int
> acpiioctl(struct dev_ioctl_args *ap)
> {
>@@ -3297,40 +3427,7 @@ acpiioctl(struct dev_ioctl_args *ap)
>       break;
>     case ACPIIO_DO_MCALL:
>       if (acpi_allow_mcall == 1) {
>-          struct acpi_mcall_ioctl_arg *params;
>-          ACPI_BUFFER result = { ACPI_ALLOCATE_BUFFER, NULL };
>-          ACPI_OBJECT *resobj;
>-
>-          error = EINVAL;
>-          params = (struct acpi_mcall_ioctl_arg *)ap->a_data;
>-          params->retval = AcpiEvaluateObject(NULL, params->path,
>-              &params->args, &result);
>-          if (ACPI_SUCCESS(params->retval) && result.Pointer != NULL &&
>-              params->result.Pointer != NULL) {
>-              params->result.Length = min(params->result.Length,
>-                  result.Length);
>-              copyout(result.Pointer, params->result.Pointer,
>-                  params->result.Length);
>-              params->reslen = result.Length;
>-              if (result.Length >= sizeof(ACPI_OBJECT)) {
>-                  resobj = (ACPI_OBJECT *)params->result.Pointer;
>-                  switch (resobj->Type) {
>-                  case ACPI_TYPE_STRING:
>-                      resobj->String.Pointer = (char *)
>-                          ((UINT8 *)(resobj->String.Pointer) -
>-                              (UINT8 *)result.Pointer +
>-                              (UINT8 *)resobj);
>-                      break;
>-                  case ACPI_TYPE_BUFFER:
>-                      resobj->Buffer.Pointer -= (UINT8 *)result.Pointer -
>-                          (UINT8 *)resobj;
>-                      break;
>-                  }
>-              }
>-              error = 0;
>-          }
>-          if (result.Pointer != NULL)
>-              AcpiOsFree(result.Pointer);
>+            error = acpi_call_ioctl(ap->a_data);
>       } else {
>               device_printf(sc->acpi_dev,
>                   "debug.acpi.allow_method_calls must be set\n");

Hi, thank you very much for providing the nice patch. We've merged it into the 
master and release branches.

Regards,
-- 
Aaron

Reply via email to