Mô phỏng Linus Torvalds: Tạo hệ điều hành của riêng bạn từ đầu (IV)

Chào mừng bạn quay trở lại loạt bài viết có tựa đề "Mô phỏng Linus Torvalds". Hôm nay chúng ta sẽ xem GDT. Đầu tiên chúng ta phải xem GDT là gì. Theo Wikipedia:

Sản phẩm Bảng mô tả toàn cầu or Giáo dục là một cấu trúc dữ liệu được sử dụng bởi Intel x86-bộ xử lý gia đình bắt đầu với 80286 để xác định các đặc tính của các vùng bộ nhớ khác nhau được sử dụng trong quá trình thực thi chương trình, bao gồm địa chỉ cơ sở, kích thước và các đặc quyền truy cập như khả năng thực thi và khả năng ghi

Những gì được dịch sẽ là Bảng mô tả toàn cục, một cấu trúc dữ liệu được sử dụng trong bộ xử lý Intel x86 từ năm 80286 để xác định các đặc tính của các vùng bộ nhớ khác nhau được sử dụng trong quá trình thực thi chương trình.

Tóm lại, nếu chúng ta đang sử dụng bộ xử lý Intel x86, chúng ta phải xác định GDT để sử dụng bộ nhớ chính xác. Chúng tôi sẽ không làm phức tạp nhiều và chúng tôi sẽ xác định 3 mục nhập trong bảng:

  • Mục nhập NULL, bắt buộc cho tất cả các bảng.
  • Một vé cho phần dữ liệu, chúng tôi sẽ sử dụng tối đa, trong 32 bit là 4 GB.
  • Một vé cho phần , chúng tôi sẽ sử dụng tối đa, trong 32 bit là 4 GB.

Như bạn có thể thấy, dữ liệu và mã sẽ sử dụng cùng một không gian. Ok, bây giờ chúng ta sẽ thực hiện nó. Đối với điều này, chúng tôi sẽ sử dụng hai cấu trúc, cấu trúc đầu tiên sẽ phụ trách chứa một con trỏ đến dữ liệu thực của GDT của chúng tôi. Và thứ hai sẽ là một mảng với các mục GDT. Hãy xác định chúng trước

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));

Bạn có thể nhận thấy __ thuộc tính __ ((đóng gói)) tò mò ở cuối cấu trúc. Điều này cho GCC biết không nên tối ưu hóa các cấu trúc vì những gì chúng ta muốn là truyền dữ liệu nguyên trạng đến bộ xử lý. Bây giờ chúng ta sẽ tạo một hàm để cài đặt GDT. Trước khi chúng ta nên khai báo các cấu trúc, bây giờ chúng ta sẽ khởi tạo chúng.

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;
}

Vì vậy, chúng tôi phải xây dựng con trỏ đi đến bảng 3 đầu vào của chúng tôi.

Nếu bạn biên dịch bằng 64 bit thì rất có thể sẽ bị lỗi ở đây. Điều này là do con trỏ trên hệ thống 64 bit rõ ràng là 64 bit và chúng tôi đang sử dụng loại 32 bit ở đây. Sử dụng tùy chọn -m32 có thể hữu ích ngay bây giờ
Bây giờ chúng ta xác định một hàm chung để đưa dữ liệu vào các đầu vào

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;
}

Và chúng tôi gọi nó 3 lần từ hàm cài đặt

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 */

Cuối cùng, chúng ta phải nói với bộ xử lý rằng chúng ta có GDT để nó có thể tải nó, và trong trường hợp của chúng ta khi tải hạt nhân bằng GRUB, hãy ghi đè lên GRUB GDT. Để tải GDT, có một lệnh trong asm được gọi là lgdt (hoặc lgdtl tùy thuộc vào cú pháp), chúng ta sẽ sử dụng nó.

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"
);

Sau khi hoàn thành việc này, hệ thống của chúng tôi sẽ có GDT. Trong chương tiếp theo, chúng ta sẽ thấy IDT, một bảng rất giống với GDT nhưng có sự gián đoạn. Tôi đã đặt một số trạng thái và thông báo xác nhận với GDT để NextDivel bây giờ trông như thế này:

Tiếp theoDivel-GDT


Để lại bình luận của bạn

địa chỉ email của bạn sẽ không được công bố. Các trường bắt buộc được đánh dấu bằng *

*

*

  1. Chịu trách nhiệm về dữ liệu: Miguel Ángel Gatón
  2. Mục đích của dữ liệu: Kiểm soát SPAM, quản lý bình luận.
  3. Hợp pháp: Sự đồng ý của bạn
  4. Truyền thông dữ liệu: Dữ liệu sẽ không được thông báo cho các bên thứ ba trừ khi có nghĩa vụ pháp lý.
  5. Lưu trữ dữ liệu: Cơ sở dữ liệu do Occentus Networks (EU) lưu trữ
  6. Quyền: Bất cứ lúc nào bạn có thể giới hạn, khôi phục và xóa thông tin của mình.

  1.   saeron dijo

    Có lẽ cấu trúc 64-bit phù hợp hơn trong thời điểm này, việc tiếp tục sử dụng 8086 là một công việc tồn đọng.

    1.    AdrianArroyoStreet dijo

      Tôi đã tìm kiếm thông tin về GDT trong x86_64 và tôi nghĩ rằng nó tuân theo mô hình cũ với một lá cờ đặc biệt. Địa chỉ 32 bit vẫn được sử dụng. Bây giờ tôi không biết chính xác phải làm như thế nào cho chính xác. Một số liên kết:
      http://wiki.osdev.org/Entering_Long_Mode_Directly
      http://f.osdev.org/viewtopic.php?f=1&t=16275

  2.   Geronimo dijo

    Trước hết, đóng góp của bạn rất tốt, nhưng tôi nghĩ tiêu đề nên
    "Mô phỏng Richard Stallman" hoặc ít nhất là tôi nghĩ vậy ,,,
    Liên quan

    1.    abimaelmartell dijo

      Linus tạo ra nhân Linux, Stallman tạo GNU là các công cụ và lệnh Unix.

      Tiêu đề phù hợp vì bạn đang tạo ra một hạt nhân.

      Một lời chào!

  3.   hồng ngọc dijo

    Rất cảm ơn các bạn đã giải đáp mọi thắc mắc của mình và đã kiên nhẫn, mình chỉ biết cơ bản với tư cách là một người lắp ráp và hầu như không biết gì về C, nhưng mình rất thích nó, hiện tại mình hơi bối rối với GDT, cùng xem nhé. hiểu biết.

    GDT sẽ có các 'bộ mô tả' toàn cầu luôn có thể được truy cập bởi bất kỳ chương trình nào và các bộ mô tả này trỏ đến các phần mà (chương trình) sẽ được thực thi? hoặc nó là khác.