Не получается вернуться в реальный режим из защищенного.

Тема в разделе "WASM.BEGINNERS", создана пользователем Microedition, 28 июн 2010.

  1. Microedition

    Microedition Active Member

    Публикаций:
    0
    Регистрация:
    5 июн 2008
    Сообщения:
    814
    Я уже давно не работал в защищенном режиме (то есть, давно не писал програми, которые
    переходят в этот режим). Сейчас опять понадобилось войти в него (1), сделать кое-что и выйти
    обратно в реальный (2).

    С (1) все получается, а вот когда дело доходит до (2), то компьютер перезагружается,
    виртуальные машины виснут (ну а Microsoft VirtualPC выдает: "An unrecoverable
    processor error has been encountered. The virtual machine will reset now).

    По порядку.

    Программа записана на дискете, грузится загрузочным сектором по адресу 1000:0000 и
    управление передается по этому адресу.

    После загрузки сразу происходит переключение в PM, при этом GDT такая:
    Код (Text):
    1. align 16
    2. GDT:
    3.     dq  0x0000000000000000  ;; 0x00: NULL
    4.     dq  0x00009A001000FFFF  ;; 0x08: CODE 16-bit, base: 0x1000, limit: 0xFFFF
    5.     dq  0x000092001000FFFF  ;; 0x10: DATA 16-bit, base: 0x1000, limit: 0xFFFF
    6.     dq  0x00CF9A000000FFFF  ;; 0x18: CODE 32-bit, base: 0x00000000, limit: 0xFFFFFFFF
    7.     dq  0x00CF92000000FFFF  ;; 0x20: DATA 32-bit, base: 0x00000000, limit: 0xFFFFFFFF
    8.  
    9. GDT_end:
    10.  
    11. align 16
    12. gdtr_image:
    13.  
    14.     dw  GDT_END - GDT - 1
    15.     dd  GDT
    16.  
    17. align 16
    18. idtr_image_rm:
    19.  
    20.     dw  0
    21.     dd  0
    Код программы написан на fasm и начинается с такой директивы: org BOOT_BASE.
    (это чтобы постоянно не корректировать смещения, когда мы защищенном режиме).
    BOOT_BASE equ 0x10000
    Вся программа в одном .asm файле. Бинарник меньше 64 килобайт.

    Вот код перехода в защищенный режим:
    Код (Text):
    1. PROC_CODE16_SELECTOR    equ 0x08
    2. PROC_DATA16_SELECTOR    equ 0x10
    3. PROC_CODE_SELECTOR      equ 0x18
    4. PROC_DATA_SELECTOR      equ 0x20
    5.  
    6. USE16
    7.  
    8.     ;;  Загрузить GDTR.
    9.  
    10.     lgdt    [gdtr_image - BOOT_BASE]
    11.  
    12.     ;;  Сохранить IDTR (для перехода в RM).
    13.  
    14.     sidt    [idtr_image_rm - BOOT_BASE]
    15.  
    16.     ;;  Заблокировать прерывания.
    17.  
    18.     cli
    19.  
    20.     ;;  Включить шлюз A20
    21.  
    22.     in  al, 0x92
    23.     or  al, 0x02
    24.     out 0x92, al
    25.  
    26.     ;;  Перейти в PM.
    27.  
    28.     mov eax, cr0
    29.     mov al, 1
    30.     mov cr0, eax
    31.  
    32.     db  0x66
    33.     db  0xEA
    34.     dd  entry32
    35.     dw  PROC_CODE_SELECTOR
    36.  
    37. USE32:
    38. entry32:
    В entry32 начинается полезная часть программы.
    Кстати, там же настраивается IDT и разрешаются прерывания.
    После её завершения происходит возврат в RM (в реальном режиме тоже кое-что
    делается, поэтому мне важно перейти в него):
    Код (Text):
    1.     ;;  Заблокировать прерывания.
    2.  
    3.     cli
    4.  
    5.     ;;  Возврат в RM.
    6.  
    7.     db  0x66
    8.     db  0xEA
    9.     dw  return_to_rm - BOOT_BASE
    10.     dw  PROC_CODE16_SELECTOR
    11.  
    12.     USE16
    13.     return_to_rm:
    14.  
    15.     mov     ax, PROC_DATA16_SELECTOR
    16.     mov     ds, ax
    17.     mov     es, ax
    18.     mov     fs, ax
    19.     mov     gs, ax
    20.     mov     ss, ax
    21.  
    22.     lidt    [idtr_image_rm - BOOT_BASE]
    23.  
    24.     mov     eax, cr0
    25.     and     al, 11111110b
    26.     mov     cr0, eax
    27.  
    28.     dw  0xEA
    29.     dw  entry16 - BOOT_BASE
    30.     dw  0x1000
    31.  
    32.     entry16:
    33.  
    34.     mov     ax, cs
    35.     mov     ds, ax
    36.     mov     ss, ax
    37.     mov     sp, 0xFFFF
    38.  
    39.     mov     ax, 0xB800
    40.     mov     es, ax
    41.     mov     di, 0x0000
    42.  
    43.     mov     al, 'X'
    44.     mov     ah, 3
    45.     mov     word[es:di], ax
    46.  
    47.  
    48.     jmp $ - BOOT_BASE
    Символ 'X' не выводится, комп перезагружется.
     
  2. Microedition

    Microedition Active Member

    Публикаций:
    0
    Регистрация:
    5 июн 2008
    Сообщения:
    814
    О, заметил одну ошибку:
    Код (Text):
    1.     ;;  Возврат в RM.
    2.  
    3.     db    0x66 ;; нужно или нет? (впрочем, даже если закоменнтировать, ничего не работает.)
    4.     db    0xEA
    5.     dw    return_to_rm - BOOT_BASE
    6.     dw    PROC_CODE16_SELECTOR
     
  3. izl3sa

    izl3sa New Member

    Публикаций:
    0
    Регистрация:
    22 апр 2010
    Сообщения:
    164
    Адрес:
    Spb
    2Microedition
    дык отладь в bochs =)
     
  4. Phantom_84

    Phantom_84 New Member

    Публикаций:
    0
    Регистрация:
    6 июн 2007
    Сообщения:
    820
    Если перед кодом указана директива org 0x10000, то в 16-разрядных дескрипторах нужно использовать соотв. базу (0x10000). Значения 0x1000 должны загружаться в сегментные регистры после переключения в реальный режим. Кроме того, fasm позволяет избежать необходимости корректировать адреса. Для этого нужно объявить несколько адресных пространств.
    Код (Text):
    1. org 0 ; используется по умолчанию - начало сегмента по адресу 0x10000
    2. ...
    3. jmp fword PROC_CODE_SELECTOR:entry32
    4.  
    5. org $+0x10000 ; внутрисегментное смещение 32-разрядного кода относительно нулевой базы с учетом местоположения 16-разрядного кода
    6. use32
    7. entry32:
    8. ...
    Нужно, т.к. ты кодируешь 16-разрядную инструкцию в 32-разрядном коде (если бы смещение в коде инструкции было 32-разрядное, тогда бы префикс указывать не нужно было). В fasm'е можно поступить проще.
    Код (Text):
    1. jmp dword PROC_CODE16_SELECTOR:return_to_rm
     
  5. Phantom_84

    Phantom_84 New Member

    Публикаций:
    0
    Регистрация:
    6 июн 2007
    Сообщения:
    820
    Код (Text):
    1. mov        sp, 0xFFFF
    Лучше, чтобы sp имел четное значение. Хочешь чтобы стек располагался в конце сегментра, обнули sp. Можно стек расположить и перед твоим сегментом, т.к. судя по всему эта память не используется.
    Код (Text):
    1.   xor ax,ax
    2.   mov ss,ax
    3.   xor sp,sp
     
  6. Microedition

    Microedition Active Member

    Публикаций:
    0
    Регистрация:
    5 июн 2008
    Сообщения:
    814
    Phantom_84
    Спасибо, помог :).
    Кроме того, была еще ошибка (опечатка), без которой не получилось бы перепрыгнуть в 16-разрядный режим:
     
  7. Microedition

    Microedition Active Member

    Публикаций:
    0
    Регистрация:
    5 июн 2008
    Сообщения:
    814
    Последнюю ошибку заметил только после дизассемблирования :lol: