Aunque la mayor parte del código en el kernel de Linux está escrito en C, todavía hay muchas partes de ese código que son muy específicas de la plataforma donde se está ejecutando y deben dar cuenta de eso.
Un ejemplo particular de esto es la memoria virtual, que funciona de manera similar en la mayoría de las arquitecturas (jerarquía de tablas de páginas) pero tiene detalles específicos para cada arquitectura (como el número de niveles en cada arquitectura, y esto ha aumentado incluso en x86 con introducción de nuevos chips más grandes.) El código del kernel de Linux introduce macros para manejar el recorrido de estas jerarquías que el compilador puede eludir en arquitecturas que tienen menos niveles de tablas de páginas (de modo que el código se escribe en C, pero toma detalles de la arquitectura en consideración.)
Muchas otras áreas son muy específicas para cada arquitectura y deben manejarse con un código específico de arco. Sin embargo, la mayoría de estos implican código en lenguaje ensamblador. Ejemplos son:
Cambio de contexto : el cambio de contexto implica guardar el valor de todos los registros para el proceso que se está desconectando y restaurar los registros del conjunto guardado del proceso programado en la CPU. Incluso el número y el conjunto de registros es muy específico para cada arquitectura. Este código generalmente se implementa en ensamblado, para permitir el acceso total a los registros y también para asegurarse de que se ejecute lo más rápido posible, ya que el rendimiento de la conmutación de contexto puede ser crítico para el sistema.
Llamadas del sistema : el mecanismo por el cual el código de espacio de usuario puede activar una llamada del sistema generalmente es específico de la arquitectura (y, a veces, incluso del modelo de CPU específico, por ejemplo, Intel y AMD introdujeron diferentes instrucciones para eso, las CPU más antiguas pueden carecer de esas instrucciones, por lo que los detalles para aquellos aún serán únicos.)
Controladores de interrupciones : los detalles sobre cómo manejar las interrupciones (interrupciones de hardware) generalmente son específicos de la plataforma y generalmente requieren un poco de pegamento de nivel de ensamblaje para manejar las convenciones de llamadas específicas que se usan para la plataforma. Además, las primitivas para habilitar / deshabilitar las interrupciones suelen ser específicas de la plataforma y también requieren un código de ensamblaje.
Inicialización : los detalles sobre cómo debe ocurrir la inicialización también suelen incluir detalles específicos de la plataforma y, a menudo, requieren un código de ensamblaje para manejar el punto de entrada al núcleo. En las plataformas que tienen múltiples CPU (SMP), los detalles sobre cómo poner en línea otras CPU también suelen ser específicos de la plataforma.
Primitivas de bloqueo : la implementación de primitivas de bloqueo (como los spinlocks) generalmente también implican detalles específicos de la plataforma, ya que algunas arquitecturas proporcionan (o prefieren) diferentes instrucciones de CPU para implementarlas de manera eficiente. Algunos implementarán operaciones atómicas, algunos proporcionarán un cmpxchg que puede probar / actualizar atómicamente (pero falla si otro escritor ingresa primero), otros incluirán un modificador de "bloqueo" para las instrucciones de la CPU. A menudo, esto también implicará escribir código de ensamblaje.
Probablemente hay otras áreas donde se necesita código específico de la plataforma o la arquitectura en un kernel (o, específicamente, en el kernel de Linux). Mirando el árbol de fuentes del kernel, hay subárboles específicos de la arquitectura debajo arch/
y debajo include/arch/
donde puedes encontrar más ejemplos de esto.
Algunos son realmente sorprendentes, por ejemplo, verá que la cantidad de llamadas al sistema disponibles en cada arquitectura es distinta y algunas llamadas al sistema existirán en algunas arquitecturas y no en otras. (Incluso en x86, la lista de llamadas al sistema difiere entre un núcleo de 32 bits y un de 64 bits).
En resumen, hay muchos casos que un núcleo debe tener en cuenta que son específicos de una plataforma. El kernel de Linux intenta abstraer la mayoría de ellos, por lo que los algoritmos de nivel superior (como el funcionamiento de la gestión de la memoria y la programación) se pueden implementar en C y funcionan de la misma manera (o casi lo mismo) en todas las arquitecturas.