El propósito de esta "wiki", documentación web, guía, como le digas, es usarla como ayuda-memoria
personal
para el desarrollo del kernel.
No tiene que ser una página ultra estética, pero me estoy esforzando para que no se note que la hice
con html, css y js vanilla como la de algún proyecto aficionado
que anda por ahí.
Un kernel de sistema operativo mínimamente funcional (todo el Kernel Space más un user space mínimo)
puede andar fácilmente en las 15.000 líneas de código por lo que, como verás;
es humanamente imposible memorizar y comprender todo el flujo del kernel por mí mismo. Además son
muchos subsistemas complejos trabajando a bajo nivel juntos para intermediar entre hardware y
software.
IR0 es un kernel de sistema operativo multipropósito desarrollado
desde cero para arquitectura
x86-64 escrito principalmente en C y ASM (Aunque
no tengo ningún problema en incluir código de otros lenguajes especializados en performance como
Cpp o Rust).
Lo estoy creando para aprender más sobre sistemas operativos y poder usarlo como materia
prima para otro proyecto que replica a WSL2 pero con mi propio kernel.
No descarto escalarlo lo suficiente como para hacerlo usable en servidores mínimos o incluso IoT,
pero entiendo que eso es al largo (larguísimo) plazo.
Este
es su Repositorio de GitHub.
Versión: no versionado aún (pero vamos a decir pre-release por ahora.)
Arquitectura: x86-64 (i386)
Bootloader: GRUB
Sintaxis ASM: Intel
A diferencia de kernels como kernel NT (Híbrido) de Microsoft, Redox-OS
(Microkernel),
o el mismo MINIX kernel (microkernel), IR0 se basa en una arquitectura más
similar a la que tiene Linux, que es monolítico.
Sin embargo, mi argumento principal es el del rendimiento. Entiendo que alguien podría venir y
señalar que, como todo monolito, si un subcomponente se rompe, se cae todo el sistema (y
tendría razón)
pero lo que respondo a eso es que "¿De qué me sirve a mí que el kernel soporte seguir sin
filesystem si no puedo hacer nada práctico sin él?", es decir, no tiene sentido que el
kernel
continúe funcionando sin uno de sus componentes clave corriendo.
Por eso no veo mejor alternativa (por ahora) que el patrón monolítico. Y además me ahorra el tener que interconectar
subsistemas clave entre sí con IPC, lo que impacta de una en el rendimiento del Sistema Operativo.
No es
perfecto, pero es estable. No es del todo trazable y requiere escalar de a poco, pero si escala bien
rinde mucho.
Sin embargo yo también tengo desacuerdos con la filosofía UNIX. Ellos (entre otras cosas y de forma resumidísima)
consideran
que si algo falla, que falle bien. Lo que en términos kernelísticos sería: Si se rompe el
scheduler, Panic() directo. Si tenés corrupción en memoria (en espacio de kernel),
Panic.
Y no es que lo cuestiono por que sí, simplemente pregunto (aunque sin soluciones todavía) "¿Por
qué no rescatar el sistema en tiempo de Panic()?, o por lo menos hacer el intento".
Mas allá del punto filosófico y para resumir, el kernel es monolítico porque es más performante y
siento que las piezas clave del núcleo deben trabajar sin overhead.
Sin embargo, si en el futuro necesitara integrar algún subsistema específico de forma híbrida,
seguramente sería pragmático.
Yo sé que hablo como si IR0 fuera usado por miles de personas y toda la historia, pero me voy a dar
el lujo de opinar al respecto.
Entonces, el punto es que el kernel space tiene que ser sólo habitable por subsistemas
que trabajen en ese Entorno,
nada mas.
Entiendo que hayan ciertos fabricantes preocupados por la seguridad de sus
clientes que,
casualmente, tienen acceso a toda interrupción que el usuario haga (saben qué teclas presionás,
el tiempo de tu sesión cada vez que prendés la compu, etc.) Y todo eso porque tienen
software funcionando en el kernel space con todos los privilegios que eso
implica.
RING 0 es únicamente para el kernel. Todo lo que venga del RING 3
se comunica con syscalls(), fin del comunicado.
Si pretendo hacer que IR0 funcione como soporte para servidores (backends, juegos, etc), que pueda
correr docker y kubernetes (al menos) y que, en algún momento,
pueda funcionar como base para IoT, necesito tener en primer lugar soporte de red, con sus
drivers, soporte de protocolos de red modernos mas todos los algoritmos que
implementan internamente.
En el Kernel Linux son mas o menos 1.500.000 de líneas de código SÓLO LA PILA DE RED
COMPLETA.
Literal, si quisiera levantarla de cero, a lo mejor pasaría una década y no estaría lista. No me
siento tan zarpado la verdad.
Te muestro como sería lo que necesito de la pila de red:
Entiédase hardware como los componentes de tu MOBO que hablan con el kernel.
Aparte, acá se ve clarito como el kernel intermedia entre el hard y el soft.
El mismo asunto tenemos con el soporte para contenedores. Acá el tema es un toque
más tranqui porque son un par menos de líneas de código en total: unas 300.000 líneas
pero igual, como pasa con la pila de red, son dos proyectos totalmente aparte.
Mas o menos esto es lo que requiere docker para andar, desde la app con su runtime, hasta sus
accesos en el kernel.
Fijate que docker necesita levantar literalmente un file system virtual, además de limitar la
cpu, acceder a RAM, tener una interfaz de red privada, usa los namespaces para aislar del
entorno su contenido, etc.
Cómo la estructura de archivos puede cambiar constantemente, prefiero que la consultes en el Repositorio de GitHub.
- Rama principal con código estable y testeado.
- Rama de desarrollo activo donde se implementan y testean nuevas features.
- La agrego porque es la rama donde se crean feats que despues pasan al upstream mergeando a dev . Es la más inestable de todas porque es donde se integra código nuevo que también debe ser testeado y revisado antes de llegar a merge.
- En esta rama, se integran features lo suficientemente inestables como para terminar en mainline pero que pueden tener potencial a futuro.
print(), write()
, etc. por que no hay sistema operativo que
responda a esas funciones . Vos sos el
sistema operativo. por eso, en el repo tengo la carpeta de dependencias "includes".
snake_case()
UPPER_CASE
struct_name_t
g_variable_name
CONSTANT_NAME
#INCLUDE -ir0/Lib.h -
(se estan migrando a ese formato)
- No hay mucha ciencia acá. Simplemente doy una revisión de los subsistemas y
algunas
features a desarrollar
a futuro.
Igual, la mejor forma de interiorizarse sobre el funcionamiento del kernel, es viendo el código del
Repositorio de GitHub.
Por ahora es un Round-Robin simple. La idea es usarlo como fallback ya que el
sched
principal debería ser preemptivo
y usa un esquema de prioridad simple (CFS o algo así).
Archivos: scheduler/scheduler.c, scheduler/task.h, scheduler/switch/switch.asm.
Basado en EXT2 y hecho desde cero. La única innovación
sería incluir optimizacion en funciones de búsqueda con una lib de
bbdd vectorial
en la que contribuí.
Archivos: A implementar.
IDT de 256 entradas, manejo de page faults, handlers y wrapper en ensamblador.
Archivos: interrupt/idt.c, interrupt/interrupt.asm, interrupt/isr_handlers.c con
sus
encabezados.
Arranque dependiendo de la arquitectura (X86_64) con punto de entrada en ASM.
Archivos: boot.asm, kmain.c arch.c, kernel_start.c.