3P by GN⁺ | ★ favorite | 댓글 1개
  • 개인 휴식용 프로젝트로 시작한 Bunnix는 x86_64 대상 Unix 계열 운영체제를 약 한 달 안에 어디까지 만들 수 있는지 실험했고, 실제 작업일 기준 27일이 걸림
  • 커널은 주로 Hare로 작성됐으며, ext4 지원용 lwext4와 커널 비디오 터미널용 libvterm 같은 C 구성요소를 함께 사용함
  • legacy boot와 EFI를 모두 지원하고 일부 실제 노트북에서 테스트됐지만, USB 미지원 때문에 PS/2 키보드나 BIOS의 PS/2 에뮬레이션이 필요함
  • 사용자 공간은 dash, Doom, gzip, less, mandoc, sbase, tcc, Vim 5.7 등 서드파티 소프트웨어 중심이며, libc는 musl libc를 Bunnix에 맞게 수정한 형태임
  • Bunnix는 동작하지만 버그가 많고 단일 사용자 시스템에 머물러 있으며, 장기 유지보다는 Helios 재작업과 커널 설계 개선으로 이어지는 실험에 가까움

Bunnix의 범위와 실행

  • Bunnix는 2024년 4월 21일 시작된 x86_64 대상 Unix 계열 운영체제 프로젝트임
  • 실제로 작업하지 않은 날을 제외하면 총 27일이 투입됨
  • 직접 실행할 수 있는 Bunnix 0.0.0 iso가 제공됨
  • qemu에서는 다음 명령으로 ISO를 부팅할 수 있음
qemu-system-x86_64 -cdrom bunnix.iso -display sdl -serial stdio
  • ISO를 USB 스틱에 기록해 실제 하드웨어에서도 부팅할 수 있음
    • 대부분의 AMD64 머신에서 동작할 가능성이 있음
    • ThinkPad X220과 Starlabs Starbook Mk IV에서 테스트됨
    • legacy bootEFI를 모두 지원함
  • 가장 큰 실행 제약은 USB 미지원
    • PS/2 키보드 또는 BIOS의 PS/2 에뮬레이션이 필요함
    • 대부분의 노트북 키보드는 PS/2 방식으로 연결됨
    • USB 키보드의 PS/2 에뮬레이션 동작 여부는 환경에 따라 다름
  • Doom 포트는 키 바인딩과 종료 동작에 제약이 있음
    • WASD로 이동
    • 오른쪽 Shift로 발사
    • Space로 문 열기
    • 게임 종료가 동작하지 않아 플레이 후 재부팅해야 함

커널 구조와 지원 기능

  • Bunnix 커널은 대부분 Hare로 작성됐고, 일부 C 구성요소를 함께 사용함
    • ext4 파일시스템 지원에는 lwext4 사용
    • 커널 비디오 터미널에는 libvterm 사용
  • 지원 드라이버는 기본 하드웨어와 저장장치 부팅에 필요한 범위에 집중됨
    • PCI legacy
    • AHCI 블록 장치
    • GPT 및 MBR 파티션 테이블
    • PS/2 키보드
    • 플랫폼 직렬 포트
    • CMOS 클록
    • 부트로더가 설정한 프레임버퍼
    • ext4 및 memfs 파일시스템
  • Unix 계열 시스템에 필요한 기본 커널 기능도 포함함
    • 가상 파일시스템과 장치

      • 블록 장치, null, zero, full 의사 장치, /dev/kbd, /dev/fb0, 직렬 및 비디오 TTY, /dev/tty 제어 터미널을 갖춘 /dev를 제공함
      • 비교적 완성된 터미널 에뮬레이터와 어느 정도 동작하는 termios 지원이 들어감
    • 시스템 호출과 사용자 모델

      • clock_gettime, poll, openat, fork, exec, pipe, dup, dup2, ioctl 등을 포함한 약 40개 시스템 호출을 지원함
      • 현재 Bunnix는 단일 사용자 시스템
      • Unix 파일 모드와 소유권을 강제하지 않음
      • 며칠 더 작업하면 다중 사용자 시스템으로 만들 수 있는 상태임

부트로더와 사용자 공간

  • Bunnix에는 두 개의 부트로더가 포함됨
    • legacy boot용 부트로더는 multiboot 호환이며 Hare로 작성됨
    • EFI용 부트로더는 C로 작성됨
  • 두 부트로더는 필요할 경우 커널을 ELF 파일과 initramfs로 로드함
    • EFI 부트로더는 initramfs 압축 해제를 위해 zlib를 포함함
    • multiboot 호환 부트로더는 압축 해제를 대신 처리함
  • 사용자 공간은 대부분 서드파티 소스로 구성됨
    • Colossal Cave Adventure advent
    • dash /bin/sh
    • Doom
    • gzip
    • less
    • lok /bin/awk
    • lolcat
    • mandoc
    • sbase core utils
    • tcc C 컴파일러
    • Vim 5.7
  • libc는 musl libc에서 파생됐고 Bunnix 요구에 맞게 여러 수정이 들어감
  • curses 라이브러리는 netbsd-curses 기반임
  • 시스템은 동작하지만 버그가 많고 일부 구현이 급하게 만들어져, 충돌에 대비해야 함

빠른 구현을 가능하게 한 요소와 난점

  • 일부 Bunnix 코드는 이전 프로젝트 Helios에서 왔음
    • GDT, IDT 같은 일반적인 CPU 설정 관련 커널 코드 일부가 포함됨
    • AHCI 같은 일부 드라이버도 Bunnix 시스템에 맞게 조정됨
    • Helios 경험이 없었다면 Bunnix를 이렇게 빠르게 만들기 어려웠을 것으로 봄
  • ext4 지원가상 터미널 통합이 특히 어려웠음
    • lwext4와 libvterm이라는 외부 의존성을 가져옴
    • 파일시스템 계층은 몇 차례 다시 작성됐고 현재도 버그가 남아 있음
    • openat과 inode 처리를 포함한 Unix 파일시스템 설계를 제대로 구현하려면 lwext4 내부를 더 들여다봐야 했음
  • Hare 프로젝트 안에서 Hare, 어셈블리, C 소스를 함께 링크하는 경험도 얻음
    • 전반적으로 잘 동작했지만 ABI 통합 장치를 만드는 부분에서 불편함이 있었음
    • C 헤더를 Hare forward declaration 모듈로 자동 변환하면 좋겠다는 필요가 생김
    • 관련 작업은 hare-c에 일부 존재하지만 아직 더 필요함
  • Vim 포트를 목표로 하면서 터미널 구현의 난도가 커짐
    • libvterm은 좋은 터미널 상태 머신 라이브러리지만 문서가 부족함
    • 정확한 통합을 위해 많은 미세 조정이 필요했음
    • 부드럽게 동작하도록 성능 최적화에도 시간을 썼음
  • 스케줄러는 Helios 기반 코드를 상당 부분 버리고 다시 작성한 영역임
    • Helios와 Bunnix는 모두 단일 CPU 시스템임
    • Bunnix는 Helios와 달리 커널 안에서 컨텍스트 전환을 허용함
    • 선점형 작업 전환도 커널을 통해 들어오고 나감
    • 이 구조에는 여러 커널 스택과 다른 작업 전환 방식이 필요함
    • 충분히 견고한 스케줄러가 있으면 디스크 읽기나 pipe(2) 같은 블로킹 작업을 wait queue로 단순하게 구현할 수 있음
  • 시그널 구현은 Unix 호환을 위해 필요했음
    • Helios는 Unix를 목표로 하지 않아 시그널 없이도 동작함
    • Bunnix에서는 dash 포트를 위해 SIGCHLD가 제대로 동작하도록 주로 맞춤
    • 최종 시그널 구현은 매우 기본적인 수준임

Helios로 이어지는 설계 교훈

  • Bunnix는 모놀리식 커널이고 Helios는 Unix가 아닌 마이크로커널 설계임
  • 파일시스템에서는 캐싱의 중요성을 확인함
    • Helios는 파일시스템 구현을 여러 드라이버와 별도 프로세스에 나눠 둠
    • 살아 있는 객체 추적만을 위해서라도 파일시스템 계층의 캐싱이 중요함
    • Helios 재작업 시 파일시스템 코드를 리팩터링하거나 다시 작성할 작업이 많아짐
  • 드라이버 접근은 모놀리식 커널에서 자연스럽게 더 단순함
    • 다만 ring 0에 많은 것을 넣은 점에는 완전히 만족하지 않음
    • Helios 스케줄러에 모놀리식 설계의 제어 흐름 요소를 일부 반영할 여지가 있음
  • 메모리 관리에서는 비트맵 할당자가 예상보다 잘 동작함
    • Helios에서는 비트맵 할당자를 피하려 했고 메모리 관리가 큰 불편 지점이었음
    • Bunnix는 시스템의 일반 페이지 전체에 단순 비트맵 할당자를 사용함
    • 우려했던 것보다 오버헤드가 크지 않았고 매우 잘 동작함
  • 30일 안에 Bunnix를 만든 것은 마이크로커널 설계로는 불가능했을 것으로 봄
    • 모놀리식 커널은 구현이 훨씬 단순함
    • 마이크로커널 설계의 장점도 매력적이며, 더 나은 답은 하이브리드 커널일 수 있음

프로젝트 상태와 남은 개선 후보

  • Bunnix는 앞으로 많은 시간을 더 들일 대상이라기보다 거의 완성된 아트 프로젝트에 가까움
    • 때때로 며칠씩 작업할 수는 있음
    • 커뮤니티 개선은 public inbox로 패치를 받을 수 있음
  • 이후 OS 개발은 Bunnix에서 얻은 교훈을 바탕으로 Helios에 돌아가 주요 재설계를 진행하는 쪽임
  • 개선 우선순위 후보는 다음과 같음
    • 파일시스템용 디렉터리 캐시와 전반적인 캐싱 개선
    • ext4 버그 수정
    • procfs와 top
    • 파일 mmap
    • SIGSEGV 같은 추가 시그널
    • 다중 사용자 지원
    • NVMe 블록 장치
    • IDE 블록 장치
    • ATAPI와 ISO 9660 지원
    • Intel HD audio 지원
    • 네트워크 스택
    • 기본 시스템의 Hare 툴체인
    • 셀프 호스팅

댓글과 토론

Hacker News 의견들
  • 정말 멋짐. 원래 Unix도 Ritchie 가족이 장인·장모를 만나러 캘리포니아로 휴가 간 몇 주 사이에 만들어졌다는 얘기가 떠오름
    출처는 Brian W. Kernighan의 UNIX: A History and a Memoir

    • Unix를 쓰기 전에도 이미 오랫동안 Multics 작업을 했다는 점은 중요함. 기억이 맞다면 Unix는 그걸 “단순화한” 버전에 가까웠고, 갑자기 무에서 튀어나온 건 아님
    • 아마 Ken Thompson을 말하는 듯함. YouTube 인터뷰를 찾아보긴 귀찮지만, 여러 번 디스크 드라이버와 몇몇 프로그램, 기타 구성요소가 이미 있었고 아내가 여행을 간 사이 빈틈을 채워 완전한 운영체제로 만들 시간이 되겠다고 생각했다는 식의 이야기를 했던 것으로 기억함
    • Unix 자체는 오래 걸렸다고 봐야 함. V7을 “제대로 완성된 Unix”로 친다면 몇 년이 걸렸고, 첫 버전은 예를 들어 파일 시스템뿐이었음
    • 내가 알기로는 빠져 있던 프로그램 3개에 관한 이야기였고, 그중 하나가 텍스트 편집기였음
      지금 기억이 가물가물해서 확인해봐야겠음
    • Dennis Ritchie와 Ken Thompson을 헷갈린 것 같음
  • “시그널이 위에서 아래까지 어떻게 동작하는지 드디어 배웠는데, 정말 추하다. Unix 설계에서 가장 약한 부분 중 하나라고 늘 느꼈고, 이 프로젝트도 그 생각을 바꾸진 못했다”는 대목에 대해 더 자세한 자료가 있으면 보고 싶음. HN 사용자나 저자가 아는 게 있다면 궁금함

    • 아직 안 봤다면 Stevens의 Advanced Programming in the Unix Environment부터 시작하겠음
      https://www.amazon.com/Advanced-Programming-UNIX-Environment...
      사용자 공간에서 시그널과 프로세스를 포함한 Unix API를 다루는 책임
      커널 안에서 시그널을 구현하고 싶다면 뭘 추천해야 할지는 잘 모르겠지만, 아마 https://pdos.csail.mit.edu/6.828/2012/xv6.html 정도가 떠오름
      Unix가 어떻게 동작하는지 자급식 예제와 함께 명확하고 체계적으로 설명하는 책을 읽는 건 정말 신선함. C를 모르면 장벽이 될 수 있지만, 블로그 글을 읽을 때도 마찬가지임
      동등한 정보가 웹 어딘가에 있다고 보지 않음. 내 블로그에도 사람들이 아직 읽는 Unix 잡지식이 많지만, 같은 수준은 아님
      Unix 시그널을 이해하려면 블로그 글, Google, LLM으로 접근하는 게 매우 비효율적인 주제 중 하나라고 봄. 중고로도 “싸다”고 하긴 어렵지만, 정보가 가치 있으니 높은 가격이 유지되는 책이고, 일하는 프로그래머에게는 상대적으로 싼 편임
    • 시그널은 비동기 입출력/시스템 호출프로세스 간 통신이 만나는 지점에 있음. 비동기와 IPC도 원래 Unix 설계의 약점이고 처음부터 있었던 요소가 아님
      시그널은 설계에 비동기 IPC를 억지로 덧댄 어색한 시도라서 경쟁 상태에 취약함. 시그널 처리 중 또 시그널을 받으면 어떻게 되는지, 프로세스가 시스템 호출 중일 때 시그널을 어떻게 할지도 애매함. 지연할지, 큐에 넣을지, 시스템 호출에서 빼낼지 결정해야 함
      모든 시스템 호출이 비동기라면, 많은 현대 운영체제가 따르는 설계 원칙처럼 그 측면은 해결됨. IPC에 신뢰할 수 있는 채널 같은 시스템이 있다면 시그널뿐 아니라 더 정교한 비동기 프로세스 간 통신이나 절차 호출도 구현할 수 있음
    • Unix 시그널은 서로 다른 개념들을 너무 많이 떠맡고 있어서 싫어하는 사람이 나오는 것 같음
      SIGSTOP/SIGCONT/SIGKILL은 실제로 프로세스에 신호를 보낸다기보다 일시정지, 재개, 종료 같은 프로세스 제어를 함
      SIGHUP, SIGUSR1, SIGUSR2, SIGTTIN, SIGTTOU 같은 단순 비동기 메시지는 설정 재읽기 등에 남용되고, 데몬화를 위해 nohup 같은 해킹식 우회가 붙음. gunicorn은 뒤의 두 개를 동적 확장·축소에 쓰기도 함. 이 범주에는 SIGWINCH처럼 이상하게 구체적인 것도 있음
      또 SIGILL, SIGSEGV, SIGFPE처럼 잘못된 명령, 세그먼테이션 위반, 부동소수점 예외를 나타내는 것들도 있음. 애초에 비동기로 두는 게 좋은지 애매한 SIGSYS 같은 것도 있음
      다른 접근에도 트레이드오프는 있음. Windows에는 이벤트, SEH, CTRL+C/CTRL+BREAK/종료 처리 루틴, IOCP, 콜백 등이 있고, Plan 9의 notes는 문자열이라 다른 프로세스에 임의 데이터를 보낼 수 있는 점은 좋지만, 프로세스 제어에도 같은 메커니즘을 쓰는 건 *nix와 같은 단점이 있으며 숫자 대신 문자열일 뿐이라고 봄
    • “signalfd is useless”가 좋은 글임: https://ldpreload.com/blog/signalfd-is-useless
      Unix 시그널의 문제를 다루고, Linux가 이를 해결하려고 만든 signalfd가 왜 잘 동작하지 않는지도 설명함
    • 이식 가능한 애플리케이션을 쓸 때 BSD와 SYSV의 시그널 처리 차이가 문제가 됐음
      https://pubs.opengroup.org/onlinepubs/009604499/functions/bs...
      시그널 처리기 안의 코드는 재진입 가능해야 한다는 점도 중요함. “재진입 불가능한 함수는 일반적으로 시그널 처리기에서 호출하기 안전하지 않다”
      https://man7.org/linux/man-pages/man7/signal-safety.7.html
  • Hare에 관심이 있었는데, 이 FAQ 항목을 보고 굉장히 자멸적인 정책이라고 느꼈음: https://harelang.org/documentation/faq.html#will-hare-suppor...
    기본적으로 개발자가 원하는 라이선스를 쓰고, 원하는 운영체제를 대상으로 삼고, 원하는 코드를 작성하는 건 지지함
    그렇다고 이 특정 정책이 좋은 생각이 되는 건 아님. 자유 소프트웨어 철학의 가장 극단적이거나 원칙적인 집단으로 여겨지는 FSF조차 Windows와 POSIX를 지원함. 불평하며 Woe32라고 부를 수는 있어도, Stallman은 자유 소프트웨어 프로젝트가 독점 시스템에서도 돌아가게 만드는 편이 독점 소프트웨어 없는 세상을 향한 싸움에 더 도움이 된다고 꽤 설득력 있게 말해왔음
    라이브러리 코드는 MPL로 라이선스해서 Hare를 쓰는 것만으로 특정 라이선스에 묶이지는 않음. 하지만 데스크톱의 95% 이상을 향해 “지원 안 함, 포럼에서 질문하지 마라, 여기 오지 마라”라는 태도를 가진 언어의 수명이 어떨지는 의문임
    아이러니하게도 Google에서 “harelang repo”를 검색하면 첫 결과가 비공식 macOS 포트이고, 실제 SourceHut 저장소는 첫 페이지에 나오지 않음
    언어는 눈덩이처럼 커지거나 사라짐. 지금 Mac에서 이 글을 쓰고 있지만, 마음만 먹으면 지금 당장 Linux 머신도 쓸 수 있음. 그런데 FSF조차 하지 않는 순수성 시험을 개발자에게 강요하는 언어를 왜 배워야 할까? 오픈소스와 자유 소프트웨어의 상당 부분이 Mac에서 작성되고, 생각보다 많은 부분이 Windows에서도 작성됨
    내가 보기엔 Hare를 Odin이나 Zig와 구분짓는 건 바로 이런 순수성과 배제의 태도임. 즐거운 해킹과 성공을 바라지만, 후자에 대해서는 비관적임

    • 한편으로는 저자들이 이루고 싶은 바를 고수하고 모든 요구를 수용하지 않는 점을 존중할 수 있음
      다른 한편 FAQ에서 눈썹이 올라가는 대목이 그것뿐은 아님
      “패키지 관리자가 없고, 공유 가치로서 코드 재사용을 덜 권장한다”
      “qbe는 LLVM보다 느린 코드를 생성하며, 성능은 비슷한 LLVM 생성 코드 대비 실행 시간 성능의 25~75% 범위다”
      “Hare에서 멀티스레딩을 쓸 수 있나? 아마도 아니다”
      “그럼 해시 테이블을 직접 구현해야 하나? 그렇다. 해시 테이블은 많은 Hare 프로그램이 처음부터 구현해야 할 흔한 자료구조다”
      현재로서는 대중적 채택을 목표로 설계된 언어는 확실히 아님. 괜찮고, 적어도 그 점을 솔직히 밝히고 있음
    • “강요”라는 표현에는 동의하지 않음. 누군가가 공짜로 뭔가를 한다면, 악의적이지 않은 한 특정 방식으로 해줄 의무는 없음
      의견을 표현할 자유는 있지만, 개발자가 이미 지침을 정해둔 상황에서 이런 비판은 건설적이지 않다고 봄
    • 당신과 Hare 쪽은 성공의 정의가 다른 것 같음. “언어는 눈덩이처럼 커지거나 사라진다”는 말도, 록스타급 인기는 없어도 수십 년 동안 꾸준히 나아간 많은 언어들을 꽤 깎아내리는 표현처럼 느껴짐
      모든 밴드가 들을 가치가 있으려면 Billboard 차트에 올라야 하는 건 아님
    • 공식적으로 Windows나 macOS를 지원하지 않겠다는 뜻임. 원한다면 다른 프로젝트가 포팅을 시도할 수 있지 않나? 의도한 지원 수준을 솔직히 밝히는 건 좋아 보임
      개발자들이 쓰지 않는 운영체제를 지원하는 건 큰 요구임
    • “언어는 눈덩이처럼 커지거나 사라진다”는 말은 사실이 아니고 순진한 표현임
      전반적으로 인기가 많지는 않아도, 확고한 틈새에서 번성하며 중요한 역할을 하는 언어들이 꽤 있음
  • 인상적이고, 아주 멋지고, 영감을 줌. “X일 만에 인상적인 걸 만들기” 같은 예시는 수년 동안 쌓은 경험과 재능이 필요함

    • 요즘과 비교하면, 나는 국제화 문자열이 들어간 버튼 텍스트 하나를 바꾸는 데 거의 일주일이 걸렸음
      영어 문자열을 카탈로그에 넣고, 여러 테스트를 갱신하고, 로컬 시스템에서 테스트를 돌리고, 변경사항을 스테이징 클러스터에 올리고, 예상 못 한 테스트 실패를 고치고, 프로덕션에 올리고, 번역 담당자에게 여러 언어로 번역을 요청하고, 문서도 갱신해야 했음
    • 12년도 더 전에 Z80 어셈블리만으로 작성한 KnightOS의 제작자이기도 함
      https://www.ticalc.org/archives/files/fileinfo/463/46387.htm...
    • Drew는 똑똑하고 일정도 짧았지만, 그저 그를 받들어 올리는 식으로 보면 잘못된 관점이라고 생각함. UNIX 클론 만들기는 대부분 대학에서 흔한 학부 프로젝트임
      그걸 완성도 있는 것으로 확장하는 데 필요한 건 특별한 천재성보다 끈기임
    • 또한 이전 커널 구현인 Helios가 있어서 최하위 코드 상당 부분을 제공했음. 성취를 깎아내리려는 건 아니지만, DD는 이 프로젝트 속도의 상당 부분이 Helios를 먼저 만들었고 그 코드를 재사용한 데 달려 있었다는 점을 꽤 공개적으로 말함
    • Helios가 있었기 때문에 빠진 몇 부분만 통합한 셈임
  • Mastodon에서 거의 매일 올라오는 업데이트를 보는 게 정말 멋졌음. 숙련된 사람이 복잡한 소프트웨어를 조금씩 맞춰가는 과정을 볼 수 있었음

  • 코드는 여기 있음: https://git.sr.ht/~sircmpwn/bunnix/tree/master
    GPLv3 라이선스임

  • 사용자 공간은 대부분 서드파티 소스에서 조립된 것임
    ISO를 클릭했을 때 60MB 다운로드가 떠서 처음 놀랐는데, 그 이유가 이해됐음
    비교하자면 Linux 0.01은 71KB 다운로드였지만 커널 소스만 들어 있었음

  • Hare는 흥미로운 언어처럼 보임
    다만 이 멀티코어 시대에는 아래 제한이 채택을 제한할 것 같음
    FAQ https://harelang.org/documentation/faq.html에 따르면, Hare에서 멀티스레딩을 쓸 수 있느냐는 질문에 “아마도 아니다”라고 답함
    입출력 작업 다중화에는 이벤트 루프를, CPU 자원을 병렬로 써야 할 때는 공유 메모리를 곁들인 다중 프로세스를 권장함
    엄밀히는 Hare 프로그램에서 스레드를 만들 수 있음. libc에 링크해서 pthreads를 쓰거나 clone(2) 시스템 호출을 직접 사용할 수 있음. Helios 같은 Hare로 구현된 운영체제는 보통 멀티스레딩을 구현함
    하지만 업스트림 표준 라이브러리는 재진입성 보장을 하지 않으므로, 발등을 쏘지 않게 전적으로 직접 책임져야 함

    • “CPU 자원을 병렬로 써야 한다면 공유 메모리를 곁들인 다중 프로세스”는 실제로 꽤 강력함
      개인적으로 대부분의 용도에 이 방식을 선호하는데, 데이터 경쟁 가능성을 공유 메모리 영역으로만 제한하기 때문임. 데이터 경쟁 관점에서는 메모리의 “unsafe block” 같은 느낌임
    • 업스트림 표준 라이브러리가 재진입성을 보장하지 않는다면, 멀티스레딩뿐 아니라 인터럽트 안에서의 사용도 배제됨. “시스템 프로그래밍 언어”치고는 꽤 큰 제한이라고 생각함
    • 클로저가 있었으면 좋겠음
  • “Linux System Call Table – Chromiumos” https://www.chromium.org/chromium-os/developer-library/refer... https://news.ycombinator.com/item?id=33395777에서 나온 내용임
    google/syzkalleR
    Fuschia / Zircon 시스템 호출: https://fuchsia.dev/fuchsia-src/reference/syscalls