개요
리눅스의 커널과 파일 시스템에 대한 이해가 아직 많이 부족하다고 생각하여 공부할 책이나 강의를 찾던 중, Kernel of Linux 강의를 알게 되었습니다.
그러나 현재 OLC CENTER에 화원가입이 불가능한 것 같아 강의를 직접 수강하지는 못했고, 해당 강의 내용을 정리한 글들을 보며 공부한 후 제가 이해한 내용에 대해 정리해보고자 글을 작성하였습니다.
참고한 강의노트
Introduction
운영체제란
운영체제란 사용자와 하드웨어 사이에서 둘을 연결해주는 프로그램으로, 사용자 프로그램이 문제없이 실행될 수 있도록 관리하고 사용자가 하드웨어를 편리하고 효율적으로 사용할 수 있도록 돕는 역할을 합니다.
Linux 운영체제는 하나의 큰 프로그램이 아니라 Kernel, Shell, Utility 등 여러개의 프로그램으로 나누어져 있는데, 이는 하나의 큰 프로그램이 아니라 기능별로 분리하여 프로그램을 만들어 사용할 경우 성능 측면(메모리에 올리는 시간, 메모리 사용 효율 등)에서 더 유리하기 때문입니다.
Kernel, Utility, Shell
Linux 운영체제를 구성하는 Kernel, Utility, Shell 프로그램은 다음과 같은 의미를 갖습니다.
Kernel은 시스템이 부팅된 후 종료되기 전까지 메모리에 상주하는 memory resident 프로그램으로, 사용자에게 System Call function을 제공하고 프로세스와 메모리, 파일, I/O와 같은 시스템 자원을 관리하는 역할을 합니다.
Utility는 Kernel과는 달리 사용 시에만 메모리에 올라가고 이외에는 disk에 상주하는 disk resident 프로그램으로, Command 또는 Job이라고도 불립니다.
Shell은 키보드 input을 읽고 해당 Command를 해석하고 실행하는 특수한 Utility로, 다른 utility를 메모리에 로드하고 해제하는 등 Job control을 담당하는 프로그램입니다.
위 프로그램들은 다음과 같이 서로 연관되어 동작합니다.
1. 먼저 시스템 부팅 시, Kernel이 메모리에 올라가게 되고 시스템이 종료되기 전까지 계속해서 메모리에 상주합니다.
2. 이후 사용자가 터미널을 키면 Shell이 메모리에 올라가게 되고, 이후 사용자 입력을 기다립니다.
3. 사용자가 Command를 입력하면, Shell은 해당 Command를 해석하여 해당 Utility를 disk에서 가져와 실행합니다.
이때 리눅스는 multi-user 시스템이기 때문에 여러 사용자가 터미널을 통해 동시에 Shell을 포함한 다양한 utility를 실행할 수 있고, 이러한 특성으로 인해 Linux 운영체제는 Window와 같은 Single-user 시스템과 달리 자원의 효율적인 활용과 각 사용자 프로세스 간의 정보 보호가 중요합니다.
Protection
리눅스 운영체제는 한 프로세스가 다른 프로세스의 Domain(file, memory 등)에 접근하여 입출력할 수 없도록 보호하기 위해 커널을 제외한 프로그램의 I/O Instruction을 금지합니다.
즉, Shell을 포함한 사용자 프로세스가 입출력 작업을 수행하기 위해서는 System Call을 통해 Kernel에 입출력을 요청해야하며, Kernel은 접근 권한을 확인한 후 정당한 요청이라면 입출력 작업을 수행하게 됩니다.
이 과정에서 mode bit라는 개념이 사용되는데, CPU 내부의 mode bit를 0 또는 1로 설정함으로써 CPU mode를 커널 모드 또는 유저 모드로 설정할 수 있고, 커널 모드에서 CPU는 모든 메모리 주소에 접근할 수 있고 모든 작업을 수행할 수 있으나 유저 모드에서는 실행중인 프로세스의 메모리 주소에만 접근할 수 있고 SP나 PC 같은 특수 register에 대한 접근이나 I/O 작업을 포함하여 다른 프로세스나 사용자에게 영향을 미칠 수 있는 작업(priviledged op-code)은 모두 불가능합니다.
유저 모드인 CPU가 명령어를 수행할 때 허용되지 않은 작업을 방지하기 위해 2번의 검사가 수행되는데, 먼저 CPU가 PC register에 저장된 메모리 주소에 접근할 때 MMU는 해당 메모리 주소가 CPU가 접근 가능한 메모리 주소 범위에 해당하는지 확인합니다. 이후 Instruction이 CIR에 fetch된 후 decode하는 과정에서 해당 Instruction의 op-code가 priviledged op-code인지 확인합니다.
두 번의 검사 과정에서 각각 메모리 접근 권한이 없거나 op-code가 priviledged op-code일 경우, trap이 발생해 CPU가 하던 작업이 중단되고 trap handler 루틴이 수행되게 됩니다.
용어 정리
- PC: 다음에 실행할 명령어의 메모리 주소를 가리키며, MAR에 전달됩니다.
- MAR: 메모리 접근 시 실제로 사용되는 주소를 저장하고, MDR과 연동하여 데이터를 주고받습니다.
- MDR: 메모리와 CPU 사이의 데이터 전송을 담당하며, MAR과 연동하여 메모리에 접근합니다.
- CIR: 현재 실행 중인 명령어를 저장하고, CPU는 CIR의 명령어를 해독하여 실행합니다.
- MMU(Memory Management Unit)란 CPU가 메모리에 접근하는 것을 관리하는 컴퓨터 하드웨어 부품으로, 가상 메모리 주소를 실제 메모리 주소로 변환하고, 메모리 보호, 캐시 관리, 버스 중재 등의 역할을 담당합니다.
- opcode와 operand는 함께 하나의 명령어를 구성합니다. opcode가 어떤 연산을 할지를 결정하고, operand는 그 연산에 필요한 데이터나 메모리 위치를 제공합니다.
ex) opcode operand
ADD R1, R2
- trap은 특정 프로세스가 시스템 기능을 사용하려고 할 때 운영체제에게 요청하는 방법을 말합니다. software interrupt라고도 불리며, 특별한 서비스가 필요할 때 의도적으로 운영체제를 호출하는 경우에도 사용됩니다.
Trap, System Call
즉, I/O 작업과 같은 priviledged op-code를 수행하기 위해서는 trap을 발생시켜 CPU mode를 커널 모드로 변경한 뒤 입출력 작업을 하는 trap handler 루틴을 수행해야 합니다.
실제로 C언어로 작성된 프로그램을 예시로 들면 printf()와 같은 I/O 작업이 필요한 함수의 경우, write()라는 system call interface를 통해 arguments와 system call number를 세팅한 후 trap을 발생시킴으로써 커널 모드에서 I/O 작업을 수행하게 됩니다.
위 이미지에서 chmodk나 int $0x80은 trap을 유발하여 CPU를 커널 모드로 전환하는 기능을 하고, 이후 system_call()이라는 trap handler 루틴이 실행됩니다.
사용자 프로세스가 priviledged op-code를 수행하는 과정을 다시 한 번 정리해보면,
1. system call wrapper를 호출하여 명령 수행에 필요한 parameter와 system call number를 설정한 뒤, trap을 유발하여 CPU를 커널 모드로 변경합니다.
2. trap handler는 parameter와 system call number를 확인하고 권한 등을 검사한 뒤, 해당 요청에 맞는 kernel function을 실행합니다.
3. kernel function이 수행이 완료되면 CPU를 유저 모드로 변경하고, 사용자 프로세스가 수행할 Instruction의 위치로 돌아갑니다.
이처럼 각 프로세스는 유저 모드와 커널 모드를 전환하며 실행되고, 각 모드에서 실행하는 function의 정보(local variable 같은)나 모드 전환 시 반환 주소 등을 저장할 필요가 있습니다. 따라서 하나의 프로세스는 유저 스택과 커널 스택을 모두 가지며, 이를 통해 유저 모드와 커널 모드를 적절히 오갈 수 있습니다.
회고
단순히 정리된 강의노트를 읽고 이해하는 것보다 이해한 내용을 정리하고 요약하여 글을 작성하는 것이 생각보다 훨씬 더 어려웠고, 그 과정에서 확실히 이해하지 못했던 단어나 내용을 정리하고 자료를 찾아 검증하는 과정에서 공부한 내용을 더 깊이 이해할 수 있었습니다.
'Cloud engineering' 카테고리의 다른 글
Kernel of Linux 정리 - System Call (0) | 2024.12.22 |
---|---|
OpenStack을 이용해 로컬 환경에 클라우드 시스템 구축하기 (0) | 2024.11.21 |
리눅스 기본 요소들을 이용해 Pod 생성하기 (0) | 2024.11.09 |
kubeadm으로 구축한 쿠버네티스 클러스터에 모니터링 시스템 구축하기 (0) | 2024.10.15 |
kubeadm으로 구축한 쿠버네티스 환경에서 GitOps 구축하기 (2) | 2024.10.08 |