pintOS에서 구현해야 하는 System call 종류는 아래와 같다.
<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. */
/* Project 3 and optionally project 4. */
SYS_MMAP, /* Map a file into memory. */
SYS_MUNMAP, /* Remove a memory mapping. */
/* Project 4 only. */
SYS_CHDIR, /* Change the current directory. */
SYS_MKDIR, /* Create a directory. */
SYS_READDIR, /* Reads a directory entry. */
SYS_ISDIR, /* Tests if a fd represents a directory. */
SYS_INUMBER, /* Returns the inode number for a fd. */
SYS_SYMLINK, /* Returns the inode number for a fd. */
/* Extra for Project 2 */
SYS_DUP2, /* Duplicate the file descriptor */
SYS_MOUNT,
SYS_UMOUNT,
};
project2에서 구현할 14개의 시스템콜 코드를 알아보기 전에 시스템 콜 핸들러(System call handler)에 대해 알아보자.
시스템 콜 핸들러에서 시스템 콜 번호를 이용하여, 해당 시스템 콜을 호출한다.
아래의 코드와 같다.
void syscall_handler(struct intr_frame *f UNUSED)
{
// TODO: Your implementation goes here.
memcpy(&thread_current()->fork_tf, f, sizeof(struct intr_frame));
uintptr_t *stack_pointer = f->rsp; // user_stack 을 가리키는 포인터
switch (f->R.rax)
{
case SYS_HALT:
halt();
break;
case SYS_EXIT:
check_address(f->R.rdi);
exit(f->R.rdi);
break;
case SYS_FORK:
check_address(f->R.rdi);
f->R.rax = fork(f->R.rdi);
break;
case SYS_EXEC:
check_address(f->R.rdi);
f->R.rax = exec(f->R.rdi);
break;
case SYS_WAIT:
check_address(f->R.rdi);
f->R.rax = wait(f->R.rdi);
break;
case SYS_CREATE:
check_address(f->R.rdi);
f->R.rax = create(f->R.rdi, f->R.rsi);
break;
case SYS_REMOVE:
check_address(f->R.rdi);
f->R.rax = remove(f->R.rdi);
break;
case SYS_OPEN:
check_address(f->R.rdi);
f->R.rax = open(f->R.rdi);
break;
case SYS_FILESIZE:
check_address(f->R.rdi);
f->R.rax = filesize(f->R.rdi);
break;
case SYS_READ:
check_address(f->R.rdi);
f->R.rax = read(f->R.rdi, f->R.rsi, f->R.rdx);
break;
case SYS_WRITE:
check_address(f->R.rdi);
f->R.rax = write(f->R.rdi, f->R.rsi, f->R.rdx);
break;
case SYS_SEEK:
check_address(f->R.rdi);
seek(f->R.rdi, f->R.rsi);
break;
case SYS_TELL:
check_address(f->R.rdi);
tell(f->R.rdi);
break;
case SYS_CLOSE:
check_address(f->R.rdi);
close(f->R.rdi);
break;
default:
thread_exit();
break;
}
}
리턴 값이 있는 시스템 콜 함수는 f->R.rax에 그 리턴 값을 저장해준다.
+ 각 함수 실행 전 check_address() 함수로 주소유효성 검사를 한다. 포인터가 가리키는 주소가 사용자 영역(0x8048000~0xc0000000)인지 확인하고 유저 영역을 벗어난 영역일 경우 프로세스 종료(exit(-1)) 시킨다.
void check_address(void *addr)
{
if(!is_user_vaddr(addr)){
exit(-1);
}
}
다음 포스팅부터 각 시스템콜 함수 구현을 확인 해보자~!