메모내용
Kernel 이란?

Kernel

Kernel 의 개념

  • Kernel : (견과류,씨앗의) 알맹이, (사상, 주제의) 핵심
  • Shell : (달걀 견과류등의 딱딱한) 껍데기
  • OS 의 핵심 프로그램 커널은 컴퓨터 시스템의 모든 것을 완전히 통제한다. S/W(소프트웨어)와 H/W(하드웨어)간의 커뮤니케이션을 관리하는 프로그램 이다. 운영 체제의 다른 부분 및 응용 프로그램 수행에 필요한 여러가지 서비스를 제공한다. 운영체제의 핵심 구성요소로서 입출력을 관리하고 소프트웨어로부터의 요청을 컴퓨터에 있는 하드웨어(CPU, 메모리, 저장장치등 I/O 장치)가 처리 할 수 있도록 요청을 변환하는 역할을 한다. 이렇게 하드웨어를 관리하고 필요한 프로세스를 관리 등 여러 시스템 자원을 제어하고, 컴퓨터 부팅시 부트로더에 의해 로드되어 항상 메모리에 상주하게 됩니다.

    커널은 강력한 경영진(하드웨어)을 위해 일하는 바쁜 비서입니다. 비서의 할 일은 직원 및 대중(사용자)으로부터 수신되는 메시지 및 요청을 경영진에게 전달하고, 어디에 무엇이 저장되어 있는지 기억(메모리)하고, 특정한 시간에 누가 경영진을 얼마 동안 만날 수 있는지 결정하는 것입니다.

    Kernel 과 Shell

    사용자가 입력한 명령어는 일련의 과정을 거쳐 하드웨어를 제어하게 됩니다. 사용자가 명령어를 작성하고 조작하기 까지 이 사이에는 몇가지 과정을 거치게 됩니다.

    1. 사용자가 명령어를 입력하면
    2. 컴퓨터 내부에는 Shell 이 이를 받아들이고, 명령어를 해석하여
    3. Kernel 을 통해 하드웨어를 조작합니다
    즉, 제일 하단에는 하드웨어가 있고, 그 위에 Kernel , Kernel 위에 Shell, Shell 위에는 사용자가 존재합니다.

    Kernel 의 역할

    Kernel 의 목표는 물리적(H/W) 자원과 추상화 자원을 관리하는 것이다. 이는 사용자가 물리적인 하드웨어에 접근하고 사용할 수 있도록 매개하기 위해서 이다. 추상화란 물리적으로 하나뿐인 하드웨어를 여러 사용자들이 번갈아 사용할 수 있도록 마치 여러개처럼 보이게 하는 기술이다. 즉, 커널이 관리함에 따라 각 사용자들을 하나의 하드웨어를 독점하는 것처럼 느낄 수 있도록 한다. 커널이 추상화하여 관리하는 물리적 자원들과 이를 추상화한 자원을 칭하는 용어로는 대표적으로 CPU - Task or Process 메모리 - Page or Segment 디스크 - File 네트워크 - Socket 등이 있다. 즉 인터페이스로서 사용자가 하드웨어와 통신할 수 있도록 도와주는 역할을 한다

    User Space와 Kernel Space 사이에는 보이지 않지만 System Call Interface가 있다. User Space의 Task 또는 Process들이 커널이 관리하는 자원에 접근해야할 필요가 있을때 System Call Interface를 통해 Kernel Space의 자원관리자에게 요청이 전달되는 방식이다. 그렇게 되면 커널은 사용자요청에 맞는 하드웨어에게 명령을 전달하고 작업을 수행하는 역할을 한다. 커널은 사용자가 System Call을 통해 컴퓨터 자원을 사용할 수 있게해주는 자원 관리자

    Kernel 의 역할

    참조 - 프로그래민 :: 커널

    SystemCall

    시스템콜 시스템 호출 또는 시스템 콜(system call), 간단히 시스콜(syscall)은 운영 체제의 커널이 제공하는 서비스(명령 또는 함수)에 대해, 유저모드의 응용 프로그램이 커널에게 요청하기 위한 인터페이스이다. 운영체제가 응용프로그램을 위해서 , 운영체제 각 기능을 사용할 수 있도록 시스템 콜이라는 명령 또는 함수를 제공한다. 시스템 콜은 이러한 커널 영역의 기능을 사용자 모드가 사용 가능하게, 즉 프로세스가 하드웨어의 필요한 기능을 사용할 수 있게 해준다.

    이는 마치 서버 - 클라이언트 모델에서 서버측에서 API 를 제공하여, 클라이언트가 이를 이용해 서버에서 요청하고 서버측에서 처리한다는 점이 운영체제의 시스템 콜과 유사하다

    CPU Mode :: [ User Mode, Kernel Mode ]

    코드의 모든 연산, 명령은 CPU 에서 이루어 지며, 즉 연산의 주체는 CPU 니까, 시스템 콜 명령에 의해 CPU 가 유저모드와 커널모드로 전환되어 디바이스에 I/O 요청을 하는것이라 생각된다.(필자생각)

    CPU 도 권한 모드라는것을 가지고 있습니다. 대다수의 운영체제들은 커널모드(Kernel Mode) 와 사용자 모드 (UserMode) 가 구분되어 있으며, 커널모드는 Ring 0 에, 사용자 모드는 Ring 3 에 속한다 ( Ring 1, 2 는 장치 드라이버 전용 )

    # KernelMode (Kernel mode by OS)

    : OS 가 CPU 를 쓸 때 모드

    커널모드는 커널 및 커널에 붙는 드라이버들이 작동하는 영역으로 모든 컴퓨터 리소스에 접근할 수 있다. 그리고 하나의 가상메모리 영역만을 공유하여, 커널과 드라이버가 서로 접근할 수 있다. 다만 그만큼 불안정해서 만일 커널이나 드라이버중 하나라도 오류가 일어나면 치명적이다.

    # UserMode (User mode by applications)

    : 응용프로그램이 CPU 를 쓸 때 모드

    사용자 모드는 일반 프로그램들이 작동되는 영역으로 컴퓨터 리소스에 제한적으로 접근이 가능하고 프로그램들은 프로세스로 작동한다. 프로세스의 가상 메모리 영역은 다른 프로세스가 볼 수 없으므로 다른 프로세스와 정보를 주고받기 위해서는 프로세스간 통신을 이용해야 한다. 대신 프로세스들은 각각 독립적으로 작동하기 때문에 한 프로세스에서 오류가 발생해도 그 프로세스만 종료될 뿐이지 운영체제와 다른 프로세스에 영향을 미치지 않아 안정성이 높다.

    일반적인 프로그램들 은 사용자 모드에서 실행되므로 커널 모드에 대한 직접적인 접근이 불가능하다. 하지만 커널에 접근할 수 없으면 사용자 모드의 프로세스들이 파일 읽기, 쓰기, 그래픽 처리 와 같은 거의 모든 작업을 할 수 없다. 이런 기능들은 커널모드 일때 CPU 가 실행이 가능하기 때문에, 반드시 시스템 콜을 사용해서 커널모드로 전환해야 한다. 따라서 시스템 콜을 사용하여 커널 모드에서 처리하고, 그 결과를 사용자 모드의 프로그램에게 전달하는 것이 바로 시스템 콜이다. 시스템 콜이 호출되면, 사용자모드에서 커널모드로 전환되고, 시스템 콜에서 정의 된 특정 작업을 수행한다. 실행이 끝나면 사용자 모드로 다시 되돌아 간다. 시스템 콜은 프로그램의 거의 모든 코드의 실행에서 발생하며 파일 생성이나 쓰기 또는 읽기, 키보드 입력, 그래픽 출력, 스레드 생성 및 제어 같은 것도 시스템 콜을 통해 커널에 요청하여 커널 모드에서 처리한다. 예로 Windows API 중 유저레벨 API중 하나인 CreateFile()을 실행시키면 내부적으로 Private API인 NtCreateFile()가 실행되는데 이 함수는 결과적으로 커널 모드의 IoCreateFile() 함수가 실행된다. 윈도우에서 커널 함수가 사용자 모드에 노출되는 것은 ntdll.dll이며 실제 구현체는 윈도우 커널인 ntoskrnl.exe이다. ntdll.dll의 대부분 함수는 커널에서 구현되고 ntdll.dll를 통해 이들 함수가 사용자 모드에 노출된다. 디바이스 드라이버는 커널 모드에서 실행되므로 시스템 콜을 통하지 않고 바로 커널 함수를 실행할 수 있다.

    시스템 콜은 운영체제에게 있어서는 매우 중요한 요소이다. 사용자 모드에 있는 프로그램이 시스템 함수를 직접 호출할 수 없으므로 따로 프로그램이 커널 호출을 요청하는 시스템을 만들어서 커널이 처리해야할 일을 프로그램으로부터 받아서 처리하는 것이다. 만약에 없으면? 사용자 모드에서 아무것도 할 수 없게 된다! 그래픽 출력이라거나 파일 다루는 등 행위도 커널의 도움으로 이루어진다.

    Contaxt Switching

    UserMode 와 Kernel 모드 를 왔다갔다에는 비용이 발생한다. 쓰레드가 어떤일을 하고 있었고, 어떤 위치에 있었는지, 필요한 정보는 무엇이었는지, 모두 레지스터에 저장되어 있었는데, Contaxt switching 이 일어나게 되면, 그 모든 정보를 RAM 에 다가 옮겼다가, 다시 레지스터에 올리게 된다

    먼가 빠르게 수행되어야 하는 순간의코 드들은 contaxt switching 을 유발하는 코드들을 자제해야 한다. 예를 들어 std::cout 등..

    Kernel Object 와 HANDLE

    HANDLE 은 커널 오브젝트를 참조하기 위한 윈도우가 관리하는 포인터다

    Window 의 resource 는 모두 메모리에 관리되고 있으며, 윈도우 객체 정보는 우리가 함부로 접근할 수 없다. 운영체제에서 관리하는 Kernel Object 라고 하는데, 객체가 분명 메모리상에 할당되었고, 포인터를 사용해 메모리 주소를 통해 접근할 수 있지만 OS 가 관리하고 있기 때문에, 그 데이터에 함부로 접근하고 조작할 수가 없다. (포인터를 사용해 메모리 주소를 통해서 접근할 수 있지만, 악의적인 프로그램이 메모리 주소를 통해서 Window resource 에 접근할 수 있기 때문에 포인터를 사용해 접근하는것은 매우 위험하다. ) 우리가 만든 오브젝트라면, 사이즈를 변경하고 싶다면, 포인터로 접근해서 사이즈 변경함수를 호출하거나 할텐데, 윈도우는 그럴 수 없다. 때문에 포인터를 사용해 Window Resource 에 접근할 수 없고, 포인터 대신 운영체제가 관리하는 커널오브젝트들은 우리에게 ID 를 준다. 그 아이디를 우리는 HANDLE 이라고 한다. Handle 이라는 (uint : 양의 정수) 값을 가지고, API 를 통해 요청하면 운영체제 가 현재 리소스의 값을 읽어서 전달해준다. 그 핸들을 가지고 윈도우에서 제공하는 함수를 사용하여 간접적으로 조작을 할 수 있다. 즉, 윈도우 에서 관리하는 객체를 핸들(ID)로 얻어다가, 조작할 수 있는 함수에다가 넣어주는 방식을 사용한다. 이 핸들이라는 객체는 DECLARE_HANDLE 이라는 전처리기로 만들어진다.

    DECLARE_HANDLE(name) name 으로 입력된 값으로 struct 를 하나 정의하는것인데, 만들어지는 struct 는 int 값을 하나 들고 있을뿐이다. DECLARE(HDC) 는 아래와 같이 치환된다.
                        
                            DECLARE_HANDLE(name) struct name##__\
                            {\
                                int a;\
                            }; typedef struct name##__ *name
                        
                    

    이렇게. 결국 모두 정수타입 구조체인데 (아이디값을 받는), HWND, HDC, HPEN, HBRUSH 이들 모두 DECLARE_HANDLE 을 사용한다. 왜 그런것일까? 우리가 구조체나 클래스로 만들었다면 구분이 되지만, 커널오브젝트로 만들어져서 는 아이디 값만 받기 때문에, 정수값 하나라고 해서 아이디를 통일해서 모든 아이디 값을 받는 구조체 하나로는 구분하기가 힘들다 따라서 용도에 따라 따로 구조체를 만들어 구분하는 방식을 사용하고 있다. 이렇게 사용함으로서 많은 실수(윈도우 아이디값을 넣어야하는데 브러쉬 아이디값을 넣는 등의 실수)도 방지할 수 있다.아예 자료형이 다르니까.

    스케쥴링 실행되는 프로세스가 여러개가 있을때, 다음 프로그램으로 어떤 것을 선택할지 결정하기 위한 알고리즘 고르는 기준은 OS 마다 다르지만, 중요도에 따라, 언제 최종적으로 실행되었는지 따라 공평하게 수행하도록 해야한다. 그리고 스케쥴링은 kernel 모드에서 실행되기 때문에, 실행중인 프로그램은 다시 kernel 에 실행권한을 넘겨야 다음 프로그램을 결정하기 위한 로직을 수행할 수 있다. 다시 넘기기 위한 방법으로 실행가능시간, 할당시간(time slice) 을 지급하는 방법이 있다. 일정시간동안만 실행할 수 있는 보장을 받는다. 시간이 지나면 실행 소유권을 Kernel 에 돌려주게 된다. 실행시간을 다 소진해야 하는것도 아니다. 더이상 실행할 것이 없다거나 하면 실행 소유권 을 반환하게 된다. 또한 kernel 모드에서 수행해야 하는 코드나(System Call), Sleep 함수를 호출했을때, 실행 소유권 을 포기하고 kernel 모드로 돌아가게 된다.