[pintos] Project 2. USER PROGRAM

채상엽·2023년 5월 7일
0

SW사관학교 정글

목록 보기
33/35
post-thumbnail

앞서 Project 1. Thread 에서는 운영체제에서 스레드간에 동기화와 스케쥴링 등을 직접 만들어보며 익힐 수 있었다.
그렇다면 Project 2. User Program에서는 어떤것들을 공부해볼 수 있을까?

Project 2. User Program의 목표

기존 코드에 사용자 프로그램을 로드하고 실행하는데 필요한 기본 코드는 있지만, I/O와 상호작용은 불가능한 상태이다. 이번 과제에서 프로그램이 system call을 통해서 OS와 상호작용 할 수 있도록 해야한다.

Project 1까지는 모두 OS 커널의 일부분이었기 때문에, 시스템 상의 중요한 부분에 접근할 수 있는 특권을 가지고 있었다고 할 수 있다. 그렇기 때문에 어떠한 제한 없이 자유롭게 모든 부분에 접근할 수 있었지만, 사용자 프로그램을 구현해야하는 Project 2에서는 커널에 자유롭게 접근해서는 안된다. 이러한 부분들을 이번 프로젝트에서 다루게 된다.

Argument Passing

Project 2의 첫 번째 요구사항인 Argument Passing은 프로세스가 생성하는 새 프로세스에 인자를 넘겨주는 것을 의미한다. 여기서의 인자는 흔히 새 프로세스를 동작 시킬때 사용되는 CLI 명령어 인자의 일부를 의미한다.

pintos에서는 ls -a와 같이 새로운 명령어가 입력되었을 경우, 해당 명령어에 해당하는 file을 disk에서 찾아와 메모리에 로드하고, 진입점 rip를 초기화하고 각 인자를 user stack에 삽입 하여 user stack을 초기화 함과 동시에 삽입되어 변화한 rsp의 위치를 저장한다.

위의 함수 진입점 rip와 스택 포인터 rsp의 값과 이외에 현재 컨텍스트의 상태를 intr_frame 이라고 부르는 자료구조에 저장한다. 나는 intr_frame이라는 자료구조를 이해하는데 꽤 시간이 걸렸다.

intr_frame이란?

인터럽트나 예외 처리 중의 cpu 컨텍스트 상태를 저장하고, 인터럽트나 예외 처리가 끝났을때 cpu 상태를 해당 상태로 복원하기 위한 자료구조이다.

이 말이 무슨 말인지 처음에 와 닿지 않았다. 우리가 Argument Passing을 통해 구현하는 내용은 사용자 프로그램에서 system call을 통해 명령어가 입력되었을때(인터럽트가 발생했을 때), 커널 모드로 진입하여 해당 명령어를 파싱하고 실행 가능한 상태로 만들어 준 뒤에 다시 사용자 모드로 되돌려 주는것이다.

즉, 여기서 intr_frame은 인터럽트나 예외 처리 중의 상태를 저장하여 사용자 모드로 전환 될 때 해당 상태로 복원하기 위해서 사용되는 자료구조라고 이해하면 될 것 같다.

System Calls

시스템 콜(System Call)이란 운영 체제의 커널이 제공하는 서비스에 대해, 응용 프로그램의 요청에 따라 커널에 접근하기 위한 인터페이스이다.

시스템 콜은 왜 필요할까?

일반적으로 우리가 사용하는 프로그램은 유저 레벨의 애플리케이션 프로그램이다. 유저 레벨만으로는 많은 기능을 구현하기 어렵기 때문에, 커널의 도움을 반드시 받아야 한다. 커널의 도움을 받기 위해서는 유저 레벨이 아닌 커널 레벨에서 작업이 수행되어야 하는데, 유저 레벨에서 커널 레벨로 컨텍스트를 바꿀 때 호출하는 인터페이스가 시스템 콜이다.

커널 레벨과 유저 레벨이 구분되어 있는 이유?

먼저 커널은 어떤 역할을 맡고 있을까? 커널은 프로그램이 구동되는데 있어서 파일을 읽고, 쓰거나 화면에 출력하는 등 프로세스가 하드웨어에 직접 접근하는 기능들을 수행한다.

즉, 커널은 운영 체제에서 중요한 작업들을 맡고 있는 부분이다. 그렇기 때문에, 누군가 악의적으로 커널을 조작하거나 초보자가 하드웨어 명령어를 마음대로 호출할 경우 운영 체제 전체를 망가뜨릴수도 있기 때문에 두 영역을 나누어 구분짓게 되었다. 따라서 커널의 명령어들은 커널 모드에서만 실행할 수 있도록 설계되어 있다.

그리고 만약 애플리케이션 프로그램에서 커널의 기능이 필요할 경우 시스템 콜 함수라는 인터페이스를 이용하여, 커널 모드의 기능을 수행할 수 있도록 함으로써 커널을 보호할 수 있게 된다.

System Call 처리 과정

앞서 구현한 Argument Passing을 사용하는 exec() 시스템콜로 처리 과정을 확인해보자.

  1. exec() system call 호출 (user mode -> kernel mode)
    • 유저 모드에서 커널 모드로 진입
  2. 인터럽트에 대한 처리
    • disk에서 memory로 적재
    • 함수 진입점 intr_frame에 세팅
    • user stack 세팅
      등 변경 상태들을 intr_frame에 저장
  3. do_iter(&_if) 를 호출 (kernel mode -> user mode)
    • cpu의 상태를 인터럽트 중에 기록된 intr_frame이 저장하고 있는 상태 값으로 전환되도록 함
    • 커널 모드에서 유저 모드로 돌아감
profile
프로게이머 연습생 출신 주니어 서버 개발자 채상엽입니다.

0개의 댓글