
valid_pointer는 앞선 0721 글의 [구현 2-2]에서 만들어 둔, 포인터 확인용 함수임에 유의.// 커널쪽: userprog/syscall.c
// [구현 2-2] 포인터가 valid한지 확인하는 함수를 만든다.
bool valid_pointer (void *p){
// 널 주소-/ 커널 영역의 주소 / 매핑되지 않은 페이지
if (p == NULL || is_kernel_vaddr(p) || pml4_get_page(thread_current() -> pml4, p) == NULL){
thread_current() -> exit_code = -1;
thread_exit();
};
}
halt[구현 3] halt 구현: 핀토스를 종료한다.
include/threads/init.h에 선언된 power_off() 함수를 사용하면 끝. 참 쉽죠?// 클라이언트쪽: lib/user/syscall.c
void halt (void);
// 커널쪽: userprog/syscall.c
#include "threads/init.h"
case SYS_HALT:
/* Halt the operating system. */
// [구현 3] 핀토스를 종료. 매우 쉽죠?
power_off();
break;
write[구현 4-1] write로 콘솔 출력하기 구현
write는 콘솔 창에 출력하는 경우와, 파일에 출력하는 경우에 따라 구현방식이 달라짐fd == 1이면 콘솔 창에 출력됨// 클라이언트쪽: lib/user/syscall.c
// fd == 1인 경우, buffer의 내용을 size만큼 콘솔창에 출력한다.
int write (int fd, const void *buffer, unsigned size);
fd는 f -> R.rdi, 둘째 인자 buffer는 f -> R.rsi, 셋째 인자 size는 f -> R.rdx에 위치함에 유의할 것putbuf 함수를 이용해, buffer의 내용을 size만큼 출력하게끔 구현putbuf는 pintos/include/lib/kernel/stdio.h에 존재하는데, #include <stdio.h>에 이미 포함됨. 추가로 인클루드할 필요 없음. // 커널쪽: userprog/syscall.c
case SYS_WRITE:
/* Write to a file. */
// [구현 4] 콘솔 창에다 출력하는 부분만 일단 우선 구현 가능.
valid_pointer(f -> R.rsi);
if ((int)(f -> R.rdi) == 1){
putbuf((char *)(f -> R.rsi), (size_t)(f -> R.rdx));
}
break;
write는 나중에 구현해보아요들레이요exit[구현 5] exit로 프로세스 terminate하기
// 클라이언트쪽: lib/user/syscall.c
void exit (int status);
thread_exit()를 호출해서 종료시키면 되는데, termination message를 출력해야 함status를 포함시켜야 함thread_exit()은 process_exit()을 호출하고, process_exit()에서 termination message 출력이 이루어짐process_exit은 인자를 받지 않아, 바로 status 값을 전달할 순 없음// include/threads/thread.h
// 구조체 내 다른 멤버들은 생략.
struct thread {
#ifdef USERPROG
int exit_code; /* exit 시 보여줄 코드 번호
#endif
}
struct thread에 int exit_code 멤버를 두어, 앞선 status를 종료하는 용도로 사용// 커널쪽: userprog/syscall.c
case SYS_EXIT:
/* Terminate this process. */
// [구현 5-1] thread 내 exit_code 멤버에 status 저장
thread_current() -> exit_code = (int)(f -> R.rdi);
thread_exit();
break;
exit_code 멤버에 status (첫 인자이므로 rdi)를 저장하고// 커널쪽: userprog/process.c
void process_exit (void) {
// [구현 5-2] exit 및 exit 메시지 띄우기 구현
struct thread *curr = thread_current ();
printf("%s: exit(%d)\n", curr -> name, curr -> exit_code);
process_cleanup ();
}
process_exit에 앞서 저장한 exit_code 멤버를 이용하여, termination 메시지를 출력시키기exec[구현 6] exec로 새로운 프로그램 실행
int exec (const char *file);
file에는 "echo x y z"와 같은 커맨드 라인이 주어짐. 실행 성공 시 반환값이 없음, 실패 시 -1을 반환.process_exec 함수를 사용하면 됨.// userprog/process.c 내 process_exec 함수
int process_exec (void *f_name) {
char *file_name = f_name;
//조금 많이 생략
palloc_free_page (file_name);
}
process_exec에서 매개변수로 받은 f_name 주소에선 palloc_free_page로 메모리 할당 해제가 이루어짐.f_name도 palloc으로 할당된 페이지의 주소여야 한다는 사실....case SYS_EXEC:
/* Switch current process. */
// [구현 6] 새로운 프로세스 실행
valid_pointer(f -> R.rdi);
char *f_name = palloc_get_page(0);
strlcpy(f_name, f->R.rdi, PGSIZE);
f -> R.rax = process_exec(f_name);
thread_exit();
break;
palloc_get_page로 페이지를 할당한 뒤, 해당 페이지에 f_name(첫 인자이므로 rdi)를 복사해 줌process_exec에 인자로 보내주고, 반환값은 rax 레지스터에 저장-1만 리턴하고 바로 반환해야 함. 이를 위해 thread_exit()가 실행시켜 줌.
생일이셨나요? 축하드려요!