처음부터 직접 운영체제 커널 만들기
(popovicu.com)- RISC-V 아키텍처에서 타임셰어링 운영체제 프로토타입 커널을 구현한 경험을 공유
- 시분할(time-sharing) 커널의 개념과 동작 방식을 실습 중심으로 설명하며, C 대신 Zig로 구현해 재현성을 높임
- 커널과 사용자 코드를 하나의 바이너리로 묶는 unikernel 접근을 취하고, 콘솔 출력과 타이머 제어를 위해 OpenSBI를 활용하는 레이어링을 채택
- 스레드는 사용자 모드(U-mode) 에서 실행되고, 커널은 감독자 모드(S-mode) 에서 타이머 인터럽트를 통해 컨텍스트 스위치를 수행하며, 시스템 호출로 경계를 넘나듦
- 핵심은 인터럽트 프로로그/에필로그가 쌓아둔 스택 프레임을 교체해 다른 스레드의 레지스터 집합과 CSR을 복원함으로써 흐름을 전환하는 기법
- QEMU 가상 머신과 최신 OpenSBI를 기반으로 누구나 재현 가능한 학습 환경을 제공하며, 스레드·프로세스·컨테이너 등 가상화 스펙트럼을 개념적으로 연결해 교육 및 실습 목적에 적합한 기초 자료로 가치가 있음
개요
- RISC-V 아키텍처에서 타임셰어링 운영체제 커널을 직접 구현한 과정을 소개함
- 주요 독자는 시스템 소프트웨어 및 컴퓨터 구조 입문자, 학생, 그리고 저수준 동작 원리 이해에 관심 있는 엔지니어
- 이 실험은 기존 C 언어 대신 Zig 언어를 사용하여 실습 재현성을 높였으며 설치가 간단함
- 최종 코드는 popovicu/zig-time-sharing-kernel 저장소에 공개되어 있으며, 본문과 약간의 싱크 차이가 있을 수 있음
- 글의 코드 발췌보다 저장소 버전을 단일 신뢰원으로 간주할 것을 권장함
- 실습 시 저장소의 링커 스크립트·빌드 옵션을 기준으로 환경을 맞추는 편의를 제공함
Recommended reading
- 글은 레지스터, 메모리 주소 지정, 인터럽트 등 컴퓨터 구조 기초를 전제함
- 선행 자료로 Bare metal on RISC-V, SBI 부팅 과정, 타이머 인터럽트 예제를 추천
- 마이크로 리눅스 배포 글은 커널·유저 공간 분리 철학 이해에 선택적으로 유용
Unikernel
- 애플리케이션과 OS 커널을 단일 실행 파일로 링크하는 unikernel 구성을 채택함
- 런타임의 로더·링커 복잡도를 회피하고, 사용자 코드를 커널과 함께 메모리에 적재하는 단순화 달성
- 교육 및 재현 목적에서 배포 단순성과 환경 일관성을 확보하는 장점 제공
SBI layer
- RISC-V는 M/S/U 모드의 권한 모델을 사용하며, 본 실험은 OpenSBI를 M-모드에 두고 커널을 S-모드에서 동작시킴
- 콘솔 출력과 타이머 장치 제어를 SBI로 위임해 이식성을 확보
- SBI 미가용 시 UART MMIO를 폴백으로 사용하되, 실습에선 최신 OpenSBI 사용을 권장
Goal for the kernel
- 단순화를 위해 정적 스레드만 지원하고, 스레드는 종료하지 않는 함수로 구성
- 스레드는 U-모드에서 실행되며 S-모드 커널로 시스템 호출을 보냄
- 타이머 틱마다 다른 스레드로 전환될 수 있도록 단일 코어 기준의 시분할 스케줄링을 구현
Virtualization and what exactly is a thread
- 시분할 스레딩은 프로그래밍 모델을 변화시키지 않고 단일 코어에서 여러 작업을 병행하는 가상화 방식
- 협력형 스케줄링과 달리 명시적 yield 없이 타이머 인터럽트로 전환이 발생
- 스레드는 각자 건드릴 수 없는 레지스터 집합과 스택을 가지며, 나머지 메모리는 공유 가능
The stack and memory virtualization
- 스레드는 별도 스택을 가져야 하며, 호출 규약상 지역 변수·ra 보존 등 실행 컨텍스트 유지에 필수 요소
- 가상화 스펙트럼은 스레드 < 프로세스 < 컨테이너 < VM로 이어지며 격리 수준과 시야(view) 가 달라짐
- 리눅스에서 컨테이너는 chroot, cgroups 등 커널 메커니즘 조합으로 구현됨
Virtualizing a thread
- 본 실험의 최소 가상화 목표는 프로그래밍 모델 불변, 레지스터·일부 CSR 보호, 개별 스택 할당
- 레지스터 뷰가 보호되지 않으면 의미 있는 계산이 불가능해지는 이유를 강조
- 초기 a0 등을 스택에 시딩해 스레드 시작 시 인자 전달을 간결히 처리
Interrupt context
- 인터럽트는 프로로그/에필로그로 레지스터를 스택에 보존/복원하는 함수 호출 유사 모델로 이해할 수 있음
- 비동기 타이머 인터럽트가 레지스터를 망가뜨리지 않도록 보존 규약 준수가 필수
- 예제 어셈블리는 x0–x31 보존에 더해 sstatus, sepc, scause, stval 등 CSR까지 저장/복원
Implementation (high-level)
Leveraging the interrupt stack convention
- 인터럽트 루틴의 본체는 프로로그와 에필로그 사이에 위치하며, sp를 다른 메모리 영역으로 교체하면 다른 컨텍스트의 레지스터 집합을 복원하게 됨
- 이는 곧 컨텍스트 스위치에 해당하며, 본 실험의 시분할 구현 핵심 아이디어
- 타이머 인터럽트가 주기적으로 개입해 메인 흐름과 인터럽트 흐름을 교차 실행함
Kernel/user space separation
-
S-모드 커널 / U-모드 사용자의 경계를 유지하며, 인터럽트와 시스템 호출 처리는 S-모드 트랩 핸들러에서 수행
- 부팅은 M-모드의 OpenSBI→ S-모드 커널 초기화→ U-모드 스레드 시작 순서로 진행
- 주기적 타이머 인터럽트가 스케줄링·문맥 전환을 가능케 함
Implementation (code)
Assembly startup
-
startup.S
에서 BSS 초기화와 초기 스택 포인터 설정 후 Zig의 main으로 점프하는 최소 시퀀스 구성- 커널 진입점은 C ABI와의 연계를 위해
export
규약을 사용
- 커널 진입점은 C ABI와의 연계를 위해
Main kernel file and I/O drivers
-
kernel.zig
의main
은 우선 OpenSBI 콘솔 기능을 점검하고, 실패 시 UART MMIO로 폴백함-
sbi.debug_print
는 ECALL 프로토콜에 맞춰 a0/a1/a6/a7 레지스터를 설정해 호출 - 타이머 설정 후 S-모드 인터럽트 핸들러를 등록하고 틱을 활성화
-
S-mode handler and the context switch
- 핸들러는 Zig의
naked
규약으로 작성해 CSR 보존을 포함한 완전한 프로로그/에필로그를 수동 구성- 본체에서
handle_kernel(sp)
를 호출하고, 반환된 sp로 교체해 스위치 여부를 결정 -
scause
로 U-모드 ECALL인지 타이머 인터럽트인지 판별해 분기 처리
- 본체에서
The user space threads
- 사용자 코드는 커널과 함께 단일 바이너리에 포함되며, 예시 스레드는 문자열 출력 → 지연 루프를 반복
-
syscall.debug_print
는 a7에 64번 시스템 호출 번호, a0/a1에 버퍼/길이를 넣고 ECALL을 수행 - 스레드 초기화 시 스택에 복귀 주소·초기 레지스터 값을 시딩해 첫 복귀 때 바로 인자 사용이 가능
-
Running the kernel
- 빌드는
zig build
, 실행은 QEMU에서 virt 머신 + nographic + OpenSBI fw_dynamic을 지정해 수행- 부팅 시 OpenSBI 배너 이후 스레드 ID별 주기적 출력이 교차 등장
-
-Ddebug-logs=true
로 빌드하면 인터럽트 원천, 현재 스택, 큐잉·디큐잉 로그가 상세히 표시
Conclusion
- 본 실험은 RISC-V + OpenSBI + Zig 조합으로 교육용 커널을 현대화해 재현성과 가독성을 높임
- 최소한의 오류 처리와 과할당 스택 등 단순화가 있으나, 컨텍스트 스위치의 본질과 권한 분리 학습에 초점이 맞춰짐
- 리얼 머신 이식성은 링커·드라이버 상수 조정과 SBI 가용성 확보를 전제로 가능
추가 메모: 가상화 스펙트럼 정리
- Threads: 레지스터·스택 가상화 위주, 메모리 공유 가능성 높음
- Process: 주소 공간 가상화로 메모리 격리, 내부에 다수 스레드 포함 가능성
- Container: 파일시스템·네트워크 네임스페이스 등 환경 시야를 조합해 구성되는 격리 단위임
- VM: 하드웨어 전반의 완전 가상화를 지향함
핵심 구현 포인트 요약
- 인터럽트 스택 교체로 컨텍스트 스위치 실현
- S-모드 트랩 핸들러에서 CSR 포함 전체 상태 보존/복원
- SBI 우선, UART MMIO 폴백의 출력 경로 이중화
- 정적 스레드·단일 코어·타임 슬라이스 중심의 단순 스케줄링
- ECALL 기반 시스템 호출로 U/S 경계 명확화
Hacker News 의견
-
비슷한 작업을 "Operating System in 1000 Lines of Code"에서 '패키지' 형태로 경험할 수 있음, 나는 예전에 Zig로 따라했는데(C 코드 스니펫을 Zig로 변환하면서 진행함) 매우 재미있었음, 내 코드와 VOD는 여기에 있음 https://github.com/kristoff-it/kristos/
- Zig에 대해 어느 정도 알고 있어야 이 연습을 할 수 있을지 궁금함, 혹시 Zig을 한 번도 다뤄보지 않은 상태에서 현실적으로 어떻게 시도해볼 수 있을지, C++ 배경 지식이 있다는 가정에서 조언을 듣고 싶음
-
글 작성자가 별도로 제출한 내용임 https://news.ycombinator.com/item?id=45236479, 글쓴이 본인이 직접 Tiny OS Kernel을 다시 제작했으며, 특정하게 RISC-V와 OpenSBI 환경에서 실험을 해보고 싶었고, 전통적인 C 대신 Zig를 사용했음, 사실 C 또는 Rust로도 쉽게 따라할 수 있을 거라고 생각함, 전체 과정이 다소 투박하지만 OS Kernel 개발과 컴퓨터 아키텍처를 배우는 첫걸음을 위한 실험과 입문용임, 주말에 재미있게 실험해볼 만한 프로젝트라고 생각함, 전체 워크스루와 Github 링크는 위에서 확인 가능함
-
이런 프로젝트는 정말 인상적임, 리눅스 역시 결국 커널 하나에 불과하지만, 그 작업이 오픈소스 유닉스를 수십억 대 기기에 설치할 수 있도록 길을 열어줬음, 정말 멋진 일이라고 생각함
-
더 재밌는 점은 맨 처음 리눅스 배포 당시 Torvalds가 "그냥 취미로 하는 거고, GNU처럼 크고 프로페셔널하진 않을 것"이라고 메일에 적었단 사실임 https://groups.google.com/g/comp.os.minix/c/dlNtH7RRrGA/m/SwRavCzVE7gJ
-
나는 이런 프로젝트가 <i>엄청나게</i> 인상적이라고는 생각하지 않음, 미니멀한 멀티태스킹 커널을 만드는 법은 이미 수십년 전에 다 알려진 경로임, 부팅하고 간단한 작업만 하는 커널을 만드는 건 어느 정도의 똑똑함과 꾸준함만 있으면 되는 일임, RISC-V에서 하면 x86 보다 약간 복잡하긴 하지만, 하드웨어 초기화 정보는 쉽게 구할 수 있음 (https://wiki.osdev.org/RISC-V_Meaty_Skeleton_with_QEMU_virt_board 참고), 이 프로젝트도 그런 점에서 저자가 "운영체제 수업에서 했던 연습을 다시 한 것"이라고 직접 밝혔음, 소프트웨어 공학 학위를 가진 사람이면 다 해낼 수 있을 만한 수준이라고 생각함, 물론 버그나 미완성 부분은 있겠지만, 멀티프로세스 혹은 MMU로 프로세스 격리하는 것 자체는 이제 어렵지 않은 일임
-
리눅스만큼, 1984년에 Stallman이 C 컴파일러와 유닉스 유틸리티를 만들기 시작한 것도 수십억 대 머신에 오픈소스 유닉스를 설치하는 길을 연 셈임
-
-
Zig는 운영체제 개발에 정말 좋음, RISC-V도 마찬가지임, 나도 똑같은 과제를 x86으로 시작했다가 레거시 보일러플레이트가 너무 많아서 금방 지침, RISC-V 쪽은 그런 게 거의 없음, 개발을 시작하기 훨씬 수월해짐 https://github.com/Fingel/aeros-v
-
x86에서 시작하면 부트로더만 잘 쓰면 보일러플레이트가 많지 않다고 생각함, 멀티부트 로더는 보통 리얼 모드에 남겨주고, 대부분의 사람들은 프로텍티드 모드를 원하기 때문에 일부 테이블 셋업하고 점프만 하면 됨, 레거시 인터럽트 컨트롤러를 끄고 싶으면 추가로 손댈 게 있지만 데스크톱 PC에서 부팅해볼 수 있다는 이점이 있음 (콘솔 인터페이스 관련 주의 필요), 내 하비용 OS는 BIOS 부트와 몇 가지 VGA 기능을 쓰다가 호환성이 나빠서 고생했는데, 시리얼 콘솔이 훨씬 쉽지만 요새 컴퓨터는 시리얼 포트가 없는 경우가 많음
-
사실상 Object Pascal이나 Modula-2의 안전성을 다시 꺼내와 C 문법으로 재포장한 셈임, C는 UNIX의 라이선스 덕분에 널리 퍼진 것 외에 특별한 점이 있었던 건 아님
-
나도 직접 해보고 싶은데, RISC-V 커널을 어떤 환경에서 실행하고 있는지 궁금함, Qemu만 사용하는지, 아니면 실제 하드웨어 중에 추천하는 게 있는지 알려주면 좋겠음
-
-
RISC-V ISA가 정말 접근성이 뛰어나다고 생각함, 문서도 훌륭하고, 예제도 정말 많고, 에뮬레이터도 상당히 많음, 언코프레스트된 머신코드도 읽기 쉬움, 나는 내 딸을 위해 직접 책을 쓰며 Forth와 타임셰어링이 있는 작은 OS를 만들고 있음 https://punkx.org/projekt0/book/part1/os.html, x86이었다면 아예 시도하지 못했을 거라고 생각함, 과정을 통해 Forth와 RISC-V 어셈블리를 동시에 배우고 있는데 정말 즐거움, 장난감 OS를 처음부터 만들고 싶다면 지금이 딱 좋은 시기라고 말하고 싶음 (1980년대만큼 흥미로움) 저렴한 RISC-V 보드(rp2350 등)를 구하고, 관련 매뉴얼 섹션을 Claude 같은 AI에 업로드하면 막힐 때 큰 도움 받음
- 내 나라에서 보드 가격을 방금 검색해봤는데 생각보다 훨씬 저렴해서 놀랐음, 단순히 재미로 하나 사서 만져볼까 90% 고민 중임
-
이런 시도는 언제나 재미있고 흥미로움, 자기만의 암호화나 어려운 것도 시도해보라고 격려하고 싶음, “자체 암호화 구현하지 말라”는 조언은 실전에 검증되지 않은 걸 쓰지 말라는 뜻임, 실험/연구용으로는 위험하지 않으니 마음껏 시도해도 됨, 우리는 더 많은 운영체제와 선택지가 필요함
-
(스페인 판결문 인용) 일단 http 차단은 그럴 수 있는데 이건 너무함...
-
스페인에서 Cloudflare(그리고 아마 다른 곳도)가 축구 중계 관련 문제로 실수로 차단된다는 얘길 들음, 이런 문제를 어떻게 우회하고 있는지 궁금함, VPN 쓰는 걸까? 중요한 IP가 막히면 업무도 영향 받을 텐데
-
(판결문에서) 스페인 프로축구협회와 Telefónica Audiovisual Digital이 시작했다는 부분을 보고 이런 사람들은 범죄자라고 생각함
-
...뭐지? 스페인 축구 단체가 국가 전체의 인터넷 접근을 제한할 권한이 있다는 거임?
-
-
저렴한 RISC 하드웨어는 어떻게 구할 수 있는지 궁금함
-
알리익스프레스에서 Milk-V Duo S라는 보드를 10달러에 판매함, 최근 추천 목록에 자주 등장함, 주요 사양은 업그레이드된 SG2000 마스터와 512MB RAM, 더 넓은 IO, 일부 모델에 WI-FI6/BT5(512M-Basic/eMMC 모델 제외), USB 2.0 호스트 포트, PoE 지원 100Mbps 이더넷, 듀얼 MIPI CSI, RISC-V와 ARM 부트 전환 스위치 지원 등임 https://aliexpress.com/w/wholesale-Milk%2525252dV-Duo-S.html
-
이미 여러 보드가 있지만 내가 흥미롭게 생각해서 펀딩한 건 VisionFive 2 Lite임 https://kickstarter.com/projects/starfive/…, 1세대 VisionFive2는 없지만, 평이 좋고 생태계가 점점 커진다고 함, 아직 미완성 부분이 있지만 곧 배송되길 기대함, 내가 개인적으로 쓰는 건 PolarFire SoC Discovery Kit임, 쿼드코어 RISC-V에 FPGA 들어간 보드이고, 다소 비싸고(130달러) 모두에게 맞진 않지만, 재밌는 점은 보드가 칩 자체보다 싸다는 점임 https://www.microchip.com/en-us/development-tool/MPFS-DISCO-KIT, 마이크로칩 관련 문서나 툴체인은 구식이고 썩 좋진 않지만, 익숙해지면 bare-metal RISC-V 코드 돌리는 게 정말 쉬움, 리눅스/베어메탈 예제가 친절함
-
당장 실제 하드웨어 없이도 x86이나 애플 머신에서 에뮬레이터로 돌려보는 게 좋다고 제안함, 실제 보드보다 개발 속도가 빠르고, QEMU 같은 걸 쓰면 바로 해볼 수 있음 https://www.qemu.org/docs/master/system/target-riscv.html
-
라즈베리파이 피코2도 RISC-V 지원해서 괜찮음 https://www.raspberrypi.com/products/raspberry-pi-pico-2/
-
여러 사람의 답변에 감사함, 질문에 비추 준 사람들은 고마울 이유가 없다고 생각함
-