
아래 그림보단 훨씬 많은 걸 해야 하는데ㅣ... 이것도 조만간 글로 올리던가 해야지

가상 메모리는 페이지, 물리 주소 메모리는 프레임 단위로 구분
PGSIZE = 4096 바이트)KERN_BASE = 0x8004000000 이상 주소KERN_BASE를 빼면 물리 주소)palloc_get_page 함수는, 실제 물리 주소가 아닌 페이지의 커널 가상주소를 반환KERN_BASE = 0x8004000000 미만 주소palloc_get_page(): 물리 프레임 할당 후, 해당 물리 프레임의 물리 주소에 대응되는 커널 가상주소를 반환PAL_USER 플래그가 설정된 경우에는 user pool에서, 설정되지 않았으면 kernel pool 에서 할당함pml4_set_page를 통해 사용자 가상주소와 매핑해야 함.malloc,calloc, realloc 은 무조건 kernel pool의 주소를 반환.

4단계로 이루어진 페이지 테이블인데, 중간과정보다는 변환을 한다는 점을 이해할 것
pml4_set_page(pml4, upage, kpage, rw)
upage)에 커널 가상주소 (kpage)를 읽기/쓰기 권한(rw)과 함께 매핑rw가 true면 읽기/쓰기, false면 읽기 전용pml4_get_page(pml4, uaddr)
pml4)에서 사용자 가상주소(uaddr)에 매핑된 물리 프레임이, 페이지 테이블에 존재하는지 확인pml4_get_page(thread_current() -> pml4, p) == NULL
thread_current() -> pml4: 현재 프로세스의 PML4 테이블p: 사용자 가상주소p가 물리 메모리에 매핑되어 있으면, 해당 물리 프레임에 대응되는 커널 가상 주소를 반환 -> 조건문 거짓p가 매핑되어 있지 않으면 NULL을 반환 -> 조건문 참fork 시스템 콜 구현 시, 부모의 페이지 테이블 내 엔트리를 자식의 페이지 테이블로 복사해야 함// userprog/process.c
static bool duplicate_pte (uint64_t *pte, void *va, void *aux) {
struct thread *current = thread_current ();
struct thread *parent = (struct thread *) aux;
void *parent_page;
void *new_page;
bool writable;
// 계속
}
pte: 부모 프로세스의 pml4 테이블 내 각 엔트리의 주소pte에 대해, duplicate_pte() 함수가 호출되어, 자식의 페이지 테이블로 복사하는 역할 수행va: pml4 테이블 내, pte에 대응되는 사용자 가상 주소aux: 부모 쓰레드의 struct thread 포인터가 전달됨// duplicate_pte 내부
/* 1. pte에 저장된 주소가 kernel pool의 프레임을 가리키는 경우, 복사하지 않음. */
if (is_kern_pte(pte)){
return true;
}
[부모 pml4의 pte] -- 주소 --> 물리 프레임
│
▼
is_kern_pte(pte)?
├─ Yes → 복사하지 않고 넘어감 (return true)
└─ No → 다음 단계 진행
true를 반환해 복제 과정을 생략해야 함is_kernel_vaddr(va) 사용하면 안 됨.va의 사용자 주소 / 커널 주소 영역 판단용인데, va는 사용자 주소이므로 무조건 true 반환/* 2. 부모의 pml4 테이블에서 va에 해당하는 페이지를 가져와, parent_page에 저장한다. */
parent_page = pml4_get_page (parent->pml4, va);
부모 프로세스 pml4 테이블
┌───────────┐
│ va -> 프레임 주소 ──────► 물리 페이지 (부모 페이지)
└───────────┘
parent_page = pml4_get_page(parent->pml4, va)
(va에 매핑된 물리 페이지를 커널 가상 주소로 변환해 저장)
va에 매핑된 물리 프레임을 찾음parent_page에 저장함./* 3. 자식 프로세스를 위해 PAL_USER (사용자영역) 옵션이 설정된 새 페이지를 할당하고, new_page에 저장한다 */
new_page = palloc_get_page(PAL_USER);
new_page = palloc_get_page(PAL_USER)
┌───────────────┐
│ 새로 할당된 4KB 페이지 │ <─ user pool에서 할당
└───────────────┘
new_page에 저장함./* 4. 부모의 페이지 내용을 new_page에 복사한 뒤, 쓰기가능 여부를 writable 변수에 저장한다. */
memcpy(new_page, parent_page, PGSIZE);
if (is_writable(pte)){
writable = 1;
} else {
writable = 0;
}
memcpy(new_page, parent_page, PGSIZE)
│
▼
부모 페이지 내용 → 새 페이지에 복사 완료
writable = is_writable(pte)
(읽기/쓰기 권한 확인)
memcpy를 이용해 현재 parent_page 주소의 내용을 new_page에 4kb(PGSIZE)만큼 복사is_writable(pte)로 해당 pte에 저장된 프레임이 읽기 전용인지 확인 -> writable 변수 설정/* 5. 자식의 페이지 테이블에 VA 주소로 new_page를 매핑하고, writable 권한과 함께 등록한다. */
if (!pml4_set_page (current->pml4, va, new_page, writable)) {
/* 6. 실패했을 경우 에러 처리를 수행한다. (일단 강제 종료되게 false를 반환) */
return false;
}
return true;
pml4_set_page(current->pml4, va, new_page, writable)
[자식 pml4 테이블]
va ─────► new_page (writable)
성공 시 true 반환
current->pml4)에, 새로 할당한 new_page를 삽입va에 new_page가 매핑되도록 함pml4_set_page는 성공하면 true, 실패하면 false를 반환하므로, 이를 통해 에러 핸들링