@Denys557

Почему ОС запускается на QEMU, а на Virtual Box нет?

Получается у меня есть ОС, но после добавления IDT и GDT она перестала запускаться на Virtual Box, и от безысходности решил попробовать запустить на QEMU, и всё заработало. Как так? Я бы оставил ссылку на репозиторий, но он пока что закрыт, так что если нужен код других файлов - говорите

IDT.cpp:

#include "IDT/IDT.h"
#include "terminal/terminal.h"
#include "utils/utils.h"

using namespace SimpleOS;

void IDT::init_idt() {
    idt_ptr.limit = (sizeof(struct IDTSlot) * IDT_SIZE) - 1;
    idt_ptr.base = (uintptr_t)&idt;

    memset(&idt, 0, sizeof(struct IDTSlot) * IDT_SIZE);
    
    load_idt();

    for(size_t i = 0; i < 32; ++i) {
        set_in_idt_slot(i, (uint32_t)dividing_by_zero, 0x08, 0x8E);
    }
}

void IDT::set_in_idt_slot(int pos, uint32_t base, uint16_t sel, uint8_t flags) {
    idt[pos].offset_first = base & 0xFFFF;
    idt[pos].selector = sel;
    idt[pos].zero = 0;
    idt[pos].type_attr = flags | 0x60;
    idt[pos].offset_second = (base >> 16) & 0xFFFF;
}

extern "C" void SimpleOS::dividing_by_zero() {
    Terminal::print("Failed operation dividing by zero");
}

IDT::IDTSlot IDT::idt[IDT_SIZE];
IDT::IDTPtr IDT::idt_ptr;


GDT.cpp:

#include "GDT/GDT.h"
#include "utils/utils.h"

using namespace SimpleOS;

void GDT::init_gdt() {
gdt_ptr.limit = (sizeof(struct GDTSlot) * 6) - 1;
gdt_ptr.base = (unsigned int)&gdt;

set_in_gdt_slot(0, 0, 0, 0, 0);

set_in_gdt_slot(1, 0, 0xFFFFFFFF, 0x9A, 0xCF);

set_in_gdt_slot(2, 0, 0xFFFFFFFF, 0x92, 0xCF);

set_in_gdt_slot(3, 0, 0xFFFFFFFF, 0xFA, 0xCF);

set_in_gdt_slot(4, 0, 0xFFFFFFFF, 0xF2, 0xCF);
write_tss(5, 0x10, 0x0);

load_gdt();
load_tss();
}

void GDT::set_in_gdt_slot(int pos, uint64_t base, uint64_t limit, uint8_t access, uint8_t gran) {
gdt[pos].base_low = (base & 0xFFFF);
gdt[pos].base_middle = (base >> 16) & 0xFF;
gdt[pos].base_high = (base >> 24) & 0xFF;
gdt[pos].limit_low = (limit & 0xFFFF);
gdt[pos].granularity = (limit >> 16) & 0X0F;
gdt[pos].granularity |= (gran & 0xF0);
gdt[pos].access = access;
}

void GDT::write_tss(int32_t pos, uint16_t ss0, uint32_t esp0) {
uintptr_t base = (uintptr_t)&tss_entry;
uintptr_t limit = base + sizeof(tss_entry);

set_in_gdt_slot(pos, base, limit, 0xE9, 0x00);

memset(&tss_entry, 0x0, sizeof(tss_entry));

tss_entry.ss0 = ss0;
tss_entry.esp0 = esp0;

tss_entry.cs = 0x0b;
tss_entry.ss =
tss_entry.ds =
tss_entry.es =
tss_entry.fs =
tss_entry.gs = 0x13;
tss_entry.iomap_base = sizeof(tss_entry);
}

GDT::GDTSlot GDT::gdt[6];
GDT::GDTPtr GDT::gdt_ptr;
GDT::tss_entry_t GDT::tss_entry;
  • Вопрос задан
  • 229 просмотров
Пригласить эксперта
Ответы на вопрос 2
maaGames
@maaGames
Погроммирую программы
попробуй у VB отключить аппаратные ускорения и прочие оптимизации виртуализации.
Ответ написан
Комментировать
jcmvbkbc
@jcmvbkbc
"I'm here to consult you" © Dogbert
Почему ОС не запускается на Virtual box, а на QEMU запускаеться?

Потому что QEMU TCG не очень точно эмулирует x86. Если в командную строку qemu добавить -enable-kvm, то оно тоже не будет работать.

А вот если добавить ret в реализацию GDT::load_gdt() и не вызывать load_tss() то оно начинает в qemu-kvm работать:
diff --git a/src/GDT/GDT_impl.s b/src/GDT/GDT_impl.s
index 4f69835abd9d..5476837f3d0a 100644
--- a/src/GDT/GDT_impl.s
+++ b/src/GDT/GDT_impl.s
@@ -2,6 +2,7 @@
 .extern _ZN8SimpleOS3GDT7gdt_ptrE
 _ZN8SimpleOS3GDT8load_gdtEv:
        lgdt _ZN8SimpleOS3GDT7gdt_ptrE
+       ret
 
 .global _ZN8SimpleOS3GDT8load_tssEv
 _ZN8SimpleOS3GDT8load_tssEv:

Подозреваю, что и в virtual box оно заработает.
Проблема в загрузке TSS, короче. Мне не знакомы дебри TSS, но для поверхностного взгляда кажется странным то, что все сегментные селекторы в твоём TSS имеют RPL=3, а селектор стека -- RPL=0.
Если ты хочешь разбираться с тем, что происходит, то разумно было бы поменять порядок инициализации, сначала загрузить IDT, чтобы иметь возможность обрабатывать исключения, а потом загружать TSS и смотреть, что за исключение эта операция выкидывает.
С другой стороны, непонятно зачем в текущей версии этой ОС нужен TSS. Подозреваю, что никакая функциональность не будет потеряна, если его не загружать.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы