
OS의 동작 과정은 두가지 모드가 존재한다.
1. 사용자에게 인터페이스를 제공하는 USER MODE
2. 하드웨어 자원을 직접 관리하는 Kernel MODE
그래서 PintOS의 VM 구조 역시
KERN BASE를 기준으로 사용자 영역과 커널 영역으로 나뉘어 있다.
그럼 왜 나누어 놨을까...?
두가지로 나눈 것의 핵심은 USER MODE 에서 직접 하드웨어에 접근하지 못한다는 점이다.
커널만이 하드웨어 자원에 접근하도록 하여 메모리 같은 OS의 핵심 부분에 침입하는 것을 방지하는 것.
두가지를 나누는 기준?
Mode Bit, 0이면 커널 모드이고 1이면 사용자 모드이다.
따라서 CPU는 이 모드 비트를 확인하고 관련 명령을 수행한다.
https://velog.io/@false90/05.28week11System-Call
PintOS에서의 System Call은 여기서...
사용자 프로그램에서 하드웨어 자원이 필요한 경우가 있다.
메모리에서 필요한 데이터가 있을 수도 있고,
혹은 파일 시스템에서 특정 파일을 읽어들이고 싶을 수도 있다.
이때 System Call 을 호출해서 커널 모드로 진입한다.
System Call 도 하나의 인터럽트 이다.
이 외에도
I/O 인터럽트(입출력)
타이머 인터럽트
전원 이상 혹은 기계 착오
0으로 나누는 경우
Overflow / Underflow
Exception
등등이 있으며, 인터럽트가 발생하면 Mode bit를 0으로 변경하여
커널 모드로 진입하게 된다.

Register
CPU 내부에서 요청을 처리하는데 필요한 데이터를 일시적으로 저장하는 기억 장치이다.
CPU 내부에서 직접 연결되어 있기 때문에 연산 속도가 가장 빠르다.
CPU는 자체적으로 데이터를 저장하는 것이 불가능하기 때문에 연산을 위해서는
반드시 이 레지스터를 거쳐가야 한다.
Memory
이름 그대로 기억장치 이다. 주로 메모리는 주 기억장치인 RAM, Main Memory 등으로 불린다.
CPU와 별도로 위치하며, 주소 Bus, Data Bus로 연결되어 있다.
메모리는 레지스터와 다르게 프로그램에 실행에 필요한 프로그램 명령어와 데이터를 저장하고 있다.

컴퓨터는 더 빠르고 효율적으로 무언가를 하기 위해 발전했다.
CPU가 원하는 데이터와 명령어를 가져오기 위해 메인 메모리에 접근하게 되면 속도가 상당히 떨어진다.
이를 방지하기 위해 지역성의 원리를 이용하여 자주 쓰이는 명령어 혹은 데이터를 저장해놓는
캐시 메모리 개념이 도입되었다.

이러한 캐싱이라는 개념을 통해서 계층적인 메모리 구조가 완성된다.

PintOS에서 rax Register는 등장을 꽤 많이 한다.
리눅스와 x86-64 ISA 로 구성된 PintOS에서 Rax는 범용 레지스터이다.

구현했던 System Call handler 함수에서 호출되는 시스템 콜의 번호를 저장하는데 사용되었다.
system_type에 저장된 번호에 따라 Switch문에서 그 번호에 맞는 System Call 함수로 진입하게 된다.

User Mode 에서 실행되는 프로세스 혹은 스레드에 의해 사용되며,
함수 호출시 해당 함수의 Parameter, 지역 변수 등이 저장된다.
해당 프로세스가 직접적으로 접근 가능하며, 프로세스의 사용자 모드 메모리 영역에 위치한다.
스택 관리 레지스터


(이런식으로 Args Passing, Stack growth 할때 rsp 포인터를 조절하기도 했다.)
OS의 커널 혹은 커널 모드에서 실행되는 코드에 의해 사용되는 스택.
주로 인터럽트 처리 혹은 시스템 콜 등 기능을 수행.
OS가 직접 관리하기 때문에 사용자 엑세스가 불가능하다.
(그래서 PintOS에서 계속 주소 유효성 검사를 했던 이유)
파일 디스크립터는 리눅스 혹은 유닉스 계열의 시스템에서 파일을 식별할때 사용하는 식별자이다.
일반적으로 0이 아닌 정수값을 갖는다
위 세가지는 기본적으로 프로세스로 메모리에서 실행히 할당된다.
핀토스에서는 File Descriptor table을 만들고 fd 값을 이용해 지칭한 뒤
추후 read System call 에서 활용하기도 했다.


OS에서의 원자적 연산은 All or Nothing, 즉 멀티 태스킹과 병렬성에서
데이터의 일관성과 동기화를 유지하는데 필수적이다.
즉 중간에 중단되지 않고 완전히 수행되는 연산을 말하며,
여러 스레드나 프로세스가 동일 데이터에 접근시 발생할 수 있는 충돌을 방지하는 것.
Mutex, Semaphore 등 원자적 연산을 통해 공유 자원에 대한 접근을 동기화하기도 한다.
CPU 레지스터에서 엑세스할 수 있는 메모리 양에 따라 32 비트인지, 64비트인지를 구분.
32 bit OS
32 비트의 데이터를 전송할 수 있는 용량을 보유한 CPU 아키텍쳐 유형
최대 4GB의 RAM을 활용하며 32비트 응용 프로그램만 지원한다.
64 bit OS
64 비트의 데이터를 전송할 수 있는 용량을 보유한 CPU 아키텍쳐 유형.
32비트에 비해 더 큰 용량의 RAM 활용이 가능하며 32비트와 64비트 응용프로그램을
모두 지원한다.
프로그램이 허용되지 않은 메모리 영역에 접근을 시도하거나, 허용되지 않은 방법으로
메모리 영역에 접근을 시도한 경우 발생한다.
예를 들어
int* array = malloc(sizeof(int) * 10); // 크기가 10인 배열을 동적 할당
array[10] = 10; // 인덱스는 0~9까지인데 10에 값 할당 (Segmentation fault 발생!)
free(array);
이런식으로 할당받지 않은 메모리에 접근할때도 Seg fault가 발생한다.