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!
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) .
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 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 .
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) .
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.
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.
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.
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.
Flash Descriptor e Intel ME son las únicas regiones requeridas.
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:
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.
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.
Ese binario se puede dividir en 4 componentes:
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.
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.
No hay información detallada disponible, solo noticias .
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.
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.
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.
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:
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.
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.
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.