Adventure Time - Finn 3

새소식

운영체제

[Pintos-Kaist] Project2 - System Call(1) - (halt, exit, create, remove)

  • -

과제 목표

  • 시스템 콜 핸들러 및 시스템 콜(halt, exit, create, remove) 구현

 

과제 설명

  • 핀토스는 시스템 콜 핸들러가 구현되어 있지 않아 시스템 콜이 처리되지 않음.
  • 핀토스의 시스템 콜 메커니즘을 이해하고 시스템 콜 핸들러를 구현한다.
  • 시스템 콜(halt, exit, createm remove)을 구현하고 시스템 콜 핸들러를 통해 호출한다.

 

 

💡 시스템 콜

  • 시스템 콜은 운영 체제가 제공하는 서비스에 대한 프로그래밍 인터페이스입니다.
  • 시스템 콜은 커널모드에서 실행되고, 처리 후 사용자 모드로 복귀됩니다.
  • 시스템 콜의 핵심은 시스템 콜 호출 시, 하드웨어 인터럽트가 발생하여 실행모드 의 우선순위가 특수모드로 상향조정 되는 것입니다.

 

시스템 콜 호출 과정(리눅스)

 

 

시스템 콜 호출 과정(핀토스)

 

  1. 유저 프로그램에서 write() 함수를 호출한다. 
  2. write() 함수는 시스템 콜로, 인자를 유저 스택에 넣고서 커널로 진입한다. 이때 스택 포인터는 인자가 들어간 영역을 가리킨다.
  3. 인터럽트 벡터 테이블에 가면 주소별로 어떤 종류의 인터럽트를 실행해야 하는지가 맵핑되어 있다. 이 중 0x30은 시스템 콜 핸들러를 호출하는 주소이다. 따라서 syscall_handler()를 호출한다.
  4. syscall_handler()에서는 유저 스택에 해당하는 넘버가 system call number로 해당하는 시스템콜을 실행한다.

 

 

💡 시스템 콜 핸들러

  • 시스템 콜 번호를 이용하여 시스템 콜 핸들러에서 해당 시스템 콜을호출합니다.

     

시스템 콜 핸들러

 

 

 

  • 추가로 시스템 콜 관련 자세한 내용은 아래 포스트에서 확인하시면 됩니다.

- https://yunchan97.tistory.com/68

 

[운영체제] 인터럽트 & 시스템 콜(Interrupt, System Call)

운영체제의 동작 과정 (Dual-Mode Execution) - 운영체제는 기본적으로 사용자에게 인터페이스를 제공하는 User Mode와 기기들을 직접 관리하는 Kernel Mode로 구분된다. User Mode : 일반적인 응용프로그램이

yunchan97.tistory.com

 

 

 

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);
}

 

Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.