나만의 운영체제를 만들고 있다고요? CottonOS
요약
Rust 언어를 사용하여 밑바닥부터 구축한 취미용 운영체제 CottonOS를 소개합니다. x86_64 아키텍처를 기반으로 커스텀 파일 시스템, GUI, 선점형 멀티태스킹 기능을 갖추었으며, 궁극적으로 온디바이스 LLM 실행을 목표로 합니다.
핵심 포인트
- Rust의 소유권 모델을 활용해 메모리 안전성이 보장된 커널 구현
- 커스텀 파일 시스템(CottonFS) 및 그래픽 데스크톱 환경 구축
- x86_64 환경에서 no_std를 이용한 베어 메탈 프로그래밍 수행
- 가볍고 독립적인 온디바이스 LLM 실행을 최종 비전으로 설정
Rust로 밑바닥부터 OS를 구축하고 있습니다 — 이미 데스크톱, 파일 시스템, 그리고 네트워킹 기능까지 갖추었습니다
CottonOS에 대한 심층 분석: 커스텀 파일 시스템, GUI, 선점형 멀티태스킹(preemptive multitasking), 그리고 실험적인 커널 내 TLS를 갖춘, 전체가 Rust로 작성된 취미용 OS.
일부 프로그래머들에게는 특유의 광기가 찾아옵니다. 단순히 운영체제를 사용하는 것에 그치지 않고, 직접 만들고 싶어 하는 충동 말이죠. 부트로더(bootloader)부터 윈도우 매니저(window manager)에 이르기까지 말입니다. 밑바탕에 Linux도 없고, BSD도 없습니다. 오직 당신과 CPU, 그리고 수많은 페이지 폴트(page faults)뿐입니다.
그것이 바로 CottonOS입니다.
저는 이것을 취미 프로젝트이자 학습 실험으로 구축해 왔습니다. x86_64를 위해 Rust로 작성된 완전한 OS 커널로, 제가 CottonFS라고 부르는 커스텀 파일 시스템, 작동 가능한 창과 작업 표시줄이 있는 그래픽 데스크톱 환경, 선점형 멀티태스킹(preemptive multitasking), 그리고 실험적인 커널 내 HTTPS 스택을 특징으로 합니다. 프로덕션 환경에 사용할 수준은 전혀 아니지만, 부팅이 가능하고, 창을 렌더링하며, 파일을 읽고 쓰고, HTTP 요청을 보낼 수 있습니다 — 이 모든 것이 완전히 밑바닥부터 이루어졌습니다.
장기적인 비전은 더 큽니다. 저는 CottonOS가 궁극적으로 기기 내에서 실행되는 가볍고 빠른, 완전히 독립적인 온디바이스 LLM(on-device LLM)을 실행하기를 원합니다. 아직 갈 길이 멀지만, 제가 작성하는 모든 서브시스템(subsystem)이 그 목표에 한 걸음 더 다가가게 합니다.
이 포스트는 제가 구축한 것, 제가 내린 결정들, 어려운 부분들, 그리고 제가 나아가고자 하는 방향에 대한 기술적인 워크스루(walkthrough)입니다. 저는 로우 레벨(low-level) 시스템 프로그래밍을 깊게 파고들고 싶어 하는 기여자들을 적극적으로 찾고 있습니다.
왜 OS에 Rust를 사용하는가?
명백한 답은 가비지 컬렉터(garbage collector) 없이도 메모리 안전성(memory safety)을 보장한다는 것입니다. 커널 코드에서 use-after-free는 단순한 버그가 아닙니다. 그것은 권한 상승(privilege escalation)이나 복구 불가능한 치명적인 충돌(hard crash)로 이어집니다. Rust의 소유권 모델(ownership model)은 이러한 실수들의 전체 클래스를 컴파일 타임(compile time)에 잡아냅니다.
하지만 진짜 이유는 더 개인적입니다. 저는 Rust를 깊이 있게 배우고 싶었고, 베어 메탈(bare metal)보다 더 깊은 환경은 없습니다. 할당자(allocator)도 없고, 표준 라이브러리(standard library)도 없으며, 당신의 실수를 잡아줄 OS도 없습니다. 오직 no_std와 하드웨어를 가리키는 커스텀 타겟 사양(target spec)뿐입니다.
커널은 95.4%가 Rust로 작성되었습니다. 나머지 약 3%는 작은 boot_stub.asm으로 구성되며, 여기에는 Multiboot2 헤더, 최소한의 GDT, 초기 페이지 테이블(page tables), 그리고 롱 모드(long mode) 진입점(entry point)이 포함됩니다. 일단 64비트 모드에 진입하면, 그 아래로는 전부 Rust로 이루어집니다.
부트 시퀀스 (Boot Sequence): 가능한 한 빠르게 Rust로 진입하기
CottonOS는 부트로더(bootloader)로 Multiboot2를 지원하는 GRUB를 사용합니다. GRUB는 1MB 물리 지점에서 커널 ELF를 로드하고 boot_stub.asm으로 제어권을 넘깁니다. 이 어셈블리 코드는 롱 모드에 진입하기 위해 필요한 최소한의 작업만을 수행합니다:
- 스택(stack) 설정
- 플랫 64비트 GDT 초기화
- 첫 1GB를 커버하는 아이덴티티 매핑(identity-mapped) PML4 페이지 테이블 생성
CR4.PAE설정,CR3에 PML4 로드,EFER.LME설정,CR0.PG를 통한 페이징(paging) 활성화- 64비트 코드 세그먼트로 Far-jump
- 우리의 Rust 진입점인
_start64호출
그 이후 _start64는 가장 먼저 시리얼 출력(serial output)을 초기화합니다(화면이 아직 뜨지 않더라도 디버그 로깅을 할 수 있도록 하기 위함). 그다음 Multiboot2 정보 구조체를 파싱하여 프레임버퍼(framebuffer)와 메모리 맵(memory map)을 찾아낸 뒤, 각 서브시스템을 순서대로 가동합니다: 인터럽트(interrupts) → 메모리(memory) → 파일 시스템(filesystem) → 프로세스(processes) → 드라이버(drivers) → GUI.
메모리 관리 (Memory Management): 3개의 계층
물리 할당자 (Physical Allocator)
4KB 프레임(frames)을 추적하는 비트맵 할당자(bitmap allocator)입니다. 부팅 시 Multiboot2 메모리 맵을 파싱하여 커널과 프레임버퍼가 점유하는 모든 영역을 사용 중으로 표시하며, 나머지는 사용 가능한 상태로 둡니다. 단순하고 예측 가능하며, 물리 계층에서의 단편화(fragmentation)가 없습니다.
가상 메모리 (Virtual Memory)
표준 x86_64 4단계 페이징(4-level paging)을 사용합니다: PML4 → PDPT → PD → PT. 커널은 현재 하위 절반(lower half)에 위치합니다(상위 절반(higher-half) 지원은 준비되어 있으나 아직 연결되지는 않았습니다). 페이지(pages)는 Present, Writable, User-accessible, No-Execute와 같은 표준 권한 플래그(permission flags)를 가집니다. 온디맨드 매핑(On-demand mapping) 방식을 통해 실제로 필요할 때만 페이지 테이블 엔트리(page table entries)를 생성합니다.
커널 힙 (Kernel Heap)
linked_list_allocator 크레이트 (crate)를 기반으로 구축되었습니다. 초기 크기는 0x02000000 위치에서 4MB이며, 16MB까지 확장 가능합니다. 이는 전역 할당자 (global allocator)로 등록되어 alloc을 사용할 수 있게 해줍니다. 즉, 커널 내부에서 Vec, String, Box, Arc 및 기타 힙 할당 컬렉션 타입 (heap-allocated collection types)들이 정상적으로 작동함을 의미합니다.
CottonFS: 커스텀 영구 파일 시스템 (Persistent Filesystem)
이 부분은 구축하는 데 가장 많은 노력이 들어간 작업 중 하나였습니다. CottonFS는 ext2의 영향을 받은 설계를 가진, 단순하지만 실제적인 영구 파일 시스템 (persistent filesystem)입니다.
디스크 레이아웃 (On-Disk Layout)
| 블록 범위 (Block Range) | 내용 (Content) |
|---|---|
| 0 | 슈퍼블록 (Superblock) |
| ... |
블록 크기는 4096 바이트입니다. 매직 넘버 (magic number)는 0x43544653 ("CTFS")입니다. 슈퍼블록은 총/여유 블록 및 아이노드 (inodes), 마운트 횟수, 마지막 마운트 시간, 그리고 루트 아이노드 (항상 inode 1)를 추적합니다.
아이노드는 디스크 상에서 128 바이트이며, 파일 메타데이터와 12개의 직접 블록 포인터 (direct block pointers) 및 하나의 간접 포인터 (indirect pointer)를 보유합니다 (파일당 최대 크기는 약 4MB로, 취미용 OS에는 충분한 수준입니다).
VFS 계층 (VFS Layer)
CottonFS 위에는 Rust 트레이트 (traits)를 사용하는 VFS 추상화 계층이 위치합니다:
pub trait FileSystem: Send + Sync {
fn root(&self) -> Result<Arc<dyn Inode>, &'static str>;
fn sync(&self) -> Result<(), &'static str>;
...
이는 /dev에 DevFS를 마운트하는 것이 매우 간단했음을 의미합니다. DevFS는 동일한 트레이트를 구현하며, /dev/null, /dev/zero, /dev/random을 가상 아이노드 (virtual inodes)로 제공하므로 커널의 나머지 부분은 그 차이를 알 필요가 없습니다.
프로세스 관리 및 스케줄러 (Process Management and the Scheduler)
CottonOS는 PIT (Programmable Interval Timer)에 의해 구동되며, 1000Hz로 실행되는 선점형 라운드 로빈 스케줄러 (preemptive round-robin scheduler)를 갖추고 있습니다.
각 프로세스는 PID, 부모 PID, 이름, 우선순위 (5단계), 상태, 그리고 종료 상태를 포함하는 Process 구조체 (struct)로 표현됩니다. 상태는 Ready, Running, Blocked, Zombie가 있습니다.
스레드 (Threads) 또한 커널 수준에서 지원되며, 스레드별 스택 (per-thread stacks)과 스레드 로컬 저장소 (thread-local storage)를 즉시 사용할 수 있도록 준비되어 있습니다.
스케줄러(scheduler)는 이 구조 위에 자리 잡고 있습니다. 매 타이머 틱(timer tick, 매 1ms마다)마다 현재 프로세스는 선점(preempted)되며, 우선순위 순서에 따라 다음에 실행 가능한(ready) 프로세스가 스케줄링됩니다. 또한, 실행 가능한 다른 프로세스가 없을 때 실행되는 유휴(idle) 프로세스도 존재합니다.
동기화 기본 요소(synchronization primitives)인 Mutex, Semaphore, CondVar는 모두 직접 구현되었습니다. 뮤텍스(mutex)는 대기 큐(wait queue)를 사용하여 차단된 스레드가 스핀(spinning)하는 대신 CPU를 양보(yield)하도록 설계되었으며, 이는 1000Hz 환경에서 실제로 중요한 역할을 합니다.
시스템 호출 (System Calls)
시스템 호출(syscall) 인터페이스는 int 0x80과 syscall 명령어를 통해 모두 노출됩니다. 다음과 같은 40개 이상의 호출이 포함되어 있습니다:
- 프로세스 (Process):
exit,fork,exec,wait,getpid,yield,sleep - 파일 I/O (File I/O):
open,close,read,write,seek,stat,fstat - 디렉토리 (Directory):
mkdir,rmdir,unlink,readdir,chdir,getcwd - 메모리 (Memory):
brk,mmap,munmap - 시스템 (System):
uname,time,uptime
사용자 공간(Userspace)은 아직 대부분 계획 단계에 있으며—현재 흥미로운 부분들은 커널 공간(kernel space)에 존재합니다—하지만 인터페이스는 마련되어 있으며 핸들러(handlers)도 구현되어 있습니다.
네트워킹: ARP부터 커널 내 TLS까지
네트워킹 스택은 CottonOS에서 가장 최신이며 실험적인 부분입니다. 현재 구현된 내용은 다음과 같습니다:
드라이버 계층 (Driver layer): PCI 탐색, 초기화, 그리고 RX/TX 프레임 처리를 수행하는 RTL8139 NIC 드라이버입니다. QEMU에서 -nic user,model=rtl8139 옵션과 함께 작동합니다.
L2/L3: 이더넷 프레이밍(Ethernet framing), ARP (캐시 + 요청/응답), 그리고 IPv4 파싱 및 디스패치(dispatch)를 지원합니다.
전송 계층 (Transport): ICMP 에코(ping), UDP 송수신, 그리고 기본적인 TCP 클라이언트 연결을 지원합니다.
애플리케이션 계층 (Application layer): 자동 설정을 위한 DHCP, A 레코드를 위한 DNS 리졸버(resolver), 그리고 두 가지 셸 명령인 일반 HTTP용 httpget과 HTTPS용 httpsget이 구현되어 있습니다.
httpsget 명령은 TLS 협상(negotiation)을 완전히 커널 내부(in-kernel)에서 수행합니다. 이는 매우 실험적인 단계입니다. 현재 구현은 암호화된 TLS 전송(transport)을 사용하지만, 아직 서버 인증서(server certificates)를 검증하지는 않습니다. 신뢰 모델(trust model) 강화가 계획되어 있으나, 하부 OS가 없는 베어메탈(bare-metal) Rust 커널에서 핸드셰이크(handshake)와 레코드 레이어(record layer)를 작동시킨 것만으로도 이미 상당한 이정표를 달성한 것입니다.
안정성 작업에는 라이브락(livelock)을 방지하기 위한 유계 폴 루프(bounded poll loops), 비차단(non-blocking) IRQ 잠금 경로, 그리고 연결 전 수동으로 ARP를 수행할 필요가 없도록 일반적인 TCP/UDP 흐름에서 재시도를 포함한 ARP 자동 해상(auto-resolution) 기능이 포함되었습니다.
데스크톱 환경 (The Desktop Environment)
사람들이 CottonOS를 보고 가장 놀라는 부분은 바로 이것입니다. 실제 그래픽 데스크톱을 갖추고 있다는 점입니다.
프레임버퍼(framebuffer)는 GRUB의 비디오 모드에서 가져옵니다. 플리커(flicker, 깜빡임)를 제거하기 위해 더블 버퍼(double-buffer)가 렌더링을 처리합니다. 폰트는 한 글자씩 그려지는 8×16 비트맵 폰트(bitmap font)를 사용합니다. 마우스 입력은 PS/2 드라이버를 통해 들어옵니다.
윈도우 매니저 (Window Manager): 창(Windows)은 제목 표시줄, Z-순서(z-order), 포커스(focus), 그리고 제목 표시줄을 통한 드래그 기능을 갖추고 있습니다. 컨트롤은 macOS 스타일(빨간색/노란색/초록색 원형)입니다. 키보드 및 마우스 이벤트는 포커스된 창으로 라우팅됩니다.
커널에 포함된 애플리케이션:
- 터미널 (Terminal) — 스크롤 가능한 출력 기록, 백스페이스 지원, 작업 디렉토리 추적 기능을 갖춘 완전한 셸 에뮬레이터(shell emulator)입니다. 아래에 나열된 모든 셸 명령을 실행합니다.
- 파일 매니저 (File Manager) — 폴더 아이콘, 파일 크기, 더블 클릭 탐색, 히스토리가 포함된 뒤로 가기 버튼, 스크롤 가능한 목록을 제공하는 그래픽 기반의 CottonFS 브라우저입니다.
- 텍스트 에디터 (Text Editor) — 커서 위치 지정, 화살표 키 탐색, 실행 취소/다시 실행(undo/redo), 파일 열기/저장/다른 이름으로 저장 대화 상자, 수정 표시기 및 줄 번호를 지원하는 다중 행 에디터입니다.
- 시스템 정보 패널 (System Info panel) — 커널 버전, 메모리 통계, 파일 시스템 사용량, 프로세스 수 및 가동 시간(uptime)을 실시간으로 표시합니다.
셸 명령 (Shell Commands)
통합 셸(터미널 앱과 GUI 로드 전의 커널 셸 모두에서 사용 가능)은 다음을 지원합니다:
셸 명령 (Shell Commands)
통합 셸(터미널 앱과 GUI 로드 전의 커널 셸 모두에서 사용 가능)은 다음을 지원합니다:
| 카테고리 | 명령어 |
|---|---|
| Filesystem | ls, cd, pwd, cat, touch, mkdir, rm, write |
| ... |
한눈에 보는 아키텍처 (The Architecture at a Glance)
+-----------------------------------------------------------------+
| 사용자 공간 (User Space) (계획 중) |
+-----------------------------------------------------------------+
...
빌드 및 실행하기 (Building and Running It)
rustup (nightly), nasm, qemu-system-x86_64, grub-mkrescue, xorriso, 그리고 x86_64-elf-ld가 필요합니다.
Ubuntu/Debian:
sudo apt install qemu-system-x86 nasm grub-pc-bin xorriso mtools
rustup override set nightly
rustup component add rust-src llvm-tools-preview
다음으로:
git clone https://github.com/aryansrao/cottonos
cd cottonos
make iso # 부팅 가능한 ISO 빌드
...
네트워킹 빠른 시작 (CottonOS 내부):
net
dhcp
dns example.com
...
다음 계획 (What's Next)
CottonOS의 로드맵에는 여러 트랙이 포함되어 있습니다:
단기 목표 (Near term):
- Higher-half 커널 마이그레이션 (페이지 테이블은 준비되었으나, 연결 작업 필요)
- TLS 스택에 대한 인증서 검증 기능
- 터미널에서 ANSI 색상 지원 및 명령어 기록(command history)
- 적절한 사용자 공간 ELF 로딩 및 격리(isolation)
중기 목표 (Medium term):
- SMP (멀티코어) 지원 — APIC 코드는 스텁(stubbed) 처리됨
- 확장 파일 시스템 기능 (이중/삼중 간접 블록을 통한 더 큰 파일 크기)
- 더 많은 장치 드라이버 (USB, virtio)
장기 목표 (Long term) (진짜 목표):
- CottonOS 내부에서 온디바이스 LLM(Large Language Model) 실행 — 경량 추론(lightweight inference), 외부 의존성 없음, 완벽하게 자체 포함됨
마지막 것은 야심적입니다. 하지만 취미 OS의 요점은 그야말로 이러한 야심 자체가 핵심입니다.
기여자 모집 (I'm Looking for Contributors)
CottonOS는 GPL-3.0 하에 오픈 소스입니다. 제가 여가 시간에 작업하는 한 명의 개발자이며, 다룰 수 있는 영역이 매우 넓습니다. 만약 로우 레벨 Rust, OS 내부 구조(OS internals), 그래픽, 네트워킹, 파일 시스템 설계 등 이 중 어떤 것이든 흥미롭다면, 어느 수준에서든 기여를 환영합니다.
시작하는 곳:
- 📁 GitHub: github.com/aryansrao/cottonos
- 입문하기 좋은 분야 (Good first areas): 터미널의 ANSI 색상 지원 (ANSI color support), 명령어 히스토리 (command history), TLS를 위한 인증서 검증 (certificate validation for TLS), 문서 개선 (documentation improvements)
- 더 큰 도전 과제 (Bigger challenges): 하이퍼 하프 커널 (Higher-half kernel), SMP (Symmetric Multiprocessing), virtio 드라이버 (virtio drivers), 유저스페이스 ELF 로딩 (userspace ELF loading)
단순히 이슈(issue)를 생성하거나, 아키텍처에 대한 피드백을 남기거나, 질문을 던지는 것만으로도 제가 설계를 더 깊이 고민하는 데 큰 도움이 됩니다. 처음부터 직접 운영체제를 만드는 과정은 외롭게 느껴질 수 있습니다. 그렇기에 커뮤니티를 구축하는 것이 제가 가장 기대하고 있는 부분입니다.
비슷한 것을 만들어 보셨거나, 아키텍처 결정 사항에 대해 의견이 있으시다면 댓글로 진심 어린 이야기를 들려주세요. 이 프로젝트는 본질적으로 학습을 위한 프로젝트이며, 모든 관점이 큰 도움이 됩니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기