
2025.05.21
오늘한 내용 : PintOS - Project2: UserProgram - User Memory, System calls
- 기본 System calls 구현 (halt, exit, wirte (fd=1), wait 기본형태)
사용자 메모리 접근 보호
WEEK 10 : 정글 끝까지(PintOS) - UserProgram
main() 함수 내에서 시스템 콜을 호출했을 때, 그 호출이 커널에서 어떻게 처리되는지를 담당하는 부분.syscall_handler()가 호출된다. 이 핸들러는 시스템 콜 번호를 읽고, 그에 해당하는 커널 함수를 호출하여 작업을 수행한다.NULL, 커널 영역 주소, 혹은 매핑되지 않은 가상 주소를 넘길 수 있다.write(1, NULL, 100) 같이 잘못된 buffer를 넘기면, 커널이 그 포인터를 그대로 접근하면 page fault가 발생하고 운영체제 전체가 죽을 수 있다.유저가 준 포인터가 (1) 유저 공간에 속하고, (2) 실제 물리 페이지가 준비되어 있는” 경우에만 메모리 접근을 허용하고, 그렇지 않으면 exit(-1) 등으로 프로세스를 강제 종료
(1)void check_user_address(const void *uaddr);
(2)void check_user_buffer(char *buffer, size_t size);
check_user_address(const void *uaddr)!uaddr → NULL 이면 즉시 프로세스 종료!is_user_vaddr(uaddr) ⇒ 주소가 PHYS_BASE 이상(커널 영역)에 있으면 종료pml4_get_page(..., uaddr) == NULL ⇒가상→물리 매핑이 안 돼 있으면 종료check_user_buffer(char *buffer, size_t size)ptr 을 바이트 단위 주소로 보고ofs 만큼 오프셋을 늘려 가며check_user_address(addr) 호출PGSIZE) 남은 크기(left)만큼 ofs += left
void syscall_handler(struct intr_frame *f UNUSED){
int syscall_num = (int)f->R.rax;
switch (syscall_num)
{
case SYS_EXIT:
break;
case SYS_WRITE:
break;
case ....:
break;
default:
break;
}
}
"movq %1, %%rax \n" // 시스템콜 번호
"movq %2, %%rdi \n" // 첫 번째 인자
"movq %3, %%rsi \n" // 두 번째 인자
"movq %4, %%rdx \n" // 세 번째 인자
"syscall \n"
"movq %%rax, %0 \n" // 반환값
exit(status) 호출 → 레지스터에 SYS_EXIT와 status를 담고 syscall 실행sys_exit() 구현 필요 → thread_exit() 수행fd에 버퍼 buffer의 내용을 size만큼 출력한다.write(fd, buf, size) 호출 → SYS_WRITE, fd, buf, size를 담고 syscall 실행sys_write() 구현 필요 → fd == 1 일때 putbuf(), 나머지 추후 구현tid의 자식 프로세스가 종료될 때까지 대기(block)하고, 그 종료 상태(exit status)를 반환한다.wait(tid) 호출 → SYS_WAIT, tid를 담고 syscall 실행process_wait() 수정 필요halt() 호출 → 레지스터에 SYS_HALT를 담고 syscall 실행sys_halt() 구현 필요 → power_off() 호출