.. _arranque: ******** Arranque ******** El primer *software* que carga un ordenador al iniciarse es el *firmware* almacenado en la placa base, el cual cumple cuatro funciones fundamentalmente: + Analizar el *hardware* presente en el ordenador con un proceso conocido como |POST|. El análisis puede detectar problemas irresolubles (lo que generalmente se señala con un breve pitido) y encontrar algún defecto que impida el funcionamiento del equipo o el arranque. De cuál sea en particular el defecto se informa mediante un código constituido por una combinación de pitidos breves y largos, cada una de las cuales identifica un problema distintos. El proceso de arranque que contiene esta comprobación se denominan :dfn:`arranque en frío`, frente al :dfn:`arranque en calente` que carece de ella. La regla es que los *arranques en frío* se producen cuando se enciende un ordenador apagado y los *arranques en caliente*, cuando se reinicia un ordenador. + Proporcionar una gestión básica de E/S para que al menos el usuario pueda utilizar el teclado. + Permitir la reconfiguración del firmware con el fin de que se pueda cambiar el comportamiento del *firmware* (p.e. para aligerar el proceso |POST| o cambiar cuál será el cargador de arranque que se lanzará posteriormente). + Cargar un programa posterior al que se le ceda el control, el cual habitualmente es el núcleo de un sistema operativo. Hay dos **estándares** fundamentales: - Desde los años 70, el antiguo |BIOS| de 16 bits. - A partir de 2005, |EFI| o |UEFI|\ [#]_ de 32 *bits* (arquitectura *x86*) ó 64 *bits* (arquitectura *x86_64*). No existe, en principio, retrocompatibilidad entre ambos sistemas y a fecha de 2020 la situación es la siguiente: a. Pueden existir aún equipos muy antiguos que disponen de |BIOS|. #. Muchos equipos incluyen |EFI|, pero añaden un modo de compatibilidad (normalmente denominado :dfn:`modo legacy`) que permite a la placa base buscar un cargador de arranque de 16 *bits* para |BIOS| o un cargador de arranque de 32 ó 64 *bits* para |EFI|. Muy comúnmente, se puede tener habilitado el modo compatibilidad a la vez que el modo normal. #. Los equipos más recientes traen un *firmware* |EFI|, que carece de *modo legacy*; y es de esperar que en el futuro el número de equipos sin la compatibilidad aumente\ [#]_. Como en todo estado de transición, es indispensable conocer ambas tecnologías, que es en lo que se afanará este epígrafe. Proceso de arranque ******************* Sea cual sea el estándar usado, en el proceso de arranque podemos distinguir las siguientes fases: #. Proceso |POST| de comprobación del *hardware*. Durante esta fase, el *firmware* mediante la pulsación de ciertas teclas\ [#]_, brinda al usuario la posibilidad de pausar el proceso para: + Reconfigurar el *firmware*, que es lo que vulgarmente se conoce como "entrar en la bios". Si se hace esto, se presenta un entorno donde el usuario puede cambiar parámetros del *firmware* que se almacenan en memoria |NVRAM| (o CMOS_ en equipos antiguos). Al término de la configuración, se escoja o no salvar los cambios, se inicia un proceso de *arranque en frío*. + Presentar un menú para seleccionar qué programa o dispositivo se desea arrancar. Los ítem de este menú son los ítem de la *secuencia de arranque* y el interesado podrá escoger cualquiera de ellos para alterar sólo en ese arranque la secuencia y que ese ítem pase a ser el primero. Aunque esta primera fase sólo está presente en un *arranque en frío*, generalmente en un *arranque en caliente* , si se es rápido pulsando la tecla apropiada, se puede entrar en la configuración del *firmware* o el *menú de arranque*. #. Arranque de algún programa siguiendo la :dfn:`secuencia de arranque`, que es una lista ordenada de todos los dispositivos detectados que se comprueban secuencialmente a fin de encontrar en ellos un programa de arranque válido. En cuanto se encuentre uno, se arranca y el *firmware* cede el control. Como ya veremos, en el caso de |UEFI|\ [#]_. esa lista puede contener, además de dispositivos, programas concretos. .. _boot-loader: Cargador de arranque ******************** Ya hemos establecido que el *firmware* de placa base se encarga de ceder el control a un programa ulterior para que habitualmente a la postre acabe por cargarse en memoria un sistema operativo. Un :dfn:`cargador de arranque` es cualquier programa que se carga antes del sistema operativo principal y atendiendo a esta definición el propio *firmware* puede considerarse un *cargador de arranque*. Todos los *cargadores de arranque*, no obstante, no tienen la misma funcionalidad: * Algunos tiene la función de cargar en memoria el núcleo de un sistema operativo y cederle el control de la máquina. Un ejemplo de cargador de arranque puro es EFIStub_, el cargador de arranque para |EFI| incluido en el propio núcleo de *Linux*\ [#]_. Con él podremos cargar un *Linux* sin necesidad de usar |GRUB|. * Otros son programas que se limitan a realizar una función muy concreta como es el caso de memtest_ (que comprueba la integridad de la memoria |RAM|) o hdt_ (que nos identifica el *hardware* de nuestro ordenador). En este caso, son programas terminales y no se pretende acabar cargando el sistema operativo. .. _boot-manager: * Por último, hay cargadores cuyo propósito es, simplemente, cargar en cadena otro cargador de arranque. Dentro de este clase de cargadores destaca el :dfn:`gestor de arranque`, cuyo propósito es permitir escoger entre múltiples cargadores de arranque y, por tanto, brindarle al usuario la posibilidad de arrancar distintos sistemas operativos o programas como los del ítem anterior. Un *gestor de arranque* puede: * ser *puro* y limitarse a cumplir el propósito descrito, por lo que todas las entradas de su menú deberán ser cargadores de arranque externos. Son gestores puros el *gestor de arranque* incluido dentro del propio |EFI| o `rEFInd `_. * incluir cargadores de arranque para arrancar con ellos algunos sistemas operativos. Son ejemplos de este tipo de gestores |GRUB| (que permite arrancar sistemas *Linux* sin que el núcleo de éstos incluya EFIStub_), o |NTLDR| o *Windows Boot Manager*, que arrancan sistemas *Windows*. .. note:: Tenga presente que entre los cargadores opcionales entre los que deja escoger un gestor de arranque puede encontrarse otro gestor de arranque (que al fin es un tipo de cargador). Esto se denomina :dfn:`carga en cadena` (*chain loading*) y es la técnica que usa |GRUB| para cargar *Windows*. Como |GRUB| no incluye cargador de arranque para *Windows* lo que hace es cargar *Windows Boot Manager* .. rubric:: Gestores de arranque .. toctree:: :glob: :maxdepth: 1 02.boot/[0-9]* .. seealso:: :program:`syslinux` es otro gestor de arranque que :ref:`se describe al tratar PXE `. Estándares ********** Analicemos las particularidades de cada estándar. .. table:: Comparativa |UEFI|/|BIOS| :class: uefi-bios +-----------------+----------------+--------------------------+ | Características | |BIOS| | |UEFI| | +=================+================+==========================+ | Arquitectura | 16bits | 32 ó 64 bits | +-----------------+----------------+--------------------------+ | Compatibilidad | No | A extinguir | +-----------------+----------------+--------------------------+ | Arranque | Dispositivos | | Dispositivos | | | | | Cargadores de arranque | +-----------------+----------------+--------------------------+ | Seguridad | Ninguna | Secure boot | +-----------------+----------------+--------------------------+ | Gestor externo | Necesario | Opcional | +-----------------+----------------+--------------------------+ | Particionado | Incomprensible | | DOS | | | | | GPT | +-----------------+----------------+--------------------------+ |BIOS| ====== Es un sistema antiguo y bastante básico que para ceder el control se limita a intentar cargar el código del |MBR|\ [#]_. Si no encuentra código en el |MBR| de un dispositivo pasa al siguiente dispositivo de la secuencia y así continua hasta que encuentra un |MBR| con cargador de arranque. Cuando esto ocurre, delega el control en ese código y ese código es el encargado de aviárselas con los sistemas y particiones que pueda contener el dispositivo. Es importante, pues, tener presente que este *firmware* no entiende de particiones ni sistemas de archivos; y, por tanto, su sistema de arranque lee el comienzo del disco (los primeros 446 bytes concretamente) y es totalmente ajeno al sistema de particionado que se haya utilizado. Aunque en un arranque |BIOS| suele existir una tecla cuya pulsación nos presenta un menú con el cual podemos seleccionar el dispositivo de arranque, esto no es un gestor de arranque completo, puesto que no podemos añadir y eliminar en él cualquier entrada, sino que las únicas entradas posibles son aquellas que permiten leer el presumible cargador de arranque que haya en el |MBR| de cada dispositivo detectado. Por tanto, si instalamos dos sistemas en dos dispositivos diferentes, podremos con este mínimo gestor escoger entre uno y otro, pero si los dos sistemas se encuentran instalados en un mismo dispositivo, no es posible; y se requiere instalar en el |MBR| de ese disco un gestor de arranque como |GRUB|. Sin embargo, los cargadores de arranque suelen ser más grandes que los escasos 446 *bytes* que caben en el espacio dedicado en el |MBR| por lo que este código alojado suele ser tan sólo una pequeña parte encargada de saber dónde debe seguir leyendo el resto del cargador. Lo habitual con *firmware* |BIOS| es que el sistema de particiones sea |DOS|, aunque no es absolutamente necesario\ [#]_, puesto que, al cabo, |BIOS| sólo se preocupa de leer al comienzo del dispositivo. Así pues, los condicionantes para conseguir que un dispositivo sea arrancable son: - Un :ref:`particionado DOS ` (matizable, pero que daremos como verdadero). - Un gestor de arranque en el |MBR|, como |GRUB| o *Windows Boot Manager*, que posibilite el arranque de los distintos sistemas almacenados en disco. Nótese que, cada vez que se instala un sistema operativo, el programa instalador sobrescribe el |MBR| con el cargador/gestor que incluya el nuevo sistema, por lo que es responsabilidad de este último gestor incluir en sus entradas el nuevo sistema y todos los que ya estén instalados en otras particiones de instalaciones previas. Como *Windows Boot Manager* sólo se cuida de detectar y arrancar sistemas *Windows*, y |GRUB|, sin embargo, sí busca todo tipo de sistemas; si planteamos instalar varios sistemas operativos en un mismo disco es preferible instalar primero los sistemas *Windows* (por orden de antigüedad, porque las versiones antiguas pueden tener problemas en detectar *Windows* más recientes) y después los sistemas *Linux*. Si no se sigue este orden, aún será posible reparar el arranque, pero nos tocará utilizar herramientas para ello. .. _boot-uefi: |UEFI| ====== Al contrario del sistema anterior, |UEFI| es *capaz de entender* las particiones del disco siempre que estas sean: + :ref:`Particiones primarias DOS `. + :ref:`Particiones GPT `. Reconoce, además, algunos sistemas de archivos (obligatoriamente |FAT| y, para dispositivos ópticos, CDFS), y dispone de un :ref:`gestor de arranque ` básico. No es preciso, pues, un gestor de arranque externo, aunque es muy común que se instale también. *Windows*, de hecho, necesita *Windows Boot Manager* para su arranque, así que de instalar un sistema *Windows* forzosamente requeriremos este gestor externo. En cambio, si sólo instaláremos distintos sistemas *Linux* podríamos arrancarlos todos sin necesidad de |GRUB| (aunque lo habitual es que también se instale) El gestor de arranque integrado es capaz de almacenar en memoria |NVRAM|\ [#]_ entradas ordenadas de arranque, cada una de las cuales recibe un nombre identificativo (p.e. "Debian") y refiere la ruta a un cargador de arranque contenido en una partición especial llamada |ESP|. Dicha partición se caracteriza por estar formateada en un sistema de archivos inteligible por el *firmware* (habitualmente |FAT|\ 32) y tener un código identificativo de partición\ [#]_: + ``0xEF`` en particionados |DOS|. + ``C12A7328-F81F-11D2-BA4B-00A0C93EC93B`` en particionados |GPT|\ [#]_ .. image:: files/part-gpt-uefi.png .. caution:: Aunque el firmware |EFI| permite el uso del particionado |DOS|, esto no se ideó más que como una solución transitoria para soslayar el problema de que en el momento del nacimiento del programa las herramientas no hubieran aún añadido soporte para el nuevo sistema de particionado |GPT|. Por tanto, lo recomendable es usar siempre este último particionado. Al referir las entradas de la secuencia de arranque archivos incluidos en un sistema de archivos, podemos tener conviviendo en un único disco arranques de distintos sistemas operativos sin necesidad de ningún gestor externo. A pesar de esto, nos podemos encontrar en una secuencia de arranque |EFI| una o varias entradas que refieren dispositivos, y no cargadores concretos. Estas entradas, en realidad, refieren también archivos (un cargador de arranque), pero en una ruta predefinida dentro de ese dispositivo. Desvelaremos más adelante cuál. .. image:: files/bootmanager-efi.png Además, a las entradas ya almacenadas en la |NVRAM|, el *firmware* añade dinámicamente una entrada por cada dispositivo extraíble detectado en la fase |POST| y que no estuviera presente ya en la secuencia. De este modo, es posible arrancar desde una memoria |USB| que se haya pinchado circunstancialmente. .. admonition:: Aclaración Podríamos considerar que las |BIOS| que, mediante la pulsación de una tecla, muestran los dispositivos conectados y permiten escoger para ese arranque qué |MBR| desea leerse tienen un gestor de arranque muy, muy simple. Su limitación es que para un dispositivo con varios sistemas operativos necesitaremos que la lectura de su |MBR| nos presente un gestor de arranque que nos permita acceder a todos ellos. En cambio, en los sistemas |EFI|, el gestor de arranque sí permite escoger entre distintos sistemas operativos incluidos dentro de un mismo dispositivo y, por tanto, es un gestor plenamente funcional; y, en teoría, no hace imprescindible el uso de un gestor externo. En cualquier caso, los *firmwares* |EFI| exigen que el usuario activamente acceda al gestor pulsando una tecla durante el arranque, en vez de tener alguna opción de configuración que lo muestre directamente y una opción de temporización que propicie que se arranque uno de los sistemas en caso de que el usuario no haga nada. .. _efi-archivos: En la partición |ESP| los cargadores de arranque se organizan bajo la siguiente estructura de directorios: .. code-block:: none / +-- EFI/ +-- debian/ +-- Windows Boot Manager/ +-- etc. +-- Boot/ +-- bootx64.efi esto es, un directorio :file:`EFI` dentro del cual cada sistema operativo crea un subdirectorio con los archivos oportunos para el arranque o para al menos comenzar el arranque. Uno de esos archivos será el que deba cargar el *firmware* |EFI|, por lo que su ruta será la que se añada como entrada en la secuencia de arranque. Como se deduce, todo está perfectamente estructurado y, por tanto, mientras exista espacio suficiente (habitualmente con **100** MiB hay más que de sobra) no hay riesgo de que el arranque de un sistema operativo interfiera con el de otros, como sí ocurre en |BIOS| en que, como sólo hay un punto de arranque por dispositivo (su |MBR|), el arranque de un sistema instalado sobrescribirá el código que en el |MBR| pudiera haber escrito la instalación de un sistema operativo instalado anteriormente. Lo normal, sin embargo, es que, al registrar un sistema operativo la entrada para su arranque, la registre como la primera en la secuencia, lo que determina que se cargue con preferencia en detrimento del resto de sistemas operativos que se hubieran podido instalar antes. Si este arranque es respetuoso con el resto y consiste en un gestor de arranque que también permite la carga de los demás, como es el caso de |GRUB|, este hecho no es relevante, ya que este gestor externo nos brindará la posibilidad de seguir arrancando el que queramos. Si en cambio el gestor no es tan gentil (como es el caso de *Windows Boot Manager*), aparentemente dejaremos de poder arrancar el resto de sistemas no *Windows*; pero sólo aparentemente, porque bastará con pulsar la tecla apropiada que nos muestre todas las entradas del gestor |EFI| integrado para que podamos escoger cualquier otra distinta de la primera. Además de poder escoger entrada a voluntad en cada arranque, también es posible cambiar la secuencia de arranque para reordenar sus entradas. Hay diversas vías: - Quizás algún método gráfico en la configuración del *firmware*. - Quizás alguna *shell* de comandos proporcionada por el propio *firmware*. Esta *shell* disponde de la orden :command:`bcfg`, que permite manipular la secuencia e incluso, añadir y borrar entradas. - Herramientas ejecutadas desde el sistema operativo. En *Linux*, este comando es :command:`efibootmgr`\ [#]_. Peso a lo anterior, lo que ahorra más trabajo es seguir la misma regla ya enunciada al tratar |BIOS| para organizar la instalación de sistemas operativos: sistemas *Windows* de más antiguo a más nuevo y sistemas *Linux* después. Volvamos para terminar a un aspecto que dejamos en suspenso: la adición dinámica de entradas para arrancar dispositivos extraíbles. De hecho, en un equipo virgen sin nada instalado aún, éstas serán las únicas entradas disponibles. Ya hemos explicado cómo el *firmware* |EFI| intenta cargar la ruta especificada en cada una de las entradas de la secuencia. En este caso, sin embargo, el sistema operativo del disposivo extraíble no ha sido instalado por un instalador que haya manipulado la |NVRAM| para registrar la ruta al cargador, por lo que la única solución es que la entrada que representa al dispositivo siempre busque lo mismo: la primera partición del dispositivo legible (o sea, con un sistema de archivos reconocible por el *firmware*) y dentro de ella la ruta :file:`/EFI/Boot/bootx64.efi`. Si tal cosa existe, el dispositivo extraíble arrancará. .. note:: Si se revisa el :ref:`esquema de archivos de la partición EFI `, se comprobará que esa ruta predefinida también se ha incluido. Por lo general, la ocupa con su arranque el último sistema instalado (aparte de haber creado su directorio particular), por lo que una entrada en la secuencia de arranque que refiera a secas el dispositivo de disco, cargará el arranque del último sistema operativo instalado. .. note:: Por simplificación, nos hemos limitado a considerar que hay un único disco con sistemas operativos arrancables y que creamos para él una partición |ESP|. Pero la unicidad de la partición |ESP| no es obligatoria para el estándar: un mismo disco podría tener varias particiones |ESP| o, en el caso de existir varios discos arrancables, podríamos tener una partición |ESP| por cada disco o una para arrancar los sistemas operativos de todos ellos. El estándar asegura que se podrá acceder a todas las particiones y cargar los cargadores de todas ellas. Por ese motivo, en |NVRAM| las referencias a los archivos no incluyen sólo la ruta estricta (:file:`/EFI/Debian/shimx64.efi`) sino también cuál es el disco, el sistema de particiones y el número de partición que identifican la partición |ESP| (véase más arriba la captura que ilustra el gestor de arranque |EFI|). .. rubric:: ¿Con qué estándar ha arrancado *Linux*? Dado un sistema *Linux* arrancadado, ¿cómo es posible conocer con qué estándar arrancó? La comprobación más simple es buscar el directorio :file:`/sys/firmware/efi`. Si existe, entonces el arranque habrá sido |EFI|. .. _secure-boot: .. rubric:: ¿Qué es Secure Boot? .. note:: Para la perfecta compresión de este apartado es forzoso que al menos se entiendan los fundamentos del :ref:`cifrado asimétrico `. Para evitar la carga de *software* malicioso (p.e. `virus del sector de arranque `_) la especificación |UEFI| introduce la posibilidad de cargar sólo *software* fiable, esto es, *software* firmado. Para ello existe una cadena de confianza: * El fabricante del *hardware* dispone una clave pública, llamada clave de plataforma (|PK|). * Sólo el fabricante (que posee la clave privada correspondiente a la |PK|) podrá añadir claves públicas a la lista de |KEK|\ s. * Los propietarios de las claves públicas anteriores (|KEK|) son los únicos capaces de añadir claves públicas a la base de firmas (**db**) o a la base de firmas prohibidas (**dbx**). * La **db** es la lista de claves autorizadas para firmar cargadores de arranque. * La **dbx** es la lista de claves vetadas: ningún cargador firmado con alguna de estas claves podrá ser cargado por el *firmware* |EFI|. * El primer cargador contiene a su vez una lista de claves que autorizan al *software* subsiguiente. |PK|, |KEK|, **db** y **dbx** vienen incluidas en el propio *firmware* de la placa y en la práctica los fabricantes de *hardware* convencional sólo incluyen en la lista de |KEK|\ s y en la **db** sendas claves propiedad de *Microsoft*, por lo que sólo *Microsoft* tiene capacidad para firmar el primer cargador tras |EFI|. Por este motivo algunas distribuciones de *Linux* (*Debian* entre ellas) incluyen un `cargador llamado shim `_ (paquete :deb:`shim-signed`) cuyo ejecutable ha pedido cada cual a *Microsoft* que firme con la "Microsoft Corporation UEFI CA" y en el que han incluido su propia clave para poder firmar a su vez ya ellas mismas el |GRUB| (paquete :deb:`grub-efi-amd64-signed`) que se carga después que a su vez se encargara de comprobar la firma del núcleo de *Linux* finalmente cargado. Puede también optarse por deshabilitar *Secure Boot* en cuyo caso el cargador de arranque no requerirá estar firmado. .. rubric:: Enlaces de interés * La wiki de Archlinux tiene un muy completo `artículo sobre UEFI `_. * La entrada `The EFI System Partition and the Default Boot Behavior `_, del blog `The Uncoöperative Organization `_. .. rubric:: Notas al pie .. [#] Intel publicó la especificación con el nombre de |EFI|. Al ser adoptada en 2005 por la industria en general pasó a llamarse |UEFI|. Así pues, ambos términos son sinónimos y debemos entender lo mismo por ellos. .. [#] Intel anunció en 2017 que dejaría de dar soporte a |BIOS| a partir de 2020 (puede leer `este artículo al respecto `_). .. [#] Las teclas varían sea cual sea el fabricante del *firmware*, por lo que no se puede indicar cuáles son exactamente.Habitualmente suelen escogerse :kbd:`Suprimir`, :kbd:`F2`, :kbd:`F8`, :kbd:`F10`, :kbd:`F11` o :kbd:`F12`. .. [#] En |UEFI| es posible porque este firmware sí entiende de particiones y es capaz de leer archivos dentro de un sistema FAT32. .. [#] Para que un kernel de linux pueda arrancarse directamente es necesario que se compile con la opción EFIStub_, disponible desde la versión 3.3.0. .. [#] Es cierto que los *floppy* no disponen de |MBR| (véase `esta explicación `_), pero dado lo anticuado del dispositivo, podemos obviarlo por completo. .. [#] De hecho, con |GRUB| puede arrancarse un sistema |BIOS| y particionado |GPT|. .. [#] En la implementación |UEFI| que traen algunos *softwares* de virtualización (OVMF_), la |NVRAM| se emula almacenando en el directorio :file:`EFI` un fichero llamado :file:`NvVars`. .. [#] El estándar prescribe que la partición que contiene los cargadores de arranque esté marcada con los códigos que se refieren a continuación. En cambio, muchos *firmware* son mas laxos y les basta con que la partición esté formateada en |FAT|\ 32. .. [#] En la utilidad :ref:`gdisk ` se muestra el código simplificado ``EF00``. .. [#] Por ejemplo, esta orden añade una nueva entrada:: # efibootmgr --create --disk /dev/sda --part 2 --loader /EFI/so/bootx64.efi \ --label "Mi primer arranque UEFI" en la que se intenta cargar el fichero :file:`/EFI/so/bootx64.efi` y la que se supone que la partición |ESP| es la segunda del disco. .. |BIOS| replace:: :abbr:`BIOS (Basic I/O System)` .. |EFI| replace:: :abbr:`EFI (Extensible Firmware Interface)` .. |UEFI| replace:: :abbr:`UEFI (Unified Extensible Firmware Interface)` .. |MBR| replace:: :abbr:`MBR (Master Boot Record)` .. |FAT| replace:: :abbr:`FAT (File allocation Table)` .. |NVRAM| replace:: :abbr:`NVRAM (Non-Volatile RAM)` .. |ESP| replace:: :abbr:`ESP (EFI System Partition)` .. |GRUB| replace:: :abbr:`GRUB (GRand Unified Bootloader)` .. |LILO| replace:: :abbr:`LILO (LInux LOader)` .. |VBR| replace:: :abbr:`VBR (Volume Boot Record)` .. |NTLDR| replace:: :abbr:`NTLDR (NT LoaDeR)` .. |WBM| replace:: :abbr:`WBM (Windows Boot Manager)` .. |RAM| replace:: :abbr:`RAM (Random Access Memory)` .. |DOS| replace:: :abbr:`DOS (Disk Operating System)` .. |GPT| replace:: :abbr:`GPT (GUID Partition Table)` .. |GUID| replace:: :abbr:`GUID (Globally Unique Identifier)` .. |POST| replace:: :abbr:`POST (Power On Self Test)` .. |USB| replace:: :abbr:`USB (Universal Serial Bus)` .. |PK| replace:: :abbr:`PK (Platform Key)` .. |KEK| replace:: :abbr:`KEK (Key Exchange Key)` .. _OVMF: https://github.com/tianocore/tianocore.github.io/wiki/OVMF .. _memtest: https://www.memtest.org/ .. _hdt: https://wiki.syslinux.org/wiki/index.php?title=Hdt_(Hardware_Detection_Tool) .. _EFIStub: https://wiki.archlinux.org/index.php/EFISTUB .. _CMOS: https://es.wikipedia.org/wiki/RAM-CMOS