¿Por qué el modo de arranque seguro de Mac es más lento que el arranque estándar?

En el proceso normal de arranque la primera vez que Mac OS X (o macOS, ahora) o iOS arrancan por primera vez, el cargador de arranque carga el kernel, y luego carga una serie de KEXTs.

Estos KEXTs son un conjunto de extensiones del kernel, que consisten principalmente en controladores y otro código que implementa clases IOKit y extensiones del kernel, incluyendo las extensiones utilizadas para la firma de código, el KEXT DontStealMacOS que verifica que la plataforma en la que se está ejecutando es un "Macintosh genuino" (hardware fabricado por Apple), etc.

Como parte de este proceso de arranque inicial, se crea una imagen del kernel con todas las extensiones que son verdaderas como si estuvieran presentes, y todas las extensiones que son falsas como si no estuvieran presentes.

Por ejemplo, ya que el mismo kernel puede funcionar en diferentes plataformas de Apple con diferentes conjuntos de controladores para diferentes hardware.

Difícilmente tiene sentido cargar un driver UHCI o EHCI para USB, si el hardware sólo soporta el único XHCI avanzado; igualmente no tiene sentido cargar el driver de nVidia para un MacBook Pro concreto, si el hardware actual no lleva ese chip porque es un MacBook Air.

Otro componente es el soporte directo de la placa base para el escalonamiento de la CPU, las velocidades de reloj de la RAM soportadas, el chipset de soporte (Haswell, etc.), y así sucesivamente; ese código en particular vive en el PE o PlatformExpert, que es único para cada SKU de la plataforma de hardware de los ordenadores de Apple.

Así que al final, hay un montón de componentes opcionales que se cargan, pero muchísimos más que no se cargan.

Pero hay que probar cada uno para ver si encaja.

Después de que todo esté configurado, una de las primeras cosas que ocurre tras el arranque es que se crea una versión post-linked del kernel con todos los KEXTs que se cargan para esa plataforma.

Esto se conoce como el "kextcache" - que se llama igual que el programa que se ejecuta para generar la imagen.

Después, el ordenador, al arrancar, carga directamente el kextcache, y arranca fantásticamente rápido (en realidad, se podría hacer más rápido ordenando las páginas de imágenes en el orden en que se van a demandar, y simplemente empezar a ejecutar el código inmediatamente; el kextcache no hace esto).

Cuando se arranca en "Modo Seguro", lo que ocurre es que los drivers opcionales (no estrictamente necesarios, y no de terceros) no se cargan - pero se salta el kextcache - que teme que pueda estar corrupto, porque por algo se arranca en "Modo Seguro".

Así que tiene que ir a cargar mach_kernel, y luego tiene que cargar los KEXTs potencialmente necesarios.

Lo que significa que tiene que pasar por todos los pasos de nuevo, lo que es sustancialmente más lento que cargar el kextcache.

La gente generalmente no se da cuenta de esto en el primer arranque, porque mientras el sistema está arrancando la primera vez, hace el "Happy First Time Boot Greeting Dance™", que distrae lo suficiente como para que el retraso del tiempo de arranque quede oculto a la observación del usuario.

En la práctica, parte del trabajo se realiza en la fábrica durante la finalización del arranque como parte del burn-in, pero suele haber una instalación tardía para que los nuevos ordenadores Apple vengan con la versión más reciente del SO (en cuyo caso, cuando el usuario lo arranque, hará la creación de la kextcache).

Para iOS y otros dispositivos que no son Mac OS X/macOS, el kextcache está pregenerado, e incluido como parte de la imagen del sistema ("No User Serviceable Parts Inside™"), ya que la configuración del hardware no cambiará, y el factor no va a hacer una instalación de enlace tardío del nuevo SO.

Para estos dispositivos, también es habitual deshabilitar ciertas interfaces del kernel que se utilizan para cargar o descargar módulos, enlazar módulos contra el kernel, etc., para evitar que sean fácilmente hackeables.

Nótese que como las APIs internas y expuestas son las mismas, es posible hackear la tabla sysent[] en un dispositivo iOS como parte del jailbreaking para volver a habilitarlas, si eres un desarrollador de kernel muy experimentado, y tienes acceso a un exploit de memoria del kernel que no implique acceder al primer Mach Port para el espacio de direcciones virtual del kernel.

En cualquier caso, la respuesta muy corta es:

Cuando se arranca en "Modo Seguro", se cargan los componentes del kernel individualmente, y se prueban un montón de componentes innecesarios para su plataforma particular y posteriormente se descargan, en lugar de utilizar la imagen de kextcache pre-optimizada.