안녕하세요? 허니데이즈입니다. 오늘은 지르콘 커널이 과연 무엇이고, 어떤 구성요소로 되어 있는지 알아보겠습니다.


 

 지르콘 커널 개념
커널은 다양한 유형의 객체를 관리한다. 시스템 호출을 통해 직접 접근할 수있는 클래스는 Dispatcher 인터페이스를 구현하는 C++ 클래스라고 보면 된다. 이는 커널/객체에서 구현되며 많은 것이 자체 포함된 상위 수준의 객체이다. 하지만 일부는 하위 레벨의 LK 프리미티브를 래핑한다.

 

 System Calls
사용자 공간에 있는 코드는 시스템 호출을 통해 커널 객체와 Handle을 통해 상호작용한다. 사용자 공간에서 Handle은 32비트 정수(zx_handle_t 타입)로 표시된다. syscalls이 실행되면 커널은 Handle 매개변수가 호출 프로세스의 Handle 테이블에있는 실제 Handle을 참조하는지 확인한다. 커널은 Handle이 올바른 유형인지(Handle을 요구하는 syscall에 스레드 Handle을 전달하여 오류가 발생함) Handle 요청된 작업에 필요한 권한을 가지고 있는지 확인한다.

시스템 호출은 접근 관점에서 크게 세 가지 범주로 나뉘게 된다.

제한이 없는 호출은 매우 적다. 예를 들면 zx_clock_get()과 zx_nanosleep() 은 모든 스레드에서 호출 할 수 있다.
Handle을 첫 번째 매개변수로 사용하여 처리할 객체를 나타내며 zx_channel_write()와 zx_port_queue() 호출 등이 있다.

새로운 객체를 생성하지만 zx_event_create()와 zx_channel_create()이 같이 Handle을 사용하지 않는 호출이 있다. 이에 대한 접근과 그들에 대한 제한은 호출 프로세스가 포함된 작업에 의해 제어된다.
시스템 호출은 Zircon 커널이 사용자 공간에 제공하는 "가상" 공유 라이브러리인 libzircon.so에 의해 제공되며 가상 동적 공유 객체나 vDSO로 더 잘 알려져 있다. zx_noun_verb()나 zx_noun_verb_direct-object() 형태의 C ELF ABI 함수로 표현된다.

시스템 호출은 syscalls.abigen에 의해 정의되고 abigen 도구에 의해 libzircon의 include 파일, glue 코드와 커널의 libsyscalls로 처리된다.

 

 Handles and Rights
객체는 하나 이상의 프로세스에서 여러 개의 Handle을 참조 할 수 있다.

거의 모든 객체의 경우, 객체를 참조하는 마지막 열려있는 Handle이 닫히면 객체는 파괴되거나 취소 할 수없는 최종 상태가 된다.

Handle은 채널에 write(zx_channel_write() 사용)하거나 zx_process_start()를 사용하여 Handle을 새 프로세스의 첫 번째 스레드의 인수로 전달하여 한 프로세스에서 다른 프로세스로 이동할 수 있다.

Handles이나 Handles과 관련된 대상에서 취할 수 있는 행동은 해당 Handles과 관련된 권한에 의해 정해진다. 동일한 Object를 참조하는 두 개의 Handle은 다른 권한을 가질 수 있다.

zx_handle_duplicate()와 zx_handle_replace() 시스템 호출이 감소된 권한으로 임의로 Handle 전달과 같은 추가 오브젝트 참조 Handle을 얻기 위해 사용될  수 있다. zx_handle_close()와 zx_handle_close_many()는 Handle이 해당 객체의 마지막 경우 시스템 호출과 이를 참조하는 객체를 닫는 기능을 한다.

 

 Kernel Object IDs
커널의 모든 객체에는 "kernel object id" 나 "koid"가 있다. 객체를 식별하는데 사용할 수 있고 실행중인 시스템의 수명동안 고유 64비트 부호없는 정수로 표현된다. 이는 koid가 결코 재사용되지 않는다는 것을 의미한다.

두 가지 특별한 koid 값이 있다. ZX_KOID_INVALID 값이 0이고 "null" 센티널으로 사용되며 ZX_KOID_KERNEL 커널은 하나 뿐이며, 커널 자체가 있다.

 

 Running Code: Jobs, Processes, and Threads
스레드는 프로세스가 소유 한 주소 공간에서 실행 스레드(CPU 레지스터, 스택 등)를 알려준다. 프로세스는 다양한 자원 제한을 정의하는 Jobs 소유이다. 작업은 부모 작업에 의해 소유되며 부팅 할 때 커널에 의해 생성되고 사용자 부팅(userboot)으로 전달되는 루트 작업까지 진행되며 실행을 시작하는 첫 번째 사용자 공간 프로세스이다. 작업 Handle이 없으면 프로세스 내의 스레드가 다른 프로세스 나 다른 작업을 작성할 수 없다. 프로그램 로딩은 커널 계층 위의 사용자 공간 기능과 프로토콜에 의해 제공된다.

참조 : process_create, process_start, thread_create, thread_start

 

 Message Passing: Sockets and Channels

소켓과 채널 모두 양방향 및 양방향인 IPC 개체이다.

소켓은 스트림 지향(stream-oriented)이며 데이터는 하나 이상의 바이트 단위로 쓰거나 읽을 수 있다. 짧은 write(소켓의 버퍼가 가득 찬 경우)와 짧은 read(버퍼보다 많은 데이터가 요청 된 경우)가 가능하다.

채널은 데이터그램 지향(datagram-oriented)이며 최대 메시지 크기가 64K(변경될 가능성이 있으며 작을 수 있음)이며 메시지에 첨부된 최대 1024개의 Handle을 가질 수 있다(또한 변경 될 수 있으며 작을 수도 있음). 짧은 read나 write를 지원하지 않는다. 메시지가 적합하거나 그렇지 않다.

Handle이 채널에 기록되면 Handle은 송신 프로세스에서 제거된다. Handle이 있는 메시지를 채널에서 읽을 때, Handle은 수신 프로세스에 추가된다. 이 두 이벤트 사이에서 Handles은 작성된 채널의 끝이 닫히지 않는 한 계속해서 존재한다(참조된 객체가 계속 존재하는지 확인). 그 시점에서 해당 끝점으로 이동하는 메시지는 삭제된다. 포함된 Handle은 닫힌다.

참조 : channel_create , channel_read , channel_write , channel_call , socket_create , socket_read, socket_write

 

 Objects and Signals
객체는 현재 상태에 대한 정보를 나타내는 최대 32개의 신호(zx_signals_t 타입과 ZX_ SIGNAL로 정의)를 가질 수 있다. 예를 들어, 채널과 소켓은 READABLE 또는 WRITABLE일 수 있다. 프로세스 또는 쓰레드가 종료 될 수 있다. 스레드는 하나 이상의 객체에서 신호가 활성화 될 때까지 대기 할 수 있다.

 

 Waiting: Wait One, Wait Many, and Ports

쓰레드는 zx_object_wait_one() 을 사용하여 단일 Handle에서 신호가 활성화될 때까지 기다리거나 zx_object_wait_many()를 사용하여 여러 Handle에서 신호를 기다릴 수 있다. 두 통신 모두 신호가 보류중인 경우에도 반환 할 수있는 제한 시간을 허용한다.

스레드가 많은 수의 Handle을 기다릴 경우 다른 객체가 바인딩 될 수있는 객체인 포트를 사용하는 것이 더 효율적이다. 즉 신호가 신호를 받으면 포트는  보류중인 신호에 대한 정보를 포함하는 패킷을 수신한다.

참조 : port_create, port_queue, port_wait, port_cancel

 

 Events, Event Pairs

이벤트는 활성 신호 모음이 아닌 다른 상태가 없는 가장 간단한 개체이다.

이벤트 페어는 서로 신호를 보낼 수 있는 한 쌍의 이벤트 중 하나이다. 이벤트 페어의 유용한 속성은 한 페어의 한 쪽이 사라지면(다른 모든 쪽 Handle이 닫힌 경우) 반대쪽에 PEER_CLOSED 신호가 어서트된다.

참조 : event_create, eventpair_create .

 

 Shared Memory: Virtual Memory Objects (VMOs)

가상 메모리 개체는 메모리의 물리 페이지 집합이나 페이지의 potential을 나타낸다(which will be created/filled lazily, on-demand).

이는 zx_vmar_map()으로 프로세스의 주소 공간에 매핑되고 zx_vmar_unmap ()으로 매핑 해제될 수 있다. 매핑 페이지의 사용 권한은 zx_vmar_protect()를 사용하여 조정할 수 있다. VMO는 zx_vmo_read()와 zx_vmo_write()를 사용하여 직접 읽고 쓸 수 있다. 따라서 주소 공간에 매핑하는 비용은 "VMO 만들기, 데이터 세트 작성, 다른 프로세스로 사용"과 같은 단 한번의 작업으로 피할 수 있다.

 

 Address Space Management

가상 메모리 주소 영역(VMAR, Virtual Memory Address Regions)은 프로세스의 주소 공간을 관리하기 위한 추상화를 제공한다. 프로세스 생성시 루트 VMAR에 대한 Handle이 프로세스 생성자에게 제공된다. 이 Handle은 전체 주소 공간에 걸친 VMAR을 참조하게 된다. 이 공간은 zx_vmar_map()와 zx_vmar_allocate() 인터페이스를 통해 조각(carved up) 할 수 있다. zx_vmar_allocate()를 사용하여 주소 공간의 일부를 함께 그룹화하는데 사용할 수 있는 새로운 VMAR(하위 영역 또는 하위라고 함)을 생성 할 수 있다. 

참조 : vmar_map, vmar_allocate, vmar_protect, vmar_unmap, vmar_destroy ,

 

 Futexes

Futexes는 효과적인 동기화 기본 요소를 구현하기 위해 사용자 공간 원자 연산과 함께 사용되는 커널 기본 요소이다(예. Mutexes는 경합하는 경우에만 syscall을 작성해야 함). 일반적으로 이들은 표준 라이브러리의 구현 개발자에게만 관심이 있다. 지르콘의 libc와 libc++는 퓨텍스의 관점에서 구현된 뮤텍스, 조건 변수 등을 위한 C11, C++, pthread API를 제공한다.

 

출처: https://fuchsia.googlesource.com/zircon/+/master/docs/concepts.md

 

 

지르콘 커널에 대해 더 알고 싶으시다면 아래 목차에서 클릭! 

지르콘 커널이란?

Zircon

지르콘 커널 개발 환경 구축하기

Getting Started

지르콘 커널 개발에 기여하는 방법

Contributing Patches

지르콘 커널의 개념 알기

Concepts Overview

지르콘 커널 구성요소(Kernel Objects)는?

Kernel Objects

지르콘 커널에서 사용되는 프로세스(Process)란?

Process Objects

지르콘 커널에서 사용되는 쓰레드(Thread)란?

Thread Objects

지르콘 커널에서 사용되는 핸들(Handles)이란?

Handles

지르콘 커널의 시스템콜하는 방식은?

System Calls

지르콘 커널의 드라이버 개발 키트 사용하는 방법 - 장치 모델

Driver Development Kit

지르콘 커널의 드라이버 개발 키트 사용하는 방법 - 장치 프로토콜

지르콘 커널의 드라이버 개발 키트 사용하는 방법 - 지르콘 드라이버 개발

지르콘 커널의 드라이버 개발 키트 사용하는 방법 - 플랫폼 버스

지르콘 커널의 드라이버 개발 키트 사용하는 방법 - 장치 펌웨어

지르콘 커널을 시험하는 방법은?

Testing

지르콘 커널의 취약점은 무엇일까?

Hacking notes

지르콘 커널의 메모리와 자원 사용은 어떻게 할까?

Memory usage analysis tools

지르콘 커널과 LK(Little Kernel)의 관계는?

Relationship with LK

지르콘 커널을 위한 마이크로 벤츠마크는?

Micro-benchmarks


+ Recent posts