Здравствуйте, понадобилось по работе осуществить такую цепочку переходов: real mode -> protected mode -> long mode -> compability mode -> protected mode-> real mode код я успешно написал и он работает, но попахивает костылями. Код (Text): use16 PML4E equ 2000000h org 100h start: ; проверка поддержки long mode ; calculate linear address of label "pm64" xor eax, eax mov eax, cs shl eax, 4 add eax, pm64 mov [cs:pm64_linear], eax ; calculate linear address of label "compat_mode" xor eax, eax mov eax, cs shl eax, 4 add eax, compat_mode mov [cs:compat_mode_linear], eax ; calculate linear address of label "metka" xor eax, eax mov eax, cs shl eax, 4 add eax, metka mov [cs:metka_linear], eax mov eax, cs mov ds, ax ;save real mode return point mov word [ds:offset_r_mode], r_mode mov [ds:old_cs], ax ;calculating linear address of GDT mov [ds:GdtLinAdr], eax shl dword [ds:GdtLinAdr], 4 ;init code 32 descr mov eax, [ds:GdtLinAdr] mov edi, descr8+2 mov [ds:edi], ax bswap eax inc edi inc edi mov [ds:edi], ah ;init code 16 descr mov eax, dword [ds:descr8+2] mov dword [ds:descr18+2], eax mov eax, descr0 add [ds:GdtLinAdr], eax cli lgdt fword [ds:GdtSize] mov eax, cr0 or al, 1 mov cr0, eax jmp 08h:p_mode32 use32 ;32 bit protected mode p_mode32: ; формируем таблицы PG ; первичная таблица PG ; снимаем cr0.PG mov eax, cr0 and eax, 7fffffffh mov cr0, eax ; устанавливаем cr4.PAE mov eax, cr4 or eax, 20h mov cr4, eax ; загружаем в cr3 адрес таблицы mov eax, PML4E mov cr3, eax ; enabling LM mov ecx, 0c0000080h; EFER rdmsr or ah, 1; LME wrmsr ; устанавливаем cr0.PG mov eax, cr0 bts eax, 31 mov cr0, eax ;переходим в защищенный режим db 0eah pm64_linear dd 0 dw 28h pm64: use64 ; делаем что то в long mode mov edi, [cs:metka_linear] ; можно ли этот выход написать менее коряво? jmp fword [rdi]; jump from long mode (64-bit) ; into compatibility mode metka: compat_mode_linear dd ? dw 0030h compat_mode: use32 ; снимаем cr0.PG mov eax, cr0 and eax, 7fffffffh mov cr0, eax ; disable LM mov ecx, 0c0000080h rdmsr and ah, 0feh wrmsr ; снятие cr4.PAE mov eax, cr4 and eax, 0ffffffdfh mov cr4, eax db 0eah; jump back from compatibility mode dd prot_32; into protected 32 mode dw 08h ;нужен ли этот переход вообще? prot_32: mov cx, 20h ;16 bit data decsr mov ds, cx db 0eah dd pm16 dw 18h ;16 bit code descr pm16: use16 mov eax, cr0 and al, 0feh mov cr0, eax db 0eah offset_r_mode dw 11 old_cs dw 0 r_mode: sti no_long_mode: mov ax, 4c00h int 21h descr0 db 0,0,0,0,0,0,0,0; descr8 db 0ffh,0ffh,0,0,0,09ah,04fh,0;32 code descr10 db 0ffh,0ffh,0,0,0,092h,0cfh,0;32 data descr18 db 0ffh,0ffh,0,0,0,09ah,0fh,0; 16 code descr20 db 0ffh,0ffh,0,0,0,092h,8fh,0; 16 data descr28 db 0ffh,0ffh,0,0,0,09ah,2fh,0 ; 64 code descr30 db 0ffh, 0ffh, 0h, 0h, 0h, 9fh, 4fh, 0h; 32-bit compatibility mode GdtSize dw 8*7 GdtLinAdr dd 0 metka_linear dd 0 Соответственно можно ли описать переходы между режимами получше, что бы не вычислять линейные адреса меток? И еще я готов выслушать дельные замечания по любым другим частям кода.
1. Не понял, зачем явное вычисление базы code32, сделайте флат (база = 0), тогда не нужно будет писать в дескриптор. Также зачем для long указание префиксов сегментов [cs:...]. Там флат, все базы сегментов игнорируются. Кроме управляющих битов, для cs: важен лишь бит L, который отличает compat от long (т.е. 32-битный код от 64-битного), но на адресацию данных это не влияет. Если у вас не флат в PM, зачем рассчитывать линейные адреса меток? Считайте их смещениями от базы, как и в RM-16. Вобщем, слегка каша... 2. Если вы прыгаете из RM в PM, то зачем явно снимать PG? Он и так снят, иначе давно было бы #GP. 3. Кроме cli неплохо бы NMI выключить. Хотя тут хз. Мутное прерывание. 4. После прыжка между режимами DS/ES/SS и прочие, какими пользуетесь, выставляются корректно? Это на всякий случай спрашиваю. 5. Зачем при переходе LM->PM дескриптор 30h? Чем 08 не угодил? Вы же из него в long ходили. Попробуйте сразу переход в 08. 6. О корявости LM-Compat. Да, коряво. Но иначе никак, если вы из-под ДОС, где CS<>0.
Vic3Dexe 1.Программа com и запускается из dos. поэтому в какой сегмент она будет заргужена не известно. Поэтому и правлю дескрипторы. А линейные адреса меток вычисляю так как все сегменты в lm игнорируются, а как эти же адреса в lm получить не знаю. С указанием прификсов, да, действительно они излишни. Если я Вас правильно понял, flat pm это с базой 0? просто pm16 и pm32 имееют не нулевую базу, а lm имеет нулевую. 2. Просто в спецификации AMD так написано, решил пусть будет) 3. Ничего сказать не могу, всегда писал cli и не парился 4. А там всего 2 дескриптора, там все нормально. 5. Это интересный вопрос, просто 30й имеет нулевую базу, а 8й нет, но по моим размышления они должны быть взаимозаменяемы. Спасибо
1. Конечно, все зависит от задачи, если вам в PM кроме скачка LM делать нечего, да page-структуры лежат в коде (т.е. адресуются по смещениям от CS), тогда не-флат имеет смысл. Тут мой косяк, я привык рассуждать с позиции своего загрузчика, который грузится бут-сектором с CS=0. Флат - это базы всех сегментов = 0, лимиты = 4 гига. 2. А в спецификации АМД не написано, что будет, если в RM выставить PG? Intel SDM v.3, 4.1.1: 3. Дык я и говорю - NMI мутная вещь, но запретить до момента готовности IDT не помешает, имхо. Лучше перебдеть, чем потом ломать голову чего оно падает. Хуже ведь не будет. 5. Воот. Еще ложка каши из п.1. Т.е. в лонг вы прыгаете из не-флат РМ, а обратно через флат, что, вообще говоря, значения не имеет, если вы не лезете в память. Так зачем плодить сущности? Возвращайтесь через 8 дескриптор да не морочьте себе голову. зы Да, и про А20 - я думал, что ее открытие подразумевается/сделано до. Вообще вроде биосы за последние лет 10 сами ее открывают изначально (могу врать!), но опять же, лучше в этом убедиться/перебдеть. Ссылку вам дали странную, там про А20 - 3 строчки. Во - http://wiki.osdev.org/A20 ззы А вообще стыдно лезть в LM, не зная про А20. Без обид.
Vic3Dexe Мне в PM только надо в памяти разместить таблицы пейджинга для LM по известным линейным адресам, и дальше идти в LM. Код снятия CR0.PG был тупо взят с документации, о его необходимисти думать не было ни времени, ни желания.IDT Я и готовить не буду, наверно тупо запрещу все до возврата в реальный режим. Наверно, вы правы, перепишу через 8й дескриптор. зы. В жизни просто с А20 не сталкивался, не нужна была, и так все работало)
drem1lin Раздели код на загрузчик и основную часть, которая размещается по фиксированному адресу, и жизнь существенно упростится. Править придётся только два дескриптора для описания сегмента в который попал загрузчик и значение для GDTR (новую IDT можно тоже разместить по фиксированному адресу). Загрузчик переходит в 16-разрядный защищённый режим, затем через селектор дескриптора, описывающего всю память, копирует основной код на нужное место, и отдаёт туда управление, а дальнейшую инициализацию можно выполнять там. Если используется страничная адресация, но страниц не много, то можно их разместить с основным кодом, иначе - генерировать динамически. Общая структура может выглядит так: Код (Text): use16 org 100h statr16: сюда весь 16 разрядный код, GDT, GDTR и всё, что нужно для перехода end16: - эта метка нужно чтобы вычислить смещение основного кода в 16 разрядном сегменте для копирования use32 org - сюда подставляем тот адрес, по которому будет начинаться основной код start32: тут размещаем 32-разрядный код IDT тоже можно разместить где-то здесь use64 start64: а здесь размещаем 64-разрядный код