이전 포스팅들에서 인자를 파싱했다. 이제 시스템 콜을 구현해 보겠다. 시스템 콜에 대한 것은 이전에 part.1에 담겨있다.
2025.05.19 - [크래프톤 정글] - [pintos] Week2~3: User Program Part.1
[pintos] Week2~3: User Program Part.1
1주 차에 Alarm Clock, Priority Scheduling과 같이 동기화와 스케줄링에 대해 다루었다면 2~3주 차는 User Program이 Pintos에서 돌아갈 수 있도록 구현을 진행한다.User Program을 OS에 로드하고, System Call을 통해 U
www.gowoong.com
우리는 그 중 (halt, exit, create, remove)를 먼저 구현해서 테스트 코드의 시작 부분을 먼저 검증하면서 진행하겠다.
1. syscall_handler() 함수
- userprog/syscall.c
시스템 콜을 호출할 때, 원하는 기능에 해당하는 시스템 콜 번호를 rax에 담는다. 그리고 시스템 콜 핸들러는 rax의 숫자로 시스템 콜을 호출하고, 해당 콜의 반환값을 다시 rax에 담아서 intr frame(인터럽트 프레임)에 저장한다.
/* The main system call interface */
void
syscall_handler (struct intr_frame *f UNUSED) {
switch (f->R.rax)
{
case SYS_HALT:
halt(); // 핀토스 종료
break;
case SYS_EXIT:
exit(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;
default:
exit(-1);
}
}
2. check_address() 함수
- userprog/syscall.c
- 주소 값이 유저 영역에서 사용하는 주소 값인지 확인
- 유저 영역을 벗어난 영역일 경우 프로세스 종료(exit(-1))
void
check_address (void *addr)
{
if (is_kernel_vaddr(addr) || addr == NULL || pml4_get_page(thread_current()->pml4, addr) == NULL)
exit(-1);
}
Pintos의 userprog 프로젝트에서 매우 중요한 보안 및 안정성 기능으로, 유저 프로그램이 잘못된 주소(커널 주소나 매핑되지 않은 주소)에 접근할 경우 이를 미리 감지하고 종료(exit) 시키기 위해 사용한다.
조건 | 의미 |
is_kernel_vaddr(addr) | 커널 영역 주소인지 확인. 유저가 커널 주소에 접근하려 하면 안 됨 |
addr == NULL | NULL 포인터 접근은 잘못된 접근이므로 종료 |
pml4_get_page(thread_current()->pml4, addr) == NULL | 현재 스레드의 페이지 테이블에서 해당 주소에 매핑된 실제 물리 주소가 없으면 → 접근 불가능한 페이지 |
이 함수를 통해 유저 프로그램이:
- 커널 메모리를 읽거나 쓰는 행위 차단
- 매핑되지 않은 주소에 접근해 Page Fault 발생시키는 것 방지
3. halt() 함수
- userprog/syscall.c
- 핀토스를 종료시키는 시스템 콜
void
halt(void)
{
power_off();
}
GitBook 설명: Pintos를 종료한다. power_off()를 호출하며, src/include/threads/init.h에 선언되어 있다. 이 시스템 콜은 디버깅에 유용하지만, 데드락 등 문제 원인을 분석할 기회를 잃게 되므로 최소한으로 사용해야 한다.
4. exit() 함수
- include/threads/thread.h
- exit(), wait()을 구현할 때 필요한 변수나 값을 구조체에 추가하고 초기화 한다.
uint64_t *pml4; /* Page map level 4 */
int exit_status;
- threads/thread.c
t->original_priority = t->priority;
t->niceness = NICE_DEFAULT;
t->recent_cpu = RECENT_CPU_DEFAULT;
/* 기존 구현 부 아래에 추가 */
t->exit_status = 0;
}
- userprog/syscall.c
- 현재 프로세스를 종료시키는 시스템 콜
- 종료 시 “프로세스 이름: exit(status)” 출력 (Process Termination Message)
- 정상적으로 종료 시 status는 0
- status : 프로그램이 정상적으로 종료됐는지 확인
void
exit(int status)
{
struct thread *t = thread_current();
t->exit_status = status;
printf("%s: exit(%d)\n", t->name, t->exit_status); // Process Termination Message
thread_exit();
}
GitBook 설명 : 현재 사용자 프로그램을 종료하고 커널에 status를 반환한다. 부모 프로세스가 wait()를 호출하면 이 status가 전달된다. 일반적으로 0은 성공, 0이 아닌 값은 에러를 의미한다.
5. create() 함수 구현
- userprog/syscall.c
- 파일을 생성하는 시스템 콜
- 성공 일 경우 true, 실패 일 경우 false 리턴
- file : 생성할 파일의 이름 및 경로 정보
- initial_size : 생성할 파일의 크기
bool
create(const char *file, unsigned initial_size)
{
check_address(file);
return filesys_create(file, initial_size);
}
GitBook 설명 : 크기 `initial_size`의 새 파일을 생성한다. 성공 시 `true`, 실패 시 `false` 반환. 생성은 열기와 다르다. 열려면 open() 호출 필요.
6. remove() 함수 구현
- userprog/syscall.c
- 파일을 삭제하는 시스템 콜
- file : 제거할 파일의 이름 및 경로 정보
- 성공 일 경우 true, 실패 일 경우 false 리턴
bool
remove(const char *file)
{
check_address(file);
return filesys_remove(file);
}
GitBook 설명 : 파일을 삭제한다. 열려 있든 닫혀 있든 상관없이 삭제 가능. 성공 시 true.
'크래프톤 정글' 카테고리의 다른 글
[pintos] Week2~3: User Program Part.6 - lock 적용 (1) | 2025.05.25 |
---|---|
[pintos] Week2~3: User Program Part.5 - 파일 디스크립터 (0) | 2025.05.25 |
[pintos] Week2~3: User Program Part.3 - 인자 파싱 (2) | 2025.05.20 |
[pintos] Week2~3: User Program Part.2 이론 - ELF 로딩 (1) | 2025.05.19 |
[pintos] Week2~3: User Program Part.1 이론 - 시스템 콜 (2) | 2025.05.19 |