3 pontos por GN⁺ 2024-05-25 | 1 comentários | Compartilhar no WhatsApp
  • 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

 
GN⁺ 2024-05-25
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

    • É importante notar que eles já haviam trabalhado no Multics por muito tempo antes de escrever o Unix. Se não me falha a memória, o Unix era mais uma versão “simplificada” daquilo, não algo que surgiu de repente do nada
    • Acho que você quer dizer Ken Thompson. Estou com preguiça de procurar a entrevista no YouTube, mas lembro que ele contou várias vezes algo como: já havia um driver de disco, alguns programas e outros componentes, e, enquanto a esposa viajava, ele achou que teria tempo para preencher as lacunas e transformá-los em um sistema operacional completo
    • O Unix em si deve ter levado bastante tempo. Se considerarmos o V7 como o “Unix devidamente completo”, isso levou anos; a primeira versão era, por exemplo, basicamente só o sistema de arquivos
    • Pelo que sei, a história era sobre três programas que faltavam, e um deles era um editor de texto
      Minha memória está meio nebulosa agora, preciso conferir
    • Acho que você confundiu Dennis Ritchie com Ken Thompson
  • 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

    • Se ainda não leu, eu começaria por Advanced Programming in the Unix Environment, de Stevens
      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 ficam no ponto de encontro entre E/S assíncrona/chamadas de sistema e comunicação entre processos. Assincronia e IPC também são pontos fracos do design original do Unix e não estavam lá desde o começo
      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
    • Acho que há gente que não gosta dos sinais Unix porque eles acabam assumindo conceitos diferentes demais
      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 nohup para 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 SIGWINCH
      També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
    • “signalfd is useless” é um bom artigo: https://ldpreload.com/blog/signalfd-is-useless
      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
    • Ao escrever aplicações portáveis, as diferenças no tratamento de sinais entre BSD e SYSV eram um problema
      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 um lado, dá para respeitar os autores por se manterem fiéis ao que querem realizar e por não aceitarem todas as demandas
      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
    • Não concordo com a expressão “impõe”. Se alguém faz algo de graça, desde que não seja malicioso, não tem obrigação de fazê-lo de um jeito específico
      Há liberdade para expressar opiniões, mas, quando os desenvolvedores já definiram as diretrizes, acho que esse tipo de crítica não é construtivo
    • Parece que você e o pessoal do Hare têm definições de sucesso diferentes. A frase “linguagens viram uma bola de neve ou desaparecem” também me soa como algo que diminui bastante muitas linguagens que avançaram de forma constante por décadas, mesmo sem popularidade de estrela do rock
      Nem toda banda precisa entrar na parada da Billboard para merecer ser ouvida
    • Significa que oficialmente eles não pretendem dar suporte a Windows ou macOS. Se quiserem, outros projetos não podem tentar fazer ports? Ser honesto sobre o nível de suporte pretendido me parece algo positivo
      Dar suporte a sistemas operacionais que os desenvolvedores não usam é uma grande exigência
    • A frase “linguagens viram uma bola de neve ou desaparecem” não é verdadeira e é ingênua
      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

    • Comparando com hoje em dia, eu levei quase uma semana para mudar o texto de um único botão que continha uma string internacionalizada
      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
    • Ele também é o criador do KnightOS, escrito há mais de 12 anos usando apenas assembly Z80
      https://www.ticalc.org/archives/files/fileinfo/463/46387.htm...
    • Drew é inteligente e o prazo foi curto, mas acho que é uma perspectiva errada simplesmente colocá-lo num pedestal. Criar um clone do UNIX é, em grande parte, um projeto comum de graduação em muitas universidades
      O que é necessário para expandir isso até algo bem-acabado é mais persistência do que genialidade especial
    • Além disso, havia a implementação anterior de kernel, Helios, que forneceu boa parte do código de nível mais baixo. Não quero diminuir a conquista, mas DD falou de forma bastante aberta que uma parte considerável da velocidade deste projeto veio de ele já ter criado o Helios antes e reutilizado esse código
    • Como já havia o Helios, foi basicamente integrar algumas partes que faltavam
  • Foi muito legal acompanhar as atualizações quase diárias no Mastodon. Dava para ver uma pessoa experiente ajustando software complexo pouco a pouco

  • 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

    • “Se for preciso usar recursos de CPU em paralelo, multiprocessamento com memória compartilhada” é, na prática, bem poderoso
      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
    • Se a biblioteca padrão upstream não garante reentrância, isso exclui não só multithreading, mas também o uso dentro de interrupções. Para uma “linguagem de programação de sistemas”, acho que é uma limitação considerável
    • Seria bom se houvesse closures
  • 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