과제 목표
- 시스템 콜 핸들러 및 시스템 콜(halt, exit, create, remove) 구현
과제 설명
- 핀토스는 시스템 콜 핸들러가 구현되어 있지 않아 시스템 콜이 처리되지 않음.
- 핀토스의 시스템 콜 메커니즘을 이해하고 시스템 콜 핸들러를 구현한다.
- 시스템 콜(halt, exit, createm remove)을 구현하고 시스템 콜 핸들러를 통해 호출한다.
💡 시스템 콜
- 시스템 콜은 운영 체제가 제공하는 서비스에 대한 프로그래밍 인터페이스입니다.
- 시스템 콜은 커널모드에서 실행되고, 처리 후 사용자 모드로 복귀됩니다.
- 시스템 콜의 핵심은 시스템 콜 호출 시, 하드웨어 인터럽트가 발생하여 실행모드 의 우선순위가 특수모드로 상향조정 되는 것입니다.
- 유저 프로그램에서 write() 함수를 호출한다.
- write() 함수는 시스템 콜로, 인자를 유저 스택에 넣고서 커널로 진입한다. 이때 스택 포인터는 인자가 들어간 영역을 가리킨다.
- 인터럽트 벡터 테이블에 가면 주소별로 어떤 종류의 인터럽트를 실행해야 하는지가 맵핑되어 있다. 이 중 0x30은 시스템 콜 핸들러를 호출하는 주소이다. 따라서 syscall_handler()를 호출한다.
- syscall_handler()에서는 유저 스택에 해당하는 넘버가 system call number로 해당하는 시스템콜을 실행한다.
💡 시스템 콜 핸들러
-
시스템 콜 번호를 이용하여 시스템 콜 핸들러에서 해당 시스템 콜을호출합니다.
- 추가로 시스템 콜 관련 자세한 내용은 아래 포스트에서 확인하시면 됩니다.
- https://yunchan97.tistory.com/68
구현
1️⃣ void check_address(void *addr)
- 주소 값이 유저 영역에서 사용하는 주소 값인지 확인 하는 함수.
- 유저 영역을 벗어난 영역일 경우 프로세스 종료(exit(-1))
/* 주소 값이 유저 영역에서 사용하는 주소 값인지 확인 */
void check_address(void *addr){
struct thread *t = thread_current();
/* 인자로 받아온 주소가 유저영역의 주소가 아니거나 , 주소가 NULL이거나
해당 페이지가 존재하지 않을경우 프로그램 종료 */
if(!is_user_vaddr(addr) || addr == NULL)
exit(-1);
if(pml4_get_page(t->pml4, addr) == NULL)
exit(-1);
}
2️⃣ void syscall_handler(struct intr_frame *f UNUSED)
- 시스템 콜이 호출될 때 관리하는 syscall_handler 구현하기.
- ex) halt(), exit(), create(), remove() 등등
- syscall_handler를 호출할 때 인자 값 수에 맞게 인자 넣어주기.
- ✔️순서는 rdi, rsi, rdx 순서대로 인자 값을 넣어주는 것이고 특별한 값이 있는게 아니다.
void syscall_handler (struct intr_frame *f UNUSED) {
/* rax = 시스템 콜 넘버 */
int syscall_n = f->R.rax; /* 시스템 콜 넘버 */
switch (syscall_n)
{
case SYS_HALT:
halt();
break;
case SYS_EXIT:
exit(f->R.rdi);
break;
case SYS_FORK:
f->R.rax = fork(f->R.rdi, f);
break;
case SYS_EXEC:
f->R.rax = exec(f->R.rdi);
break;
case SYS_WAIT:
f->R.rax = wait(f->R.rdi);
break;
case SYS_CREATE:
f->R.rax = create(f->R.rdi, f->R.rsi);
break;
case SYS_REMOVE:
f->R.rax = remove(f->R.rdi);
break;
case SYS_OPEN:
f->R.rax = open(f->R.rdi);
break;
case SYS_FILESIZE:
f->R.rax = filesize(f->R.rdi);
break;
case SYS_READ:
f->R.rax = read(f->R.rdi, f->R.rsi, f->R.rdx);
break;
case SYS_WRITE:
f->R.rax = write(f->R.rdi, f->R.rsi, f->R.rdx);
break;
case SYS_SEEK:
seek(f->R.rdi, f->R.rsi);
break;
case SYS_TELL:
f->R.rax = tell(f->R.rdi);
break;
case SYS_CLOSE:
close(f->R.rdi);
}
}
① halt()
- halt()함수 호출 시 핀토스를 종료시키는 시스템 콜
- 핀토스를 종료시키는 함수 power_off()
/* pintos 종료시키는 시스템 콜 */
void halt(void){
power_off();
}
② exit()
- exit()은 현재 실행중인 프로세스만 종료시키는 시스템 콜
- 스레드를 종료시키는 함수 thread_exit()
- thread의 상태를 가져와야하니 thread의 구조체에 상태를 나타내는 exit_status 변수추가
- init_thread부분에 exit_status 0으로 초기화
/* 현재 프로세스를 종료시키는 시스템 콜*/
void exit(int status){
/* 종료 시 프로세스 이름 출력하고 정상적으로 종료시 status 0*/
struct thread *t = thread_current();
printf("%s: exit(%d)\n", t->name, status);
thread_exit();
}
③ create()
- create()는 파일을 생성하는 시스템 콜
- 파일 이름과 파일 사이즈를 인자 값으로 받아 파일을 생성하는 함수 filesys_create()
bool create (const char *file, unsigned initial_size){
/*주소 값이 유저 영역에서 사용하는 주소 값인지 확인*/
check_address(file);
/*파일 이름과 파일 사이즈를 인자 값으로 받아 파일 생성*/
return filesys_create(file, initial_size);
}
④ remove()
- create()는 파일을 생성하는 시스템 콜
- 파일 이름에 해당하는 파일을 제거하는 함수 filesys_remove()
bool remove (const char *file){
/*주소 값이 유저 영역에서 사용하는 주소 값인지 확인*/
check_address(file);
/*파일 이름에 해당하는 파일을 제거하는 함수*/
return filesys_remove(file);
}