목표

Implement user memory access

To implement syscalls, you need to provide ways to read and write data in user virtual address space. You don't need this ability when getting the arguments. However, when you read the data from the pointer provided as the system call's argument, you should proxied through this functionallity. This can be a bit tricky: what if the user provides an invalid pointer, a pointer into kernel memory, or a block partially in one of those regions? You should handle these cases by terminating the user process.

사용자 프로세스가 커널에게 시스템 콜을 이용해 어떤 동작을 요청할 때, 포인터도 같이 준다.

개선

첫 번째 방식을 사용해 해당 주소가 유효한 주소인지 아닌지를 판단한 다음 해당 주소에 접근(역참조)하도록 한다.

userprog/syscall.c/check_address() 구현

인자로 받은 주소 값이

  1. KERN_BASE보다 높은 값의 주소값을 가지는 경우
  2. 매핑되지 않은 주소인 경우

인지를 체크한 후, 만약 위의 두 경우에 해당된다면 프로세스를 종료한다.

void check_address(void *addr){
	if (!is_user_vaddr(addr) || pml4_get_page(thread_current->plm4, addr) == NULL)
		exit(1);
}

threads/vaddr.h/is_user_vaddr()

해당 주소가 커널 메모리 공간의 경계 KERN_BASE보다 밑에 있는지를 확인한다.

/* Returns true if VADDR is a user virtual address. */
#define is_user_vaddr(vaddr) (!is_kernel_vaddr((vaddr)))

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

userprog/mmu.c/pml4_get_page()