Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
Tags
- 사이드프로젝트
- 핀토스
- 나만무
- CSS
- 시스템콜
- 크래프톤정글
- 백준
- 티스토리챌린지
- Flutter
- userprog
- 자바스크립트
- 리액트
- Java
- defee
- corou
- 소켓
- pintos
- Vue.js
- HTML
- 크래프톤 정글
- 오블완
- TiL
- JavaScript
- 스택
- 자바
- 4기
- 큐
- 알고리즘
- 모션비트
- 코드트리
Archives
- Today
- Total
미새문지
pintOS - project2(Userprog) syscall.c 본문
728x90
syscall.c
< macro >
더보기
#define MSR_STAR 0xc0000081 /* 세그먼트 셀렉터 MSR, 64비트 모드로 전환할 때 사용되는 셀렉터를 저장 */
#define MSR_LSTAR 0xc0000082 /* 롱 모드 SYSCALL 목표 주소를 저장하는 MSR */
#define MSR_SYSCALL_MASK 0xc0000084 /* 실행 시 EFLAGS 레지스터에 적용될 마스크를 저장한다. */
MSR_STAR (0xc0000081) : 시스템 콜이나 리턴 시 CS와 SS 세그먼트 레지스터를 로드하는데 사용
MSR_LSTAR 0xc0000082 : 64비트에서 syscall 명령어가 실행될 때, CPU는 이 레지스터에 저장된 주소로 점프MSR_SYSCALL_MASK 0xc0000084 : syscall이 실행될 때 일부 EFLAGS 비트를 클리어하는 데 사용된다.
< find_file_descriptor >
더보기
// 파일 디스크립터(fd)에 해당하는 구조체를 찾아 반환한다.
struct file_descriptor *find_file_descriptor(int fd) {
// 리스트 포인터 fd_table에 현재 스레드의 fd_table을 저장한다.
struct list *fd_table = &thread_current()->fd_table;
// fd_table이 없거나 fd가 1보다 작으면 종료
ASSERT(fd_table != NULL);
ASSERT(fd > 1);
// fd_table이 비어있으면 NULL반환
if (list_empty(fd_table))
return NULL;
struct file_descriptor *file_descriptor;
struct list_elem *e = list_begin(fd_table); // fd_table의 시작 노드를 가져온다.
ASSERT(e != NULL);
// fd_table의 꼬리까지 순회
while (e != list_tail(fd_table)) {
// file_descriptor에서 e와 같은 fd_elem을 가져온다.
file_descriptor = list_entry(e, struct file_descriptor, fd_elem);
// file_descriptor의 fd가 인자로 받아온 fd와 동일하면 file_descriptor를 반환
if (file_descriptor->fd == fd) {
return file_descriptor;
}
e = list_next(e); // e에 리스트의 다음 노드를 저장
}
return NULL;
}
< syscall_init >
더보기
// 시스템 호출을 초기화
void
syscall_init (void) {
/* MSR_STAR 레지스터에 사용자 모드와 커널 모드 사이에서 전환될 때 사용되는
세그먼트 셀렉터 값을 설정한다. */
write_msr(MSR_STAR, ((uint64_t)SEL_UCSEG - 0x10) << 48 |
((uint64_t)SEL_KCSEG) << 32);
/* MSR_LSTAR 레지스터에 syscall_entry 함수의 주소를 설정한다.
(시스템 호출이 발생했을 때 실행될 함수를 지정하는 역할) */
write_msr(MSR_LSTAR, (uint64_t) syscall_entry);
/* The interrupt service rountine should not serve any interrupts
* until the syscall_entry swaps the userland stack to the kernel
* mode stack. Therefore, we masked the FLAG_FL.
* 인터럽트 서비스 반올림은 인터럽트 서비스를 제공해서는 안 됩니다
* syscall_entry가 userland 스택을 커널 모드 스택으로 스왑할 때까지. 따라서 FLAG_FL을 마스킹했습니다.*/
write_msr(MSR_SYSCALL_MASK,
FLAG_IF | FLAG_TF | FLAG_DF | FLAG_IOPL | FLAG_AC | FLAG_NT);
// 파일 시스템에 대한 접근을 동기화하기 위해 lock을 초기화한다.
lock_init(&filesys_lock);
}
< syscall_handler >
더보기
// 시스템 호출을 받기 위한 핸들러
void
syscall_handler (struct intr_frame *f) {
struct thread *t = thread_current();
t->tf = *f;
// 유효하지 않은 주소라면 isnotvaddr을 출력하고 스레드 종료
if(!is_user_vaddr(f->rsp)){
printf("isnotvaddr\n");
thread_exit();
}
// 주소가 커널 주소에 속하거나 음수인 경우 smaller를 출력하고 스레드 종료
else if(f->rsp > KERN_BASE || f->rsp < 0){
printf("smaller\n");
thread_exit();
}
// 다음 명령어의 주소를 계산 후, 위의 두 주소검사를 수행해 걸린다면 third condition을 출력하고 스레드 종료
int addr = (f->rsp + 8);
if (!is_user_vaddr(addr) || (addr > KERN_BASE || addr<0)) {
printf ("third condition\n");
thread_exit();
}
/* 받아온 인자대로 시스템 호출을 올바르게 수행하기 위해 switch문 실행.
받아온 인자에 맞게 각 시스템 호출을 올바른 매개변수를 전달해 실행.
f->R.rax 값에 담는 것은 void를 제외한 return값이 존재하는 함수만 */
switch(f->R.rax){
case SYS_HALT:
halt();
break;
case SYS_EXIT:
exit(f->R.rdi);
break;
case SYS_FORK:
f->R.rax = fork(f->R.rdi, f);
break;
case SYS_EXEC:
f->R.rax = exec(f->R.rdi);
break;
case SYS_WAIT:
f->R.rax = wait(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;
case SYS_OPEN:
f->R.rax = open(f->R.rdi);
break;
case SYS_FILESIZE:
f->R.rax = filesize(f->R.rdi);
break;
case SYS_READ:
f->R.rax = read(f->R.rdi,f->R.rsi,f->R.rdx);
break;
case SYS_WRITE:
f->R.rax = write(f->R.rdi,f->R.rsi,f->R.rdx);
break;
case SYS_SEEK:
seek(f->R.rdi,f->R.rsi);
break;
case SYS_TELL:
f->R.rax = tell(f->R.rdi);
break;
case SYS_CLOSE:
close(f->R.rdi);
break;
default:
break;
}
}
< halt >
더보기
// 핀토스 종료
void halt(void)
{
// 강제 종료
power_off();
}
< exit >
더보기
// 현재 유저 프로그램 종료 (status를 반환함)
void exit(int status)
{
// 현재 스레드의 종료 상태에 인자로 받아온 status로 변경
thread_current()->exit_status = status;
// 스레드 종료
thread_exit();
}
< fork >
더보기
// 프로세스를 복제하는 함수
tid_t fork (const char *thread_name, struct intr_frame *f){
// 인자로 받아온 스레드 이름을 process_fork에 전달한 값을 반환
return process_fork(thread_name, f);
}
< exec >
더보기
// 현재 프로세스를 file로 바꿈
int exec (const char *file){
// pml4_get_page : 주어진 가상 주소에 해당하는 페이지를 현재 스레드의 페이지 테이블에서 찾는다.
/* 이 함수가 NULL을 반환하거나 file이 NULL이거나, file이 유효한 사용자 가상 주소가 아니면 -1을 반환 후 종료 */ */
if(pml4_get_page(thread_current()->pml4, file) == NULL || file == NULL || !is_user_vaddr(file))
exit(-1);
char* file_in_kernel;
file_in_kernel = palloc_get_page(PAL_ZERO); // PAL_ZERO는 할당된 페이지를 0으로 초기화한다는 뜻
// 할당된 페이지가 없으면 exit함수에 -1을 보냄으로써 종료
if (file_in_kernel == NULL)
exit(-1);
// 인자로 받은 file을 최대 PGSIZE만큼 file_in_kernel에 복사한다.
strlcpy(file_in_kernel, file, PGSIZE);
// process_exec에 페이지를 보내서 -1이 반환되면 exec함수도 -1을 반환
if (process_exec(file_in_kernel) == -1)
return -1;
}
< wait >
더보기
// 자식 프로세스 tid가 끝날때까지 기다림 & 자식프로세스의 status를 반환함
int wait (tid_t t)
{
// process_wait에 thread_id인 tid를 매개로 보내 반환된 값을 반환
return process_wait(t);
}
< create >
더보기
// file이라는 파일을 만들고, 성공시 true 반환
// 파일 생성은 해당 파일을 열지는 않음. 열기 위해서는 open을 사용
// 메인 쓰레드의 fd_table 리스트에 할당
bool create (const char *file, unsigned initial_size)
{
// 가상메모리 주소에 해당하는 물리메모리 주소를 확인하고, 커널의 가상메모리 주소를 반환함
if(pml4_get_page(thread_current()->pml4, file) == NULL || file == NULL || !is_user_vaddr(file) || *file == '\0')
exit(-1);
// filesys_create로 file과 file크기를 보내서 생성 여부를 success에 저장
// 파일의 동시성 문제를 막기 위해 lock을 사용하여 현재 파일만 관리할 수 있게 함
lock_acquire(&filesys_lock);
bool success = filesys_create(file, initial_size);
lock_release(&filesys_lock);
// 파일의 생성 여부를 반환
return success;
}
< remove >
더보기
// file이라는 파일을 삭제
// 성공시 true 반환
bool remove (const char *file)
{
// 가상메모리 주소에 해당하는 물리메모리 주소를 확인하고, 커널의 가상메모리 주소를 반환함
if(pml4_get_page(thread_current()->pml4, file) == NULL || file == NULL || !is_user_vaddr(file) || *file == '\0')
exit(-1);
// create처럼 file이 제거되었는지의 성공 여부를 success에 담고 동시성 문제를 위해 lock을 사용
lock_acquire(&filesys_lock);
bool success = filesys_remove(file);
lock_release(&filesys_lock);
// file 제거 여부를 반환
return success;
}
< open >
더보기
// file이라는 파일을 연다
// fd반환
int open (const char *file)
{
// 메모리 누수를 위해 파일 생성을 126개로 제한했다.(multi-oom 테스트를 통과하기 위한 제한 조건)
// 현재 스레드의 마지막 생성 fd가 126이면 스레드를 종료한다.
if (thread_current()->last_created_fd == 126) {
exit(126);
}
// 가상메모리 주소에 해당하는 물리메모리 주소를 확인하고, 커널의 가상메모리 주소를 반환함
if(pml4_get_page(thread_current()->pml4, file) == NULL || file == NULL || !is_user_vaddr(file))
exit(-1);
// 동시성 문제를 위해 lock으로 실행 코드를 감싸준다.
lock_acquire(&filesys_lock);
struct file *open_file = filesys_open(file); // file을 인자로 filesys_open함수를 사용해 변수에 file을 저장한다.
int fd = -1; // 첫 fd를 -1로 초기화
// 파일이 열리지 않았다면 lock을 해제하고 -1(오류)인 fd를 반환
if(open_file == NULL){
lock_release(&filesys_lock);
return fd;
}
fd = process_add_file(open_file); // 오픈한 파일을 fd_table에 추가한다.
// fd가 -1이라면(process_add_file에서 file을 추가 못했다면 fd의 처음값인 -1이 저장되있다.) 파일 닫기
if (fd == -1)
file_close(open_file);
lock_release(&filesys_lock); // 얻어논 lock을 다시 해제
return fd; // fd_table에 저장된 fd를 반환
}
< filesize >
더보기
// 파일 크기를 반환
int filesize (int fd)
{
// 받아온 인자 fd를 매개로 find_file_descriptor에서 반환받은 파일 디스크립터를 저장
struct file_descriptor *file_desc = find_file_descriptor(fd);
// 받아오지 못했다면 -1을 반환(에러)
if(file_desc == NULL)
return -1;
// 받아왔다면 file_length에 파일디스크립터의 파일을 보내 크기를 가져와 반환
return file_length(file_desc->file);
}
< read >
더보기
// fd에 맞는 파일을 읽어온다.
int read (int fd, void *buffer, unsigned size)
{
if(pml4_get_page(thread_current()->pml4, buffer) == NULL || buffer == NULL || !is_user_vaddr(buffer) || fd < 0)
exit(-1);
struct thread *curr = thread_current();
struct list_elem *start;
off_t buff_size;
// fd가 0이면(표준 입력 상태) input_getc()를 실행
// input_getc : 입력 버퍼에서 입력된 키를 찾는 함수, 버퍼가 비어있으면 입력될 때까지 대기
if (fd == 0)
{
return input_getc();
}
// fd가 0보다 작거나 없거나 1일 때(에러거나 표준 출력일 때) 스레드 종료
else if (fd < 0 || fd == NULL || fd == 1)
{
exit(-1);
}
// bad-fd는 page-fault를 일으키기 때문에 page-fault를 처리하는 함수에서 확인
// 즉, 올바르게 가져온 파일 fd만 이 조건문에 타게 된다.
else
{
// fd_table 처음부터 끝까지 돌며 read_fd에 파일디스크립터에서 fd 에 맞는 요소를 가져오기
for (start = list_begin(&curr->fd_table); start != list_end(&curr->fd_table); start = list_next(start))
{
struct file_descriptor *read_fd = list_entry(start, struct file_descriptor, fd_elem);
// 가져온 fd 가 인자로 받은 fd 와 동일하면
if (read_fd->fd == fd)
{
// buff_size에 file_read로 읽어온 바이트 수를 저장해 반환한다.
lock_acquire(&filesys_lock);
buff_size = file_read(read_fd->file, buffer, size);
lock_release(&filesys_lock);
}
}
}
return buff_size;
}
< write >
더보기
// 선언한 버퍼에서 데이터를 읽어와 지정 대상에 쓰는 역할
int write (int fd, const void *buffer, unsigned size)
{
if(pml4_get_page(thread_current()->pml4, buffer) == NULL || buffer == NULL || !is_user_vaddr(buffer) || fd < 0)
exit(-1);
struct thread *curr = thread_current();
struct list_elem *start;
// fd == 1이라는 의미는 표준 출력을 의미함. 따라서 화면에 입력된 데이터를 출력하는 함수 pufbuf를 호출.
// putbuf 함수는 buffer에 입력된 데이터를 size만큼 화면에 출력하는 함수.
// 이후 버퍼의 크기 -> size를 반환한다.
// fd == 0 과 fd == 1은 표준 입출력을 의미하는 파일 식별자이기 때문에 해당되는 파일이 존재하지 않는다.
// 따라서 정상적인 write가 이루어지지 않는다. fd == 1이면 write 함수의 반환값은 0임.
if (fd == 1)
{
putbuf(buffer, size);
return size;
}
else if (fd < 0 || fd == NULL)
{
exit(-1);
}
for (start = list_begin(&curr->fd_table); start != list_end(&curr->fd_table); start = list_next(start))
{
struct file_descriptor *write_fd = list_entry(start, struct file_descriptor, fd_elem);
// 작성할 fd가 인자 fd와 동일할 시 작성할 파일 바이트수를 반환한다.
if (write_fd->fd == fd)
{
lock_acquire(&filesys_lock);
// 이 부분 빼고는 read와 코드가 다른게 별로 없다.
off_t write_size = file_write(write_fd->file, buffer, size);
lock_release(&filesys_lock);
return write_size;
}
}
}
< seek >
더보기
// 열려있는 fd에서 다음에 읽고 쓸 바이트 위치를 pos 위치로 변경해준다.
// 기존에 작성되있던 함수
void seek (int fd, unsigned position)
{
struct thread *curr = thread_current();
struct list_elem *start;
// fd_table 리스트를 돌며 가져온 fd가 인자fd와 같으면 file_seek함수를 실행해 새 pos값을 반환
for (start = list_begin(&curr->fd_table); start != list_end(&curr->fd_table); start = list_next(start))
{
struct file_descriptor *seek_fd = list_entry(start, struct file_descriptor, fd_elem);
if (seek_fd->fd == fd)
{
return file_seek(seek_fd->file, position);
}
}
}
< tell >
더보기
// 열려있는 fd에서 다음에 읽고 쓸 바이트 위치를 알려준다.
// tell함수도 이미 구현되어 있다.
unsigned tell (int fd)
{
struct thread *curr = thread_current();
struct list_elem *start;
// fd_table 리스트를 돌며 가져온 fd가 인자fd와 같으면 file_tell을 실행해 위치값을 반환
for (start = list_begin(&curr->fd_table); start != list_end(&curr->fd_table); start = list_next(start))
{
struct file_descriptor *tell_fd = list_entry(start, struct file_descriptor, fd_elem);
if (tell_fd->fd == fd)
{
return file_tell(tell_fd->file);
}
}
}
< close >
더보기
// 열려있는 fd를 닫아준다
void close (int fd) {
struct thread *curr = thread_current();
struct list_elem *start;
// 현재 스레드의 fd_table을 순회하며 닫을 fd와 인자 fd가 같으면 파일을 닫고 리스트에서 삭제한다.
for (start = list_begin(&curr->fd_table); start != list_end(&curr->fd_table); start = list_next(start))
{
struct file_descriptor *close_fd = list_entry(start, struct file_descriptor, fd_elem);
if (close_fd->fd == fd)
{
file_close(close_fd->file);
list_remove(&close_fd->fd_elem);
}
}
return;
}
< process_add_file >
더보기
// 인자로 받은 f를 실행중인 스레드의 fd_table에 추가한다.
int process_add_file(struct file *f)
{
struct thread *curr = thread_current();
struct file_descriptor *new_fd = malloc(sizeof(struct file_descriptor));
// 현재 스레드의 fd가 126 이상이면 -1 반환(multi-oom, 메모리 누수를 막기 위함)
if (curr->last_created_fd >= 126) {
return -1;
}
curr->last_created_fd += 1; // 현재 스레드의 fd값을 1 증가
new_fd->fd = curr->last_created_fd; // fd에 현재 마지막 fd를 넣기
new_fd->file = f; // 파일 디스크립터의 file에 인자 f를 넣기
list_push_back(&curr->fd_table, &new_fd->fd_elem); // fd_table에 마지막fd의 요소를 넣기
// 파일 디스크립터의 fd를 반환
return new_fd->fd;
}
728x90
'크래프톤 정글 > pintOS' 카테고리의 다른 글
pintOS - project2(Userprog) process.c (1) | 2024.03.30 |
---|---|
pintOS - Project 2 Userprog WIL (2) | 2024.03.23 |
pintOS - project1(Thread) synch.c (2) | 2024.03.12 |
pintOS - project1(Thread) thread.c - mlfqs (3) | 2024.03.11 |
pintOS - project1(Thread) thread.c (1) | 2024.03.11 |