나만의 공부 노트

xv6 - trap & interrupts 본문

운영체제

xv6 - trap & interrupts

va95 2021. 4. 3. 16:52

1. User Program에서 system call(=write) 호출

 

2. user.h의 system call 선언과 usys.S의 system call 정의를 linking

eax 레지스터에 시스템 콜 number를 기록(시스템 콜 trap인 경우)

int n 수행

 

* Interrupt Descriptor

부팅 시, IDTR 레지스터에 base address 셋팅

int n 명령어의 n(=IDT Offset)과 조합하여 해당 idt를 가르키는 주소값 생성

idt는 trap.c의 tvinit을 통해 descriptor의 값들이 셋팅된다.

 

3. int n instruction 

int n 수행 시, 해당하는 idt의 n번째 descriptor의 값들을 가져온다.

descriptor의 값들을 이용하여 해당 workflow를 수행한다.

3번의 과정을 수행하기 위해서 새로운 workflow로 진입해야하고 이때 gdt를 참조한다.

여기서 Code Segment Descriptor에는 SEG_KCODE<<3이 들어가고, GDTR 레지스터(마찬가지로 부팅 시에 셋팅)에 있는 base address와 조합하여 해당 gdt를 가르키는 descriptor 값들을 확인한다.

 

* int n 3번 이후의 동작

3. 유저 스택의 esp, ss 레지스터 값을 internal register에 잠시 보관하고, task segment descriptor(tss 레지스터를 이용)에 들어있는 커널 스택의 ss, esp 값을 실제 cpu의 ss, esp 레지스터에 로드

잠시 보관 했던 유저 스택의 esp, ss를 커널 스택에 푸쉬

->해당 과정은 모드 스위치가 일어날 경우에만 동작한다.

4. eflags(=오버플로우 발생 여부 등), cs(CPL=current privilege level을 저장하는 레지스터), eip(다음 명령어 수행 주소)를 커널 스택에 푸쉬

5. eflags 초기화

6. descriptor에 있는 cs, eip 레지스터를 실제 cpu의 cs, eip 레지스터에 로드

 

4. vectors 함수

int n 수행 -> idt 수행 -> vector 수행 순으로 진행된다.

idt의 entry point로 vectors 배열이 들어간다.

int n이 수행된 이후 이므로 ss, esp, eflags, cs, eip가 커널 스택에 저장되어 있고, vector 함수는 error code와 trapno를 커널 스택에 푸쉬한다.

 

5. alltraps

차례로 유저 프로그램의 정보를 갖고 있는 레지스터들을 저장하고, 마지막에 esp 레지스터 값을 저장한다.

즉 커널 스택에 쌓여있는 모든 유저 프로그램의 정보를 접근할 수 있도록 esp 레지스터의 값을 푸쉬함으로써, 함수의 인자로 넘겨주는 역할을 하게 된다.

위의 인자(주소값)을 통해 유저 프로그램의 정보를 접근할 수 있다.  

 

6. trap

alltraps에서 trap으로 넘어오고, trapno를 통해 trap 종류에 맞는 workflow를 수행한다.

trapno == 64 인 경우, syscall.c의 syscall()함수를 호출하며, syscall()함수는 tp->eax에 들어있는 번호를 통해 어떠한 syscall이 호출되었는지 확인한다.

해당 번호를 통해 syscalls배열에 들어있는 시스템 콜을 호출하여 수행한다.

'운영체제' 카테고리의 다른 글

Concurrency  (0) 2021.05.15
xv6 - virtual memory  (0) 2021.04.12
Memory Virtualization  (0) 2021.04.12
xv6 - System call  (0) 2021.03.19
CPU Virtualization  (0) 2021.03.12