diff --git a/blog/content/edition-2/posts/05-cpu-exceptions/index.ko.md b/blog/content/edition-2/posts/05-cpu-exceptions/index.ko.md index 4fe4dc23..e6dd65d5 100644 --- a/blog/content/edition-2/posts/05-cpu-exceptions/index.ko.md +++ b/blog/content/edition-2/posts/05-cpu-exceptions/index.ko.md @@ -50,28 +50,28 @@ x86 아키텍처에는 20가지 정도의 CPU 예외가 존재합니다. 그 중 예외 발생을 포착하고 대응할 수 있으려면 _인터럽트 서술자 테이블 (Interrupt Descriptor Table; IDT)_ 이 필요합니다. 이 테이블을 통해 우리는 각각의 CPU 예외를 어떤 예외 처리 함수가 처리할지 지정합니다. 하드웨어에서 이 테이블을 직접 사용하므로 테이블의 형식은 정해진 표준에 따라야 합니다. 테이블의 각 엔트리는 아래와 같은 16 바이트 구조를 따릅니다: -타입| 이름 | 설명 -----|--------------------------|----------------------------------- -u16 | Function Pointer [0:15] | 예외 처리 함수에 대한 64비트 포인터의 하위 16비트 -u16 | GDT selector | [글로벌 디스크립터 테이블 (global descriptor table)][global descriptor table]에서 코드 세그먼트를 선택하는 값 -u16 | Options | (표 아래의 설명 참조) -u16 | Function Pointer [16:31] | 예외 처리 함수에 대한 64비트 포인터의 2번째 하위 16비트 -u32 | Function Pointer [32:63] | 예외 처리 함수에 대한 64비트 포인터의 상위 32비트 -u32 | Reserved | 사용 보류 중인 영역 +| 타입 | 이름 | 설명 | +| ---- | ------------------------ | ------------------------------------------------------------------------------------------------------------- | +| u16 | Function Pointer [0:15] | 예외 처리 함수에 대한 64비트 포인터의 하위 16비트 | +| u16 | GDT selector | [글로벌 디스크립터 테이블 (global descriptor table)][global descriptor table]에서 코드 세그먼트를 선택하는 값 | +| u16 | Options | (표 아래의 설명 참조) | +| u16 | Function Pointer [16:31] | 예외 처리 함수에 대한 64비트 포인터의 2번째 하위 16비트 | +| u32 | Function Pointer [32:63] | 예외 처리 함수에 대한 64비트 포인터의 상위 32비트 | +| u32 | Reserved | 사용 보류 중인 영역 | [global descriptor table]: https://en.wikipedia.org/wiki/Global_Descriptor_Table Options 필드는 아래의 형식을 갖습니다: -비트 구간 | 이름 | 설명 -------|-----------------------------------|----------------------------------- -0-2 | Interrupt Stack Table Index | 0: 스택을 교체하지 않는다, 1-7: 이 인터럽트 처리 함수가 호출된 경우 Interrupt Stack Table의 n번째 스택으로 교체한다. -3-7 | Reserved | 사용 보류 중인 영역 -8 | 0: Interrupt Gate, 1: Trap Gate | 비트가 0이면 이 예외 처리 함수가 호출 이후 인터럽트 발생 억제 -9-11 | must be one | 각 비트는 언제나 1 -12 | must be zero | 언제나 0 -13‑14 | Descriptor Privilege Level (DPL) | 이 예외 처리 함수를 호출하는 데에 필요한 최소 특권 레벨 -15 | Present | +| 비트 구간 | 이름 | 설명 | +| --------- | -------------------------------- | -------------------------------------------------------------------------------------------------------------------- | +| 0-2 | Interrupt Stack Table Index | 0: 스택을 교체하지 않는다, 1-7: 이 인터럽트 처리 함수가 호출된 경우 Interrupt Stack Table의 n번째 스택으로 교체한다. | +| 3-7 | Reserved | 사용 보류 중인 영역 | +| 8 | 0: Interrupt Gate, 1: Trap Gate | 비트가 0이면 이 예외 처리 함수가 호출 이후 인터럽트 발생 억제 | +| 9-11 | must be one | 각 비트는 언제나 1 | +| 12 | must be zero | 언제나 0 | +| 13‑14 | Descriptor Privilege Level (DPL) | 이 예외 처리 함수를 호출하는 데에 필요한 최소 특권 레벨 | +| 15 | Present | 각 예외마다 IDT에서의 인덱스가 배정되어 있습니다. invalid opcode 예외는 테이블 인덱스 6이 배정되어 있고, 페이지 폴트 예외는 테이블 인덱스 14가 배정되어 있습니다. 하드웨어는 미리 배정된 인덱스를 이용해 각 예외에 대응하는 IDT 엔트리를 자동으로 불러올 수 있습니다. OSDev 위키의 [Exception Table][exceptions]의 “Vector nr.”로 명명된 열을 보시면 모든 예외 및 배정된 인덱스를 확인하실 수 있습니다. @@ -166,10 +166,10 @@ _preserved_ 레지스터들의 값은 함수 호출 전/후에 보존되어야 x86_64에서는 C 함수 호출 규약이 preserved 레지스터와 scratch 레지스터를 아래와 같이 정합니다: -preserved 레지스터 | scratch 레지스터 ----|--- -`rbp`, `rbx`, `rsp`, `r12`, `r13`, `r14`, `r15` | `rax`, `rcx`, `rdx`, `rsi`, `rdi`, `r8`, `r9`, `r10`, `r11` -_callee-saved_ | _caller-saved_ +| preserved 레지스터 | scratch 레지스터 | +| ----------------------------------------------- | ----------------------------------------------------------- | +| `rbp`, `rbx`, `rsp`, `r12`, `r13`, `r14`, `r15` | `rax`, `rcx`, `rdx`, `rsi`, `rdi`, `r8`, `r9`, `r10`, `r11` | +| _callee-saved_ | _caller-saved_ | 컴파일러는 이 규칙들에 따라 코드를 컴파일 합니다. 예를 들면 대부분의 함수들은 `push rbp` 로 시작하는데, 이는 callee-saved 레지스터인 `rbp`를 스택에 저장합니다.