- Bunnix, que comenzó como un proyecto personal de descanso, experimentó con qué tan lejos se podía llegar en alrededor de un mes creando un sistema operativo tipo Unix para x86_64, y tomó 27 días de trabajo efectivo
- El kernel se escribió principalmente en Hare, junto con componentes en C como lwext4 para soporte de ext4 y libvterm para la terminal de video del kernel
- Soporta tanto legacy boot como EFI y se probó en algunas laptops reales, pero debido a la falta de soporte para USB, requiere un teclado PS/2 o emulación PS/2 del BIOS
- El espacio de usuario se basa principalmente en software de terceros como dash, Doom, gzip, less, mandoc, sbase, tcc y Vim 5.7; libc es una versión de musl libc modificada para Bunnix
- Bunnix funciona, pero tiene muchos bugs y sigue siendo un sistema de un solo usuario; más que apuntar al mantenimiento a largo plazo, es un experimento que deriva en una reelaboración de Helios y mejoras en el diseño del kernel
Alcance y ejecución de Bunnix
- Bunnix es un proyecto de sistema operativo tipo Unix para x86_64 iniciado el 21 de abril de 2024
- Excluyendo los días en que no se trabajó realmente, se invirtieron en total 27 días
- Se ofrece una ISO de Bunnix 0.0.0 que se puede ejecutar directamente
- En qemu, se puede arrancar la ISO con el siguiente comando
qemu-system-x86_64 -cdrom bunnix.iso -display sdl -serial stdio
- También se puede grabar la ISO en una memoria USB y arrancarla en hardware real
- Es probable que funcione en la mayoría de las máquinas AMD64
- Se probó en una ThinkPad X220 y una Starlabs Starbook Mk IV
- Soporta tanto legacy boot como EFI
- La mayor limitación de ejecución es la falta de soporte para USB
- Se necesita un teclado PS/2 o emulación PS/2 del BIOS
- La mayoría de los teclados de laptop están conectados mediante PS/2
- Que funcione la emulación PS/2 de un teclado USB depende del entorno
- El port de Doom tiene limitaciones en los atajos de teclado y en el comportamiento de salida
- Movimiento con WASD
- Disparo con Shift derecho
- Abrir puertas con Space
- Salir del juego no funciona, así que hay que reiniciar después de jugar
Estructura del kernel y funciones soportadas
- El kernel de Bunnix está escrito mayormente en Hare y usa algunos componentes en C
- Para soporte del sistema de archivos ext4 usa lwext4
- Para la terminal de video del kernel usa libvterm
- Los drivers soportados se concentran en lo necesario para hardware básico y arranque desde almacenamiento
- PCI legacy
- Dispositivos de bloque AHCI
- Tablas de particiones GPT y MBR
- Teclado PS/2
- Puertos seriales de plataforma
- Reloj CMOS
- Framebuffer configurado por el bootloader
- Sistemas de archivos ext4 y memfs
- También incluye funciones básicas del kernel necesarias para un sistema tipo Unix
-
Sistema de archivos virtual y dispositivos
- Proporciona
/dev con dispositivos de bloque, pseudodispositivos null, zero y full, /dev/kbd, /dev/fb0, TTY seriales y de video, y la terminal de control /dev/tty
- Incluye un emulador de terminal relativamente completo y soporte de termios que funciona en cierta medida
-
Llamadas al sistema y modelo de usuario
- Soporta unas 40 llamadas al sistema, incluidas
clock_gettime, poll, openat, fork, exec, pipe, dup, dup2, ioctl, entre otras
- Actualmente Bunnix es un sistema de un solo usuario
- No aplica los modos de archivo ni la propiedad de Unix
- Con unos días más de trabajo, está en condiciones de convertirse en un sistema multiusuario
Bootloaders y espacio de usuario
- Bunnix incluye dos bootloaders
- El bootloader para legacy boot es compatible con multiboot y está escrito en Hare
- El bootloader para EFI está escrito en C
- Ambos bootloaders cargan el kernel como archivo ELF e initramfs cuando es necesario
- El bootloader EFI incluye zlib para descomprimir initramfs
- El bootloader compatible con multiboot se encarga de la descompresión por su cuenta
- El espacio de usuario está compuesto en su mayor parte por fuentes de terceros
- Colossal Cave Adventure
advent
dash /bin/sh
- Doom
- gzip
- less
lok /bin/awk
- lolcat
- mandoc
- sbase core utils
- Compilador de C tcc
- Vim 5.7
- libc deriva de musl libc y tiene varias modificaciones para ajustarse a las necesidades de Bunnix
- La biblioteca curses está basada en netbsd-curses
- El sistema funciona, pero tiene muchos bugs y algunas implementaciones se hicieron con prisa, así que hay que estar preparado para fallos
Factores que permitieron una implementación rápida y dificultades
- Parte del código de Bunnix proviene del proyecto anterior Helios
- Incluye parte del código de kernel relacionado con configuración general de CPU, como GDT e IDT
- Algunos drivers, como AHCI, también se adaptaron al sistema Bunnix
- Se considera que, sin la experiencia con Helios, habría sido difícil crear Bunnix tan rápido
- La integración de soporte ext4 y terminal virtual fue especialmente difícil
- Se incorporaron dependencias externas: lwext4 y libvterm
- La capa de sistema de archivos se reescribió varias veces y aún conserva bugs
- Para implementar correctamente el diseño de sistemas de archivos Unix, incluido
openat y el manejo de inodes, fue necesario examinar más a fondo el interior de lwext4
- También se ganó experiencia enlazando fuentes en Hare, assembly y C dentro del proyecto Hare
- En general funcionó bien, pero hubo incomodidades al construir mecanismos de integración de ABI
- Surgió la necesidad de convertir automáticamente headers de C en módulos de declaraciones forward para Hare
- Parte de ese trabajo existe en
hare-c, pero todavía hace falta más
- Apuntar al port de Vim elevó la dificultad de la implementación de la terminal
- libvterm es una buena biblioteca de máquina de estados de terminal, pero tiene poca documentación
- Hicieron falta muchos ajustes finos para una integración correcta
- También se dedicó tiempo a optimización de rendimiento para que funcionara con fluidez
- El scheduler fue un área en la que se descartó gran parte del código basado en Helios y se reescribió
- Tanto Helios como Bunnix son sistemas de una sola CPU
- A diferencia de Helios, Bunnix permite cambios de contexto dentro del kernel
- Los cambios de tarea preventivos también entran y salen a través del kernel
- Esta estructura requiere varias pilas de kernel y otro método de cambio de tareas
- Con un scheduler lo suficientemente robusto, las operaciones bloqueantes como lecturas de disco o
pipe(2) pueden implementarse de forma sencilla con wait queues
- La implementación de señales fue necesaria para compatibilidad con Unix
- Helios no apunta a Unix, por lo que funciona sin señales
- En Bunnix se ajustó principalmente para que
SIGCHLD funcionara correctamente para el port de dash
- La implementación final de señales es de nivel muy básico
Lecciones de diseño que se trasladan a Helios
- Bunnix es un kernel monolítico, mientras que Helios tiene un diseño de microkernel que no es Unix
- En el sistema de archivos se confirmó la importancia del caching
- Helios divide la implementación del sistema de archivos entre varios drivers y procesos separados
- Aunque solo sea para rastrear objetos vivos, el caching en la capa del sistema de archivos es importante
- Al reelaborar Helios, habrá mucho trabajo de refactorización o reescritura del código del sistema de archivos
- El acceso a drivers es naturalmente más simple en un kernel monolítico
- Sin embargo, no hay satisfacción completa con haber puesto tantas cosas en ring 0
- Hay margen para reflejar algunos elementos del flujo de control de un diseño monolítico en el scheduler de Helios
- En gestión de memoria, el asignador por bitmap funcionó mejor de lo esperado
- En Helios se había intentado evitar el asignador por bitmap, y la gestión de memoria era un punto muy incómodo
- Bunnix usa un asignador por bitmap simple para todas las páginas generales del sistema
- La sobrecarga fue menor de lo temido y funcionó muy bien
- Se considera que crear Bunnix en menos de 30 días no habría sido posible con un diseño de microkernel
- Un kernel monolítico es mucho más simple de implementar
- Las ventajas del diseño de microkernel también son atractivas, y una mejor respuesta podría ser un kernel híbrido
Estado del proyecto y posibles mejoras pendientes
- Bunnix es más bien un proyecto artístico casi terminado que algo a lo que se le vaya a dedicar mucho más tiempo
- Ocasionalmente podrían dedicarle algunos días de trabajo
- Las mejoras de la comunidad pueden enviarse como parches a public inbox
- El desarrollo posterior de sistemas operativos irá en la dirección de volver a Helios y realizar rediseños importantes a partir de las lecciones obtenidas con Bunnix
- Las posibles prioridades de mejora son las siguientes
- Caché de directorios para el sistema de archivos y mejoras generales de caching
- Corrección de bugs de ext4
- procfs y top
- mmap de archivos
- Señales adicionales como
SIGSEGV
- Soporte multiusuario
- Dispositivos de bloque NVMe
- Dispositivos de bloque IDE
- Soporte de ATAPI e ISO 9660
- Soporte de Intel HD audio
- Stack de red
- Toolchain de Hare en el sistema base
- Self-hosting
1 comentarios
Opiniones de Hacker News
Realmente genial. Me recuerda la historia de que el Unix original también se creó durante unas semanas en las que la familia de Ritchie se fue de vacaciones a California para visitar a sus suegros.
La fuente es UNIX: A History and a Memoir, de Brian W. Kernighan.
Ahora lo recuerdo medio borroso, así que tendría que comprobarlo.
Me gustaría ver material más detallado sobre la parte que dice: “Por fin aprendí cómo funcionan las señales de arriba abajo, y son realmente feas. Siempre sentí que eran una de las partes más débiles del diseño de Unix, y este proyecto no me hizo cambiar de opinión”. Si algún usuario de HN o el autor sabe algo, me interesa.
https://www.amazon.com/Advanced-Programming-UNIX-Environment...
Cubre las responsabilidades de trabajar con la API de Unix en espacio de usuario, incluidas señales y procesos.
Si quieres implementar señales dentro del kernel, no estoy seguro de qué recomendar, pero quizá algo como https://pdos.csail.mit.edu/6.828/2012/xv6.html se me ocurre.
Leer un libro que explica con claridad y de forma sistemática cómo funciona Unix, con ejemplos autocontenidos, es realmente refrescante. No saber C puede ser una barrera, pero lo mismo aplica al leer la entrada del blog.
No creo que exista información equivalente en algún lugar de la web. En mi blog también hay mucho conocimiento suelto sobre Unix que la gente todavía lee, pero no está al mismo nivel.
Creo que entender las señales de Unix es uno de esos temas para los que acercarse mediante entradas de blog, Google o LLMs es muy ineficiente. Incluso de segunda mano no diría que es “barato”, pero es un libro cuyo precio se mantiene alto porque la información lo vale, y para un programador en actividad es relativamente barato.
Las señales son un intento torpe de añadir a la fuerza IPC asíncrono al diseño, por lo que son propensas a condiciones de carrera. Queda ambiguo qué pasa si llega otra señal mientras se está manejando una señal, o qué hacer con una señal cuando el proceso está en medio de una llamada al sistema. Hay que decidir si diferirla, ponerla en una cola o sacar al proceso de la llamada al sistema.
Si todas las llamadas al sistema fueran asíncronas, como principio de diseño que siguen muchos sistemas operativos modernos, ese aspecto quedaría resuelto. Si el IPC tuviera un sistema como canales confiables, se podrían implementar no solo señales, sino también comunicación asíncrona entre procesos o llamadas a procedimientos más sofisticadas.
SIGSTOP/SIGCONT/SIGKILL en realidad hacen control de procesos, como pausar, reanudar y terminar, más que enviar una señal al proceso.
Los mensajes asíncronos simples como SIGHUP, SIGUSR1, SIGUSR2, SIGTTIN, SIGTTOU se abusan para cosas como recargar configuración, y se les agregan atajos tipo hack como
nohuppara demonizar procesos. gunicorn también usa las dos últimas para escalar dinámicamente hacia arriba y hacia abajo. En esta categoría también hay cosas extrañamente específicas como SIGWINCH.Además están las que indican instrucciones inválidas, violaciones de segmentación y excepciones de punto flotante, como SIGILL, SIGSEGV y SIGFPE. También hay casos como SIGSYS, donde de entrada es discutible si conviene que sean asíncronas.
Otros enfoques también tienen trade-offs. Windows tiene eventos, SEH, rutinas de manejo para CTRL+C/CTRL+BREAK/cierre, IOCP, callbacks, etc., y las notes de Plan 9 son cadenas, así que es bueno que puedan enviar datos arbitrarios a otro proceso, pero usar el mismo mecanismo para control de procesos tiene las mismas desventajas que en *nix; en mi opinión, solo son cadenas en vez de números.
Trata los problemas de las señales de Unix y también explica por qué signalfd, que Linux creó para intentar resolverlos, no funciona bien.
https://pubs.opengroup.org/onlinepubs/009604499/functions/bs...
También es importante que el código dentro de un manejador de señales sea reentrante. “Por lo general, las funciones no reentrantes no son seguras para llamarse desde un manejador de señales”.
https://man7.org/linux/man-pages/man7/signal-safety.7.html
Me interesaba Hare, pero al ver esta entrada del FAQ me pareció una política tremendamente autodestructiva: https://harelang.org/documentation/faq.html#will-hare-suppor...
Básicamente, apoyo que los desarrolladores usen la licencia que quieran, apunten al sistema operativo que quieran y escriban el código que quieran
Pero eso no convierte a esta política específica en una buena idea. Incluso la FSF, considerada uno de los grupos más extremos o principistas de la filosofía del software libre, da soporte a Windows y POSIX. Uno puede quejarse y llamarlo Woe32, pero Stallman ha argumentado de forma bastante convincente que hacer que los proyectos de software libre también funcionen en sistemas propietarios ayuda más en la lucha por un mundo sin software propietario
El código de las bibliotecas está licenciado bajo MPL, así que usar Hare no te ata a una licencia específica. Pero me pregunto qué vida puede tener un lenguaje con una actitud de “no damos soporte, no preguntes en el foro, no vengas aquí” hacia más del 95% de los escritorios
Irónicamente, si buscas “harelang repo” en Google, el primer resultado es un port no oficial para macOS, y el repositorio real de SourceHut ni siquiera aparece en la primera página
Los lenguajes crecen como una bola de nieve o desaparecen. Estoy escribiendo esto desde una Mac, pero si quisiera podría usar una máquina Linux ahora mismo. Entonces, ¿por qué debería aprender un lenguaje que impone a los desarrolladores una prueba de pureza que ni siquiera la FSF exige? Una parte considerable del open source y del software libre se escribe en Mac, y más de lo que uno cree también se escribe en Windows
A mi juicio, lo que distingue a Hare de Odin o Zig es precisamente esa actitud de pureza y exclusión. Les deseo hacking feliz y éxito, pero soy pesimista respecto de lo segundo
Por otro lado, eso no es lo único del FAQ que hace levantar una ceja
“No hay gestor de paquetes, y como valor compartido se fomenta menos la reutilización de código”
“qbe genera código más lento que LLVM, y el rendimiento está en el rango de 25 a 75% del rendimiento en tiempo de ejecución frente a código similar generado por LLVM”
“¿Se puede usar multithreading en Hare? Probablemente no”
“¿Entonces tengo que implementar mi propia tabla hash? Sí. Las tablas hash son una estructura de datos común que muchos programas en Hare tendrán que implementar desde cero”
Por ahora, definitivamente no es un lenguaje diseñado con la adopción masiva como objetivo. Está bien, y al menos son honestos al respecto
Tienes libertad para expresar tu opinión, pero cuando los desarrolladores ya fijaron sus lineamientos, este tipo de crítica no me parece constructiva
No todas las bandas tienen que aparecer en las listas de Billboard para valer la pena escucharlas
Dar soporte a sistemas operativos que los desarrolladores no usan es pedir mucho
Hay bastantes lenguajes que, aunque no son populares en general, prosperan en nichos sólidos y cumplen roles importantes
Impresionante, muy genial e inspirador. Ejemplos como “construir algo impresionante en X días” requieren experiencia y talento acumulados durante años
Tuve que poner la cadena en inglés en el catálogo, actualizar varias pruebas, correr las pruebas en el sistema local, subir los cambios a un clúster de staging, arreglar fallas inesperadas en las pruebas, desplegar a producción, pedirle al equipo de traducción que la tradujera a varios idiomas y actualizar la documentación
https://www.ticalc.org/archives/files/fileinfo/463/46387.htm...
Lo que se necesita para expandirlo hasta algo pulido es más perseverancia que una genialidad especial
Fue realmente genial ver las actualizaciones que publicaba casi todos los días en Mastodon. Se podía ver cómo una persona experimentada iba encajando poco a poco software complejo
https://fosstodon.org/@drewdevault/112319697309218275
El código está aquí: https://git.sr.ht/~sircmpwn/bunnix/tree/master
Tiene licencia GPLv3
El espacio de usuario está ensamblado en su mayoría a partir de fuentes de terceros
Al principio me sorprendió que al hacer clic en la ISO apareciera una descarga de 60 MB, pero ahora entiendo por qué
A modo de comparación, Linux 0.01 era una descarga de 71 KB, aunque solo incluía el código fuente del kernel
Hare parece un lenguaje interesante
Sin embargo, en esta era multinúcleo, creo que la siguiente limitación podría restringir su adopción
Según las FAQ https://harelang.org/documentation/faq.html, ante la pregunta de si se puede usar multithreading en Hare, la respuesta es “probablemente no”
Para multiplexar operaciones de entrada/salida recomiendan un event loop, y cuando se necesita usar recursos de CPU en paralelo, recomiendan múltiples procesos con memoria compartida
Estrictamente hablando, se pueden crear threads en un programa Hare. Se puede enlazar con libc y usar pthreads, o usar directamente la llamada al sistema clone(2). Los sistemas operativos implementados en Hare, como Helios, suelen implementar multithreading
Pero como la biblioteca estándar upstream no garantiza reentrancia, es completamente tu responsabilidad evitar pegarte un tiro en el pie
Personalmente prefiero este enfoque para la mayoría de los usos, porque limita la posibilidad de data races únicamente a las regiones de memoria compartida. Desde el punto de vista de las data races, se siente como un “unsafe block” de la memoria
Esto viene de “Linux System Call Table – Chromiumos” https://www.chromium.org/chromium-os/developer-library/refer... https://news.ycombinator.com/item?id=33395777
google/syzkalleR
Llamadas al sistema de Fuschia / Zircon: https://fuchsia.dev/fuchsia-src/reference/syscalls
“Memory Sealing ‘Mseal’ System Call Merged for Linux 6.10”
https://news.ycombinator.com/context?id=40474551