1P by GN⁺ 13시간전 | ★ favorite | 댓글 1개
  • 이 글은 Rust로 개발된 리눅스 커널용 최신 GPU 드라이버 Tyr의 개발 과정과 GPU 드라이버의 동작 원리에 초점을 맞춤
  • GPU 드라이버 개발에서 UMD(유저 모드 드라이버)KMD(커널 모드 드라이버) 의 역할 구분과 상호 작용을 VkCube 예제를 통해 설명함
  • UMD는 고수준 API를 GPU가 이해할 수 있는 저수준 명령으로 변환하며, KMD는 메모리 할당, 작업 스케줄링, 장치 초기화 등 핵심 역할을 담당함
  • Tyr 드라이버가 제공하는 API는 Panthor와 동일하며, 장치 쿼리, 메모리 관리, 그룹 관리, 작업 제출, Tiler 힙 관리 등으로 구성됨
  • 다음 글에서는 Arm CSF 하드웨어 아키텍처와 핵심 구성요소(예: MCU) 및 부팅 과정을 다룰 예정임

소개: Rust 기반의 최신 GPU 커널 드라이버 개발

  • 본 글은 리눅스 커널에서 Arm Mali CSF 기반 GPU를 지원하는 최첨단 Rust GPU 드라이버 Tyr 개발 시리즈의 두 번째 글임
  • 실제 예제로서 Vulkan API를 사용해 회전하는 큐브를 렌더링하는 단순 3D 프로그램인 VkCube를 선택해 GPU 드라이버 내부 동작 방식을 설명함
  • VkCube의 단순 구조는 GPU 드라이버 동작 원리를 학습하는 데 적합한 사례임

GPU 드라이버 기초: UMD와 KMD의 역할 및 구조

  • User Mode Driver(UMD)Kernel Mode Driver(KMD) 로 구성됨
    • UMD: panvk(Mesa의 Vulkan 드라이버 등)와 같이 일반 프로그램의 API(Vulkan, OpenGL 등)를 구현함
    • KMD: Tyr 등, 하드웨어에 대한 권한 있는 커널 레벨 드라이버로, 리눅스 커널 일부로 동작함
  • 커널 모드 GPU 드라이버는 컸던 UMD와 실제 GPU 사이를 연결하며, UMD는 API 명령어를 해석해 GPU가 이해할 수 있는 명령 집합으로 변환함
  • UMD는 장면 구성에 필요한 지오메트리, 텍스처, 셰이더 등 데이터를 준비하고, 이를 실행 전에 KMD에게 GPU 메모리에 할당해 달라고 요청함
  • 셰이더는 GPU에서 구동되는 독립적인 프로그램으로, VkCube에서는 큐브 배치, 컬러링, 회전 구현 등 역할을 담당함. 셰이더 실행에는 외부 데이터(지오메트리, 컬러, 회전 행렬 등)가 필요함
  • UMD는 준비된 명령(예: VkCommandBuffers)을 KMD에 전달해 실행하며, 해당 작업이 완료되면 알림을 받아 결과를 메모리에 저장할 수 있음

KMD(커널 모드 드라이버)의 주요 책임

  • GPU 메모리 할당 및 매핑(애플리케이션별로 격리 제공)
  • 하드웨어 큐에 작업 제출 및 완료 시점 사용자에게 알림 제공
  • 비동기·병렬 하드웨어 환경에서는 작업 의존성 관리가 필수적이며, 올바른 결과 확보를 위해 KMD가 스케줄링 및 의존성 검증 역할을 수행함
  • 장치 초기화, 클럭/전압 레귤레이터 구동, 스타트업 코드 실행, 다수 클라이언트가 공평하게 하드웨어를 공유하도록 접근 로테이션 관리 등도 포함됨

복잡성의 위치: UMD와 KMD의 분업

  • GPU 드라이버의 복잡성은 대부분 UMD에서 집중
    • UMD: 고수준 API 명령어를 하드웨어 명령어로 변환
    • KMD: UMD가 제대로 동작할 수 있도록 메모리 격리, 공유, 공평한 접근성 등 핵심 기능 제공

Tyr가 제공하는 드라이버 인터페이스(API) 구조

  • Tyr 드라이버 API(=Panthor와 동일)는 크게 5개 그룹으로 분류할 수 있음
    1. 장치 정보 쿼리: DEV_QUERY(IOCTL로 GPU 하드웨어 정보 확인, ROM 영역 활용)
    2. 메모리 할당 및 격리: VM_CREATE, VM_BIND, VM_DESTROY, VM_GET_STATE, BO_CREATE, BO_MMAP_OFFSET 등
    3. 스케줄링 그룹 관리: GROUP_CREATE, GROUP_DESTROY, GROUP_GET_STATE(상세 설명은 후속 글 예정)
    4. 작업 제출: GROUP_SUBMIT(디바이스 명령 버퍼를 통해 GPU에 실행 요청)
    5. Tiler 힙 관리: TILER_HEAP_CREATE, TILER_HEAP_DESTROY(타일드 렌더링 GPU의 메모리 요구 사항 충족)
  • 해당 API들은 실제로 직접 그림을 그리는 작업과는 거리가 있지만, UMD가 실제 명령어 실행을 담당하고 KMD는 하드웨어 접근을 위해 위 인터페이스만 제공함

결론 및 이후 계획

  • 이번 글에서는 GPU 드라이버의 전반적인 구조와 내부 흐름, 그리고 Tyr가 제공하는 핵심 API에 대해 살펴봄
  • 이 내용을 토대로 시리즈의 후속 글에서 Arm CSF 하드웨어 아키텍처, 마이크로 컨트롤러 유닛(MCU) 등 핵심 구성요소 및 드라이버 초기화 과정을 다룰 예정임
Hacker News 의견
  • 정말 좋은 글이었음, 그런데 내용이 너무 짧았음, 이제 막 흥미로워지기 시작했는데 끝난 느낌임, 다음 편이 기대됨
    • 다음 주에도 흥미진진한 에피소드가 이어질 예정임, GPU에서 대기 중이던 명령이 큐에서 빠져나와 실행되는 모습을 보게 될 것임, 이번 글에서 다루는 추상화 수준은 사용자/커널 경계에서 데이터를 넘기는 부분임, 주로 큐와 버퍼 관리만 다루다 보니 연산 자체는 많지 않음, 진짜 중요한 내용은 큐에 넣어진 명령들이 실행될 때 일어나게 됨, GPU에서 또 다른 명령 완료 신호가 반대로 전달되는데, 그것도 궁금함, 이런 비동기 처리 대부분은 드라이버가 아니라 사용자 코드 쪽에서 처리됨, 드라이버는 완료 신호만 넘겨주는 구조임
  • 나는 rk3588 기기 중 하나를 데스크톱으로 사용하면서 panfrost를 쓰고 있는데, 가끔 Firefox에서 화면이 검게 나오거나 투명한 영역이 생기는 버그가 있음, 이상한 현상임
    • RK3588은 실제로 panfrost가 아니라 해당 글의 주제인 panthor 드라이버를 사용함
  • uring_cmd를 ioctls 대신 활용하는 방안이 고려됐는지 궁금함, 이 프로젝트가 완전히 새로 만드는 것이니까 적용 가능성도 있어 보였음, 그 이점이 거의 없다고 본 이유가 궁금함
    • GPU는 이미 자체 비동기 명령 큐를 가지고 있기 때문에, IOCTL은 원래 비교적 저렴하게 그 명령 큐에 쓰는 역할임, 그래서 CPU 단에도 비동기 큐를 하나 더 만들어서 그 쓰기를 스케줄하는 건 쓸모가 제한적인 선택임, 혹시 GPU 명령 큐 자체를 uring으로 만들어 userspace에 매핑하자는 제안이라면, io_uring API 사양을 제대로 지원하려면 펌웨어를 꽤 대대적으로 바꿔야 하고, 하드웨어 특성상 아예 불가능할 수도 있음
    • 기고문에서 설명하는 드라이버는 userspace Mesa 라이브러리가 요구하는 API를 그대로 따르고 있음
  • 정말 흥미롭게 읽었음, 혹시 후속 파트가 있거나 논리적으로 이어질 만한 내용이 있을까 궁금했음
    • 오늘 처음 공개된 글이라 이후에 업데이트가 더 나올 걸로 기대됨
  • "Rust GPU driver"라는 제목이 클릭을 더 유도하는 건 알겠지만, 사실상 이건 Arm Mali CSF 기반 GPU 드라이버 아님? 툴 개발을 위한 메타툴에 시선이 가는 게 개인적으로 별로임, 실제 목적이 Rust로 뭔가를 만드는 걸로 들림, 기사에서는 "arm mali 기반의 gpu 드라이버 커널"이라 명시했으면서도 굳이 arm mali 드라이버라고 부르지 않음, 드라이버를 만든다는 건 운영체제 API와 하드웨어 제조사 API를 연결하는 일에 불과함, 그 위에 추가로 추상화 계층을 구축하는 프레임워크를 만드는 건 아니라고 생각함, 조금 직설적으로 표현한 점 양해 바람
    • 이번 사례가 리눅스에서 처음 시도되는 Rust 기반 GPU 드라이버 중 하나라는 점에서 러스트가 중요한 키워드임
    • 나는 거칠게 말한 걸 미안해하지 않음, 당신 말투를 보니 현대 GPU 드라이버가 어떤 건지 전혀 모르는 것 같음, 15년 전까지만 해도 써 본 적 있지만 그동안 더 복잡해졌다는 것만큼은 알고 있음, 리눅스 커널 소스코드만 봐도 GPU 드라이버가 코드 라인 수로 가장 많은 비중을 차지하는 영역임, 거의 모든 드라이버가 여러 그래픽카드를 지원하기까지 함, 매번 완전히 독립적인 드라이버를 각각의 GPU 카드마다 별도로 만드는 게 비합리적인 거라는 사실 아는지 의문임, GPU 드라이버 작업은 두 API를 단순히 '선만 연결'하는 일이 아님, 실제론 생각보다 많이 다름, 혹시 반박할 수 있다면 본인이 작성한 GPU 드라이버를 보여주면 됨, 진짜로 선을 몇 개만 연결해서 끝났는지 확인해보고 싶음
    • Rust가 중요한 이유는 이것이 최초(또는 최초 중 하나)로 러스트 인프라를 GPU 드라이버에 사용한 사례이기 때문임