Linus Torvalds 에뮬레이션 : 처음부터 자신 만의 운영 체제 만들기 (IV)

"Linus Torvalds 모방"이라는 제목의이 게시물 시리즈에 다시 오신 것을 환영합니다. 오늘 우리는 GDT를 볼 것입니다. 먼저 GDT가 무엇인지 확인해야합니다. Wikipedia에 따르면 :

  글로벌 설명자 테이블 or GDT 에서 사용하는 데이터 구조입니다. 인텔 x86-로 시작하는 제품군 프로세서 80286 기본 주소, 실행 가능성 및 쓰기 가능성과 같은 액세스 권한 및 크기를 포함하여 프로그램 실행 중에 사용되는 다양한 메모리 영역의 특성을 정의하기 위해

번역 된 것은 프로그램 실행 중에 사용되는 다양한 메모리 영역의 특성을 정의하기 위해 86 이후 Intel x80286 프로세서에서 사용 된 데이터 구조 인 Global Descriptor Table입니다.

요약하면 Intel x86 프로세서를 사용하는 경우 올바른 메모리 사용을 위해 GDT를 정의해야합니다. 우리는 그다지 복잡하지 않고 테이블에 3 개의 항목을 정의 할 것입니다.

  • 모든 테이블에 필요한 NULL 항목.
  • 구간 티켓 데이터, 32 비트에서 4GB 인 최대 값을 사용합니다.
  • 구간 티켓 암호, 32 비트에서 4GB 인 최대 값을 사용합니다.

보시다시피 데이터와 코드는 동일한 공간을 사용합니다. 자, 이제 우리는 그것을 구현할 것입니다. 이를 위해 우리는 두 개의 구조를 사용할 것입니다. 첫 번째 구조는 GDT의 실제 데이터에 대한 포인터를 포함하는 역할을합니다. 두 번째는 GDT 항목이있는 배열입니다. 먼저 정의합시다

struct Entry{
uint16_t limit_low;
uint16_t base_low;
uint8_t base_middle;
uint8_t access;
uint8_t granularity;
uint8_t base_high;
} __attribute__((packed));
struct Ptr{
uint16_t limit;
uint32_t base;
} __attribute__((packed));

구조 끝에 흥미로운 __attribute __ ((packed))가 있음을 알 수 있습니다. 이것은 우리가 원하는 것은 데이터를있는 그대로 프로세서에 전달하는 것이기 때문에 GCC가 구조를 최적화하지 않도록 지시합니다. 이제 GDT를 설치하는 기능을 만들 것입니다. 구조를 선언하기 전에 이제 초기화 할 것입니다.

struct ND::GDT::Entry gdt[3];
struct ND::GDT::Ptr gp;
void ND::GDT::Install()
{
gp.limit=(sizeof(struct ND::GDT::Entry)*3)-1;
gp.base=(uint32_t)&gdt;
}

그래서 우리는 3- 입력 테이블로가는 포인터를 구축합니다.

64 비트를 사용하여 컴파일하면 여기서 실패 할 가능성이 높습니다. 64 비트 시스템의 포인터는 분명히 64 비트이고 여기서는 32 비트 유형을 사용하기 때문입니다. -m32 옵션을 사용하면 도움이 될 수 있습니다.
이제 데이터를 입력에 넣는 공통 함수를 정의합니다.

void ND::GDT::SetGate(int num, uint32_t base, uint32_t limit, uint8_t access,uint8_t gran)
{
gdt[num].base_low=(base & 0xFFFF);
gdt[num].base_middle=(base >> 16) & 0xFF;
gdt[num].base_high=(base >> 24) & 0xFF;
gdt[num].limit_low=(limit & 0xFFFF);
gdt[num].granularity=(limit >> 16) & 0x0F;
gdt[num].granularity |= (gran & 0xF0);
gdt[num].access=access;
}

그리고 install 함수에서 3 번 호출합니다.

ND::GDT::SetGate(0,0,0,0,0); /* NULL segmente entry */
ND::GDT::SetGate(1,0,0xFFFFFFFF,0x9A,0xCF); /* 4 GiB for Code Segment */
ND::GDT::SetGate(2,0,0xFFFFFFFF,0x92,0xCF); /* 4 GiB for Data segment */

마지막으로, 우리는 GDT가 있다는 것을 프로세서에 알려서로드 할 수 있도록해야합니다. 우리의 경우 GRUB로 커널을로드 할 때 GRUB GDT를 덮어 씁니다. GDT를로드하기 위해 asm에 lgdt (또는 구문에 따라 lgdtl)라는 명령어가 있습니다.이 명령어를 사용할 것입니다.

asm volatile("lgdtl (gp)");
asm volatile(
"movw $0x10, %ax \n"
"movw %ax, %ds \n"
"movw %ax, %es \n"
"movw %ax, %fs \n"
"movw %ax, %gs \n"
"movw %ax, %ss \n"
"ljmp $0x08, $next \n"
"next: \n"
);

일단 우리가 이것을 마치면 우리 시스템은 이미 GDT를 갖게 될 것입니다. 다음 장에서는 GDT와 매우 유사하지만 중단이있는 테이블 인 IDT를 볼 것입니다. GDT에 몇 가지 상태 및 확인 메시지를 넣었으므로 NextDivel은 다음과 같이 보입니다.

NextDive-GDT


코멘트를 남겨주세요

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

*

*

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

  1.   새론

    아마도 64 비트 구조가이시기에 더 적합 할 것입니다. 8086을 계속 사용하는 것은 지연입니다.

    1.    AdrianArroyoStreet

      x86_64에서 GDT에 대한 정보를 찾고 있었는데 특수 플래그가있는 이전 모델을 따르는 것 같습니다. 32 비트 주소는 계속 사용됩니다. 이제 정확히 어떻게해야할지 모르겠습니다. 일부 링크 :
      http://wiki.osdev.org/Entering_Long_Mode_Directly
      http://f.osdev.org/viewtopic.php?f=1&t=16275

  2.   제로니모

    첫 번째는 여러분의 공헌이 아주 좋았지 만 제목은
    "리처드 스톨만 모방"정도라고 생각합니다.
    안부

    1.    Abimaelmartell

      Linus는 Linux 커널을 만들었고 Stallman은 Unix 도구 및 명령 인 GNU를 만들었습니다.

      핵을 만들고 있기 때문에 제목이 적절합니다.

      인사말!

  3.   루비

    내 모든 질문에 답하고 인내심을 가져 주셔서 대단히 감사합니다. 어셈블러로서 저는 기본 사항 만 알고 C로서 거의 아무것도 알지 못합니다.하지만 저는 그것을 많이 좋아합니다. 이제 저는 GDT와 약간 헷갈립니다. 이해하다.

    GDT에는 모든 프로그램에서 항상 액세스 할 수있는 전역 '설명자'가 있으며 이러한 설명자는 (프로그램)이 실행될 섹션을 가리 킵니다. 아니면 그렇지 않습니다.