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

Trong phần thứ năm này, chúng ta sẽ thấy một bảng khá giống với GDT cả về lý thuyết và cách sử dụng, chúng ta tham khảo IDT. IDT là viết tắt của Bảng mô tả ngắt y là một bảng được sử dụng để xử lý các ngắt xảy ra. Ví dụ, ai đó thực hiện phép chia cho 0 thì hàm phụ trách xử lý được gọi. Các chức năng này là ISR (Quy trình dịch vụ gián đoạn). Vì vậy, hãy tạo IDT và thêm một số ISR.

Đầu tiên chúng ta sẽ khai báo các cấu trúc tương ứng với 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));

Có thể thấy nếu bạn so sánh với GDT, cấu trúc Ptr giống hệt nhau và Entry khá giống nhau. Do đó các chức năng đặt mục nhập (SetGate) và cài đặt (Install) rất giống nhau.

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

Tải về:

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

Nếu chúng ta quan sát, chúng ta sẽ thấy rằng hàm cài đặt sử dụng hàm ND :: Bộ nhớ :: Đặt mà chúng ta đã khai báo trong bài viết khác. Chúng tôi cũng có thể đánh giá cao cách chúng tôi chưa thực hiện bất kỳ lệnh gọi nào đến SetGate và chúng tôi gọi ND :: IDT :: Flush, đối với hàm này, chúng tôi sử dụng lại câu lệnh asm variable:

asm volatile("lidtl (idtptr)");

Nếu mọi thứ diễn ra suôn sẻ và chúng tôi sắp xếp hợp lý, nó sẽ trông như thế này:

NextDivel-RTD

Được rồi, bây giờ chúng ta sẽ bắt đầu điền IDT với các ngắt. Ở đây tôi sẽ chỉ tạo một cái nhưng phần còn lại sẽ giống nhau. Tôi sẽ thực hiện phép chia cho số không. Như bạn đã biết trong toán học, một số không thể chia cho 0. Nếu điều này xảy ra trong bộ xử lý, một ngoại lệ sẽ được tạo ra vì nó không thể tiếp tục. Trong IDT, ngắt đầu tiên trong danh sách (0) tương ứng với sự kiện này.

Chúng tôi thêm điều này vào giữa cài đặt bộ nhớ và xả trong chức năng Cài đặt của IDT:

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

Hàm gọi lại sẽ là ND :: ISR :: ISR1 khá đơn giản mặc dù chúng ta phải sử dụng ASM:

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

ND_ISR_Common, chúng tôi sẽ định nghĩa nó như một hàm trong ngôn ngữ C. Để lưu tệp và cải thiện khả năng đọc, chúng tôi có thể sử dụng 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"
);
}

Mã này trong ASM có thể hơi khó hiểu nhưng điều này là do chúng ta sẽ khai báo một cấu trúc trong C để truy cập dữ liệu được tạo ra bởi ngắt. Rõ ràng, nếu bạn không muốn điều đó, bạn có thể gọi Kernel Panic trong ND :: ISR :: ISR1 hoặc một cái gì đó tương tự. Cấu trúc có hình dạng như vậy:

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

Và cuối cùng, chúng tôi tạo hàm ND_ISR_Handler (cũng có liên kết C), trong đó chúng tôi hiển thị sự hoảng loạn của hạt nhân và một mô tả nhỏ về lỗi theo như chúng tôi có trong danh sách các lỗi.

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

Tốt và với điều này, chúng tôi đã có thể xử lý sự gián đoạn này. Với phần còn lại của các gián đoạn, nó sẽ xảy ra tương tự ngoại trừ có một số trả về các tham số và chúng tôi sẽ sử dụng cấu trúc reg để lấy nó. Tuy nhiên, bạn có thể tự hỏi làm thế nào chúng tôi biết nếu nó thực sự hoạt động. Để kiểm tra xem nó có hoạt động hay không, chúng tôi sẽ giới thiệu một dòng đơn giản sau ND :: IDT :: Install ():

int sum=10/0;

Nếu chúng tôi biên dịch, nó sẽ đưa ra một cảnh báo và nếu chúng tôi cố gắng thực thi nó, chúng tôi sẽ nhận được một màn hình đẹp:

Tiếp theoDivel-ISR


Và với điều này kết thúc bài đăng này, tôi nghĩ rằng nó là một trong những phần mở rộng nhất nhưng khá chức năng.


Để 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.   mesodabler dijo

    Tôi chuyển sang LFS, nó liên tục hơn.

  2.   eliotime3000 dijo

    Thánh ... Dù sao, các hướng dẫn là tốt.

  3.   sc dijo

    Rất tốt, tôi đã theo dõi nó ngay từ đầu. Bạn có thể đính kèm mã vào mỗi đoạn giới thiệu không?

    1.    AdrianArroyoStreet dijo

      Bạn có tất cả mã nguồn trên GitHub: http://github.com/AdrianArroyoCalle/next-divel Từ đó, bạn có thể tải xuống tệp ZIP, TAR.GZ hoặc chỉ sử dụng git.

  4.   sắc thái dijo

    Hahaha rất tốt! Phê duyệt! 🙂