Переход в long mode и обратно

Тема в разделе "WASM.OS.DEVEL", создана пользователем drem1lin, 9 июн 2011.

  1. drem1lin

    drem1lin Member

    Публикаций:
    0
    Регистрация:
    17 мар 2009
    Сообщения:
    300
    Здравствуйте, понадобилось по работе осуществить такую цепочку переходов:
    real mode -> protected mode -> long mode -> compability mode -> protected mode-> real mode
    код я успешно написал и он работает, но попахивает костылями.
    Код (Text):
    1. use16
    2. PML4E equ 2000000h
    3. org 100h
    4. start:
    5.     ; проверка поддержки long mode
    6.    
    7.     ; calculate linear address of label "pm64"
    8.     xor eax, eax
    9.     mov eax, cs
    10.     shl eax, 4
    11.     add eax, pm64
    12.     mov [cs:pm64_linear], eax
    13.    
    14.     ; calculate linear address of label "compat_mode"
    15.     xor eax, eax
    16.     mov eax, cs
    17.     shl eax, 4
    18.     add eax, compat_mode
    19.     mov [cs:compat_mode_linear], eax
    20.    
    21.     ; calculate linear address of label "metka"
    22.     xor eax, eax
    23.     mov eax, cs
    24.     shl eax, 4
    25.     add eax, metka
    26.     mov [cs:metka_linear], eax
    27.    
    28.     mov eax, cs
    29.     mov ds, ax
    30.    
    31.     ;save real mode return point
    32.     mov word [ds:offset_r_mode], r_mode
    33.     mov [ds:old_cs], ax
    34.    
    35.     ;calculating linear address of GDT
    36.     mov [ds:GdtLinAdr], eax
    37.     shl dword [ds:GdtLinAdr], 4
    38.    
    39.     ;init code 32 descr
    40.     mov eax, [ds:GdtLinAdr]
    41.     mov edi, descr8+2
    42.     mov [ds:edi], ax
    43.     bswap eax
    44.     inc edi
    45.     inc edi
    46.     mov [ds:edi], ah
    47.    
    48.     ;init code 16 descr
    49.     mov eax, dword [ds:descr8+2]
    50.     mov dword [ds:descr18+2], eax
    51.    
    52.     mov eax, descr0
    53.     add [ds:GdtLinAdr], eax
    54.     cli
    55.     lgdt fword [ds:GdtSize]
    56.     mov eax, cr0
    57.     or  al, 1
    58.     mov cr0, eax
    59.     jmp 08h:p_mode32
    60.  
    61. use32   ;32 bit protected mode
    62. p_mode32:
    63.     ; формируем таблицы PG
    64.     ; первичная таблица PG
    65.    
    66.            ; снимаем cr0.PG
    67.     mov eax, cr0
    68.     and eax, 7fffffffh
    69.     mov cr0, eax
    70.     ; устанавливаем cr4.PAE
    71.     mov eax, cr4
    72.     or eax, 20h
    73.     mov cr4, eax
    74.     ; загружаем в cr3 адрес таблицы
    75.     mov eax, PML4E
    76.     mov cr3, eax
    77.    
    78.     ; enabling LM
    79.     mov ecx, 0c0000080h;    EFER
    80.     rdmsr
    81.     or ah, 1;       LME
    82.     wrmsr
    83.    
    84.     ; устанавливаем cr0.PG
    85.     mov eax, cr0
    86.     bts eax, 31
    87.     mov cr0, eax
    88.    
    89.            ;переходим в защищенный режим
    90.     db 0eah
    91.     pm64_linear dd 0
    92.     dw 28h
    93.    
    94. pm64:
    95. use64
    96.  
    97.     ; делаем что то в long mode
    98.    
    99.     mov edi, [cs:metka_linear]                                  ; можно ли этот выход написать менее коряво?
    100.     jmp fword [rdi];        jump from long mode (64-bit)
    101.          ;          into compatibility mode
    102. metka:
    103.     compat_mode_linear dd ?
    104.     dw 0030h
    105.  
    106. compat_mode:
    107. use32
    108.     ; снимаем cr0.PG
    109.     mov eax, cr0
    110.     and eax, 7fffffffh
    111.     mov cr0, eax
    112.     ; disable LM
    113.     mov ecx, 0c0000080h
    114.     rdmsr
    115.     and ah, 0feh
    116.     wrmsr
    117.     ; снятие cr4.PAE
    118.     mov eax, cr4
    119.     and eax, 0ffffffdfh
    120.     mov cr4, eax
    121.    
    122.     db 0eah;            jump back from compatibility mode
    123.     dd prot_32;     into protected 32 mode
    124.     dw 08h                           ;нужен ли этот переход вообще?
    125.  
    126. prot_32:
    127.     mov cx, 20h ;16 bit data decsr
    128.     mov ds, cx
    129.    
    130.     db 0eah
    131.     dd pm16
    132.     dw 18h  ;16 bit code descr
    133.  
    134. pm16:
    135. use16  
    136.     mov eax, cr0
    137.     and al, 0feh
    138.     mov cr0, eax   
    139.    
    140.     db 0eah
    141.     offset_r_mode  dw 11      
    142.     old_cs    dw 0                
    143. r_mode:
    144.     sti
    145. no_long_mode:
    146.     mov ax, 4c00h
    147.     int 21h
    148.  
    149. descr0      db 0,0,0,0,0,0,0,0;
    150. descr8      db 0ffh,0ffh,0,0,0,09ah,04fh,0;32 code
    151. descr10     db 0ffh,0ffh,0,0,0,092h,0cfh,0;32  data
    152. descr18     db 0ffh,0ffh,0,0,0,09ah,0fh,0; 16 code
    153. descr20     db 0ffh,0ffh,0,0,0,092h,8fh,0; 16 data
    154. descr28     db 0ffh,0ffh,0,0,0,09ah,2fh,0 ; 64 code
    155. descr30     db 0ffh, 0ffh, 0h, 0h, 0h, 9fh, 4fh, 0h;    32-bit compatibility mode
    156.  
    157. GdtSize dw 8*7
    158. GdtLinAdr dd 0
    159. metka_linear    dd  0
    Соответственно можно ли описать переходы между режимами получше, что бы не вычислять линейные адреса меток? И еще я готов выслушать дельные замечания по любым другим частям кода.
     
  2. Vic3Dexe

    Vic3Dexe New Member

    Публикаций:
    0
    Регистрация:
    8 авг 2009
    Сообщения:
    53
    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.
     
  3. NoName

    NoName New Member

    Публикаций:
    0
    Регистрация:
    1 авг 2004
    Сообщения:
    1.229
    Это все конечно замечательно, но линии A20 нету.
     
  4. drem1lin

    drem1lin Member

    Публикаций:
    0
    Регистрация:
    17 мар 2009
    Сообщения:
    300
    Vic3Dexe
    1.Программа com и запускается из dos. поэтому в какой сегмент она будет заргужена не известно. Поэтому и правлю дескрипторы. А линейные адреса меток вычисляю так как все сегменты в lm игнорируются, а как эти же адреса в lm получить не знаю. С указанием прификсов, да, действительно они излишни. Если я Вас правильно понял, flat pm это с базой 0? просто pm16 и pm32 имееют не нулевую базу, а lm имеет нулевую.
    2. Просто в спецификации AMD так написано, решил пусть будет)
    3. Ничего сказать не могу, всегда писал cli и не парился
    4. А там всего 2 дескриптора, там все нормально.
    5. Это интересный вопрос, просто 30й имеет нулевую базу, а 8й нет, но по моим размышления они должны быть взаимозаменяемы.
    Спасибо
     
  5. drem1lin

    drem1lin Member

    Публикаций:
    0
    Регистрация:
    17 мар 2009
    Сообщения:
    300
    NoName
    можно более развернутый ответ?
     
  6. NoName

    NoName New Member

    Публикаций:
    0
    Регистрация:
    1 авг 2004
    Сообщения:
    1.229
  7. Vic3Dexe

    Vic3Dexe New Member

    Публикаций:
    0
    Регистрация:
    8 авг 2009
    Сообщения:
    53
    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. Без обид.
     
  8. drem1lin

    drem1lin Member

    Публикаций:
    0
    Регистрация:
    17 мар 2009
    Сообщения:
    300
    Vic3Dexe
    Мне в PM только надо в памяти разместить таблицы пейджинга для LM по известным линейным адресам, и дальше идти в LM. Код снятия CR0.PG был тупо взят с документации, о его необходимисти думать не было ни времени, ни желания.IDT Я и готовить не буду, наверно тупо запрещу все до возврата в реальный режим. Наверно, вы правы, перепишу через 8й дескриптор.
    зы. В жизни просто с А20 не сталкивался, не нужна была, и так все работало)
     
  9. NoName

    NoName New Member

    Публикаций:
    0
    Регистрация:
    1 авг 2004
    Сообщения:
    1.229
    drem1lin
    Тогда могут неожиданно возникнуть пропуски памяти.
     
  10. Black_mirror

    Black_mirror Active Member

    Публикаций:
    0
    Регистрация:
    14 окт 2002
    Сообщения:
    1.035
    drem1lin
    Раздели код на загрузчик и основную часть, которая размещается по фиксированному адресу, и жизнь существенно упростится.
    Править придётся только два дескриптора для описания сегмента в который попал загрузчик и значение для GDTR (новую IDT можно тоже разместить по фиксированному адресу). Загрузчик переходит в 16-разрядный защищённый режим, затем через селектор дескриптора, описывающего всю память, копирует основной код на нужное место, и отдаёт туда управление, а дальнейшую инициализацию можно выполнять там. Если используется страничная адресация, но страниц не много, то можно их разместить с основным кодом, иначе - генерировать динамически. Общая структура может выглядит так:
    Код (Text):
    1. use16
    2. org 100h
    3. statr16:
    4. сюда весь 16 разрядный код, GDT, GDTR и всё, что нужно для перехода
    5. end16: - эта метка нужно чтобы вычислить смещение основного кода в 16 разрядном сегменте для копирования
    6.  
    7. use32
    8. org - сюда подставляем тот адрес, по которому будет начинаться основной код
    9. start32:
    10. тут размещаем 32-разрядный код
    11. IDT тоже можно разместить где-то здесь
    12.  
    13. use64
    14. start64:
    15. а здесь размещаем 64-разрядный код