. [PintOS, Project2] System Call
본문 바로가기
Pintos Project/Project 2

[PintOS, Project2] System Call

by 불냥이_ 2021. 2. 17.

0. System Call이란?

 시스템 콜은 사용자가 커널 영역에 접근하고 싶을 때, 원하는 목적을 대신해서 작업하는 프로그래밍 인터페이스이다. 그렇기 때문에 시스템 콜은 커널 모드에서 실행되고, 작업 후 사용자 모드로 복귀한다. PintOS에서는 이를 시스템 콜 핸들러를 통해 시스템 콜 (halt, exit, create, remove)를 호출한다.

 

 시스템 콜을 호출할 때, 원하는 기능에 해당하는 시스템 콜 번호를 rax에 담는다. 그리고 시스템 콜 핸들러는 rax의 숫자로 시스템 콜을 호출하고, 해당 콜의 반환값을 다시 rax에 담아서 intr frame(인터럽트 프레임)에 저장한다.

 

 

1. Syscall Handler

@/userprog/syscall.c


/* The main system call interface */
void syscall_handler(struct intr_frame *f UNUSED)
{
	// TODO: Your implementation goes here.
	printf("system call!\n");
	uint64_t arg[7];
	switch (arg[0])
	{
	case SYS_HALT:
		halt();
		break;
	case SYS_EXIT:
		exit(arg[1]);
		break;
	}

	thread_exit();
}

 여기에 HALT, EXIT, FORK, EXEC, WAIT, CREATE, OPEN, FILESIZE, READ, WRITE, SEEK, TELL, CLOSE를 추가해야한다. 

 

 

1.1 Halt

case SYS_HALT:
	halt();
	break;

 

 

/*-------------------------- project.2-System call -----------------------------*/
void
halt (void) {
	power_off();
}
/*-------------------------- project.2-System call -----------------------------*/

 power_off()함수를 호출하면서 PintOS를 종료시키는 시스템 콜이다. 딱히 볼 것은 없다. 

 

 

 

1.2 Exit

case SYS_EXIT:
	exit(f->R.rdi);
	break;

 

 

/*-------------------------- project.2-System call -----------------------------*/
void
exit (int status) {
	struct thread *t = thread_current();
        t->exit_status = status;
	printf("%s: exit(%d)\n", t->name, status);
	thread_exit();
}
/*-------------------------- project.2-System call -----------------------------*/

 현재 실행 중인 프로세스를 종료시키는 시스템 콜이다. 프로세스를 완전히 종료시키기 전에 thread 구조체에 int형인 exit_status에 인자로 받은 status를 저장한다. 그리고 thread_exit()를 호출하여 thread를 완전히 종료시킨다.

 

 ※ 곧 사라질 thread의 exit_status에 status를 저장하는 것은 만약 현재 프로세스가 자식 프로세스여서 부모 프로세스가 wait 상태일 경우, 자식 프로세스가 사라지면서 종료 상태(exit_status)를 부모에게 알려주기 위함이다. 정상적 종료라면 0을 저장한다.

 

 

1.3 Create

case SYS_CREATE: 
	check_address(f->R.rdi);
	f->R.rax = create(f->R.rdi, f->R.rsi);
	break;

 

 

/*-------------------------- project.2-System call -----------------------------*/
bool create(const char *file , unsigned initial_size) {
    if (file == NULL) exit(-1);
    bool result = (filesys_create (file, initial_size));
    return result;
}
/*-------------------------- project.2-System call -----------------------------*/

  file을 만드는 시스템 콜이다. 인자로 받은 file 이름과 크기(initial_size)에 해당하는 파일을 생선한다. 파일 생성에 성공하면 true를 반환하고 실패하면 false를 반환한다. filesys_create가 실질적으로 작업을 수행하므로 크게 볼 것은 없다. (파일을 만들고 바로 열지 않는다. 여는 것은 open() 시트템 콜을 사용해서 따로 실행한다.) 

 

 create를 실행하기 전에 해당 file이 유저 영역에 있는 file인지 확인해야한다. 이는 check_address()로 확인할 수 있다.

 

 

 

1.4 Check Address

/*-------------------------- project.2-System call -----------------------------*/
void
check_address(void *addr) {
	
	if (is_kernel_vaddr(addr))
    {
        exit(-1);
    }
}
/*-------------------------- project.2-System call -----------------------------*/

 Check_Address() 는 해당 주소 값이 주소 영역에 있는 주소 값인지 확인하는 함수이다. PintOS에서는 시스템 콜이 접근할 수 있는 주소를  0cx0000000 ~ 0x8048000 (이 이상은 커널 영억이다.) 으로 제한하기 때문에 유저 영억을 벗어난 영역일 경우 비정상 접근이라고 판단해 exit(-1)로서 프로세스를 종료한다. (exit는 위에 나와있는 exit()함수이다.)

 

 주소가 유저영역인지 (= 커널 영역에 있지 않은지) 는 is_kernel_vaddr()로 확인할 수 있다.

 

/* Physical address of kernel base. */
#define LOADER_KERN_BASE 0x8004000000

/* Returns true if VADDR is a kernel virtual address. */
#define is_kernel_vaddr(vaddr) ((uint64_t)(vaddr) >= KERN_BASE)

 위에서 말한대로 0x8048000 위면 커널 영역이다. 그래서 주소값이 이 이상이면 true를 반환한다. 

 

 

댓글