사용자 프로그램을 커널 위에서 실행 가능하게 만드는 것이 목적
사용자 프로그램은 커널이 아닌 비특권 모드에서 실행되는 일반적인 프로그램. Linux로 치면 우리가 작성해서 gcc로 컴파일하고 실행하는 C 프로그램들.
Pintos에서는 이런 사용자 프로그램들을 실행시킬 수 있도록 운영체제를 확장해나가는 작업을 진행
exit(), write(), read() 등의 기본 함수들은 시스템 콜int 0x30)로 커널에 제어를 넘긴다.threads/interrupt.c의 인터럽트 핸들러에서 처리된다main(int argc, char **argv) 형식으로 인자를 전달하기 위해, 커널은 프로세스의 스택을 직접 구성해야 한다..open(), read(), write() 등에서 사용하는 정수형 핸들.process_wait() 구현을 위해, 부모가 자식의 종료 상태를 기다릴 수 있어야 한다| 테스트 이름 | 설명 |
|---|---|
args-none | 인자가 없는 실행 확인 |
args-single | 인자 1개 전달 확인 |
args-multiple | 여러 개 인자 전달 확인 |
args-dbl-space | 중복 공백이 있을 때 인자 처리 확인 |
args-many | 많은 수의 인자 처리 테스트 |
| 테스트 이름 | 설명 |
|---|---|
halt | halt() 호출 시 시스템 종료 확인 |
exit | exit(status)가 정상 작동하고 부모가 상태 수신하는지 확인 |
wait-simple | 기본적인 wait() 동작 확인 |
wait-twice | 동일 자식에 대해 두 번 wait 시 -1 반환 |
wait-killed | 자식이 예외로 종료된 경우 wait() 결과 -1 확인 |
| 테스트 이름 | 설명 |
|---|---|
exec-once | exec()로 한 번 실행 후 종료 여부 확인 |
exec-arg | exec() 호출로 인자 전달 여부 확인 |
exec-missing | 존재하지 않는 파일을 exec() 시도 시 실패 처리 |
exec-bad-addr | 잘못된 포인터를 exec()에 넘길 경우 예외 처리 확인 |
exec-read | 실행 중 프로그램이 자신의 파일 읽기 시도 가능 여부 |
| 테스트 이름 | 설명 |
|---|---|
create | 파일 생성 시스템 콜 create() 테스트 |
open | 파일 열기 테스트 (open()) |
close | 파일 디스크립터 닫기 (close()) |
read-normal | 정상 read() 호출 후 내용 읽기 확인 |
read-bad-ptr | 잘못된 포인터로 읽기 요청 시 예외 발생 |
read-stdin | read(0, ...)을 통한 입력 읽기 처리 |
write-normal | write()로 파일 또는 stdout 출력 확인 |
write-bad-ptr | 잘못된 포인터로 출력 요청 시 예외 처리 |
write-stdout | write(1, ...)으로 콘솔 출력 확인 |
filesize | filesize(fd)로 파일 크기 확인 |
seek, tell | 파일 오프셋 조작 및 현재 위치 반환 확인 |
| 테스트 이름 | 설명 |
|---|---|
sc-boundary | 포인터가 페이지 경계에 걸칠 때 처리 |
sc-bad-addr | 주소가 물리 메모리 외일 때 예외 발생 확인 |
sc-null | NULL 포인터 접근 처리 확인 |
sc-bad-sp | 잘못된 스택 포인터로 시스템 콜 접근 시 처리 |
rox-simple, rox-child, rox-multichild | 실행 중인 파일에 write() 시도 시 거부 여부 확인 |
| 테스트 이름 | 설명 |
|---|---|
multi-recurse, exit-recurse | 깊은 재귀 호출과 정상 종료 여부 확인 |
multi-oom | 많은 프로세스 생성 시 메모리 부족 대응 테스트 |
| 파일명 | 설명 |
|---|---|
process.c / process.h | 프로세스 생성과 로딩, 종료 처리를 담당합니다. ELF 실행 파일을 로드하고 초기 스택을 설정하는 코드가 들어 있습니다. 인자 전달도 이 파일에서 구현합니다. |
syscall.c / syscall.h | 시스템 콜 인터페이스 처리: 유저 프로그램이 커널 기능을 요청할 때 인터럽트를 받아 분기 처리하는 메인 로직입니다. syscall_handler()가 핵심입니다. |
exception.c / exception.h | 예외 처리: 유저 프로그램이 잘못된 메모리에 접근했을 때 발생하는 page fault 등을 처리합니다. page_fault() 수정 가능성이 있습니다. |
pagedir.c / pagedir.h | 페이지 테이블 관리 유틸리티: 유저 메모리 접근 시 페이지가 유효한지 확인할 때 사용합니다. 직접 수정은 드물지만 함수 호출은 자주 합니다. |
gdt.c / gdt.h | Global Descriptor Table 설정: 세그먼트 기반 보호 모드 설정에 필요한 코드입니다. 수정할 필요는 거의 없습니다. |
tss.c / tss.h | Task-State Segment 설정: 인터럽트 진입 시 유저에서 커널 스택으로 전환하기 위한 구조입니다. 마찬가지로 읽기만 하면 되고, 수정하지 않아도 됩니다. |
process_exec)syscall.c)deny_write)dup2() 지원userprog 디렉토리에서 작업을 시작합니다.make를 통해 빌드하고, 테스트를 실행할 수 있는지 확인합니다.userprog/syscall.csyscall-read-bad-ptrsyscall-write-bad-ptruserprog/syscall.chalt: Pintos 종료exit: 현재 프로세스 종료 및 상태 반환write: 콘솔 출력 구현haltexitwrite-normalwrite-bad-ptruserprog/process.cprocess_execute에서 프로그램 이름과 인자를 분리setup_stack에서 스택에 인자들을 올바르게 배치args-singleargs-multipleargs-manyuserprog/process.cprocess_wait: 자식 프로세스의 종료를 대기하고 상태 반환process_exit: 프로세스 종료 시 자원 정리wait-simplewait-twicewait-killeduserprog/syscall.c, filesys/file.ccreate, remove, open, filesize, read, write, seek, tell, close 등의 시스템 콜 구현open-missingclose-twiceread-normalwrite-normaluserprog/syscall.copen-twiceclose-stdinclose-stdoutuserprog/syscall.c, threads/synch.cmulti-oomread-bad-ptrwrite-bad-ptrmake checkpintos -q run 'test-name' 예를 들어, args-single 테스트를 실행하려면:pintos -q run 'args-single'Argument Passing (인자 전달)
• 모든 사용자 프로그램은 실행 초기에 argc, argv를 읽기 때문에 스택에 올바르게 인자들을 설정하지 않으면 페이지 폴트(page fault) 가 발생하게 됩니다.
• 간단한 테스트를 위해 *esp = PHYS_BASE - 12;로 변경하여 시작할 수도 있어요.
User Memory Access (사용자 메모리 접근)
• 사용자 스택에서 시스템 콜 번호 및 인자를 읽으려면, 사용자 메모리에 접근할 수 있어야 합니다.
• get_user()와 put_user() 함수로 안전하게 접근하도록 구현하세요.
System Call Infrastructure 구축
• 시스템 콜 번호를 읽고, 해당하는 핸들러로 디스패치하는 기본 골격을 syscall.c에 구축합니다.
• 이 구조를 먼저 만들어 놓으면 이후 syscall 들을 하나씩 붙이기 쉬워요.
exit 시스템 콜
• 모든 프로그램은 종료 시 exit()을 호출하므로, 가장 먼저 구현되어야 할 syscall 중 하나입니다.
write 시스템 콜
• 대부분의 테스트 프로그램은 콘솔 출력이 필요하기 때문에, write() (특히 fd 1, 즉 콘솔)을 지원해야 정상 작동합니다.
process_wait() 무한 루프화
• 초기에는 process_wait()를 무한 루프로 구현하여, 부모 프로세스가 자식 프로세스를 기다리는 상황을 단순화하세요.
항상 잘 보고있습니다. 감사합니다 지성님.