Решил тут вспомнить, как под интели писать, и начал с перехода в long mode. Переход выполняю строго по мануалу, но происходит сброс, хотя на исключения установлены обработчики.
Дано: защищенный режим, страничное преобразование выключено. В качестве загрузчика я использую SYSLINUX, поэтому содержимое GDT и IDT не определено, но задана плоская модель. Построены таблицы переадресации, базовый адрес PML4 загружен в cr3.
Во всех эмуляторах (QEMU, Bochs, VirtualBox, VMWare) код работает, на реальной машине - сбрасывает в момент включения страничной адресации, т.е. в момент перехода в long mode.
Делаю следующее:
- Запрещаю маскируемые и немаскируемые прерывания
- Строю и устанавливаю IDT на 32 исключения
- Загружаю GDT, содержащую следующие сегменты:
- Сегмент 32-битного кода
- Сегмент данных
- Сегмент 64-битного кода
- TSS для хранения стеков
- Перезагружаю CS сегментом кода, а DS, ES, FS, GS и SS - сегментом данных
- Загружаю новую TSS, заполненную нулями, в TR
- Включаю PAE (бит 5 регистра cr4)
- Включаю long mode (бит 8 MSR IA32_EFER)
- Включаю страничную адресацию
- Обнуляю IDT
- Делаю дальний переход для перезагрузки CS
По идее, сброс вызывает тройная ошибка, которая происходит после перехода в long mode из-за того, что IDT осталась 32-битная, но для нее нет причины: #PF быть не может, таблицы переадресации обеспечивают для загрузчика правильное отображение на те же адреса и разрешают чтение, запись, исполнение, а #GP или другие ошибки там просто нечему вызывать.
Маскировку NMI и загрузку ненулевой IDT я добавил позже, во время отладки. Без этого поведение было тем же самым.
Что я упускаю?
Код переключалки.