[Linux Kernel] Introduction

whatSup CheatSheet·2022년 10월 16일
2

Linux Kernel

목록 보기
1/7
post-thumbnail
  • 컨테이너에 대해 공부하면서 리눅스 커널에 대한 이해가 간략하게나마 필요함을 느끼게 되었고, 이에 본 시리즈를 작성합니다.
  • [Linux Kernel] 시리즈는 olc.kr의 강의를 기반으로 작성되었으며, 이해가 되지 않는 부분은 여러 블로그들을 참고하였습니다. 참고한 블로그는 각 글의 하단 Reference탭에 명시하였습니다.

운영체제란 ?

  • 운영체제: 하드웨어 자원들을 관리하고 프로그램들을 지원해주는 시스템
  • 운영체제의 목표
    • 사용자와 하드웨어 사이에서 중개자 역할을 함
    • 사용자가 각 하드웨어의 동작을 이해할 필요가 없이 OS가 알아서 이를 처리
    • 하드웨어를 효율적으로 사용할 수 있도록 함

프로그램이란 ?

  • 프로그래밍 언어로 코딩을 할 때, 다양한 함수들과 main()을 만들고, 이들을 컴파일 하면 바이너리가 나옴. 우리는 이것을 프로그램이라고 부름.
  • 그렇다면 왜 대부분의 프로그램들은 분리되어 있는가?
    → 프로그램들이 분리되어 있지 않고, 하나의 커다란 프로그램으로 운영될 경우 비효율성이 발생
    • 거대한 프로그램은 사용하지 않을 프로그램까지 모두 실행하기 때문에 부팅 시간, 메모리 사용 등에 있어서 심각한 비효율성을 초래함
  • 위와 같은 이유로 리눅스도 OS를 하나의 커다란 프로그램으로 만든 것이 아니라 Kernel, Shell, Utility 등의 프로그램으로 분할해놓은 것임

프로그램 vs 프로세스

  • 프로그램은 보조 기억 장치에서 실행되기만을 기다리는 정적인 데이터의 집합임
  • 프로그램이 메모리에 적재되면, 프로세스가 됨. 즉, 프로세스란 실행 중인 프로그램을 뜻함

Kernel, Utility, Shell, File

  • Kernel
    • Memory resident한 독립된 C 프로그램
    • ** Memory resident: 부팅되고나서부터 꺼질 때까지 항상 메모리에 상주하고 있는 것
    • 커널이 아닌 다른 프로그램들은 Memory resident한 특성을 가지지 않음 → 대신 수요에 의해 load되는 Disk resident한 특성을 가짐
  • Utility
    • Disk resident한 C 프로그램
      • Disk resident하기 때문에 항상 현 주소가 disk이며,
      • 사용자가 요청하면 메모리에 올라옴.
      • 따라서 Utility는 command(job)라고도 부림
  • Shell
    • 많은 프로그램들(Utility)들이 disk로부터 언제 올라오고, 언제 내려가는지 등을 컨트롤하는 프로그램(A special utility)
      • 한 마디로 표현하면 Job(command) Control을 담당함
  • File
    • 유닉스에서 파일은 Sequence of bytes를 의미함. 즉, 바이트들의 배열을 의미.
      • 모든 함수와 명령어들은 결국 기계어로 해석하면 0과 1의 나열에 불과함
    • 유닉스에서는 모든 것이 file임
      • I/O device 등도 file로 취급함.

커널-쉘-유틸리티의 관계

  1. 가장 처음 컴퓨터를 키면, 부팅이 되며 Kernel(a.out)이 메모리에 올라오게 됨
    • 즉, 커널 실행파일이 메모리에 로딩됨

  1. 부팅이 완료되고 user들이 터미널을 키면, 그 터미널 위에서 shell이란 프로그램이 (메인 메모리에) 올라옴
    • 이후 유저가 키보드로 커맨드를 입력하기를 기다림
  2. 커맨드가 입력되면, shell은 커맨드에 대응하는 Utility를 디스크로부터 가져와서 실행시킴
    • 위 그림처럼, 만약 User B가 ppt를 실행시키라고 명령을 내리면 쉘이 child process를 생성해서 ppt를 실행시켜주게 됨

Linux vs Window

Resource Usage 관련

  • 윈도우는 Single-user 시스템이고, 리눅스는 Multi-user 시스템임.
  • 따라서 리눅스에서는 여러 사람이 동시에 리소스를 사용하기 때문에 최대한 효율있게 사용하여야 함

Protection 관련

  • Protection : 리눅스에는 여러 사람의 정보가 같이 있기 떄문에 Protection을 더 잘 신경써야함
  • 이러한 보안 문제를 해결하기 위해 리눅스에서는 사전방지(prevent)에 많은 노력을 기울이게 됨
  • 리눅스의 사전방지(prevent) 시스템은 다음과 같다.
    • 사용자가 I/O 작업을 할 땐 반드시 커널에 요청하는 방식으로 진행할 수 있음
    • 이때 커널이 요청을 받게 되면, 커널이 가지고 있는 function으로 I/O를 해주는데, 무조건적으로 해주는 것이 아니라, 그 I/O가 정상적인 것인지 검사를 하고 난 뒤에 해주게 됨
    • 즉, 커널에 요청이 들어오면, 커널 내 function을 이용해서 I/O를 진행하는데, 이러한 요청을 바로 System call이라고 부름

Binary bit mode (for System call)

  • 리눅스는 system call을 위해 하드웨어(CPU)에 Binary bit mode라는 개념을 도입합.
    • cpu에는 바이너리 비트인 모드 비트가 있으며, 이것은 0 또는 1의 값을 가짐.
    • 만약 모드 비트가 kernel mode로 세팅되어 있으면, cpu는 어떠한 메모리 영역도 접근할 수 있으며, 어떠한 명령도 다 수행할 수 있음
    • 하지만 user mode로 되어 있으면 cpu는 내 주소 영역에만 접근 가능하며 제한적인 명령어 수행(로컬한 영역)이 가능함.

리눅스 CPU 명령어 처리 과정

  1. CPU 명령어 사이클이 돌면서 PC 레지스터에서 인출된 명령어의 주소. 즉, 수행해야 할 명령의 주소를 먼저 메모리에게 보냄
  2. 메모리는 해당 주소를 받게되고, 이것이 IR 레지스터에 들어가게 됨. 즉 IR(Instruction Register) 레지스터에 이번에 수행해야 할 명령어가 오게 됨
    • MAR(Memory Address Register)는 MAR이 읽어들인 주소에 해당하는 데이터를 MBR(Memory Buffer Register)에 담아 IR에 보냄
    • 명령어는 그림 우측 하단처럼 opcode + operand로 구성됨
      • op-code에는 수행해야 할 명령어가 있으며
      • operands에는 메모리 주소가 담겨져 있음

  1. IR 레지스터에 있는 명령어의 op-code를 들여다보고, operands 부분에 들어있는 주소에 해당하는 메모리 주소에 담겨 있는 값을 메모리에서 또 가져온 뒤, 실제 연산이 수행됨

리눅스 CPU 명령어 처리 과정에서의 모드 비트 검사

CPU 명령어 처리 과정을 다시 보면, 레지스터에서 메모리로 수행할 명령어의 주소를 보낼 때

  • 당시 mode bit가User 모드라면, CPU와 메모리 사이(요즘에는 주로 CPU)에 존재하는 MMU(Memory Management Unit) 하드웨어가 CPU에서 메모리에 연결되어 있는 버스를 살펴보면서, 전송되는 address를 체킹함
    • 만약 요청한 명령어의 address가 자신의 로컬 범위 밖에 위치한다면, 요청한 명령어 주소를 얻지 못하고 끝나버림
    • 만약 정상적으로 명령어를 가져왔다면(Instruction Fetch), Decode 단계에서 op-code를 보고 어떠한 역할인지를 파악하는데, 만약 Privileged op-code(중요한 역할을 하는 실행)를 시도하려 한다면 그 순간 CPU를 뻇겨버림
  • 물론 Kernel 모드라면 위와 같은 검증 절차를 전혀 밟지 않는다.

그렇다면, User가 파일을 읽고 쓰는 로직을 구현하려 한다고 해보자. 내 프로세스는 User Mode이고, 커널이 아닌데 어떻게 I/O를 할 수 있을까?

User가 I/O를 하는 방법

User가 파일을 읽는 로직을 코딩 해 놓고 실제 컴파일을 하고나서 바이너리르 보면, 그 안에는 I/O statement가 없음.

  • 즉 소스코드에서만 개발자가 입출력을 관리하는 것처럼 보일 뿐 실제로는 System Call을 통해 커널이 가지고 있는 function을 호출하는 것임

개발자가 I/O를 담은 소스코드를 컴파일한다면, 컴파일러가 해당 부분들에 chmodk(change CPU protection mode to Kernel)이라는 function이 수행될 수 있게끔 만들어줌. 이를 통해 CPU의 모드비트를 바꾸고, I/O 명령을 수행하게 됨.

  • 이때, 커널의 fuction을 호출한다는 건 커널에게 부탁을 하고, 커널이 해당 함수를 수행해주는 개념임. 즉, System call을 의미

chmodk가 수행되면, 하드웨어는 다음과 같은 동작을 수행함

  • chmodk는 privileged 명령임.
  • 따라서 user 프로그램은 이를 수행하지 못하고, CPU (권한)을 뻇겨버림 → 이를 trap에 걸린다고 표현함
    • trap이 될 때(즉, system call을 통해 커널에게 요청을 할 때) 요청 명령이 어떤 처리(read, write, open, close)인지를 알려줄 파라미터가 함께 trap handler로 들어가게 됨
  • trap에 걸리고 나면 mode bit가 커널 모드로 바뀌게 되며, trap handler 루틴(트랩을 처리하는 루틴) 이 수행되게 됨

이후 소프트웨어에서는 다음과 같은 동작이 수행됨

  • 유저가 해당 디스크나 메모리 영역에 권한(read, write, execute)이 있는지를 확인
  • 정상적인 요청이면, 커널에서 I/O를 수행하고, 다시 trap을 통해 사용자 프로그램에게 정보를 넘겨줌

모든 프로세스는 두 개의 stack을 가지게 됨

  • user-mode에서 수행될때 유저의 프로그램안에 있는 함수의 로컬 변수를 계속해서 호출해야하니까 stack이 필요
  • kernel-mode에서도 커널 안에 있는 함수의 로컬 변수를 계속 호출해야 하기 떄문에 stack이 필요
  • 결국 모든 프로세스는 user stack, kernel stack 2개를 포함

위 과정을 정리하면 다음과 같다.

  • 프로그램이 수행되면, 위 그림과 같이 user-mode와 kernel-mode가 번갈아가며 수행되는 것을 알 수 있다.
    • 유저모드가 자신의 코드를 수행하다가 커널에게 부탁할 일이 생기면 System call을 함.
    • 커널모드로 집입하여 Kernel a.out 이 진행되며 커널이 일을 처리한 후 다시 유저모드로 돌아와서 작업을 진행
    • 위 과정을 프로그램이 종료할 때까지 반복

Reference

profile
AI Engineer : Lv 0

0개의 댓글