Pintos Project 1: Threads
thread_init
์ ํ๋ฉด main thread(initial_thread
)๊ฐ ๋ง๋ค์ด์ง๊ณ ์คํ๋๋ค. ์ค์ผ์ค๋ง์ ์ํด thread_start
๋ฅผ ์คํํ๋ฉด, idle_thread
๋ฅผ ๋ง๋ค๊ณ ๋๋ฆฐ๋ค. idle_thread
๋ ์ธํฐ๋ฝํธ๋ฅผ ๋นํ์ฑํํ๊ณ ์๊ธฐ ์์ ์ ๋ธ๋ฝํ ๋ค์, sti; hlt;
๋ช
๋ น์ด๋ฅผ ์คํํ์ฌ ์ธํฐ๋ฝํธ๋ฅผ ํ์ฑํํ๊ณ , ์ธํฐ๋ฝํธ๊ฐ ๋ฐ์ํ ๋๊น์ง CPU๋ฅผ ๋๊ธฐ ์ํ๋ก ์ ํํ๋ ์ผ์ ๋ฐ๋ณตํ๋ค. create_thread
๋ ์ค๋ ๋ ์ด๋ฆ, ์ฐ์ ์์๋ฅผ ์ธ์๋ก ๋ฐ์ ์ค๋ ๋๋ฅผ ์ด๊ธฐํ(init_thread
)ํ๊ณ , ์ค๋ ๋ ๋ด๋ถ intr_frame
๊ตฌ์กฐ์ฒด์ ์ธ์๋ก ๋ฐ์ ์คํ ํจ์ (thread_func
type)์ ๊ทธ ์ธ์๋ฅผ ์ ์ฅํ ํ thread_unblock
์ ํตํด status๋ฅผ THREAD_READY
๋ก ๋ฐ๊พผ ํ ready_list์
๋ฃ๋๋ค. ๊ทธ๋ฌ๋ฉด ์ธํฐ๋ฝํธ๋ง๋ค ์คํ๋๋ ํจ์์ธ thread_tick
์ if(thread_tick >= TIME_SLICE) intr_yield_on_return();
๋ผ์ธ์ ์ํด thread_yield
๊ฐ ์ผ์ด๋ ๋ ready_list
์์ ๊บผ๋ด์ด์ ธ์, thread_launch
์ do_iret
ํจ์์ ์ํด ์ค์ง์ ์ธ context switching์ด ๋ฐ์ํ์ฌ ์คํ๋๊ฒ ๋๋ค.
๊ทธ๋ฌ๋ฉด ์ธํฐ๋ฝํธ๋ ๋๊ฐ ๋ณด๋ด๋ ๊ฑธ๊น? Programmable Interval Timer (PIT)์ธ 8254 ํ์ด๋จธ๊ฐ ๋ณด๋ธ๋ค. ์ด ํ์ด๋จธ๋ ์ปดํจํฐ์ ๋ฉ์ธ๋ณด๋์ ์์นํ์ฌ* , init_timer
์์ ์ธํ
๋ ์ธํฐ๋ฒ๋ง๋ค PIC (Programmable Interrupt Controller, ์ ํต์ ์ผ๋ก๋ 8259A)์ ์ธํฐ๋ฝํธ๋ฅผ ๋ฐ์์์ผ์ผ ํ๋ค๋ ์์ฒญ์ ์ ๋ฌํ๋ค. ๊ตฌ์ฒด์ ์ผ๋ก๋ IRQ0, Interrupt Request 0 ๋ผ์ธ์ ํตํด master PIC์ ์์ฒญํ๋ค. x86์ํคํ
์ฒ์์ IRQ์ ๊ฐ์ ๋ฒกํฐ๊ฐ 0x08๋ก ๋งคํ๋์ด ์๋ค. ๊ทธ๋ฐ๋ฐ ์ด๊ฒ์ internal interrupt (CPU ์์ธ)์ ๋ฒกํฐ๊ฐ๊ณผ ์ค๋ณต๋๊ธฐ ๋๋ฌธ์, PIC์์ 0x08 ๋ฒกํฐ๋ฅผ 0x20์ผ๋ก ์กฐ์ ํ์ฌ CPU์ ์ ๋ฌํ๋ค.
ํํ ์ค์์ ์ธํฐ๋ฝํธ ํธ๋ค๋ง์ ์ํธ๋ฆฌ๋ intr-stubs.S์ ์ ์๋์ด ์๋ค. ๋ด๋ถ ๋๋ ์ธ๋ถ ์ธํฐ๋ฝํธ๊ฐ ๋ฐ์ํ๋ฉด CPU๋ ์๋์ผ๋ก rip, cs, eflag, rsp, ss๋ฅผ ์คํ์ ํธ์ํ๋ค. ๊ทธ๋ฆฌ๊ณ ์ธํฐ๋ฝํธ ๋ฒกํฐ๊ฐ์ ์ฐธ์กฐํด idt์์ ์คํํ stub ์ฝ๋๋ฅผ ์ฐพ๊ณ (์ด idt ๋งคํ์ interrupt.c
์ register_handler()
ํจ์๊ฐ ํ๋ค) ์คํํ๋ค. stub์ ๋ค์๊ณผ ๊ฐ์ด ์ ์๋์ด ์๋ค.
// intr-stubs.S
#define zero pushq $0; // error code 0์ ์คํ์ ํธ์ํ๋ค
#define REAL // cpu๊ฐ pushํ๋ค
.section .data
.globl intr_stubs
intr_stubs: // stub์ ๋ฐฐ์ด
/* STUB ๋งคํฌ๋ก๋ฅผ ์ ์ํ๋ค */
#define STUB(NUMBER, TYPE)
.section .text; // ๋ฐ์ดํฐ ์น์
์ ๋ช
๋ น์ด๋ฅผ ์์น์์ผ๋ผ
.globl intr##NUMBER##_stub; // intr00_stub๊ณผ ๊ฐ์ ์ ์ญ ํจ์ ์ ์ธ
.func intr##NUMBER##_stub; // ํจ์ ์ ์ ์์
intr##NUMBER##_stub:
TYPE; // type (zero์ธ ๊ฒฝ์ฐ pushq $0)
push $0x##NUMBER; // $0x00๊ณผ ๊ฐ์ vec_no push
jmp intr_entry; // intr_entry ๋ก jump
.endfunc;
.section .data; // ๋ฐ์ดํฐ ์น์
์
.quad intr##NUMBER##_stub; // intr00_stub์ ์ฃผ์๋ฅผ 8๋ฐ์ดํธ๋ก ์ ์ฅ
/* ํ๋์ ์ธํฐ๋ฝํธ ํธ๋ค๋ฌ๋ฅผ ์ ์ฅํ๋ STUB๋งคํฌ๋ก */
STUB(00, zero) STUB(01, zero) STUB(02, zero) ... 256
stub ์ฝ๋๋ ์์๋๋ก error_code, vector number๋ฅผ ์คํ์ pushํ๊ณ intr_entry
๋ก ์ ํํ๋ค. ๊ทธ๋ฌ๋ฉด intr_entry
๋ ๋ญ ํ ๊น?
.section .text
.func intr_entry
intr_entry:
/* Save caller's registers. */
subq $16,%rsp
movw %ds,8(%rsp)
movw %es,0(%rsp)
subq $120,%rsp
movq %rax,112(%rsp)
movq %rbx,104(%rsp)
movq %rcx,96(%rsp)
movq %rdx,88(%rsp)
movq %rbp,80(%rsp)
movq %rdi,72(%rsp)
movq %rsi,64(%rsp)
movq %r8,56(%rsp)
movq %r9,48(%rsp)
movq %r10,40(%rsp)
movq %r11,32(%rsp)
movq %r12,24(%rsp)
movq %r13,16(%rsp)
movq %r14,8(%rsp)
movq %r15,0(%rsp)
cld /* String instructions go upward. */
/* kernel data segement์ selector๋ฅผ %rax์ ์ ์ฅ */
movq $SEL_KDSEG, %rax
/* ๋ฐ์ดํฐ ์ธ๊ทธ๋จผํธ ๋ ์ง์คํฐ์ %ax ์ ์ฅ */
movw %ax, %ds
movw %ax, %es
movw %ax, %ss
movw %ax, %fs
movw %ax, %gs
/* %rdi๊ฐ intr_handler์ ์ธ์์ด๋ค */
movq %rsp,%rdi
/* interrupt handler call */
call intr_handler
movq 0(%rsp), %r15
movq 8(%rsp), %r14
movq 16(%rsp), %r13
movq 24(%rsp), %r12
movq 32(%rsp), %r11
movq 40(%rsp), %r10
movq 48(%rsp), %r9
movq 56(%rsp), %r8
movq 64(%rsp), %rsi
movq 72(%rsp), %rdi
movq 80(%rsp), %rbp
movq 88(%rsp), %rdx
movq 96(%rsp), %rcx
movq 104(%rsp), %rbx
movq 112(%rsp), %rax
addq $120, %rsp
movw 8(%rsp), %ds
movw (%rsp), %es
addq $32, %rsp
iretq
.endfunc
ํ์ฌ์ ๋ ์ง์คํฐ๊ฐ์ ์คํ์ pushํ๊ณ , ์ธ๊ทธ๋จผํธ ๋ ์ง์คํฐ์ $SEL_KDSEG
, ์ฆ ์ปค๋ ๋ฐ์ดํฐ ์ธ๊ทธ๋จผํธ ์ ํ์ (gdt์ ์ธ๋ฑ์ค)๋ฅผ ์ ์ฅํ๋ค. ๊ทธ๋ฆฌ๊ณ movq %rsp, %rdi
๋ก ์คํ ํฌ์ธํฐ๋ฅผ %rdi ๋ ์ง์คํฐ์ ์ ์ฅํ๋๋ฐ, ์ด๋ ์ผ๋ฐ์ ์ผ๋ก ํจ์์ ์ธ์๋ฅผ ๊ฐ๋ฆฌํค๋ ๋ ์ง์คํฐ๋ค. ๋ฐ๋ผ์, ์คํ ํฌ์ธํฐ๋ฅผ ์ธ์๋ก ํ์ฌ call intr_handler
๋ฅผ ํธ์ถํ๋ ๊ฒ์ด๋ค.
void intr_handler(struct intr_frame *frame);
intr_handler
๋ interrupt.c
์ ์ ์๋์ด ์๋ค. ์ฆ, stack์ intr_frame
๊ตฌ์กฐ์ฒด์ ํด๋นํ๋ ๋ค์ ๊ฐ์ ์์ฐจ์ ์ผ๋ก pushํ๊ณ , ์คํ ํฌ์ธํฐ๋ฅผ ์ธ์๋ก ๋๊ธด๋ค. intr_handler๋ ์ธ์๋ก ๋๊ฒจ์ง frame
์์ vec_no
๋ฅผ ์ฐพ์ ํ์ฌ ์ด๋ค ์ธํฐ๋ฝํธ๊ฐ ๋ฐ์ํ๋์ง ์ธ์ํ๊ณ , register_handler()
์ ์ํด ๋งคํ๋ ์ธํฐ๋ฝํธ ์ฒ๋ฆฌ ํจ์๋ฅผ intr_handlers
์์ ๋ฒกํฐ๊ฐ์ผ๋ก ์ธ๋ฑ์ฑํด ์ฐพ์ ์คํํ๋ค. pintos์ ํ์ด๋จธ ์ธํฐ๋ฝํธ์ ๊ฒฝ์ฐ, ์ด ๋ ์คํ๋๋ ํจ์๊ฐ timer.c
์ timer_interrupt()
์ด๋ค.
/* Interrupt stack frame. */
struct gp_registers { /* 8byte * 16 */
uint64_t r15;
uint64_t r14;
uint64_t r13;
uint64_t r12;
uint64_t r11;
uint64_t r10;
uint64_t r9;
uint64_t r8;
uint64_t rsi;
uint64_t rdi;
uint64_t rbp;
uint64_t rdx;
uint64_t rcx;
uint64_t rbx;
uint64_t rax;
} __attribute__((packed));
struct intr_frame {
/* Pushed by intr_entry in intr-stubs.S.
These are the interrupted task's saved registers. */
struct gp_registers R; /* rax to r15 (64bit registers) */
uint16_t es; /* segment register */
uint16_t __pad1; /* padding */
uint32_t __pad2; /* padding */
uint16_t ds; /* data segment */
uint16_t __pad3;
uint32_t __pad4;
/* Pushed by intrNN_stub in intr-stubs.S. */
uint64_t vec_no; /* Interrupt vector number.
์ธํฐ๋ฝํธ ๋ฒกํฐ๊ฐ, ์ด๊ฑธ๋ก ์ธํฐ๋ฝํธ ํธ๋ค๋ฌ๋ฅผ ์ฐพ์ */
uint64_t error_code; /* Sometimes pushed by the CPU,
otherwise for consistency pushed as 0 by intrNN_stub.*/
uintptr_t rip; /* Instruction Pointer */
uint16_t cs; /* Code Segment */
uint16_t __pad5; /* padding */
uint32_t __pad6; /* padding */
uint64_t eflags; /* EFLAG: CF, PF, AF, ZF, SF, TF, IF, DF, OF */
uintptr_t rsp; /* Stack Pointer */
uint16_t ss; /* Segment Register */
uint16_t __pad7;
uint32_t __pad8;
} __attribute__((packed));
intr_handler
๋ ํญ์ ์ธํฐ๋ฝํธ๋ฅผ ๋นํ์ฑํํ๊ณ ์์ํ๋๋ฐ, ์ด๋ ์ผ๋ฐ์ ์ผ๋ก ํ๋์ ์ธํฐ๋ฝํธ ํธ๋ค๋ง์ ๋ค๋ฅธ ์ธํฐ๋ฝํธ์ ์ํด ์ค๋จ๋ ์ ์๊ธฐ ๋๋ฌธ์ด๋ค. ์ธํฐ๋ฝํธ๊ฐ ์ข
๋ฃ๋ ํ์๋, call intr_handler
ํ๊ธฐ ์ stack์ pushํด๋์๋ ๋ค์ ์ธ์คํธ๋ญ์
์ฃผ์๋ฅผ popํด์์ %rip๋ฅผ ํด๋น ์ธ์คํธ๋ญ์
์ ์ฃผ์๋ก ๋ฐ๊พผ๋ค.
*ํ๋ ์ปดํจํฐ์์ ํ์ด๋จธ๋ cpu์ ์๋ค. 1988 ์๋ฃ์์ ์์๋ง์.
๐ PIC์์ ์ ๋ฒกํฐ๊ฐ์ ์ฌ๋งคํํด์ผ ํ ๊น?
์ ์ด์ ์ค๊ณ ๋จ๊ณ์์ ์ ๋ถ๋ฆฌํด๋์ผ๋ฉด ์๋๋ ๊ฑธ๊น? ํ์ง๋ง ์ปดํจํฐ ์ํคํ ์ฒ๋ ์ญ์ฌ์ ์ผ๋ก ๋ฐ์ ๋์ด ์์ผ๋ฉฐ, ์์คํ ์ ๋ณต์ก์ฑ์ด ์ฆ๊ฐํจ์ ๋ฐ๋ผ ์ฒ๋ฆฌํด์ผ ํ ์ธํฐ๋ฝํธ์ ์๊ฐ ์ ์ฐจ ์ฆ๊ฐํ๊ธฐ๋ ํ๋ค. ์ด์ ๋ฐ๋ผ ๋ฒกํฐ๊ฐ์ ์๋ก ๋ค ํ ๋นํ๊ธฐ๋ณด๋ค๋ ์ํํธ์จ์ด์ ์ผ๋ก ์ฌ๋งคํํ์ฌ ์ฒ๋ฆฌํ ํ์์ฑ์ด ์๊ฒจ๋ฌ๋ค. ์ํคํ ์ฒ๋ ์ญ์ฌ์ ์ฐ์ถ๋ฌผ์ด๋ฏ๋ก.. ์ด๋ ํ ์๊ฐ์ ์๋ฒฝํ ์ค๊ณ์ ์ํด ํ์ํ ๊ฒ์ ์๋๋ค.
๐ค ์ง๋ฌธ์ ๋ตํด๋ณด์
- %rip, %rsp register์ ์๋ฏธ์ CPU ๋์์์์ ์ญํ
%rip๋ ํ์ฌ ์ธ์คํธ๋ญ์ ์ ๊ฐ๋ฆฌํจ๋ค. %rsp๋ ์คํ์ top์ ๊ฐ๋ฆฌํจ๋ค. - assembly ๋ช ๋ น์ด JMP์ CALL์ ์ฐจ์ด์ JMP๋ ํน์ ์ฃผ์์ ์ธ์คํธ๋ญ์ ์ผ๋ก ์ด๋ํ๋ค. CALL์ ๋ค์์ ์คํ๋์ด์ผ ํ ์ธ์คํธ๋ญ์ ์ฃผ์๋ฅผ stack์ ์ ์ฅํด๋๊ณ ์ด๋ํ๋ค. stack์ ์ด๋ป๊ฒ ์ ์ฅํ๋๊ฐ? %rsp๋ฅผ 8 ๊ฐ์์์ผ์ ์คํ ์์ญ์ 8byte ๋ํ๊ณ , ํ์ฌ %rip๋ฅผ %rsp์ ํธ์ํ๋ค.
- JMP, CALL, RET, PUSH, POP, IRET ๋ช ๋ น์์ %rip, %rsp๋ ์ด๋ป๊ฒ ๊ฐ์ด ๋ณํ๋๊ฐ?
- JMP 0xa๋ฅผ ํ๋ฉด %rip๋ 0xa๊ฐ ๋๋ค. %rsp๋ ๋ณํ์ง ์๋๋ค.
- CALL 0xa์ ํ๋ฉด %rip๋ 0xa๊ฐ ๋๋ค. %rsp๋ 8 ๊ฐ์ํ๋ค. (๋ค์์ ์คํ๋ ์ธ์คํธ๋ญ์ ์ฃผ์ ํฌ๊ธฐ๋งํผ)
- RET์ ํ๋ฉด %rip๋ (%rsp) ๊ฐ ๋๋ค. %rsp๋ 8 ์ฆ๊ฐํ๋ค.
- PUSH a๋ฅผ ํ๋ฉด %rsp๋ a์ ํฌ๊ธฐ(8)๋งํผ ๊ฐ์ํ๋ค. %rip๋ ๋ณํ์ง ์๋๋ค.
- POP์ ํ๋ฉด %rsp๋ 8๋งํผ ์ฆ๊ฐ์ํจ๋ค. %rip๋ ๋ณํ์ง ์๋๋ค.
- IRET์ ํ๋ฉด %rsp๋ 8๋งํผ ์ฆ๊ฐํ๋ค. %rip๋ ์คํ์์ pop๋ ๊ฐ์ด๋ค.
- interrupt ๋ฐ์ ์ CPU๋ ์ด๋ป๊ฒ ๋์ํ๋๊ฐ? register ๊ฐ ๋ฐ ์ฐ๊ด๋ memory๋? interrupt ๋ฐ์ํ๋ฉด CPU๋ ํด๋น ์ธํฐ๋ฝํธ ๋ฒกํฐ๊ฐ์ ๋งคํ๋ interrupt handler๋ฅผ idt์์ ์ฐพ์ callํ๋ค. call์ ํ๋ฉด interrupt handler๊ฐ iret์ผ๋ก ๋ฐํ๋ ์ดํ ์คํ๋์ด์ผ ํ ์ธ์คํธ๋ญ์ ์ ์ฃผ์๋ฅผ ์คํ์ ์ ์ฅํ๊ณ , interrupt handler์ ์ฃผ์๋ก %rip๋ฅผ ๋ณ๊ฒฝํ๋ค.
- interrupt๋ฅผ ์ฒ๋ฆฌํ ํ์๋ ์ด๋ป๊ฒ ๋๋๊ฐ? inpterrupt์ฒ๋ฆฌ๊ฐ ์๋ฃ๋ ํ์๋, call์ ์ stack์ pushํด๋์๋ ์ฃผ์๋ฅผ ์ฐพ์ ์คํํ๋ค.
- interrupt๋ ์ด๋ป๊ฒ enable/disable ์ํฌ ์ ์๋๊ฐ? enable/disable ๋๋ฉด ๋ญ๊ฐ ๋ฌ๋ผ์ง๋๊ฐ? interrupt flag๋ฅผ ๋๋ฉด disable, ์ผ๋ฉด enable์ด๋ค. interrupt flag๋ EFLAG ๋ ์ง์คํฐ์ 9๋ฒ์งธ ๋นํธ์ ์์นํ๊ณ ์์ด, 1์ธ ๊ฒฝ์ฐ ์ธํฐ๋ฝํธ๋ฅผ ํ์ฉ, 0์ธ ๊ฒฝ์ฐ ์ธํฐ๋ฝํธ๋ฅผ ๋นํ์ฉํ๋ค. ์ด์
๋ธ๋ฆฌ ๋ช
๋ น์ด๋ก๋ sti (set interrupt flag)๊ฐ ์ธํฐ๋ฝํธ๋ฅผ ํ์ฉํ๊ณ , cli (clear interrupt flag)๊ฐ ์ธํฐ๋ฝํธ๋ฅผ ๋นํ์ฉํ๋ค. sti๋ ์ธํฐ๋ฝํธ๋ฅผ ํ์ฉํ์ง๋ง, ๋ฐ๋ก ๋ค์์ ๋์ค๋ ๋ช
๋ น์ด๊น์ง๋ ์ธํฐ๋ฝํธ๋ฅผ ๋นํ์ฉํ๋ค. ์ฆ,
sti; hlt;
๋ฅผ ํ๋ฉด ์ด๋ค ๋ช ๋ น์ด๊ฐ ๋ค ์คํ๋ ๋๊น์ง๋ ์ธํฐ๋ฝํธ์ ์ํด ๋ฐฉํด๋ฐ์ง ์๊ณ ์ํ ๋ฏนํ๊ฒ ์คํ๋๋ค๋ ๊ฒ์ด๋ค. - NMI (Non-Maskable Interrupt)๋ ๋ฌด์์ธ๊ฐ? ์ธํฐ๋ฝํธ ๋ง์คํน์ด๋, ํธ๋ค๋ง ์ค์ธ ์ธํฐ๋ฝํธ๋ฅผ ์ค๋จํ๊ณ ๋ฐ์ํ ์ธํฐ๋ฝํธ๋ฅผ ๋จผ์ ์ฒ๋ฆฌํ๋ ๊ฒ์ด๋ค. Non Maskable Interrupt๋ ์ด๋ ๊ฒ ์ค๋จ๋ ์ ์๋ ์ธํฐ๋ฝํธ๋ฅผ ๋งํ๋ค.
- timer interrupt๋ ๋๊ฐ ๋ฐ์์ํค๋๊ฐ? Pintos์์๋ 8254 Timer (Programmable Timer)๊ฐ ์๋ค. ์ด ํ์ด๋จธ๋ฅผ timer_init๋ฑ์ผ๋ก ์ผ์ ๊ฐ๊ฒฉ๋ง๋ค ์ธํฐ๋ฝํธ๋ฅผ ๋ฐ์์ํค๋๋ก ์ค์ ํ๋ฉด, ๋ฒกํฐ๊ฐ 0x20์ ๊ฐ๊ฒฉ๋ง๋ค CPU๋ด IPC ์นฉ์ผ๋ก ๋ณด๋ด์ ์ธํฐ๋ฝํธ๋ฅผ ๋ฐ์์ํจ๋ค.
- EFLAGS register๋ ๋ฌด์์ธ๊ฐ? ์ํ๋ฅผ ๋ํ๋ด๋ ์ ๋ณด๋ฅผ ๋ด๊ณ ์๋ ๋ ์ง์คํฐ์ด๋ค. Interrupt ํ์ฉ/๋นํ์ฉ์ ์ค์ ํ๋ Interrupt Flag (IF)๊ฐ ์ด ๋ ์ง์คํฐ์ ์๋ค.
'DevLog ๐จ' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[DevLog][PintOS] PRJ3 Virtual Memory/Memory Management to Stack Growth (2) | 2023.10.17 |
---|---|
[DevLog][PintOS] PRJ2 User Program/Out of Memory Test (0) | 2023.10.10 |
[DevLog][PintOS] PRJ1 Threads/Scheduling Algorithms (0) | 2023.10.03 |
[DevLog][PintOS] PRJ1 Threads/Priority Scheduling (0) | 2023.09.27 |
[DevLog][CSAPP] 10์ฅ ์์คํ ์์ค ์ ์ถ๋ ฅ (10.1~10.5) (0) | 2023.09.24 |