Después de muchos años volví a experimentar con ACPI, concretamente, con la tabla DSDT. Por aquel entonces era poco práctico, no tanto modificar la tabla, sino implementarla. En un principio, Debian y otras distribuciones permitían anular la tabla DSDT usando un parche initrd, de esta forma, se podía introducir una tabla DSDT modificada en /etc/initramfs-tools/dsdt.aml y regenerar el initrd con: update-initramfs -u -k all
. —Fácil verdad—
Sin embargo, a partir del kernel 2.6.31.x, aproximadamente, se retiró el apoyo al parche initrd por razones de seguridad. La única forma que tuve para anular la tabla DSDT fue compilando un nuevo kernel. Ciertas modificaciones al archivo .config eran necesarias:
- CONFIG_STANDALONE=n
- CONFIG_ACPI_CUSTOM_DSDT=y
- CONFIG_ACPI_CUSTOM_DSDT_FILE=»/root/dsdt/dsdt-custom.hex».
Los tiempos han cambiado en Linux y, aunque la compilación del kernel sigue siendo una opción viable, en la actualidad se puede utilizar un proceso mucho más simple para anular la DSDT, —como en los viejos tiempos—.
Archivo fuente: kernel/drivers/acpi/tables.c introduce soporte para actualización de tablas mediante initrd:
void __init acpi_table_upgrade(void) { void *data = (void *)initrd_start; size_t size = initrd_end - initrd_start; int sig, no, table_nr = 0, total_offset = 0; long offset = 0; struct acpi_table_header *table; char cpio_path[32] = "kernel/firmware/acpi/"; struct cpio_data file; if (data == NULL || size == 0) return;
Las tablas DSDT pueden diferir mucho unas de otras, de acuerdo a la marca, o fabricante del firmware. De todas formas, es posible encontrar errores típicos en tablas DSDT que otros usuarios han corregido y documentado. Hay mucha información en la red sobre este tema y, con suerte, se pueden encontrar soluciones a estos errores.
Herramientas necesarias
- acpica-tools
- cpio
- editor (Sublime Text, vim, emacs…)
- xxd (opcional)
- qemu (opcional)
¿Que es la tabla DSDT?
Según Arch Linux:
DSDT (Tabla de descripción del sistema diferenciada) es parte de la especificación ACPI. Proporciona información sobre eventos de energía admitidos en un sistema determinado. Las tablas ACPI se proporcionan en el firmware del fabricante. Un problema común de Linux es la falta de la funcionalidad ACPI, como: ventiladores que no funcionan, pantallas que no se apagan cuando la tapa está cerrada, etc. Esto puede deberse a DSDT creados específicamente para Windows, que pueden repararse después de la instalación.
Básicamente, una tabla DSDT es el código que se ejecuta en eventos ACPI (Administración de energía).
¿Cual es el fin de anular la tabla DSDT?
Actualmente Linux/ACPI funciona en prácticamente cualquier firmware sin modificar, muchas soluciones están implementadas en el núcleo. No obstante, problemas como los mencionados arriba, o de: suspensión, energía, control de brillo, temperatura, pueden seguir siendo un problema. Intentar reemplazar la DSDT original que viene en el BIOS por una tabla modificada puede ser una solución.
En tal caso linux-acpi nos advierte:
Anular la DSDT es sólo una técnica de depuración. No es un camino viable para ejecutar un sistema de producción, ya que ningún proveedor apoyaría un sistema cuando el cliente ha modificado el firmware del sistema, y ningún distribuidor de Linux, posiblemente, podría apoyar el firmware del sistema modificado tampoco.
Lo que sigue a continuación son los pasos que realicé para anular mi tabla DSDT, más que nada como objeto de estudio. Mi portátil funciona bastante bien.
Instalar herramientas necesarias
En Debian instalando el paquete acpica-tools ya tenemos las herramientas necesarias para el: volcado, extracción, desensamblado y compilación de las tablas.
sudo apt install acpica-tools
Herramientas que forman parte de acpica-tools:
- iasl
- acpibin
- acpidump
- acpiexec
- acpihelp
- acpinames
- acpisrc
- acpixtract
Ejecuta: acpidump -h
acpixtract -h
iasl -h
para obtener más información.
Extraer las tablas ACPI
Lo primero que hago es crear un directorio de trabajo:
mkdir Devel; cd Devel
Hay varias formas de extraer las tablas ACPI, expongo las opciones más comunes:
opción 1:
En el directorio /sys/firmware/acpi/tables se encuentran otras tablas además de DSDT: FACS, MCFG, SLIC, SSDT, etc. La que realmente me interesa es la tabla DSDT.
sudo cat /sys/firmware/acpi/tables/DSDT > dsdt.dat
opción 2: acpidump
Esta opción es más completa que la anterior e involucra todas las tablas. Direcciono la salida de acpidump al archivo tables.dat:
sudo acpidump > tables.dat
A diferencia de la primera opción, ahora, todas las tablas están contenidas dentro de un mismo archivo (tables.dat), puede ser otro nombre, menos dsdt.dat, este al igual que las otras tablas (ssdt, facs, facp, boot, slic, etc) no deben ser usados, ya que son nombrados .dat por acpixtract y en caso de existir el nombre del archivo, fallará en la extracción.
A continuación es necesario extraerlas del fichero donde están contenidas, en mi caso: tables.dat:
acpixtract tables.dat
usando la opción -a (all) extrae absolutamente todas la tablas que acpidump volcó en el fichero tables.dat, realmente no necesitamos esto, pero es otra opción.
acpixtract -a tables.dat
Desensamblado
Todas las tablas están en formato AML (ACPI Machine Language), es necesario convertirlas a ASL (ACPI Source Code) para poder editarlas. iasl realiza ambas tareas. Suponiendo que utilicé la opción de acpidump, desensamblo únicamente la que me interesa:
iasl -d dsdt.dat
El resultado será un archivo con extensión .dsl, el cual ya se puede modificar. En caso de tener varias tablas, si quisiéramos desensamblarlas a todas, usamos el siguiente comando: iasl -d *.dat
. La siguiente imagen muestra el archivo dsdt.dsl editable:
Antes de compilar incremento OEM Revision (primeras lineas del archivo dsdt.dsl):
DefinitionBlock ("", "DSDT", 1, "ACRSYS", "ACRPRDCT", 0x00000001)
por:
DefinitionBlock ("", "DSDT", 1, "ACRSYS", "ACRPRDCT", 0x00000002)
Compilación
Una compilación temprana del archivo dsdt.dsl nos hará saber la cantidad de: Errors, Warnings, Remarks, Optimizations. iasl muestra información detallada del tipo de error, número de linea y código del error. La solución hay que buscarla en la documentación de ACPI o en la red. Otros usuarios posiblemente han tenido el mismo error, lo han resuelto y documentado.
iasl -tc dsdt.dsl
La opción -tc genera, además del archivo .aml, un archivo .hex. Esto es importante si se usa el método de compilación del kernel, el cual no admite .aml.
A saber, en caso de contener tan solo un error, el compilador no generará el archivo aml necesario, por lo tanto, es imperativo que la tabla DSDT quede sin errores para que sea utilizable en el lenguaje máquina.
Solución de errores
Es apropiado tener los mensajes del compilador en un archivo de texto para manipularlo fácilmente cuando buscamos información. El comando iasl, por defecto, no direcciona una salida estándar de los mensajes a un archivo de forma completa, no obstante, se puede obtener un archivo de texto plano (dsdt.lst) con toda la salida del compilador utilizando el siguiente comando:
iasl -l dsdt.dsl
Otra consideración muy importante, es el modo que debemos utilizar para corregir los errores. Empezando desde arriba (1er. error) se van corrigiendo, uno a uno, ya sean: errores, advertencias o remarcaciones. En muchos casos, errores en las lineas inferiores del código son consecuencia de algún error de más arriba.
Utilicé el comando iasl -ve dsdt.dsl
para que me arroje únicamente los mensajes de error (opción -ve), en definitiva son los que realmente importan. Mi tabla DSDT arroja 4 errores fáciles de resolver.
Error 6114
dsdt.dsl 1054: (Local0 + 0x02) Error 6114 - ^ Result is not used, operator has no effect
Linea 1054: indica que «el resultado no es usado y el operador no tiene efecto». Encontré poca información con este error en particular, dependiendo del fabricante de la BIOS hay, al menos, dos soluciones: poner entre comillas dobles «Local0» o reemplazarlo por un valor nulo: Zero o 0x00.
Cualquiera de estas opciones soluciona el error.
("Local0" + 0x02) (0x00 + 0x02) (Zero + 0x02)
Error 6136
dsdt.dsl 1270: Name (_HID, "pnp0c14") // _HID: Hardware ID Error 6136 - Non-hex letters must be upper case ^ (pnp0c14)
Un error muy común que se resuelve sin contratiempos, el compilador nos advierte en linea 1270: «Las letras no hexadecimales deben estar en mayúscula».
Simplemente reemplazar: «pnp0c14» por «PNP0C14»
Error 6043
dsdt.dsl 1632: 0x00000000, // Length Error 6043 - ^ Invalid combination of Length and Min/Max fixed flags dsdt.dsl 1639: 0x00000000, // Length Error 6043 - ^ Invalid combination of Length and Min/Max fixed flags
En este tipo de error hay que mirar más de cerca:
Las matemáticas básicas dicen que la diferencia entre: rango máximo – rango mínimo nunca puede ser igual a 0 (cero). La mínima diferencia que puede existir entre dos rangos (máx./mín.) es 1 —un bit en este caso—. En las lineas 1632 y 1639 dan como resultado 0 (cero) de longitud.
La ecuación para obtener el valor real se reduce a: rango máximo - rango mínimo + 1 = longitud
. Utilizando una calculadora con método hexadecimal, o simplemente usando el intérprete de python, obtuve los resultados correctos:
>>> hex(0xfebfffff - 0x00000000 + 1) '0xfec00000' >>> hex(0xfed44fff - 0xfed40000 + 1) '0x5000'
Corregidos los 4 errores la compilación final iasl -tc dsdt.dsl
arrojó 0 (cero) errores.
Compilation complete. 0 Errors, 38 Warnings, 91 Remarks, 36 Optimizations, 1 Constants Folded
Finalmente se generaron los archivos necesarios para anular la tabla original utilizada por la BIOS, ya sea por el método kernel (dsdt.hex), o initrd (dsdt.aml). Luego generé un registro con todos los cambios realizados para un eventual parche: diff -u dsdt.dsl dsdt-fixed.dsl
.
Advertencias y remarcaciones
Si bien hay una gran cantidad de advertencias y remarcaciones, la mayoría son mensajes inocuos propios del compilador. El consejo que dan en foros especializados es que deben ser ignorados, solo hay que centrarse en los errores. Es muy probable que al intentar solucionar las advertencias y remarcaciones, terminemos generando más errores.
Aún así, es posible encontrar soluciones a ciertos mensajes de advertencia y remarcación. Voy a exponer un caso típico de cada uno:
La advertencia (3107) en linea 9218 indica que: el método reservado debe devolver un valor entero/cadena/buffer requerido por _WED. Insertando Return (Zero)
antes de finalizar el método resuelve la advertencia código 3107 y 3115 respectivamente.
En el caso de la remarcación código 2011 es muy común. El compilador iasl se queja del guión bajo generado por el compilador de Windows.
Name (_T_0, Zero) // _T_x: Emitted by ASL Compiler, x=0-9, A-Z ^ Use of compiler reserved name (_T_0)
Solución: reemplazar todos los _T_0 por T_0, lo mismo tuve que hacer para _T_1, _T_2 y _T_3. En Vim puedes utilizar el comando :%s/_T_0/T_0/g
. Aunque cualquier editor que permita buscar/reemplazar está muy bien, por ej. Sublime Text
Ahora mi archivo dsdt.dsl con esas correcciones arroja lo siguiente:
Compilation complete. 0 Errors, 36 Warnings, 80 Remarks, 36 Optimizations, 1 Constants Folded
Llegó el momento de implementar mi tabla DSDT sin errores.
Implementación de la tabla DSDT en el initrd
El la configuración del kernel ya viene por defecto seleccionado: CONFIG_ACPI_TABLE_UPGRADE=y
, por lo tanto mi tabla DSDT va a ser leída en el initrd y la actualizará.
El primer paso es crear los directorios kernel/firmware/acpi:
mkdir -p kernel/firmware/acpi
copiamos la/s tabla/s .aml modificadas en acpi
cp dsdt.aml kernel/firmware/acpi/
El siguiente comando añade la/s tabla/s ACPI .aml a un archivo cpio sin comprimir. Los directorios kernel/firmware/acpi/ deben estar dentro del archivo cpio. Las siguientes acciones hay que realizarlas como root.
Creando el archivo cpio sin comprimir:
find kernel | cpio -H newc --create > /boot/fixed_initrd
concateno el initrd original (initrd.img-4.19.0-8-amd64) con el creado por cpio.
cat /boot/initrd.img-4.19.0-8-amd64 >> /boot/fixed_initrd
La imagen a continuación muestra como quedo instrumentado el archivo cpio en la parte superior del initrd original:
Comprobar el nuevo initrd
Es importante probar la tabla DSDT en un sistema virtual antes de llevarlo a un sistema real. Yo utilicé qemu y lo configuré para que arranque solamente con los parámetros del kernel y mi initrd modificado.
qemu-system-x86_64 -nographic -no-reboot -kernel /boot/vmlinuz-4.19.0-8-amd64 \ -initrd fixed_initrd -append "panic=1 console=ttyS0"
Una ves comprobado que no hay fallos en el inicio del sistema, lo implemento en mi sistema Debian, pero antes, hago un backup del initrd original:
sudo cp /boot/initrd.img-4.19.0-8-amd64 /boot/initrd.img-4.19.0-8-amd64.back
luego:
sudo cp /boot/fixed_initrd /boot/initrd.img-4.19.0-8-amd64
La salida del comando sudo dmesg
muestra que la tabla ha sido implementada exitosamente.
También puede observarse como modificó rangos de memoria, aunque no entiendo nada de esto, fue evidente que se realizaron varios cambios. Otra peculiaridad es en la especificación, la tabla original no la reconoce como Intel:
- DSDT original: (v01 ACRSYS ACRPRDCT 00000001 1025 01000013)
- DSDT fixed: (v01 ACRSYS ACRPRDCT 00000002 INTL 20181213)
Recomendaciones finales
Ya no es muy habitual realizar este tipo de prácticas, aún así, es una alternativa que puede favorecer a más de uno. Existen muchas tablas DSDT circulando por la red que ya fueron arregladas y que pudieran implementarse fácilmente. Sin embargo no lo recomiendo, se corre el riesgo de dañar el sistema.
La mayoría de las tablas están parcheadas para marcas específicas, o modificadas para solucionar algún problema con un dispositivo determinado, del cual nuestra computadora probablemente no tenga. Lo mejor es intentar solucionar la tabla DSDT de nuestro sistema, en lugar de usar una ajena.
¿Tienes curiosidad?
Puedes comprobar si tu tabla DSDT está libre de errores, sin necesidad de implementarla.
Fuente:
https://www.acpica.org/documentation
https://01.org/linux-acpi/documentation/overriding-dsdt
https://wiki.archlinux.org/index.php/DSDT
https://www.kernel.org/doc/Documentation/acpi/initrd_table_override.txt
https://www.osx86spain.com/77/17682/guia-dsdt-osx86.html
Mano, me tome la molestia de tocar tu nick, y leer articulos anteriores, y creeme, es mas que genial los articulos, empezando por este, que empece a leer, y ni idea de que hablabas hahaha. Excelentes todos tus articulos, men.
Muchas gracias a vos por leernos y que te gusten los artículos. Yo también entiendo poco y nada, el lenguaje de las tablas DSDT es muy complejo, es más que nada leer y leer documentación.
Saludos.
jajaja me paso lo mismo, comencé a leer, y mi mente por poco explota, y me dijo, aunque ni idea de lo que habla, igual le dejo un comentario con el agradecimiento por el esfuerzo y por tremendo artículo que se ha publicado, y me encuentro este comentario jaja
Nada, en hora buena, lástima que no haya podido entender nada, mis conocimientos no son tan avanzados, pero el articulo si se merece los mayores elogios.
Gracias @fr0st-w4rr10r por tu comentario. Es un tema que se hablaba mucho hace una década, y un poco más diría yo. En ese tiempo los portátiles tenían problemas muy comunes como: Suspensión y Control de brillo, entre otros.
Compañías como Foxconn estaban en el ojo de la tormenta por sabotear -presuntamente- las BIOS Linux, Microsoft tampoco estaba ajeno a esta manera de proceder. No quedaba más remedio que recurrir a las prácticas que describí en el artículo. Ahora Linux ha mejorado mucho y puede suplir las deficiencias que teníamos en el pasado.
Otra clase magistral, gracias colega
Gracias @Maikel. De a poco me voy aflojando, recuerda que fue idea tuya lo de impulsarme a escribir artículos, el que debe agradecerte soy yo. Cuesta encontrar temas que agraden a la mayoría de los lectores de GUTL. El que rompió el molde es «Python y la sucesión de Fibonacci» más de 50000 leídas, que pena que no haya pythonianos escribiendo algún artículo por aquí.
Saludos.
OT(sorry): Quiero comenzar a programar en python, y al no tener Internet me es un poco dificil, si dominas el lenguaje crees que para futuros articulos, pudieras hacer algunos de python para ayudar a los que comienzan. Claro, si el tiempo te da.
Lamentablemente no soy programador y no domino python. El artículo que escribí fue más bien enfocándome en puntos específicos del lenguaje, me salté algunos capítulos del libro, algo que no se debe hacer. Era más bien para tocar un tema en particular (Suc. de Fibonacci). No suelo comprometerme con algo que no voy a poder cumplir.
Dejé de estudiar python hace un tiempo, en algún momento volveré a empezar de cero. De vez en cuando hago programación básica, ahora estoy creando un programa para parsear subtítulos .json a .srt, pero es más que nada observando otros programas y documentación de python. En el artículo hay un manual para descarga (https://gutl.jovenclub.cu/wp-content/uploads/2015/12/TutorialPython3.pdf) ideal para los que recién comienzan. Espero te sirva.
Saludos.
Gracias
Excelente desarrollo. Encomio lo actuado.
Atte.
Juan Perón
Gracias Juan Perón por tu comentario, y por visitarnos.
Saludos.