Как изменить сегмент данных? Что я делаю неправильно?
Я занимаюсь разработкой 32-битной ОС и разработал работающий загрузчик ELF, который работает просто отлично. Теперь у меня не включена подкачка страниц (я планирую позже, но сейчас я просто пытаюсь загрузить модули ядра), и я пытаюсь запускать модули при загрузке. По сути, поскольку в настоящее время многозадачность еще не полностью реализована, я просто хочу загрузить каждый модуль, вызвать init (который установит обработчики прерываний и просто настроит то, для чего предназначен модуль), а затем выйдет и выполнит следующий. Это работает, но я ничего не могу сделать с указателями в программе C (потому что он все еще думает, что использует сегмент данных ядра). Поэтому в основном я хочу создать новый сегмент данных, который указывает на сегмент модулей.data в оперативной памяти. Я делаю это, устанавливая запись № 6 в GDT, как.
setGDTEntry(6, DataAddress,DataSize, 0xF2, 0xCF);
Метод setEntry работает просто отлично, похоже
void setGDTEntry(int num, uint Base, uint limit, byte access, byte gran)
Снова оба работают на 100%, проблема, которая у меня возникает, когда я меняю селектор сегмента данных. Я делаю это в сборке, точка входа ELF хранится в EAX.
mov ax, 30h ; This is 8 * 6, the GDT entry containing the new data segment
mov ds, ax ; set data segment
call address ; JUMP!!!!
mov ax, 0x10 ; Restore kernel data segment
mov ds, ax ; set data segment
Это заставит мое ядро запаниковать, выдав процессор 0x6, недопустимый код операции. Исходный код моей программы на C - это просто программа hello world, которая копирует текст в видеопамять (ничего особенного не видно). Кто-нибудь знает, что я делаю не так? Я новичок во всей концепции GDT и селекторов сегментов.......... И я не могу включить пейджинг или многозадачность в это время, я действительно не хочу объяснять, почему....
1 ответ
Прежде всего, вам нужно установить не только ds
, но также es
а также ss
, Если вы этого не сделаете, некоторые инструкции будут использовать ds.base
в качестве основы сегмента (например, mov eax, [ebx]
), в то время как другие будут использовать ss.base
(например mov eax, [ebp+8]
) или же es.base
(например rep movsd
) и они будут разными, что приведет к несовместимой адресации.
Другая проблема, которая может возникнуть cs
(недопустимое исключение инструкции указывает на это). Код x86 вообще не зависит от позиции. Так же, как вы должны создать и использовать отдельный сегмент данных, чтобы компенсировать разницу между тем, где разделы данных загружаются в память и где они должны находиться в памяти (различные заголовки / разделы ELF сообщают вам об этом), вы должны сделать то же самое для раздела кода. Ты можешь измениться cs
используя дальний вызов, дальний прыжок или дальний возврат.