Linus Torvalds 에뮬레이션 : 0 (V)에서 자체 운영 체제 만들기

이 다섯 번째 기사에서는 이론과 사용 모두에서 GDT와 매우 유사한 테이블을 볼 수 있습니다. 우리는 IDT를 참조합니다. IDT는 인터럽트 설명 테이블 y는 발생하는 인터럽트를 처리하는 데 사용되는 테이블입니다. 예를 들어, 누군가가 0으로 나누면 처리를 담당하는 함수가 호출됩니다. 이러한 기능은 ISR (인터럽트 서비스 루틴). 이제 IDT를 만들고 ISR을 추가해 보겠습니다.

먼저 IDT에 해당하는 구조를 선언합니다.

struct Entry{
uint16_t base_low;
uint16_t sel;
uint8_t always0;
uint8_t flags;
uint16_t base_high;
} __attribute__((packed));
struct Ptr{
uint16_t limit;
uint32_t base;
} __attribute__((packed));

GDT와 비교하면 알 수 있듯이 Ptr 구조는 동일하고 Entry도 매우 유사합니다. 따라서 항목 입력 (SetGate)과 설치 (Install) 기능은 매우 유사합니다.

void ND::IDT::SetGate(uint8_t num,uint32_t base,uint16_t sel, uint8_t flags)
{
idt[num].base_low=(base & 0xFFFF);
idt[num].base_high=(base >> 16) & 0xFFFF;
idt[num].sel=sel;
idt[num].always0=0;
idt[num].flags=flags;
}

설치:

idtptr.limit=(sizeof(struct ND::IDT::Entry)*256)-1;
idtptr.base=(uint32_t)&idt;
ND::Memory::Set(&idt,0,sizeof(struct ND::IDT::Entry)*256);
ND::IDT::Flush();

살펴보면 install 함수는 다른 포스트에서 선언 한 ND :: Memory :: Set 함수를 사용하는 것을 볼 수 있습니다. 또한 아직 SetGate를 호출하지 않고 ND :: IDT :: Flush를 호출하는 방법도 이해할 수 있습니다.이 함수에 대해 asm volatile 문을 다시 사용합니다.

asm volatile("lidtl (idtptr)");

모든 것이 잘되고 미적 배치를하면 다음과 같이 보일 것입니다.

다음다이벌-IDT

자, 이제 우리는 인터럽트로 IDT를 채우기 시작할 것입니다. 여기서는 하나만 만들지 만 나머지는 동일합니다. 제로 브레이크로 나누겠습니다. 수학에서 잘 알고 있듯이 숫자는 0으로 나눌 수 없습니다. 프로세서에서 이런 일이 발생하면 계속할 수 없기 때문에 예외가 생성됩니다. IDT에서 목록 (0)의 첫 번째 인터럽트는이 이벤트에 해당합니다.

IDT의 설치 기능 내에서 메모리 설정과 플러시 사이에 다음을 추가합니다.

ND::IDT::SetGate(0,(unsigned)ND::ISR::ISR1,0x08,0x8E);

콜백 함수는 ND :: ISR :: ISR1이 될 것입니다. ASM을 사용해야하지만 매우 간단합니다.

void ND::ISR::ISR1()
{
asm volatile(
"cli \n"
"pushl 0 \n"
"pushl 0 \n"
"jmp ND_ISR_Common \n"
);
}

ND_ISR_Common을 C 언어의 함수로 정의하겠습니다. 파일을 저장하고 가독성을 높이기 위해 extern«C»{}를 사용할 수 있습니다.

extern "C"
void ND_ISR_Common()
{
asm volatile(
"pusha \n"
"push %ds \n"
"push %es \n"
"push %fs \n"
"push %gs \n"
"movw $0x10, %ax \n"
"movw %ax, %ds \n"
"movw %ax, %es \n"
"movw %ax, %fs \n"
"movw %ax, %gs \n"
"movl %esp, %eax \n"
"push %eax \n"
"movl $ND_ISR_Handler, %eax \n"
"call *%eax \n"
"popl %eax \n"
"popl %ds \n"
"popl %es \n"
"popl %fs \n"
"popl %gs \n"
"popa \n"
"addl 8, %esp \n"
"iret \n"
);
}

ASM의이 코드는 이해하기가 조금 어려울 수 있지만 인터럽트에 의해 생성 된 데이터에 액세스하기 위해 C로 구조를 선언하기 때문입니다. 분명히 원하지 않으면 ND :: ISR :: ISR1 또는 이와 유사한 것으로 Kernel Panic을 호출 할 수 있습니다. 구조는 다음과 같은 모양을 갖습니다.

struct regs{
uint32_t ds;
uint32_t edi, esi, ebp, esp, ebx, edx, ecx, eax;
uint32_t int_no, err_code;
uint32_t eip, cs, eflags, useresp, ss;
};

그리고 마지막으로 ND_ISR_Handler 함수 (C 링크 포함)를 만들어서 커널 패닉과 오류 목록에있는 오류에 대한 작은 설명을 보여줍니다.

extern "C"
void ND_ISR_Handler(struct regs *r)
{
if(r->int_no < 32) { ND::Panic::Show(exception_messages[r->int_no]);
for(;;);
}
}

음, 이것으로 우리는이 중단을 처리 할 수 ​​있습니다. 나머지 중단에서는 매개 변수를 반환하는 일부가 있고이를 얻기 위해 reg 구조를 사용한다는 점을 제외하면 유사하게 발생합니다. 그러나 실제로 작동하는지 어떻게 알 수 있는지 궁금 할 수 있습니다. 작동하는지 테스트하기 위해 ND :: IDT :: Install () 뒤에 간단한 줄을 도입 할 것입니다.

int sum=10/0;

컴파일하면 경고가 표시되고 실행하려고하면 멋진 화면이 표시됩니다.

NextDive-ISR


그리고 이것으로이 포스트를 끝내고, 저는 그것이 가장 광범위하지만 상당히 기능적인 것 중 하나라고 생각합니다.


5 코멘트, 당신의 것을 남겨주세요

코멘트를 남겨주세요

귀하의 이메일 주소는 공개되지 않습니다. 필수 필드가 표시되어 있습니다 *

*

*

  1. 데이터 책임자 : Miguel Ángel Gatón
  2. 데이터의 목적 : 스팸 제어, 댓글 관리.
  3. 합법성 : 귀하의 동의
  4. 데이터 전달 : 법적 의무에 의한 경우를 제외하고 데이터는 제 XNUMX 자에게 전달되지 않습니다.
  5. 데이터 저장소 : Occentus Networks (EU)에서 호스팅하는 데이터베이스
  6. 권리 : 귀하는 언제든지 귀하의 정보를 제한, 복구 및 삭제할 수 있습니다.

  1.   메소다블러

    LFS로 전환했는데 더 연속적입니다.

  2.   엘리오타임3000

    이런 ... 어쨌든, 튜토리얼은 좋습니다.

  3.   sc

    아주 좋아, 나는 처음부터 그것을 따라왔다. 각 트레일러에 코드를 첨부 할 수 있습니까?

    1.    AdrianArroyoStreet

      GitHub에서 모든 소스 코드를 사용할 수 있습니다. http://github.com/AdrianArroyoCalle/next-divel 거기에서 ZIP, TAR.GZ를 다운로드하거나 git을 사용할 수 있습니다.

  4.   미묘한

    하하하 아주 좋아요! 승낙! 🙂