13P by GN⁺ 7시간전 | ★ favorite | 댓글 1개
  • 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, stvalCSR까지 저장/복원

Implementation (high-level)

Leveraging the interrupt stack convention

  • 인터럽트 루틴의 본체는 프로로그와 에필로그 사이에 위치하며, sp를 다른 메모리 영역으로 교체하면 다른 컨텍스트의 레지스터 집합을 복원하게 됨
    • 이는 곧 컨텍스트 스위치에 해당하며, 본 실험의 시분할 구현 핵심 아이디어
    • 타이머 인터럽트가 주기적으로 개입해 메인 흐름과 인터럽트 흐름을 교차 실행함

Kernel/user space separation

  • S-모드 커널 / U-모드 사용자의 경계를 유지하며, 인터럽트와 시스템 호출 처리는 S-모드 트랩 핸들러에서 수행
    • 부팅은 M-모드의 OpenSBIS-모드 커널 초기화U-모드 스레드 시작 순서로 진행
    • 주기적 타이머 인터럽트가 스케줄링·문맥 전환을 가능케 함

Implementation (code)

Assembly startup

  • startup.S에서 BSS 초기화와 초기 스택 포인터 설정Zig의 main으로 점프하는 최소 시퀀스 구성
    • 커널 진입점은 C ABI와의 연계를 위해 export 규약을 사용

Main kernel file and I/O drivers

  • kernel.zigmain은 우선 OpenSBI 콘솔 기능을 점검하고, 실패 시 UART MMIO로 폴백함
    • sbi.debug_printECALL 프로토콜에 맞춰 a0/a1/a6/a7 레지스터를 설정해 호출
    • 타이머 설정 후 S-모드 인터럽트 핸들러를 등록하고 틱을 활성화

S-mode handler and the context switch

  • 핸들러는 Zig의 naked 규약으로 작성해 CSR 보존을 포함한 완전한 프로로그/에필로그를 수동 구성
    • 본체에서 handle_kernel(sp)를 호출하고, 반환된 sp로 교체해 스위치 여부를 결정
    • scauseU-모드 ECALL인지 타이머 인터럽트인지 판별해 분기 처리

The user space threads

  • 사용자 코드는 커널과 함께 단일 바이너리에 포함되며, 예시 스레드는 문자열 출력 → 지연 루프를 반복
    • syscall.debug_printa7에 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/

    • 여러 사람의 답변에 감사함, 질문에 비추 준 사람들은 고마울 이유가 없다고 생각함