paint-brush
El mundo oculto del firmware: explorando el proceso de arranque de su computadorapor@tristejoursoir
3,126 lecturas
3,126 lecturas

El mundo oculto del firmware: explorando el proceso de arranque de su computadora

por Aleksandr Goncharov15m2023/04/21
Read on Terminal Reader

Demasiado Largo; Para Leer

En este artículo, hacemos una descripción general del proceso de arranque, incluidas sus diversas etapas, los componentes clave involucrados y los desafíos que enfrentamos durante el proceso. Si bien nuestro enfoque principal estará en la **arquitectura x86** (la más utilizada), otras arquitecturas tendrían muchas similitudes en su proceso de arranque.
featured image - El mundo oculto del firmware: explorando el proceso de arranque de su computadora
Aleksandr Goncharov HackerNoon profile picture


Mucha gente está interesada en cómo se inicia la computadora. Aquí es donde comienza la magia y continúa mientras el dispositivo esté encendido. En este artículo, veremos una descripción general del proceso de arranque , incluidas sus diversas etapas, los componentes clave involucrados y los desafíos que enfrenta durante el proceso.


Si bien nuestro enfoque principal estará en la arquitectura x86 (la más utilizada), otras arquitecturas tendrían muchas similitudes en su proceso de arranque. Espero que este artículo sea un recurso valioso para cualquiera que busque profundizar sus conocimientos en este campo. ¡Aquí vamos!

Tabla de contenido:

  • ROM DE ARRANQUE
    • Memoria no volátil
      • Programable una vez
      • Programable en campo
    • Ejecutar en el lugar (XIP)
      • Caché como RAM (CAR)
    • Diseño y mapeo de memoria
      • Modo no descriptor
      • Intel Flash Descriptor / Modo descriptor
      • Tabla de interfaz de firmware de Intel (FIT)
      • Estructura de firmware integrado de AMD
  • Inicialización de silicio
    • Paquete de soporte de firmware de Intel (FSP)
    • Arquitectura de software encapsulada genérica de AMD (AGESA)
  • Subsistemas autónomos
    • Intel ME
    • AMD PSP
  • Secuencias de potencia de hardware

ROM DE ARRANQUE

Un circuito integrado (chip) que se encuentra en la placa base y almacena el código de firmware encargado de arrancar la computadora se llama BOOT ROM . Este nombre no está estandarizado, por lo que otros desarrolladores a menudo lo llaman FLASH ROM , BIOS FLASH , BOOT FLASH , SPI FLASH , etc. No se preocupe, estos términos son intercambiables. El código de firmware en la ROM DE ARRANQUE se ejecuta primero cuando se enciende la computadora. Realiza pruebas básicas, inicializa el hardware y luego carga el cargador del sistema operativo desde un dispositivo de arranque, como un disco duro o una unidad USB, en la memoria. Este chip está hecho de memoria no volátil (NVM) .

Memoria no volátil

La memoria no volátil es un tipo de memoria de computadora que conserva su contenido incluso cuando se apaga la alimentación . Hace que este tipo de memoria sea ideal para almacenar datos importantes que deben conservarse incluso cuando la computadora está apagada. Además, la discusión se centrará solo en la memoria que contiene el código de firmware. No hablaremos de almacenamiento como unidades de disco duro (HDD), unidades de estado sólido (SSD), disquetes, etc.


Básicamente, podemos categorizar este tipo de memoria en los siguientes grupos.

Programable una vez

  • ROM enmascarada: los contenidos se determinan en el momento de la fabricación y no se pueden cambiar después de eso.
  • ROM programable (PROM): a diferencia de la ROM enmascarada, este tipo de memoria se puede programar después de la fabricación. Pero aún así sólo una vez.

Programable en campo

  • ROM programable borrable (EPROM): se puede programar varias veces, pero su contenido se puede borrar y reprogramar con luz ultravioleta .


  • Programable borrable eléctricamente (EEPROM): se puede reprogramar varias veces mediante señales eléctricas .


    • Memoria Flash NOR : Arquitectónicamente dispuesta en bloques donde los datos se borran a nivel de bloque y se pueden leer o escribir a nivel de byte . Se puede acceder directamente a la memoria NOR mediante una interfaz estándar como byte paralelo, I2C o SPI.


      En la industria, existe una convención para reservar el término EEPROM a las memorias borrables por bytes en comparación con las memorias flash borrables por bloques.


La memoria programable viene con una regla: borrar antes de escribir . En dicha memoria, escribir nuevos datos es más complicado porque los datos se almacenan como una carga en una puerta flotante (la razón por la que la mayor parte radica en la física de las celdas de memoria). La cantidad de carga en la puerta determina si la celda almacena "0" o "1".


Cuando borra un chip de memoria flash, establece todos los bits de datos almacenados en él en un estado conocido (predeterminado), normalmente un "1" lógico. Esto le permite comenzar con una pizarra limpia, por así decirlo, y programar nuevos datos en el chip sin tener ningún remanente de los datos antiguos aún almacenados en él. Cuando se escriben nuevos datos en el chip, el estado de los bits individuales cambia de "1" a "0" para representar los nuevos datos.


Si simplemente escribe datos nuevos en el chip sin borrarlos primero, los datos nuevos se combinarán con los datos antiguos, lo que dará como resultado resultados impredecibles. Por ejemplo, considere un chip de memoria flash que tiene 8 bits de memoria que almacenan el valor "0110 0010". Si escribe nuevos datos "1100 1001" en el chip sin borrarlos primero, el estado resultante del chip sería "0100 0000", que puede no ser lo que pretendía.


La principal confusión está relacionada con la palabra ROM , que significa memoria de solo lectura . El término "Memoria de solo lectura" se ha utilizado históricamente para referirse a la memoria que es permanente y el usuario no puede modificarla. Sin embargo, a medida que la tecnología ha avanzado, la definición de ROM ha cambiado, y ahora se usa a menudo para referirse a la memoria que está preprogramada en la fábrica y que el usuario final no puede cambiar fácilmente . Pero si el usuario tiene las habilidades deseadas y el equipo especializado (por ejemplo, un programador), la persona puede reprogramar el chip. El nombre ROM se ha mantenido, aunque la definición ha cambiado, como una referencia histórica al propósito original de la memoria.


Al aplicar la protección contra escritura, algunos tipos de ROM reprogramables pueden convertirse temporalmente en memoria de solo lectura.


Estos NO son TODOS los tipos existentes de memoria no volátil, pero la mayoría de los populares de los que puede escuchar por casualidad. Hoy en día, en la mayoría de las placas base, estos chips se fabrican utilizando la tecnología NOR Flash .

Ejecutar en el lugar (XIP)

Execute in Place (XIP) es un método que permite que el procesador ejecute código directamente desde la memoria flash sin copiarlo primero en la memoria volátil (como la RAM ). Esto se logra asignando la memoria flash al espacio de direcciones del procesador, de modo que la ejecución del código se pueda realizar directamente desde la memoria flash. Por lo tanto, el sistema puede comenzar a ejecutar el código lo antes posible, sin tener que esperar a que la RAM se inicialice primero.


Espere... ¿la CPU puede comunicarse con la ROM de ARRANQUE a través del protocolo SPI/Parallel/etc? Por supuesto que no, es solo obtener instrucciones de la memoria del sistema, las solicitudes a esta región de memoria se redirigen a Intel Direct Media Interface (DMI ) o AMD Infinity Fabric (IF) / Unified Media Interface (UMI) (predecesor). Es el vínculo entre la CPU y el chipset en la placa base. En este punto, la decodificación de la dirección se realiza a través de decodificadores ubicados en el conjunto de chips y los datos del chip se devuelven al procesador.


Cuando el chip está hecho de memoria flash NOR, que admite lecturas de acceso aleatorio, pero no escrituras de acceso aleatorio, surgió un problema. En la medida en que la memoria de escritura no esté disponible, todos los cálculos deben realizarse dentro de los registros del procesador. En este punto, el código solo se puede escribir en lenguaje ensamblador y tiende a configurar el entorno para lenguaje de alto nivel (normalmente, para lenguaje C ). La razón de esto es que la inicialización de la memoria se ha vuelto tan compleja que sería difícil escribir únicamente en ensamblador. Dado que tales lenguajes requieren al menos un montón y una pila, necesitamos memoria de escritura. Algunos procesadores tienen SRAM integrada en el propio chip, pero un enfoque más moderno es utilizar la memoria caché integrada como RAM (CAR) .


Caché como RAM (CAR)

La caché de la CPU es una memoria de alta velocidad que almacena una copia de los datos e instrucciones de uso frecuente de la memoria principal. Una memoria caché se encuentra más cerca del procesador y se organiza en varios niveles (L1, L2, L3, ...), siendo cada nivel más grande y más lento que el anterior.


Si los datos están en la memoria caché, la CPU puede recuperar los datos solicitados de la memoria caché (se denomina acierto de memoria caché ). Cuando la memoria caché de la CPU no puede encontrar los datos necesarios, se produce un error de memoria caché . Esto puede ocurrir porque los datos nunca se almacenaron en la memoria caché o porque los datos se almacenaron anteriormente pero se expulsaron de la memoria caché. De todos modos, el procesador tiene que llegar hasta la memoria principal para acceder a los datos y copiarlos en la memoria caché.


El desalojo de caché es el proceso de eliminar datos del caché para liberar espacio para nuevos datos. El desalojo de datos puede ser iniciado por el sistema de almacenamiento en caché (generalmente cuando un caché está lleno y es necesario almacenar nuevos datos, o cuando la política de tiempo de vida de los datos ha expirado) o por solicitud explícita.


Sin embargo, si queremos usar la memoria caché de la CPU como RAM , debemos configurar la memoria caché para que funcione en modo sin expulsión , también llamado modo sin relleno . Esta técnica evita el desalojo debido a una falta de caché . En su lugar, la memoria caché se trata como una SRAM normal y todos los accesos (lectura/escritura) llegarán a la memoria caché y no a la memoria principal. El modo se puede activar usando instrucciones de CPU específicas del proveedor.

Diseño y mapeo de memoria

En realidad, la ROM DE ARRANQUE contiene varios tipos de firmware. Una vez que se almacena un montón de firmware en la ROM de ARRANQUE, debe organizarse de alguna manera para distinguir entre ellos. Veamos cómo se hace.

Modo no descriptor

Originalmente, el conjunto de chips realiza una asignación directa de todo el contenido de la ROM de ARRANQUE a la memoria (de 4 GB a 4 GB - 16 MB). Por lo general, si la ROM de arranque tiene menos de 16 MB, los contenidos se asignan repetidamente. La CPU y el firmware pueden leer/escribir en la memoria flash sin restricciones.





El modo sin descriptor ya no es compatible con los nuevos conjuntos de chips.

Intel Flash Descriptor / Modo descriptor

Eventualmente, en el ICH8, Intel presenta un diseño especial para BOOT ROM. El flash se divide en las siguientes regiones:


  • Flash Descriptor (FD): esta estructura de datos debe ubicarse al comienzo del dispositivo con un desplazamiento de 0x10 . Se compone de once secciones como se muestra en la siguiente figura:



El Descriptor MAP tiene punteros a las otras regiones y también al tamaño de cada una.


La sección Componente tiene información sobre los flashes en el sistema (número de componentes, densidad de cada uno, instrucciones no válidas, etc.).


La sección Masters define los permisos de lectura/escritura para las regiones. En lo que respecta a lectura/escritura, los permisos deben establecerse en Solo lectura, la información almacenada en esta región solo se puede escribir durante el proceso de fabricación.


  • BIOS: solo esta región se asigna a la memoria.





  • Intel Converged Security and Management Engine (CSME / ME): el firmware para admitir diferentes tecnologías Intel y ME.
  • Gigabit Ethernet (GbE): solo se puede acceder directamente mediante el controlador Gigabit Ethernet.
  • Datos de la plataforma
  • Controlador integrado (EC)


Flash Descriptor e Intel ME son las únicas regiones requeridas.

Tabla de interfaz de firmware de Intel (FIT)

El FIT es una estructura de datos dentro de la región del BIOS y contiene varias entradas que describen la configuración de la plataforma. Cada entrada de la tabla tiene un tamaño de 16 bytes. El primero se llama encabezado FIT , el otro se llama entrada FIT . Está ubicado por un puntero FIT en una dirección física 0xFFFFFFC0 (4GB - 0x40).


Estos componentes deben procesarse antes de ejecutar la primera instrucción de la CPU desde el vector de reinicio . Las entradas incluyen actualizaciones de microcódigo de CPU, ACM de inicio, políticas de arranque de plataforma/TPM/BIOS/TXT y otras cosas. Pero al menos el FIT debe incluir entradas de actualización de microcódigo y encabezado FIT . Por lo tanto, el uso común de FIT es actualizar el microcódigo antes de ejecutar el vector de reinicio .


Así es como se ve el mapa de memoria:






Estructura de firmware integrado de AMD

Desafortunadamente, hay mucha menos información, no pude encontrar ninguna documentación filtrada del chipset AMD con detalles sobre su diseño. Así que no puedo decirte mejor que lo que dice la documentación de coreboot . Está escrito en base a la documentación de AMD que solo está disponible bajo NDA.


En realidad, será suficiente saber que el análogo de AMD de Flash Descriptor es una estructura de firmware integrada y contiene punteros a la tabla de directorios de PSP , la tabla de directorios de BIOS y otro firmware.


Inicialización de silicio

Si desea ver cómo se inicializan exactamente la memoria moderna y la CPU, entonces tengo que molestarlo. Intel y AMD no tienen prisa por lanzar el Código de inicialización de silicio a la comunidad. En la medida en que dicha información no esté disponible públicamente, ofrecen distribución binaria del código de inicialización de silicio necesario. Esto debe considerarse una biblioteca para desarrolladores de firmware y contiene código binario para inicializar el controlador de memoria, el conjunto de chips, la CPU y otras partes diferentes del sistema.

Paquete de soporte de firmware de Intel (FSP)

Ese binario se puede dividir en 4 componentes:


  • FSP-T: configuración del entorno de ejecución temprana ("RAM temporal") en el que se puede ejecutar el código C. En la práctica, este binario configura CAR, pero también realiza una inicialización temprana del hardware, como configurar el espacio de configuración mapeado en memoria PCIe.
  • FSP-M: inicialización de la memoria permanente (como DRAM).
  • FSP-S: finalización de la inicialización de silicio, incluida la inicialización de la CPU y el controlador IO.
  • FSP-O: componente opcional que proporciona inicialización de dispositivos OEM.


Aquí hay un repositorio de archivos binarios Intel FSP publicados por Intel que puede encontrar en su GitHub. La especificación FSP v2.1 se puede obtener del sitio web de Intel.

Arquitectura de software encapsulada genérica de AMD (AGESA)

AGESA para productos anteriores a Family 17h se conoce como v5 o Arch2008 . En ese momento, AGESA era de código abierto y el código estaba disponible en el repositorio de coreboot (fue obsoleto después de la versión 4.18). La especificación para Arch2008 se puede encontrar en el sitio web de AMD.


Con la introducción de los productos Family 17h (microarquitectura Zen), AMD no ha publicado el código fuente de AGESA, solo soluciones binarias prediseñadas. Tal sucesor se llama AGESA v9 y es compatible con Family 17h y versiones posteriores.

abiertoSIL

No hay información detallada disponible, solo noticias .

Subsistemas Autónomos

Una parte integral del proceso de arranque x86 moderno, sin el cual los núcleos x86 nunca se activarían. Por lo tanto, es imposible deshabilitarlos por completo . Estas tecnologías son responsables de la inicialización del hardware, la verificación de la integridad del sistema, la administración de energía y el lanzamiento de la CPU. El firmware para estos subsistemas se carga y ejecuta antes de que el procesador principal comience a ejecutar su propio firmware. Un código en dichos sistemas se ejecuta independientemente de los núcleos de CPU de la plataforma.


Mientras muchas empresas de hardware han incorporado el principio de seguridad por oscuridad , no se dispone ni del código fuente ni de la documentación de estos subsistemas. Afortunadamente, sabemos cómo afecta el proceso de arranque; consulte Secuencias de energía de hardware .


No entraremos en detalles, porque ya hay extensos artículos en Internet de investigadores de todo el mundo. Pero solo te daré una breve descripción de lo que es.

Motor de administración Intel (ME)

Intel ME es un microprocesador i486/80486 separado integrado en el chipset Intel (PCH) desde 2008. Tiene su propia RAM, ROM incorporada, puentes de bus a todos los buses dentro del chipset (como resultado, puede acceder a la red e incluso la RAM principal de la CPU), y así sucesivamente. Ejecuta un sistema operativo personalizado basado en MINIX.

Procesador de seguridad de la plataforma AMD (PSP)

AMD PSP es un núcleo ARM que se basa en la extensión Trustzone, que se inserta en la matriz de la CPU como coprocesador. Este chip se ha integrado en la mayoría de las plataformas AMD desde 2013. Ejecuta un sistema operativo patentado y no documentado.

Secuencias de potencia de hardware

Este proceso, también conocido como Power On Sequence o Power Sequencing , proporciona una cantidad de niveles de voltaje derivados y/o rieles de suministro de energía en un orden particular que se necesita en la plataforma. En términos más simples, enciende varios componentes de la plataforma en un orden específico. El proceso varía según el sistema o el diseño de la plataforma, pero normalmente una PC estándar incluye los siguientes pasos:


  • Presionas el botón de encendido . Pero espere... este botón está en la carcasa de la computadora que no es una parte necesaria de una computadora. Por lo general, el botón de encendido es un cable. Tenemos un botón en un lado y un interruptor que colocamos en dos puntas de metal en la placa base en el otro lado. Cuando presionamos el botón, estas clavijas se conectan para que la electricidad pueda pasar a través de ellas. Mire el video a continuación sobre cómo encender una computadora sin un botón de encendido si está interesado.


  • La placa base envía una señal a la unidad de fuente de alimentación (PSU).


  • La fuente de alimentación recibe la señal, proporciona la cantidad adecuada de electricidad y envía una señal a la placa base.
  • Una vez que la placa base recibe la señal de buena alimentación, enciende los componentes de la plataforma, como el núcleo, los relojes, el chipset, la memoria, los diferentes controladores, etc.
  • Una variedad de subsistemas, incluidos los subsistemas autónomos (discutidos anteriormente), pueden comenzar antes que el procesador principal.


  • Sistemas basados en AMD (para Family 17h y posteriores)


    • PSP se ejecuta en -chip BOOT ROM.

    • PSP localiza la tabla de firmware integrada en la ROM de arranque fuera del chip y ejecuta el firmware de PSP.

    • PSP analiza la tabla de directorios de PSP para encontrar etapas ABL y las ejecuta.

    • Las etapas ABL inicializan la memoria principal, ubican la imagen del BIOS en la ROM DE ARRANQUE y la cargan en la DRAM (se descomprime si la imagen está comprimida).


      Esta plataforma no tiene motivos para usar CAR porque la DRAM ya está disponible y PSP carga la imagen del firmware en ella.


  • Sistemas basados en Intel
    • Chipset (ICH/PCH) encuentra el Intel Flash Descriptor en la ROM de ARRANQUE.
    • El chipset copia el firmware CSME en la memoria interna donde Intel ME puede acceder y el último comienza a ejecutarlo.
    • El conjunto de chips asigna la región del BIOS a la memoria.
    • Las actualizaciones de microcódigo ubicadas en la tabla de interfaz de firmware se cargan en la CPU. Deben aplicarse en cada arranque del sistema .
    • (opcional) Si se encuentran módulos de código autenticado (ACM), se ejecuta esa entrada.


  • Durante todo este tiempo, la señal de reinicio de la CPU se afirma para evitar que la CPU se inicie antes de que otras partes del sistema estén listas. Cuando la plataforma está lista, la línea de reinicio de la CPU se anula. En un sistema multiprocesador o multinúcleo, una CPU se elige dinámicamente para que sea el procesador de arranque (BSP) que ejecuta todo el código de inicialización del firmware. Los procesadores restantes, llamados procesadores de aplicaciones (AP) en este punto, permanecen detenidos hasta más adelante, cuando el firmware/kernel los activa explícitamente.


  • Después de que la CPU se enciende por primera vez, funciona en modo real . La mayoría de los registros tienen valores bien definidos , incluidos el puntero de instrucción (IP), el segmento de código (CS) y la caché de descriptores , que es una copia de cada descriptor de segmento dentro del procesador para permitir un acceso rápido a la memoria del segmento.


    El descriptor de segmento es una entrada en la tabla de descriptores globales (GDT) y contiene la dirección base, el límite de segmento y la información de acceso (esta parte se ignora porque el modo real no tiene control de acceso como el modo protegido). En lugar de acceder a la GDT (que se encuentra en la memoria) para cada acceso a la memoria, la información se almacena en un caché de descriptores.


    Sin embargo, la GDT no está involucrada en modo real, por lo que el procesador genera entradas internamente. El registro selector CS, utilizado para acceder al descriptor de segmento, se carga con 0xF000 . La dirección base de CS se inicializa en 0xFFFF_0000 . La IP se inicializa en 0xFFF0 .


    Por lo tanto, el procesador comienza a obtener instrucciones de la memoria ubicada en la dirección física 0xFFFF_FFF0 ( 0xFFFF_0000 + 0x0000_FFF0 ). La primera instrucción ejecutada en esa dirección se denomina vector de reinicio .


    NOTA: este truco le da acceso al espacio de direcciones alto, sin embargo, no puede acceder al código debajo de la dirección 0xFFFF_0000 . La dirección base de CS permanece en este valor inicial hasta que el firmware carga el registro selector de CS. Se puede hacer ejecutando un salto lejano .


    En este punto, la mejor decisión es cambiar al modo protegido con 4 GB de capacidad de direccionamiento. Si el firmware no lo hace, para que funcione el modo real, el conjunto de chips debe poder crear un alias de un rango de memoria por debajo de 1 MB a un rango equivalente justo por debajo de 4 GB. Ciertos conjuntos de chips no tienen este alias y pueden requerir un cambio a otro modo operativo antes de realizar el primer salto largo.


  • La dirección está en una sección de memoria no volátil , por lo que la CPU utiliza el método Execute In Place (XIP). Aunque si es un sistema basado en AMD, probablemente estés leyendo desde la memoria principal.


  • La CPU ejecuta un código de firmware.


Le recomiendo que vea el video a continuación sobre la secuencia de encendido, que explica el proceso usando la placa base ASUS P9X79 como ejemplo. A pesar de que está en ruso, podrás entenderlo todo si activas los subtítulos en inglés generados automáticamente.




Este artículo ha proporcionado mucha información teórica relacionada con el funcionamiento del arranque. Sin embargo, para comprender verdaderamente este proceso, debemos observar más de cerca el código fuente y la arquitectura del firmware existente.


En el próximo artículo, profundizaremos en BIOS , UEFI y coreboot para examinarlos en detalle.

Recursos