Skip to content
Snippets Groups Projects
Commit 5b447a23 authored by kim hakjun's avatar kim hakjun
Browse files

핸들링 수정

parent e940c2c7
Branches
No related tags found
No related merge requests found
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <assert.h>
#include "list_head.h" #include "list_head.h"
#include "vm.h" #include "vm.h"
...@@ -63,26 +63,24 @@ extern unsigned int mapcounts[]; ...@@ -63,26 +63,24 @@ extern unsigned int mapcounts[];
* Return true if the translation is cached in the TLB. * Return true if the translation is cached in the TLB.
* Return false otherwise * Return false otherwise
*/ */
bool lookup_tlb(unsigned int vpn, unsigned int rw, unsigned int *pfn) { int lookup_tlb(unsigned int vpn, char access_type) {
// TLB 항목을 순회 // TLB 항목을 순회
for (int i = 0; i < NR_TLB_ENTRIES; i++) { for (int i = 0; i < NR_TLB_ENTRIES; i++) {
// 항목이 유효하고 VPN이 일치하는지 확인 // 항목이 유효하고 VPN이 일치하는지 확인
if (tlb[i].valid && tlb[i].vpn == vpn) { if (tlb[i].valid && tlb[i].vpn == vpn) {
// 요청된 접근 유형에 대한 권한 확인 // 요청된 접근 유형에 대한 권한 확인
if ((rw & ACCESS_READ && tlb[i].rw & ACCESS_READ) || if ((access_type == 'r' && (tlb[i].rw & ACCESS_READ)) ||
(rw & ACCESS_WRITE && tlb[i].rw & ACCESS_WRITE)) { (access_type == 'w' && (tlb[i].rw & ACCESS_WRITE))) {
// TLB 히트 // TLB 히트
*pfn = tlb[i].pfn; return tlb[i].pfn;
return true;
} else { } else {
// 권한 불일치, TLB 미스 // 권한 불일치, TLB 미스
return false; return -1;
} }
} }
} }
// TLB 미스 // TLB 미스
return false; return -1;
} }
/** /**
...@@ -98,6 +96,7 @@ bool lookup_tlb(unsigned int vpn, unsigned int rw, unsigned int *pfn) { ...@@ -98,6 +96,7 @@ bool lookup_tlb(unsigned int vpn, unsigned int rw, unsigned int *pfn) {
*/ */
void insert_tlb(unsigned int vpn, unsigned int rw, unsigned int pfn) { void insert_tlb(unsigned int vpn, unsigned int rw, unsigned int pfn) {
int index = -1; int index = -1;
for (int i = 0; i < NR_TLB_ENTRIES; i++) { // 기존 엔트리 업데이트 for (int i = 0; i < NR_TLB_ENTRIES; i++) { // 기존 엔트리 업데이트
if (tlb[i].valid){ if (tlb[i].valid){
if(tlb[i].vpn == vpn) { if(tlb[i].vpn == vpn) {
...@@ -144,17 +143,17 @@ unsigned int alloc_page(unsigned int vpn, unsigned int rw) { ...@@ -144,17 +143,17 @@ unsigned int alloc_page(unsigned int vpn, unsigned int rw) {
if (mapcounts[i] == 0) { if (mapcounts[i] == 0) {
mapcounts[i] = 1; mapcounts[i] = 1;
if (ptbr->pdes[first_pte_index] == NULL) { // 빈 페이지 테이블의 경우 if (current->pagetable.pdes[first_pte_index] == NULL) { // 빈 페이지 테이블의 경우
ptbr->pdes[first_pte_index] = malloc(sizeof(struct pte_directory)); current->pagetable.pdes[first_pte_index] = malloc(sizeof(struct pte_directory));
memset(ptbr->pdes[first_pte_index], 0, sizeof(struct pte_directory)); memset(current->pagetable.pdes[first_pte_index], 0, sizeof(struct pte_directory));
} }
struct pte *pte = &ptbr->pdes[first_pte_index]->ptes[second_pte_index]; struct pte *pte = &current->pagetable.pdes[first_pte_index]->ptes[second_pte_index];
pte->valid = true; pte->valid = true;
pte->rw = rw; pte->rw = rw;
pte->pfn = i; pte->pfn = i;
pte->private = (rw == ACCESS_READ) ? 0 : 1 ; pte->private = (rw == ACCESS_READ) ? 0 : 1 ;
current->pagetable = *ptbr;
insert_tlb(vpn, rw, i); insert_tlb(vpn, rw, i);
return i; return i;
...@@ -185,6 +184,8 @@ void free_page(unsigned int vpn) ...@@ -185,6 +184,8 @@ void free_page(unsigned int vpn)
ptbr->pdes[out_idx]->ptes[vpn_idx].pfn = 0; ptbr->pdes[out_idx]->ptes[vpn_idx].pfn = 0;
} }
/** /**
* handle_page_fault() * handle_page_fault()
* *
...@@ -203,37 +204,37 @@ void free_page(unsigned int vpn) ...@@ -203,37 +204,37 @@ void free_page(unsigned int vpn)
*/ */
bool handle_page_fault(unsigned int vpn, unsigned int rw) bool handle_page_fault(unsigned int vpn, unsigned int rw)
{ {
int out_idx = 0; unsigned int first_vpn = vpn != 0 ? vpn / NR_PTES_PER_PAGE : 0;
int vpn_idx = vpn%NR_PTES_PER_PAGE; unsigned int second_vpn = vpn % NR_PTES_PER_PAGE;
if(vpn != 0) out_idx = vpn/NR_PTES_PER_PAGE;
if(!ptbr->pdes[out_idx]) //case 0 if (!ptbr->pdes[first_vpn] || !ptbr->pdes[first_vpn]->ptes[second_vpn].valid) {
return false; return false;
if(ptbr->pdes[out_idx]->ptes[vpn_idx].valid == false) //case 1 }
return false;
if(ptbr->pdes[out_idx]->ptes[vpn_idx].private == 1) //case 2, writable
{
ptbr->pdes[out_idx]->ptes[vpn_idx].rw = ACCESS_WRITE;
if(mapcounts[ptbr->pdes[out_idx]->ptes[vpn_idx].pfn] != 1) //more then 2 process if (ptbr->pdes[first_vpn]->ptes[second_vpn].private == 1) {
{ ptbr->pdes[first_vpn]->ptes[second_vpn].rw = ACCESS_WRITE + ACCESS_READ;
for(unsigned int i = 0; i < NR_PAGEFRAMES; i++)
{ if (rw == ACCESS_WRITE && mapcounts[ptbr->pdes[first_vpn]->ptes[second_vpn].pfn] != 1) {
if(mapcounts[i]) continue; int original_pfn = ptbr->pdes[first_vpn]->ptes[second_vpn].pfn;
mapcounts[ptbr->pdes[out_idx]->ptes[vpn_idx].pfn]--;
ptbr->pdes[out_idx]->ptes[vpn_idx].pfn = i; //use other pfn
mapcounts[i]++;
for (unsigned int i = 0; i < NR_PAGEFRAMES; i++) {
if (mapcounts[i] == 0) {
// 빈 프레임을 찾아서 매핑
mapcounts[original_pfn]--;
ptbr->pdes[first_vpn]->ptes[second_vpn].pfn = i;
mapcounts[i]++;
break; break;
} }
} }
} else if(rw == ACCESS_READ || rw == 2){ //cannot write wanna write
insert_tlb(vpn,rw,ptbr->pdes[out_idx]->ptes[vpn_idx].pfn);
return false;
} }
return true; //wanna read, write on 1 }
else if (rw == ACCESS_WRITE) {
return false;
} }
return true;
}
/** /**
* switch_process() * switch_process()
...@@ -259,7 +260,7 @@ void switch_process(unsigned int pid) ...@@ -259,7 +260,7 @@ void switch_process(unsigned int pid)
struct process *new_process; struct process *new_process;
struct list_head *pos, *n; struct list_head *pos, *n;
// processes 리스트에서 주어진 pid를 가진 프로세스를 찾습니다 // 주어진 PID를 가진 프로세스를 찾습니다.
list_for_each_safe(pos, n, &processes) { list_for_each_safe(pos, n, &processes) {
struct process *p = list_entry(pos, struct process, list); struct process *p = list_entry(pos, struct process, list);
if (p->pid == pid) { if (p->pid == pid) {
...@@ -268,37 +269,39 @@ void switch_process(unsigned int pid) ...@@ -268,37 +269,39 @@ void switch_process(unsigned int pid)
} }
} }
// 프로세스를 찾은 경우
if (target) { if (target) {
// 현재 프로세스를 processes 리스트의 끝으로 이동합니다 // PID를 가진 프로세스가 존재하는 경우
// 현재 프로세스를 processes 리스트에 추가합니다.
list_add_tail(&current->list, &processes); list_add_tail(&current->list, &processes);
// target 프로세스를 processes 리스트에서 제거합니다 // target 프로세스를 processes 리스트에서 제거합니다.
list_del(&target->list); list_del(&target->list);
// 현재 프로세스를 target 프로세스로 설정합니다 // 현재 프로세스를 target 프로세스로 설정합니다.
current = target; current = target;
// 페이지 테이블 베이스 레지스터를 새 프로세스의 페이지 테이블로 설정합니다 // 페이지 테이블 베이스 레지스터를 설정합니다.
ptbr = &current->pagetable; ptbr = &current->pagetable;
// TLB의 모든 엔트리를 무효화합니다 // TLB를 플러시합니다.
for (int i = 0; i < NR_TLB_ENTRIES; i++) { for (int i = 0; i < NR_TLB_ENTRIES; i++) {
tlb[i].valid = false; tlb[i].valid = false;
} }
// 프로세스를 찾지 못한 경우
} else { } else {
// 새 프로세스를 현재 프로세스로부터 포크합니다 // PID를 가진 프로세스가 존재하지 않는 경우
// 현재 프로세스를 복제하여 새로운 프로세스를 생성합니다.
new_process = (struct process *)malloc(sizeof(struct process)); new_process = (struct process *)malloc(sizeof(struct process));
assert(new_process != NULL);
new_process->pid = pid; new_process->pid = pid;
INIT_LIST_HEAD(&new_process->list); INIT_LIST_HEAD(&new_process->list);
// 현재 프로세스의 페이지 테이블을 복사합니다 // 현재 프로세스의 페이지 테이블을 새로운 프로세스로 복사합니다.
for (int i = 0; i < NR_PDES_PER_PAGE; i++) { for (int i = 0; i < NR_PDES_PER_PAGE; i++) {
if (current->pagetable.pdes[i] != NULL) { if (current->pagetable.pdes[i] != NULL) {
new_process->pagetable.pdes[i] = (struct pte_directory *)malloc(sizeof(struct pte_directory)); new_process->pagetable.pdes[i] = (struct pte_directory *)malloc(sizeof(struct pte_directory));
assert(new_process->pagetable.pdes[i] != NULL);
for (int j = 0; j < NR_PTES_PER_PAGE; j++) { for (int j = 0; j < NR_PTES_PER_PAGE; j++) {
struct pte *src_pte = &current->pagetable.pdes[i]->ptes[j]; struct pte *src_pte = &current->pagetable.pdes[i]->ptes[j];
struct pte *dest_pte = &new_process->pagetable.pdes[i]->ptes[j]; struct pte *dest_pte = &new_process->pagetable.pdes[i]->ptes[j];
...@@ -306,15 +309,15 @@ void switch_process(unsigned int pid) ...@@ -306,15 +309,15 @@ void switch_process(unsigned int pid)
if (src_pte->valid) { if (src_pte->valid) {
*dest_pte = *src_pte; *dest_pte = *src_pte;
// 쓰기 가능 페이지는 읽기 전용으로 변경하고, private 비트를 설정합니다 // Copy-on-Write 처리
if (src_pte->rw & ACCESS_WRITE) { if (src_pte->rw & ACCESS_WRITE) {
src_pte->rw &= ~ACCESS_WRITE; src_pte->rw &= ~ACCESS_WRITE; // 원본을 읽기 전용으로 만듭니다.
dest_pte->rw &= ~ACCESS_WRITE; dest_pte->rw &= ~ACCESS_WRITE; // 복사본을 읽기 전용으로 만듭니다.
src_pte->private = 1; src_pte->private = 1; // COW로 표시
dest_pte->private = 1; dest_pte->private = 1; // COW로 표시
} }
// 공유 페이지에 대한 map count 증가시킵니다 // mapcounts 증가
mapcounts[src_pte->pfn]++; mapcounts[src_pte->pfn]++;
} }
} }
...@@ -323,13 +326,16 @@ void switch_process(unsigned int pid) ...@@ -323,13 +326,16 @@ void switch_process(unsigned int pid)
} }
} }
// 현재 프로세스를 processes 리스트의 끝으로 이동합니다 // 현재 프로세스를 processes 리스트에 추가합니다.
list_add_tail(&current->list, &processes); list_add_tail(&current->list, &processes);
// 현재 프로세스를 새 프로세스로 설정합니다
// 현재 프로세스를 새로운 프로세스로 설정합니다.
current = new_process; current = new_process;
// 페이지 테이블 베이스 레지스터를 새 프로세스의 페이지 테이블로 설정합니다
// 페이지 테이블 베이스 레지스터를 설정합니다.
ptbr = &current->pagetable; ptbr = &current->pagetable;
// TLB의 모든 엔트리를 무효화합니다
// TLB를 플러시합니다.
for (int i = 0; i < NR_TLB_ENTRIES; i++) { for (int i = 0; i < NR_TLB_ENTRIES; i++) {
tlb[i].valid = false; tlb[i].valid = false;
} }
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment