Krafton Jungle/5. PintOS

[PintOS 2주차] Day 6

munsik22 2025. 5. 20. 10:27

꽃보다 문식이

💥 pml4 이슈 발생

어제 write()까지 system call 기능을 구현했지만, pml4에서 assertion이 발생하는 에러가 발생했다.

Kernel PANIC at ../../threads/mmu.c:206 in pml4_activate():
assertion `is_kernel_vaddr(pml4 ? pml4 : base_pml4)' failed.

새로 작성한 구역을 주석 처리를 해도 문제가 해결되지 않아서, 이전의 커밋으로 돌아가서 다시 작업을 시작했다.

argument passing할 때 실행했던 유저 프로그램 args-single이 실행되지 않아 살펴보니 filesys.dsk가 초기화되어 있었다. 분명 argument passing을 구현할 때 디스크를 만들어주었는데 사라진 점이 이상하다.

$ ../../utils/pintos-mkdisk filesys.dsk 10
$ pintos -v --fs-disk=filesys.dsk -- -f -q
$ cp tests/userprog/args-single ./args-single
$ pintos -v -k --fs-disk=filesys.dsk -p args-single -- -f -q
$ pintos -v -k --fs-disk=filesys.dsk -- -q run 'args-single onearg'

🚨 Page fault 발생

args-single 테스트에서 출력이 제대로 나오는지 확인하기 위해 SYS_WRITE 일부를 구현했다.

case SYS_WRITE:                  /* Write to a file. */
	printf("%s", f->R.rsi);
	// f->R.rax = write(f->R.rdi, f->R.rsi, f->R.rdx);
	break;

그런데 SYS_WRITE를 설정해주니 (args) argv[0] = 'args-single'가 나와야 할 부분부터 Page Fault가 발생했다. f->R.rsi를 받는 데에서 문제가 생겼나 싶어 "write"를 출력하게 바꿔도 똑같이 세 번째 "write"가 출력되야 할 부분에서 PF가 발생했다.

위에서 rsi 부분을 잘 보자. rsprbp에는 유저 스택 메모리 주소값이 잘 들어가 있지만, rsi에는 이상한 값이 들어가 있다.

process_exec() {
    …
    _if.R.rsi = (uint64_t) argv;
    …
    argument_stack(&_if);
    hex_dump(_if.rsp, _if.rsp, USER_STACK - (uint64_t)_if.rsp, true);
}

기존에 설정한 _if.R.rsi는 커널 영역의 배열을 가리키고 있었기 때문에 rsi가 이상한 주소를 가리키고 있었던 것이다. 그래서 유저 스택을 쌓은 후에 다시 rsi 값을 유저 스택 상의 주소로 설정해 줘야 된다고 한다.

argument_stack(&_if);
_if.R.rsi = _if.rsp + sizeof(uintptr_t); // ← 코드 추가
hex_dump(_if.rsp, _if.rsp, USER_STACK - (uint64_t)_if.rsp, true);

이제 page fault가 발생하지 않고 잘 출력된다 😇


System call 구현

🔹 시스템 콜 핸들러

void syscall_handler (struct intr_frame *f UNUSED) {
	switch(f->R.rax) {
		case SYS_HALT:                   /* Halt the operating system. */
			halt();
		case SYS_EXIT:                   /* Terminate this process. */
			exit(f->R.rdi);
		case SYS_FORK:                   /* Clone current process. */
			break;
		case SYS_EXEC:                   /* Switch current process. */
			break;
		case SYS_WAIT:                   /* Wait for a child process to die. */
			break;
		case SYS_CREATE:                 /* Create a file. */
			f->R.rax = create(f->R.rdi, f->R.rsi);
			break;
		case SYS_REMOVE:                 /* Delete a file. */
			f->R.rax = remove(f->R.rdi);
			break;
		case SYS_OPEN:                   /* Open a file. */
			f->R.rax = open(f->R.rdi);
			break;
		case SYS_FILESIZE:               /* Obtain a file's size. */
			f->R.rax = filesize(f->R.rdi);
			break;
		case SYS_READ:                   /* Read from a file. */
			f->R.rax = read(f->R.rdi, f->R.rsi, f->R.rdx);
			break;
		case SYS_WRITE:                  /* Write to a file. */
			f->R.rax = write(f->R.rdi, f->R.rsi, f->R.rdx);
			break;
		case SYS_SEEK:                   /* Change position in a file. */
			seek(f->R.rdi, f->R.rsi);
			break;
		case SYS_TELL:                   /* Report current position in a file. */
			f->R.rax = tell(f->R.rdi);
			break;
		case SYS_CLOSE:                  /* Close a file. */
			close(f->R.rdi);
			break;
		default:
			exit(f->R.rdi);
	}
}

 

🔹 halt

void halt (void) {
	power_off();
}

 

🔹 exit

void exit(int status) {
    printf("%s: exit(%d)\n", thread_current()->name, status);
	thread_exit();
}

🔹 create

bool create (const char *file, unsigned initial_size) {
	if (file == NULL) exit(-1); // return false;
	return filesys_create(file, initial_size);
}

🔹 remove

bool remove (const char *file) {
	return filesys_remove(file);
}

 

🔹 open

int open (const char *filename) {
	struct file *file = filesys_open(filename);
	if (file == NULL) return -1; // Return -1 if file is not opened
	struct thread *curr = thread_current();
	int fd;
	for(fd = 2; fd <= curr->next_fd; fd++) {
		if (curr->fdt[fd] == NULL) {
			curr->fdt[fd] = file;
			break;
		}
	}
	if (fd == curr->next_fd && curr->next_fd < 63) curr->next_fd++;
	else if (fd == curr->next_fd+1) {
		fd = -1; // Return -1 if the FDT is full
		file_close(file);
	}
	return fd;
}

🔹 filesize

int filesize (int fd) {
	if (fd < 2 || fd > 63) exit(-1); // invalid fd
	struct file *file = thread_current()->fdt[fd];
	if (file == NULL) return 0; // file not found
	return file_length(file);
}

 

🔹 read

int read (int fd, void *buffer, unsigned size) {
	if (fd == 0) return input_getc(); // fd0 is stdin
	else if (fd == 1) exit(-1); // fd1 is stdout
	else if (fd < 2 || fd > 63) exit(-1); // invalid fd
	else {
		struct file *file = thread_current()->fdt[fd];
		if (file == NULL) exit(-1);
		return file_read(file, buffer, size);
	}
}

🔹 write

int write(int fd, const void *buffer, unsigned size) {
	if(fd == 1) { // fd1 is stdout
		putbuf(buffer, size);
		return size;
	} else if (fd == 0) exit(-1); // fd0 is stdin
	else if (fd < 2 || fd > 63) exit(-1); // invalid fd
	else {
		struct file *file = thread_current()->fdt[fd];
		if (file == NULL) exit(-1);
		return file_write(file, buffer, size);
	}
}

🔹 seek

void seek (int fd, unsigned position) {
	if (fd < 2 || fd > 63) exit(-1); // invalid fd
	struct thread *curr = thread_current();
	struct file *file = curr->fdt[fd];
	if (file == NULL) exit(-1); // file not found
	file_seek(file, position);
}

 

🔹 tell

void seek (int fd, unsigned position) {
	if (fd < 2 || fd > 63) exit(-1); // invalid fd
	struct thread *curr = thread_current();
	struct file *file = curr->fdt[fd];
	if (file == NULL) exit(-1); // file not found
	file_seek(file, position);
}

 

🔹 close

void close (int fd) {
	if (fd < 2 || fd > 63) exit(-1); // invalid fd
	struct thread *curr = thread_current();
	struct file *file = curr->fdt[fd];
	if (file == NULL) exit(-1); // file not found
	curr->fdt[fd] = NULL;
	if (fd == curr->next_fd && curr->next_fd > 2) curr->next_fd--;
	file_close(file);
}

'Krafton Jungle > 5. PintOS' 카테고리의 다른 글

[PintOS 2주차] Day 8  (0) 2025.05.22
[PintOS 2주차] Day 7  (2) 2025.05.21
[PintOS 2주차] Day 4-5  (0) 2025.05.19
[PintOS 2주차] Day 3  (0) 2025.05.17
[PintOS 2주차] Day 2  (0) 2025.05.16