PintOS P2 #4. System Call 서론

유저 프로그램이 작동하기 위해서는 직접 내용을 요청하기보단 시스템 콜을 통한 본래의 기계 내의 서비스를 이용하는 것이 필요하다. 그에 대한 대리 수행은 System Call로 이루어진다. 그 내용을 확인 해보자.


2025.05.21 - [구현하기] - PintOS P2 #3 : Argument Passing 본편

 

PintOS P2 #3 : Argument Passing 본편

파싱 자체는 사실 어렵지 않다. 문제는 파싱 대상의 문자열을 담은 공간을 언제까지 유의미한 값으로 남기게 시킬 것인가를 생각해야한다. 너무 빨리 해제하면 참조 시도시 프로그램이 박살난

hyeonistic.tistory.com

이 글에서 이어진다.

 

System Call은 다양한 역할이 있으나 또 모든 내용을 할 수 있는 것만은 아니다. 대표적으로, 파일 입출력과 직접 연관된 것, 또는 시스템과 직접 연관되는 자식 쓰레드(또는 프로세스. PintOS는 똑같은걸로 치고 있다)를 생성하고 기다리는 일련의 내용들을 포함한다.

모든 과정을 완벽하게 파악하지 못했지만, 유저 프로그램은 argument를 받은 뒤 좀 뒤에 자신의 내용을 실행하기 위해 syscall.c 내에 있는 syscall_handler를 호출한다. 그리고 syscall_handler는 텅 비어있었다. 그리고 호출자의 인터럽트 프레임만 덜렁 주어진채로 이제 만들어 나가야한다. 뭐부터 하지? 라는 생각을 가졌었다.

 

마치 그 상황은 손에 잡히는 딱 한 개의 공구와 방에 갇혀있는 느낌이었다. 우린 이 공구를 어찌저찌 잘 써보자. 이러한 사전 정보가 있다 :

시스템 콜이 발생한 상황에서, 어떤 시스템 콜을 요청했는지는 인터럽트 프레임안의 레지스터 저장소, 그리고 rax에 담겨있다.

추가적으로, syscall-nr.h에서 이 시스템 콜의 배정 번호를 자세하게 확인 할 수 있다.

 

/* System call numbers. */
enum {
	/* Projects 2 and later. */
	SYS_HALT,                   /* Halt the operating system. */
	SYS_EXIT,                   /* Terminate this process. */
	SYS_FORK,                   /* Clone current process. */
	SYS_EXEC,                   /* Switch current process. */
	SYS_WAIT,                   /* Wait for a child process to die. */
	SYS_CREATE,                 /* Create a file. */
	SYS_REMOVE,                 /* Delete a file. */
	SYS_OPEN,                   /* Open a file. */
	SYS_FILESIZE,               /* Obtain a file's size. */
	SYS_READ,                   /* Read from a file. */
	SYS_WRITE,                  /* Write to a file. */
	SYS_SEEK,                   /* Change position in a file. */
	SYS_TELL,                   /* Report current position in a file. */
	SYS_CLOSE,                  /* Close a file. */
 . ... .....

enum은 0부터 시작하는 양수에 단어를 부여할 수 있게 한다. 어쨌든, 간단히 이야기하면 SYS_EXIT은 1번이다.

그럼 이걸 기준으로 분기를 고려 할 수 있게 되었다. 이에 대한 분기문을 작성해나가면 :

void
syscall_handler (struct intr_frame *f) {
	switch(f->R.rax)
	{
	case SYS_HALT:
		halt();
		break;
	case SYS_EXIT:
		exit(something);
		break;
    case SYS_...:

이러한 구현을 만들어 나갈 수 있다.

 

 

대부분의 시스템 콜은 한 개쯤의 매개변수가 필요하다. 없는 경우가 있지만 잘 없다. 그럼 이러한 사전 정보도 도움이 될 수 있다 :

매개변수는 6개의 레지스터에 배정되는데, 차례로 rdi, rsi, rdx ... 등이 있다. PintOS에서는 3개 활용이 최대이니 이정도만 적는다.

단편의 내용으로, write이라는 시스템 콜은 세 개의 매개변수를 필요로 한다. 그러면 :

write(f->R.rdi, f->R.rsi, f->R.rdx);

이런식으로 정리 할 수 있다.

 

 

우리는 PintOS의 User Program 구현에서 꼭 필요한 내용인 System Call에 대해 알아보았다.

다음 글로 쉬운 시스템 콜부터 차례로 구현해나가보자.