- Bunnix, iniciado como um projeto pessoal de descanso, experimentou até onde seria possível levar um sistema operacional do tipo Unix para x86_64 em cerca de um mês e levou 27 dias de trabalho efetivo
- O kernel foi escrito principalmente em Hare, usando também componentes em C, como lwext4 para suporte a ext4 e libvterm para o terminal de vídeo do kernel
- Suporta tanto legacy boot quanto EFI e foi testado em alguns notebooks reais, mas, por não ter suporte a USB, exige um teclado PS/2 ou emulação PS/2 pela BIOS
- O espaço de usuário é centrado em software de terceiros, como dash, Doom, gzip, less, mandoc, sbase, tcc e Vim 5.7; a libc é uma versão da musl libc modificada para o Bunnix
- O Bunnix funciona, mas tem muitos bugs e permanece um sistema de usuário único; é mais um experimento que levou ao retrabalho do Helios e a melhorias no projeto do kernel do que algo destinado à manutenção de longo prazo
Escopo e execução do Bunnix
- Bunnix é um projeto de sistema operacional do tipo Unix para x86_64 iniciado em 21 de abril de 2024
- Excluindo os dias em que não houve trabalho efetivo, foram investidos 27 dias no total
- Está disponível uma ISO do Bunnix 0.0.0 que pode ser executada diretamente
- No qemu, é possível inicializar a ISO com o seguinte comando
qemu-system-x86_64 -cdrom bunnix.iso -display sdl -serial stdio
- Também é possível gravar a ISO em um pendrive USB e inicializá-la em hardware real
- Há chance de funcionar na maioria das máquinas AMD64
- Foi testado em um ThinkPad X220 e em um Starlabs Starbook Mk IV
- Suporta tanto legacy boot quanto EFI
- A maior restrição de execução é a ausência de suporte a USB
- É necessário um teclado PS/2 ou emulação PS/2 pela BIOS
- A maioria dos teclados de notebooks é conectada via PS/2
- O funcionamento da emulação PS/2 para teclados USB varia conforme o ambiente
- O port de Doom tem limitações nos atalhos de teclado e no comportamento de encerramento
- Movimentação com WASD
- Disparo com Shift direito
- Abrir portas com Space
- O encerramento do jogo não funciona, então é preciso reiniciar depois de jogar
Estrutura do kernel e recursos suportados
- O kernel do Bunnix foi escrito em sua maior parte em Hare, usando também alguns componentes em C
- Usa lwext4 para suporte ao sistema de arquivos ext4
- Usa libvterm para o terminal de vídeo do kernel
- Os drivers suportados se concentram no escopo necessário para hardware básico e inicialização por dispositivos de armazenamento
- PCI legacy
- Dispositivo de bloco AHCI
- Tabelas de partição GPT e MBR
- Teclado PS/2
- Porta serial da plataforma
- Relógio CMOS
- Framebuffer configurado pelo bootloader
- Sistemas de arquivos ext4 e memfs
- Também inclui recursos básicos de kernel necessários para um sistema do tipo Unix
-
Sistema de arquivos virtual e dispositivos
- Fornece
/dev com dispositivos de bloco, pseudodispositivos null, zero e full, /dev/kbd, /dev/fb0, TTYs seriais e de vídeo e o terminal de controle /dev/tty
- Inclui um emulador de terminal relativamente completo e suporte a termios funcionando em certa medida
-
Chamadas de sistema e modelo de usuário
- Suporta cerca de 40 chamadas de sistema, incluindo
clock_gettime, poll, openat, fork, exec, pipe, dup, dup2 e ioctl
- Atualmente, o Bunnix é um sistema de usuário único
- Não aplica modos de arquivo nem propriedade do Unix
- Está em um estado em que poderia se tornar um sistema multiusuário com mais alguns dias de trabalho
Bootloaders e espaço de usuário
- O Bunnix inclui dois bootloaders
- O bootloader para legacy boot é compatível com multiboot e foi escrito em Hare
- O bootloader para EFI foi escrito em C
- Os dois bootloaders carregam o kernel como um arquivo ELF e um initramfs quando necessário
- O bootloader EFI inclui zlib para descompactar o initramfs
- O bootloader compatível com multiboot cuida da descompactação por outro meio
- O espaço de usuário é composto principalmente por código-fonte de terceiros
- Colossal Cave Adventure
advent
dash /bin/sh
- Doom
- gzip
- less
lok /bin/awk
- lolcat
- mandoc
- sbase core utils
- compilador C tcc
- Vim 5.7
- A libc deriva da musl libc e recebeu várias modificações para atender aos requisitos do Bunnix
- A biblioteca curses é baseada na netbsd-curses
- O sistema funciona, mas tem muitos bugs e algumas implementações foram feitas às pressas, então é preciso estar preparado para falhas
Fatores que viabilizaram a implementação rápida e dificuldades
- Parte do código do Bunnix veio do projeto anterior Helios
- Inclui parte do código de kernel relacionado à configuração comum da CPU, como GDT e IDT
- Alguns drivers, como AHCI, também foram adaptados ao sistema Bunnix
- Considera-se que, sem a experiência com o Helios, teria sido difícil criar o Bunnix tão rapidamente
- A integração do suporte a ext4 e do terminal virtual foi particularmente difícil
- Foram trazidas dependências externas, lwext4 e libvterm
- A camada de sistema de arquivos foi reescrita algumas vezes e ainda há bugs
- Para implementar corretamente o projeto de sistema de arquivos Unix, incluindo
openat e tratamento de inodes, foi necessário investigar mais a fundo os internos do lwext4
- Também houve experiência em vincular fontes em Hare, assembly e C dentro do projeto Hare
- No geral funcionou bem, mas houve incômodo na criação do aparato de integração de ABI
- Surgiu a necessidade de converter automaticamente headers C em módulos de forward declaration em Hare
- Parte desse trabalho existe em
hare-c, mas ainda é preciso mais
- Ao mirar o port do Vim, a dificuldade da implementação do terminal aumentou
- libvterm é uma boa biblioteca de máquina de estados de terminal, mas tem pouca documentação
- Foi necessário muito ajuste fino para uma integração correta
- Também foi dedicado tempo à otimização de desempenho para que funcionasse de forma suave
- O escalonador foi uma área em que grande parte do código baseado no Helios foi descartada e reescrita
- Tanto o Helios quanto o Bunnix são sistemas de CPU única
- Diferentemente do Helios, o Bunnix permite troca de contexto dentro do kernel
- A troca preemptiva de tarefas também entra e sai pelo kernel
- Essa estrutura exige várias pilhas de kernel e uma forma diferente de troca de tarefas
- Com um escalonador suficientemente robusto, operações bloqueantes como leitura de disco ou
pipe(2) podem ser implementadas de forma simples com wait queues
- A implementação de sinais foi necessária para compatibilidade com Unix
- O Helios não tem o Unix como objetivo e funciona mesmo sem sinais
- No Bunnix, o ajuste foi feito principalmente para que
SIGCHLD funcionasse corretamente no port do dash
- A implementação final de sinais é muito básica
Lições de projeto que levam ao Helios
- O Bunnix é um kernel monolítico, enquanto o Helios tem um projeto de microkernel que não é Unix
- No sistema de arquivos, confirmou-se a importância do cache
- O Helios divide a implementação do sistema de arquivos entre vários drivers e processos separados
- Mesmo que apenas para rastrear objetos vivos, o cache na camada de sistema de arquivos é importante
- Ao retrabalhar o Helios, haverá muito a refatorar ou reescrever no código do sistema de arquivos
- O acesso a drivers é naturalmente mais simples em um kernel monolítico
- Ainda assim, não há satisfação completa com a inclusão de tanta coisa no ring 0
- Há espaço para refletir alguns elementos do fluxo de controle do projeto monolítico no escalonador do Helios
- Na gestão de memória, o alocador por bitmap funcionou melhor do que o esperado
- No Helios, havia tentativa de evitar um alocador por bitmap, e a gestão de memória era um grande ponto de incômodo
- O Bunnix usa um alocador simples por bitmap para todas as páginas gerais do sistema
- O overhead foi menor do que o temido e funcionou muito bem
- Considera-se que criar o Bunnix em menos de 30 dias teria sido impossível com um projeto de microkernel
- Um kernel monolítico é muito mais simples de implementar
- As vantagens de um projeto de microkernel também são atraentes, e a melhor resposta pode ser um kernel híbrido
Estado do projeto e possíveis melhorias restantes
- O Bunnix é mais próximo de um projeto artístico quase concluído do que de algo em que será investido muito mais tempo
- Pode haver trabalho ocasional de alguns dias
- Melhorias da comunidade podem ser enviadas como patches para a public inbox
- O desenvolvimento de SO daqui em diante seguirá para retornar ao Helios e fazer grandes reformulações com base nas lições obtidas com o Bunnix
- Candidatos a prioridades de melhoria incluem:
- Cache de diretórios para o sistema de arquivos e melhorias gerais de cache
- Correção de bugs do ext4
- procfs e top
- mmap de arquivos
- Sinais adicionais, como
SIGSEGV
- Suporte multiusuário
- Dispositivo de bloco NVMe
- Dispositivo de bloco IDE
- Suporte a ATAPI e ISO 9660
- Suporte a Intel HD audio
- Pilha de rede
- Toolchain Hare no sistema base
- Self-hosting
1 comentários
Opiniões do Hacker News
Muito legal. Isso me lembra a história de que o Unix original também foi criado nas poucas semanas em que a família de Ritchie saiu de férias para a Califórnia para visitar os sogros
A fonte é UNIX: A History and a Memoir, de Brian W. Kernighan
Minha memória está meio nebulosa agora, preciso conferir
Eu gostaria de ver material mais detalhado sobre o trecho: “Finalmente aprendi como os sinais funcionam de ponta a ponta, e é realmente feio. Sempre achei que era uma das partes mais fracas do design do Unix, e este projeto não mudou essa opinião”. Se usuários do HN ou o autor souberem de algo, tenho curiosidade
https://www.amazon.com/Advanced-Programming-UNIX-Environment...
Ele cobre as responsabilidades de lidar, no espaço de usuário, com a API Unix, incluindo sinais e processos
Se você quiser implementar sinais dentro do kernel, não sei bem o que recomendar, mas algo como https://pdos.csail.mit.edu/6.828/2012/xv6.html me vem à mente
É realmente revigorante ler um livro que explica de forma clara e sistemática como o Unix funciona, com exemplos autocontidos. Não saber C pode ser uma barreira, mas o mesmo vale ao ler posts de blog
Não acho que exista informação equivalente em algum lugar da web. No meu blog também há bastante conhecimento avulso sobre Unix que as pessoas ainda leem, mas não está no mesmo nível
Para entender sinais Unix, acho que recorrer a posts de blog, Google e LLMs é uma forma muito ineficiente de abordar o tema. Mesmo usado, não dá para dizer que é “barato”, mas é um livro cujo preço alto se mantém porque a informação tem valor e, para um programador profissional, é relativamente barato
Sinais são uma tentativa desajeitada de enxertar IPC assíncrono no design, então são vulneráveis a condições de corrida. O que acontece se você receber outro sinal enquanto está tratando um sinal? O que fazer com um sinal quando o processo está no meio de uma chamada de sistema? É preciso decidir se ele será adiado, enfileirado ou se a chamada de sistema será interrompida
Se todas as chamadas de sistema fossem assíncronas, esse aspecto estaria resolvido, como no princípio de design seguido por muitos sistemas operacionais modernos. Se o IPC tivesse um sistema como canais confiáveis, seria possível implementar não só sinais, mas também comunicação assíncrona entre processos ou chamadas de procedimento mais sofisticadas
SIGSTOP/SIGCONT/SIGKILL na prática fazem controle de processos, como pausar, retomar e encerrar, em vez de realmente “enviar um sinal” ao processo
Mensagens assíncronas simples como SIGHUP, SIGUSR1, SIGUSR2, SIGTTIN, SIGTTOU são abusadas para reler configurações etc., e há gambiarras como
nohuppara daemonização. O gunicorn também usa os dois últimos para escalar para cima e para baixo dinamicamente. Nessa categoria também há coisas estranhamente específicas, como SIGWINCHTambém há sinais como SIGILL, SIGSEGV e SIGFPE, que indicam instrução inválida, violação de segmentação e exceção de ponto flutuante. Há ainda coisas como SIGSYS, para as quais é discutível se faz sentido serem assíncronas desde o início
Outras abordagens também têm trade-offs. No Windows há eventos, SEH, rotinas de tratamento de CTRL+C/CTRL+BREAK/encerramento, IOCP, callbacks etc.; as notes do Plan 9 são strings, então é bom poder enviar dados arbitrários a outro processo, mas usar o mesmo mecanismo para controle de processos tem a mesma desvantagem do *nix, sendo apenas strings em vez de números
Ele aborda os problemas dos sinais Unix e também explica por que o signalfd, criado pelo Linux para tentar resolvê-los, não funciona bem
https://pubs.opengroup.org/onlinepubs/009604499/functions/bs...
Também é importante que o código dentro de um tratador de sinal seja reentrante. “Funções não reentrantes geralmente não são seguras para serem chamadas a partir de um tratador de sinal”
https://man7.org/linux/man-pages/man7/signal-safety.7.html
Eu estava interessado em Hare, mas ao ver este item do FAQ achei uma política extremamente autodestrutiva: https://harelang.org/documentation/faq.html#will-hare-suppor...
No fundo, apoio que desenvolvedores usem a licença que quiserem, tenham como alvo o sistema operacional que quiserem e escrevam o código que quiserem
Mas isso não torna essa política específica uma boa ideia. Até a FSF, considerada um dos grupos mais extremos ou mais principistas da filosofia de software livre, dá suporte a Windows e POSIX. Dá para reclamar e chamar de Woe32, mas Stallman argumentou de forma bastante convincente que fazer projetos de software livre rodarem também em sistemas proprietários ajuda mais na luta por um mundo sem software proprietário
O código de biblioteca é licenciado sob a MPL, então usar Hare por si só não prende você a uma licença específica. Mas fico me perguntando qual será a longevidade de uma linguagem que diz a mais de 95% dos desktops: “não damos suporte, não perguntem no fórum, não venham para cá”
Ironicamente, ao pesquisar “harelang repo” no Google, o primeiro resultado é um port não oficial para macOS, e o repositório real no SourceHut não aparece na primeira página
Linguagens viram uma bola de neve ou desaparecem. Estou escrevendo isto agora em um Mac, mas, se quisesse, poderia usar uma máquina Linux neste exato momento. Então por que eu deveria aprender uma linguagem que impõe aos desenvolvedores um teste de pureza que nem a FSF impõe? Uma parte considerável do open source e do software livre é escrita em Mac, e uma parcela maior do que se imagina também é escrita em Windows
A meu ver, o que diferencia Hare de Odin ou Zig é justamente essa atitude de pureza e exclusão. Desejo bons hacks e sucesso, mas sou pessimista quanto a este último
Por outro, esse não é o único trecho do FAQ que levanta sobrancelhas
“Não há gerenciador de pacotes, e, como valor compartilhado, a reutilização de código é menos incentivada”
“qbe gera código mais lento que LLVM, e o desempenho fica na faixa de 25% a 75% do desempenho em tempo de execução de código gerado por LLVM comparável”
“Posso usar multithreading em Hare? Provavelmente não”
“Então preciso implementar minha própria tabela hash? Sim. Tabelas hash são uma estrutura de dados comum que muitos programas em Hare precisarão implementar do zero”
Por enquanto, definitivamente não é uma linguagem projetada visando adoção em massa. Tudo bem, e pelo menos eles são honestos sobre isso
Há liberdade para expressar opiniões, mas, quando os desenvolvedores já definiram as diretrizes, acho que esse tipo de crítica não é construtivo
Nem toda banda precisa entrar na parada da Billboard para merecer ser ouvida
Dar suporte a sistemas operacionais que os desenvolvedores não usam é uma grande exigência
Há várias linguagens que, mesmo sem serem muito populares no geral, prosperam em nichos sólidos e desempenham papéis importantes
Impressionante, muito legal e inspirador. Exemplos do tipo “criar algo impressionante em X dias” exigem experiência e talento acumulados ao longo de anos
Tive que colocar a string em inglês no catálogo, atualizar vários testes, rodar os testes no sistema local, enviar as mudanças para o cluster de staging, corrigir falhas inesperadas nos testes, subir para produção, pedir aos responsáveis por tradução que traduzissem para vários idiomas e também atualizar a documentação
https://www.ticalc.org/archives/files/fileinfo/463/46387.htm...
O que é necessário para expandir isso até algo bem-acabado é mais persistência do que genialidade especial
Foi muito legal acompanhar as atualizações quase diárias no Mastodon. Dava para ver uma pessoa experiente ajustando software complexo pouco a pouco
https://fosstodon.org/@drewdevault/112319697309218275
O código está aqui: https://git.sr.ht/~sircmpwn/bunnix/tree/master
Está sob licença GPLv3
O espaço de usuário foi montado em grande parte a partir de fontes de terceiros
No começo me surpreendi ao clicar na ISO e ver um download de 60 MB, mas entendi o motivo
Para comparação, o Linux 0.01 era um download de 71 KB, mas continha apenas o código-fonte do kernel
Hare parece ser uma linguagem interessante
Mas, nesta era multicore, a limitação abaixo parece que vai restringir sua adoção
Segundo o FAQ https://harelang.org/documentation/faq.html, à pergunta sobre se é possível usar multithreading em Hare, a resposta é “provavelmente não”
Para multiplexação de operações de entrada/saída, recomenda-se um event loop; quando for preciso usar recursos de CPU em paralelo, recomenda-se multiprocessamento com memória compartilhada
A rigor, é possível criar threads em um programa Hare. Dá para linkar com a libc e usar pthreads, ou usar diretamente a chamada de sistema clone(2). Sistemas operacionais implementados em Hare, como o Helios, normalmente implementam multithreading
No entanto, a biblioteca padrão upstream não garante reentrância, então evitar dar um tiro no próprio pé fica totalmente por sua conta
Pessoalmente, prefiro essa abordagem para a maioria dos usos, porque ela limita a possibilidade de data races apenas às regiões de memória compartilhada. Do ponto de vista de data races, parece algo como um “unsafe block” da memória
Isso veio de “Linux System Call Table – Chromiumos” https://www.chromium.org/chromium-os/developer-library/refer... https://news.ycombinator.com/item?id=33395777
google/syzkalleR
Chamadas de sistema do 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