USER PROGRAMS를 시작하기 앞서 관련된 키워드를 살펴보겠다.
1. **User mode vs Kernel mode**:
운영체제는 보안과 안정성을 위해 두 가지 모드를 사용합니다. 사용자 프로그램이 실행되는 User mode에서는 제한된 권한만을 가지지만, 시스템 호출을 통해 필요한 서비스를 요청하면 운영체제는 Kernel mode로 전환하여 요청된 작업을 수행합니다.
2. **Register vs Memory**:
레지스터와 메모리는 컴퓨터 시스템에서 데이터를 저장하는 두 가지 주요 장치입니다. 레지스터는 CPU 내부에 위치하여 빠른 접근이 가능하지만 용량이 작습니다. 반면에 메모리는 용량이 크지만 CPU 외부에 위치하여 접근 속도가 느립니다.
3. **User Stack**:
User Stack은 사용자 모드에서 실행되는 프로그램이 함수 호출, 지역 변수 저장 등을 위해 사용하는 메모리 영역입니다.
4. **System Call**:
사용자 프로그램이 커널의 서비스를 요청할 때 사용하는 인터페이스입니다. 시스템 호출을 통해 파일 열기, 네트워크 통신 등의 작업을 요청할 수 있습니다.
5. **File Descriptor**:
시스템 호출을 통해 파일을 열면, 운영체제는 해당 파일에 대한 참조인 파일 디스크립터를 반환합니다. 이 파일 디스크립터를 통해 파일을 읽거나 쓸 수 있습니다.
6. **Cache**:
CPU와 메모리 사이의 속도 차이를 줄이기 위해 사용하는 중간 저장소입니다. 자주 사용하는 데이터나 명령어를 빠르게 접근할 수 있도록 캐시에 저장합니다.
7. **Atomic Operation**:
원자적 연산은 여러 단계로 이루어진 연산이지만, 한 번에 수행되는 것처럼 보장(CAS, lock...)하는 연산입니다. 이는 멀티 스레드 환경에서 동시성 문제를 해결하는 데 중요한 역할을 합니다.
8. **rax register**:
rax 레지스터는 x86-64 아키텍처에서 주로 사용되는 레지스터로, 시스템 호출의 결과값을 저장하는 데 사용됩니다.
9. **32 bit OS vs 64 bit OS**:
32비트 운영체제는 한 번에 32비트의 데이터를 처리하고, 최대 4GB의 물리 메모리를 지원합니다. 반면에 64비트 운영체제는 한 번에 64비트의 데이터를 처리하고, 훨씬 더 큰 메모리를 지원합니다.
운영체제는 사용자 프로그램이 실행되는 환경을 제공하며, 이를 위해 User mode와 Kernel mode를 구분하고 System Call을 통해 서비스를 제공합니다. 사용자 프로그램은 User mode에서 실행되며, 필요한 기능을 운영체제에 요청하기 위해 System Call을 사용합니다. 프로그램이 실행되기 위해서는 Memory에 로드되어야 하며, 이때 Memory는 코드와 데이터를 저장하는 공간으로 사용됩니다. 또한 CPU의 Register는 연산의 중간 결과나 프로세스의 상태 정보를 빠르게 접근할 수 있도록 저장하는 공간으로 사용됩니다.
User Stack은 함수 호출과 관련된 정보를 관리하는데 사용되며, File Descriptor는 프로세스가 파일을 다루는 인터페이스로 사용됩니다. 이를 통해 프로세스는 파일을 열고 읽고 쓰는 등의 작업을 수행할 수 있습니다. 또한, 운영체제는 Cache를 통해 자주 사용하는 데이터나 명령어를 빠르게 접근할 수 있도록 하고, Atomic Operation을 통해 동시성 문제를 해결합니다. 이 모든 과정은 운영체제의 관리 아래에서 이루어지며, 프로세스는 필요한 서비스를 안전하고 효율적으로 이용할 수 있도록 지원합니다.
*CAS
CAS 명령어: Compare-and-Swap(CAS) 명령어는 원자적 연산을 수행하는 데 사용됩니다. 이 명령어는 메모리의 값을 읽고, 기대하는 값과 비교한 후, 값이 일치하면 새로운 값을 저장하는 원자적인 작업을 수행합니다. CAS 명령어는 다중 스레드 환경에서 데이터의 일관성과 상호 배제를 보장하는 데 사용됩니다.
User mode vs Kernel mode
사용자모드(User mode)와 커널모드를 살펴보기 전에 시스템 콜의 탄생부터 알면 좋다.
운영체제 코드는 일반 라이브러리 코드와는 다르게 하드웨어 장치( CPU, 주기억 장치, 보조기억 장치, 입력 장치, 출력 장치 등)의 제어를 담당한다. 일반적인 응용 프로그램 코드와는 다르게 취급되어야 한다는 의미다. 그렇지 않다면 어떤 프로그램이든 원하는 모든 파일을 읽을 수 있게 된다. 개인정보 보호가 불가능해진다. 이런 이유 때문에 저장장치 하드웨어를 다루는 파일 시스템과 같은 프로그램들은 일반적인 라이브러리 형태로 구현을 하면 자료의 기록과 보호라는 원래 의도했던 역할을 할 수가 없다. 이런 문제를 해결하기 위해 시스템 콜이라는 아이디어가 발명되었다.
운영체제를 라이브러리가 아니라 특별한 하드웨어 명령어와 하드웨어 상태를 결합하여 운영체제로 전환하기 위해서는 정해진 규칙에 따라 제어 가능한 과정을 거치 도록 만들었다.
시스템 콜과 프로시저 콜의 결정적 차이는 시스템 콜은 제어를 운영체제에게 넘길 때 (예, 분기) 하드웨어 특권 수준(hardware privilege level)을 상향 조정한다는 것이다. 사용자 응용 프로그램은 사용자 모드(user mode)라고 불리는 상태에서 실행된다. 사용자 모드에서는 응용 프로그램이 할 수 있는 일을 하드웨어적으로 제한한다. 예를들어 사용자 모드에서 실행 중인 응용 프로그램은 디스크 입출력, 물리 메모리 페이지접근 또는 네트워크 패킷 송신 등의 작업을 할 수 없다. 시스템 콜은 보통 trap이라고 불리는 특별한 하드웨어 명령어를 이용하여 호출된다. 시스템 콜 시작 시, 하드웨어는 미리 지정된 트랩 핸들러(trap handler) 함수에게 제어권을 넘기고 특권 수준을 커널 모드(kernel mode)로 격상시킨다. 트랩 핸들러 함수는 운영체제가 미리 구현해 놓는다. 커널 모드에서 운영체제는 시스템의 하드웨어를 자유롭게 접근할 수 있으며 입출력 또는 메모리 할당 등과 같은 작업을 할 수 있다. 운영체제가 서비스를 완료하면 return-from-trap 특수 명령어를 사용하여 제어권을 다시 사용자에게 넘긴다. 이 명령어는 응용 프로그램이 출발했던 지점으로 제어권을 넘기는 동시에 사용자 모드로 다시 전환한다.
정리하자면
사용자 모드(User mode):
일반적인 프로그램이 실행되는 모드로, 하드웨어와 시스템 리소스에 직접 접근할 수 없다. 필요한 작업은 시스템 콜을 통해 요청
커널 모드(Kernel mode):
운영체제가 동작하는 모드로, 하드웨어와 시스템 리소스를 직접 제어할 권한이 있다. 시스템 콜 처리, 하드웨어 제어, 메모리 관리 등의 작업을 수행한다.
이 두 모드 간의 전환은 시스템 콜을 통해 이루어진다.
https://learn.microsoft.com/ko-kr/windows-hardware/drivers/gettingstarted/user-mode-and-kernel-mode
*추가적인 개념
보호 링(Protection Ring) :
사용자 모드와 커널 모드는 하드웨어의 보호 링 메커니즘을 통해 구현됩니다. 이는 시스템의 보안을 강화하기 위해 만들어진 개념으로, 커널 모드는 보호 링 0(최고 권한)에 위치하고, 사용자 모드는 보호 링 3(최저 권한)에 위치합니다. 이로 인해 사용자 모드에서는 커널 모드의 자원에 직접 접근할 수 없습니다.
컨텍스트 스위칭(Context Switching) :
시스템 콜을 통해 사용자 모드에서 커널 모드로 전환될 때, 현재 실행 중인 프로세스의 상태를 저장하고, 새로 실행될 프로세스의 상태를 불러오는 과정을 컨텍스트 스위칭이라고 합니다. 이는 시스템 콜이 발생할 때마다 일어나며, 이로 인해 CPU는 여러 프로세스를 동시에 실행하는 것처럼 보이게 됩니다.
Register vs Memory
레지스터(Register)와 메모리(Memory). 둘 다 컴퓨터에서 데이터를 저장하는 공간이지만, 그 역할과 특성이 다르다.
운영체제는 레지스터와 메모리에서 각각 다른 역할을 합니다.
레지스터에서의 운영체제의 역할 :
레지스터는 CPU 내부에 위치한 매우 속도가 빠른 작은 저장 공간입니다. 운영체제는 프로세스의 컨텍스트 스위칭(Context Switching) 때, 현재 실행 중인 프로세스의 레지스터 값을 저장하고, 새로운 프로세스의 레지스터 값을 불러옵니다. 이를 통해 각 프로세스가 독립적으로 실행되는 것처럼 보이게 합니다.
메모리에서의 운영체제의 역할 :
메모리는 프로그램의 명령어와 데이터를 저장하는 공간입니다. 운영체제는 메모리 관리를 통해 각 프로세스에게 독립적인 메모리 공간을 할당하고, 필요에 따라 회수합니다. 또한, 운영체제는 메모리 보호 기능을 통해 한 프로세스가 다른 프로세스의 메모리 공간에 접근하는 것을 방지합니다.
운영체제는 레지스터와 메모리에서 프로세스의 독립성을 보장하고, 시스템의 안정성과 보안을 유지하는 역할을 합니다.
*rax register
`RAX` 레지스터는 x86-64 아키텍처(즉, 64비트 인텔 및 AMD 프로세서)에서 사용되는 범용 레지스터입니다. 이 레지스터는 64비트 크기를 가지며, 다양한 연산에 사용될 수 있는 저장 공간을 제공합니다.
왜 `RAX` 레지스터가 운영체제에서 특히 중요할까요?
1. **시스템 호출**: `RAX` 레지스터는 시스템 호출의 번호를 저장하는 데 사용됩니다. 시스템 호출은 사용자 모드에서 커널 모드로 전환하여 운영체제의 서비스를 요청하는 방법입니다. 이때, 특정 시스템 호출을 지정하는 번호가 `RAX`에 저장되며, 시스템 호출의 결과도 `RAX`에 저장됩니다. 따라서, `RAX`는 시스템 호출을 통한 운영체제와의 인터페이스 역할을 수행합니다.
2. **산술 연산 및 데이터 반환**: `RAX`는 다양한 산술 연산의 결과를 저장하는 데 주로 사용되며, 함수 호출의 결과를 반환하는 데도 사용됩니다. 이는 `RAX`가 고속의 CPU 레지스터이기 때문에, 결과를 빠르게 처리하고 전달할 수 있습니다.
따라서, `RAX` 레지스터는 운영체제와의 인터페이스 역할을 하고, 연산 결과를 빠르게 처리하고 전달하는 데 필수적인 역할을 수행합니다. 이러한 역할로 인해 `RAX`는 운영체제에서 중요한 레지스터로 간주됩니다.
User Stack
운영체제는 사용자 스택에서 스택 메모리 할당 및 관리, 스택 오버플로우 방지, 메모리 보호 같은 역할을 수행합니다.
스택 메모리 할당 및 관리 :
운영체제는 프로세스가 생성될 때마다 각 프로세스에게 독립적인 사용자 스택 공간을 메모리에서 할당합니다. 이 공간은 해당 프로세스의 함수 호출에 필요한 정보(예: 매개변수, 반환 주소, 지역 변수 등)를 저장하는 데 사용됩니다. 프로세스가 종료되면 운영체제는 그 프로세스의 사용자 스택을 메모리에서 회수합니다.
메모리 보호 :
운영체제는 각 프로세스의 사용자 스택을 다른 프로세스로부터 보호하는 역할을 합니다. 이를 통해 한 프로세스가 다른 프로세스의 스택 메모리를 침범하거나 오염시키는 것을 방지하여 시스템의 안정성과 보안을 유지합니다.
스택 오버플로우 방지 :
운영체제는 각 프로세스의 사용자 스택이 메모리를 초과하여 쓰는 것, 즉 스택 오버플로우를 방지하는 역할을 합니다. 이를 위해 운영체제는 스택의 크기를 모니터링하고, 스택이 너무 커져서 메모리를 초과할 위험이 있을 때는 프로세스를 종료하거나 오류 메시지를 전달하는 등의 조치를 취합니다.
이러한 역할을 통해 운영체제는 프로세스의 독립성을 보장하고, 프로그램의 실행을 관리하며, 시스템의 전반적인 성능과 안정성을 유지하는 데 기여합니다.
System Call
시스템 호출(System Call)은 운영체제가 제공하는 서비스를 사용자 프로그램이 사용하기 위한 인터페이스입니다.
시스템 호출의 과정
1. 사용자 프로그램은 필요한 서비스(예: 파일 열기, 프로세스 생성 등)에 대한 시스템 호출을 수행합니다.
2. 이를 위해 사용자 프로그램은 특정 시스템 호출 번호와 필요한 인자를 설정하고, 트랩 명령어를 실행하여 CPU를 트랩 모드로 전환합니다. 이렇게 하면 CPU는 운영체제의 코드를 실행할 수 있게 됩니다.
3. 운영체제는 시스템 호출 번호를 확인하고, 해당 번호에 대응하는 서비스를 수행합니다.
4. 서비스가 완료되면 결과를 사용자 프로그램에 반환하고, CPU를 사용자 모드로 전환하여 사용자 프로그램의 실행을 계속합니다.
시스템 호출은 다양한 종류가 있으며, 대표적으로 파일 관리, 프로세스 관리, 네트워크 관리 등이 있다. 파일 관리 시스템 호출에는 open, read, write, close 등이 있고, 프로세스 관리 시스템 호출에는 fork, exec, exit 등이 있다. 시스템 호출을 통해 운영체제는 사용자 프로그램이 제한된 권한으로만 시스템 리소스를 사용하도록 제어할 수 있다. 또한, 시스템 호출의 오버헤드는 프로그램의 성능에 큰 영향을 미칠 수 있으므로, 시스템 호출의 사용은 신중하게 고려되어야 한다.
File Descriptor
파일 디스크립터(File Descriptor)는 운영체제가 파일을 추상화하여 관리하는 방법 중 하나로, 열린 파일을 가리키는 정수값입니다. 운영체제는 프로세스가 파일을 열 때마다 고유한 파일 디스크립터를 할당하고, 이를 통해 해당 파일에 대한 다양한 작업을 수행합니다.
파일 디스크립터의 주요 특징과 사용 방법:
1. **파일 디스크립터의 할당**:
프로세스가 파일을 열면(open 시스템 호출 사용), 운영체제는 해당 파일에 대한 정보를 유지하고, 이 정보를 참조하는 파일 디스크립터를 프로세스에게 반환한다.
2. **파일 디스크립터의 사용**:
프로세스는 할당받은 파일 디스크립터를 통해 파일을 읽거나(write 시스템 호출), 쓰거나(read 시스템 호출), 파일의 위치를 이동하는(lseek 시스템 호출) 등의 작업을 수행한다.
3. **파일 디스크립터의 해제**:
프로세스가 파일 작업을 완료하면 파일 디스크립터를 닫아야 한다(close 시스템 호출 사용). 이렇게 하면 운영체제는 해당 파일 디스크립터를 해제하고, 필요한 정리 작업을 수행한다.
4. **특수한 파일 디스크립터**:
모든 프로세스는 시작할 때 표준 입력(0), 표준 출력(1), 표준 에러(2)라는 세 가지 특수한 파일 디스크립터를 자동으로 할당받는다. 이들은 각각 키보드 입력, 화면 출력, 에러 메시지 출력을 위해 사용된다.
따라서, 파일 디스크립터는 프로세스가 파일을 다루는 데 필수적인 요소로, 운영체제와 프로세스 사이의 중요한 인터페이스이다. 이를 통해 운영체제는 프로세스의 파일 접근을 효과적으로 관리하고 제어할 수 있다.
'개발일지 > PintOS' 카테고리의 다른 글
pintos - virtual memory(3) (0) | 2023.12.19 |
---|---|
pintos - Virtual Memory(1) (0) | 2023.12.14 |
pintos (부끄러운)실수 기록 (0) | 2023.12.14 |
pintos - USER PROGRAMS (1) (0) | 2023.12.05 |
pintos - THREADS(1) (0) | 2023.11.28 |