# page fault: 주소 변환 실패가 항상 프로그램 오류는 아닙니다

v6.18.37 / arch/arm64/mm/fault.c

CPU가 주소를 변환하지 못하면 커널이 그 접근의 이유를 판단합니다. 아직 물리 페이지를 붙이지 않은 정상적인 사용자 영역일 수도 있고 잘못된 주소일 수도 있습니다. arm64의 do_translation_fault는 먼저 사용자 주소 범위로 처리할 수 있는지 구분한 뒤 자세한 처리를 넘깁니다.

## do_translation_fault

```c

static int __kprobes do_translation_fault(unsigned long far,
					  unsigned long esr,
					  struct pt_regs *regs)
{
	unsigned long addr = untagged_addr(far);

	if (is_ttbr0_addr(addr))
		return do_page_fault(far, esr, regs);

	do_bad_area(far, esr, regs);
	return 0;
}

```

### 782행

```c

static int __kprobes do_translation_fault(unsigned long far,

```

주소 변환 실패를 처리할 함수입니다. far는 CPU가 보고한 접근 주소이며 __kprobes는 예외 처리와 프로브 계측의 관계에 필요한 표기입니다.

### 783행

```c

					  unsigned long esr,

```

esr에는 실패 종류와 접근 특성이 들어 있습니다. 주소 숫자만으로는 읽기·쓰기 등 예외의 의미를 충분히 알 수 없습니다.

### 784행

```c

					  struct pt_regs *regs)

```

regs는 예외가 발생했을 때 저장한 CPU 문맥입니다. 사용자 실행 중이었는지, 어느 명령에서 발생했는지 판단하는 데 사용됩니다.

### 786행

```c

	unsigned long addr = untagged_addr(far);

```

주소 범위를 판정하기 위해 태그를 제외한 addr를 만듭니다. 원래 far 변수 자체를 덮어쓰지는 않습니다.

### 788행

```c

	if (is_ttbr0_addr(addr))

```

해당 주소가 TTBR0 쪽 주소 범위인지 확인합니다. 단순히 현재 커널 모드인지 여부만 검사하는 조건이 아닙니다.

### 789행

```c

		return do_page_fault(far, esr, regs);

```

TTBR0 범위라면 VMA와 실제 메모리 상태를 확인하는 do_page_fault로 원래 예외 정보를 넘기고 그 결과를 반환합니다.

### 791행

```c

	do_bad_area(far, esr, regs);

```

앞 조건에 해당하지 않은 주소는 잘못된 영역 처리로 넘깁니다. 이 줄에서 무조건 사용자 지연 할당을 시도하지 않습니다.

### 792행

```c

	return 0;

```

이 처리 경로의 반환 규약에 따라 0을 돌려줍니다. 새 페이지 할당 성공의 개수를 뜻하지 않습니다.

