Это скорее всего происходит из-за аппаратных прерываний. Нужно запретить все необрабатываемые прерывания в контроллере и в добавок поставить заглушки вместо обработчиков. У меня для всех аппаратных прерываний нет ни одного обнуленного дескриптора, только для зарезервированных/неиспользуемых исключений и программных прерываний.
Я таким образом запретил прерывания: Code (Text): mov ax, 0xFEFF ; запрещаем, всё кроме 8-го прерывания out 0x21, ax ошибка перестала вылетать, но и обработчик не обрабатывает если делать jmp, туда где лежит обработчик, он отрабатывает но если сделать Code (Text): int 8 я славливаю #GP
поправка: Code (Text): mov ax, 0xFFFE ; запрещаем, всё кроме 8-го прерывания(IRQ0) out 0x21, ax и с тиком таймера #GP
Hell_Knight Если все так плачевно попробуйте заюзать QEMU - в нем дебагер есть. Ну как минимум посмотрите состояние регистров и памяти на момент креша. А вообще проверьте 1) сам код обработчика прерывания (там они немного разные кстати, разное кол-во параметров в стек заносится, в зависимости от типа прерывания). 2) валидность адресов\страниц А вообще че-то я не пойму. Вначале вроде запрещается все, включая NMI. А потом уже разрешаем. А на наоборот. Для теста можете сделать даже так. Запрещаете все аппаратные. И разрешаете одно программное. вызываете int 3 - сработало? Ну и далее по обстоятельствам. Ну и покажите код настройки контроллера прерываний. А так же поиск по форуму - уже 1000 раз код приводился кстати.
окей, щас скачаю, просмотрю в чем может быть ошибка... В обработчики стоит заглушка: вывод красной полоски и jmp $ при прямомо jmp на обработчик всё окей, срабатывает на самом деле всё как положено, это я щас отключал, что бы исключить ситуации когда появляется #GP из-за других прерываний поэтому оно действительно от тика таймера не сработало....
Значит вот проверяйте правильность адресов, что хранит IDTR после загрузки, что вы имеете в нем, какие адреса. Кажись все дело в том, что вы не по тому адресу записали вашу таблицу. И в итоге оттуда откуда считывается инфа - там пусто. Ну и биты доступа дескрипторов проверьте.
вот элемент IDT Code (Text): dd 0x00083000 dd 0x00008E00 параметры: Смещение: 0x00003000 такое, как и должно быть! указывает на планировщик если jmp 0x3000 то будет выполнен код планировщика Селектор сегмента кода обработчика: 0x0008 (у меня страничная адресация поэтому, на всякий случай посатвил 8, может RPL работает ) 0x8E00 = 10001110 0000 P = 1 DPL = 0 вроде бы всё правильно... сохранял обратно IDTR и проверял значения... всё они правильно указывают... я же написал процедуру вывода на экран значения 32-битного значения втолкнутого в стэк проверял так.... и в IDT элемент вроде бы правильный... значит возможно я неправильно составил элемент дескприптора... ?? может есть еще какой-то подводный камень в который и упирается всё это ? подскажите пожалуйста правильно ли я делаю ?
щас дополнительно просмотрел запись в таблице страниц куда она указывает: 0x0009167 ну как и нужно: G = 1 глобальная страница A = 1 бит доступа установлен, т. к. к нему мы обратились... D = 1 dirty, это же IDT мы в него записывали элементы... R/W = 1 страница доступна для чтения/записи U/S = 1 страница доступна пользователю и супервизору P = 1 бит присутствия З.Ы. страница с планировщиком (обработчиком IRQ0) обладает такими же параметрами 0x0003167
Hell_Knight Эх как я не люблю такие записи. Вы хотите чтоб мы все за вас разбирали? И так разбираем: 0x00083000 переводим в двоичную: 0000 0000 0000 1000 0011 0000 0000 0000 Сопоставляем: Сегмент селектор: 0000 0000 0000 1000, Смещение (15:00 биты): 0011 0000 0000 0000 Вроде верно. Разбираем сл значение: 0x00008E00 переводим в двоичную: 0000 0000 0000 0000 1000 1110 0000 0000 Сопоставляем: Смещение (31:16 биты): 0000 0000 0000 0000, P - 1, DPL - 00 , 0, Size Of Gate - 1, 110, 0000 0000 Тоже верно. Далее покажите таблицу вашу GDT которая. Желательно всю. А лучше всего - прикрепите код наконец, который у вас не работает.
у меня ведь страничная адресация... оно у меня работало, просто потом бац, и перестало)))) и хз почему))) аж смешно... GDT: у меня правильный Code (Text): GDT: ; нулевой дескриптор NULL_descr db 8 dup(0) ; дескриптор 32-разрядного сегмента кода: база = 0000 0000h, размер = FFFF FFFFh CODE_descr db 0xFF, 0xFF, 0x0, 0x0, 0x0, 10011010b, 11001111b, 0x0 ; дескриптор 32-разрядного сегмента данных: база = 0000 0000h, размер = FFFF FFFFh DATA_descr db 0xFF, 0xFF, 0x0, 0x0, 0x0, 10010010b, 11001111b, 0x0 ; размер таблицы GDT: GDT_size db $-GDT GDTR dw GDT_size-1 dd ? не жалуюсь на него...
стэк, может как-то влиять ? у меня он как в real mode указывал на 0x7c00 так я его до сих пор не менял... а при попытки сменить возникает #GP я даже для него делал отдельную страничку... ну так и оставил на месте
Скачай GRUB, укажи в нем лог в файл, запусти, произойдет исключение, он вылетит, но в логе будет записана ошибка из-за которой произошло исключение, содержимое регистров и и даже используемые регистры GDT. После этого уже можно некоторые заключения сделать, а так только голову ломать, ошибка может находится в самом неподходящем месте.
Стек НУЖНО менять сразу после входа в PM, в SS нужно записать селектор данных, в ESP (именно ESP, а не SP!!!) место где он будет храниться + размер, я для начала не рекомендую создавать для стека отдельный сегмент с обратной адресацией - можно легко запутаться, особенно с VM конечно если ты сразу хочешь использовать VM, то нужно подготовить страницы для данных, кода, стека... желательно для отладки еще до входа в PM, еще не забудь о различиях в физической адресации и в типе RM сегмент/смещение.
элемент GDT стэк: Code (Text): ; стэк база 0, лимит максимум ; S = 1, данные, растет вниз, доступен, чтение/запись ; DPL = 0; p = 1; AVL = 00; D/B = 1(32-bits); G=1 STACK_descr dd 0x0000FFFF, 00000000110011111001011100000000b вот как я его инициализировал: Code (Text): mov ax, 11000b ; #3 эелемент GDT mov ss, ax mov esp, 0xFFFFFFF0 в итоге словил неприятный #GP
извинияюсь болван я) установил стэк в то место где код)))) установил я успешно этот стэк... Code (Text): ; стэк база 0x9000, 0x03FF + 1 ; S = 1, данные, растет вниз, доступен, чтение/запись ; DPL = 0; p = 1; AVL = 00; D/B = 1(32-bits); G=0 STACK_descr dd 0x900003FF, 00000000010000001001011100000000b а нужно делать стэк шлюзов там ? у меня же ведь страничная адресация ? дескриптор ведь не юзается...
Это чего за изобретение? и где(там)? Кто сказал, что режим VM отменяет сегментацию? просто по верх сегментов происходит отображение адресов. зачем тебе сегментация если ты используешь VM?, хватит всего 2 дескриптора: 1 - для кода, 2 - для данных и стека (база = 0, предел = 4ГБ), не делай обратной адресации в сегменте если не хочешь дважды вступить на одни и те же грабли...
т. е. работает сразу 2 режима сегментация + страничная ? з.ы. поправил, ss инициализировал сегментом данных, в esp пробил нужный адрес + размер З.З.Ы. поймите меня правильно, я не халявщик, пришедший за готовым кодом, я просто хочу понять как оно работает, и во что она в данном случае упирается, и из-за чего у меня возникает #GP ну или скажите в каком мануале прочитать по этому поводу, в английском немного разбираюсь так что, что-то пойму да пойму
Hell_Knight Не отменяет. Работают оба режима. Просто вы неявно обращаетесь к сегментным регистрам. Вспомните fs:[30h] (если вам это говорит о чем то). Ну и да. Без стека нельзя. Сразу его делайте как сегмент данных, так что вам правильно подсказали. И #GP скорее всего из-за того, что прерывания, если вы помните, ложат в стек инфу, код\ адрес возврата\флаги. В общем почитайте маны интела . И про #GP там есть инфа. И в конце концов. Вы отладчик включите наконец?
ну конечно знаю =) если бы не знал, я бы не брался за разработку ОС из селектора, который в fs извлекается идентификатор дескриптора (15..3 биты) далее по адресу: смотрим куда указывает GDTR + идентификатор дескриптора * 8 элемент GDT в нём смотрим базовый адрес + смещение в данном случае смещение 30h да я бы с радостью, но к сожалению, другими виртуальными машинами, кроме VMware я пользоваться не умею... в qemu что-то не так настроил, запустилось и машина вылетела с ошибкой в boch тоже не догнал с настройками, вроде бы указываю верно грузиться с образа жесткого диска, так всёравно так и не грузится... в grub, его еще чем-то нужно скомпилировать, не знаю чем... P.S. единственное чего не знаю так это что такое TSS всё остальное мне известно
TSS - Task Segment State - сегмент состояния задачи, структура куда процессор сохраняет контекст задачи(регистры, etc) при переключении задачи, при этом состояние новой задачи он восстанавливает из сегмента на который указывает селектор для новой задачи. Сама структура TSS формируется в ОЗУ, также в GDT(LDT для задач неприменим) формируется дескриптор особого формата задачи указывающий на TSS в памяти. Ну собственно по селектору куда попал дескриптор TSS и происходит переключение задачи, например far jmp [selector]:[смещение любое - все равно игнорируется], также существуют и другие способы переключения задач, существует понятие вложенной задачи, т.е. вызывается call far как процедура и возвращает управление в вызвавшую ее задачу. А вообще переключение задач - дело творческое для разработчика оси, я например (давно уже это было...) использовал обычный far jmp...