Переход из защищенного режима в реальный. Базовый вектор прерываний

Тема в разделе "WASM.OS.DEVEL", создана пользователем GLEB, 6 сен 2011.

  1. GLEB

    GLEB New Member

    Публикаций:
    0
    Регистрация:
    12 ноя 2007
    Сообщения:
    83
    Приветствую!

    При переходе в защищенный режим изменяю базовый вектор прерываний на 0x20:

    Код (Text):
    1. mov al,00010001b
    2. out 0x20, al
    3.  
    4. mov al, 0x20
    5. out 0x21,al
    6.  
    7. mov al, 00000100b
    8. out 0x21, al
    9.  
    10. mov al, 00000001b
    11. out 0x21, al
    Теперь нужно переключиться обратно в реальный режим и соответвенно восстановить контроллер прерываний на исходное состояние.

    Подскажите как.
     
  2. Phantom_84

    Phantom_84 New Member

    Публикаций:
    0
    Регистрация:
    6 июн 2007
    Сообщения:
    820
    У младших 8 прерываний база 8. Про старшие говорить не буду, т.к. ты их базу не менял, что кстати весьма странно.
     
  3. Pavia

    Pavia Well-Known Member

    Публикаций:
    0
    Регистрация:
    17 июн 2003
    Сообщения:
    2.409
    Адрес:
    Fryazino
  4. GLEB

    GLEB New Member

    Публикаций:
    0
    Регистрация:
    12 ноя 2007
    Сообщения:
    83
    Phantom_84
    Старшие как я понял 0x70

    а что странного, что база вектров slave контроллера не перенесена? Переносится же мастер, с 8 на 32 чтоб освободить место под исключения
    из прерываний я обрабатываю только таймер и клавиатуру?

    Код (Text):
    1. ; для реального
    2. mov al, 0x11
    3. out 0x20, al
    4. out 0xA0, al
    5. mov al, 0x8 <--
    6. out 0x21, al
    7. mov al, 0x70 <--
    8. out 0xA1, al
    9. mov al, 4
    10. out 0x21, al
    11. mov al, 2
    12. out 0xA1, al
    13. mov al, 0x1
    14. out 0x21, al
    15. mov al, 0x1
    16. out 0xA1, al
    17.  
    18. ; для защищенного
    19. mov al, 0x11
    20. out 0x20, al
    21. out 0xA0, al
    22. mov al, 0x20 <--
    23. out 0x21, al
    24. mov al, 0x28 <--
    25. out 0xA1, al
    26. mov al, 4
    27. out 0x21, al
    28. mov al, 2
    29. out 0xA1, al
    30. mov al, 0x1
    31. out 0x21, al
    32. mov al, 0x1
    33. out 0xA1, al
    Так будет правильно?
     
  5. Phantom_84

    Phantom_84 New Member

    Публикаций:
    0
    Регистрация:
    6 июн 2007
    Сообщения:
    820
    Я немного перегнул. Просто инициализировать и управлять PIC/APIC/IDT для последовательно возрастающих номеров векторов немного проще. Также лучше инициализировать под себя аппаратуру полностью, даже несмотря на высокую степень гарантии ее нахождения в определенном состоянии.
     
  6. GLEB

    GLEB New Member

    Публикаций:
    0
    Регистрация:
    12 ноя 2007
    Сообщения:
    83
    Возникла такая проблема.
    Переключение в защищенный и в реальный работает нормально, но возникла проблема с клавиатурой.

    Переключаюсь в защищенный режим, ставлю обработчик для клавиатуры. По нажатию клавиши загружаю в память файл, переключаюсь в реальный передаю на него управление. Загруженный код работает, но иногда не реагирует на нажатие клавиш.

    В общем что-то типа загрузчика

    Загружал ntldr, memtest86, свои программы на виртуалке все ок, на большинстве компов тоже, а вот на домашнем не работает.

    Проблема точно в обработке клавиатуры, т.к. если ничего не нажимать, потом все работает нормально.
    Также если зажать клавишу, а отпустить ее уже после загрузки кода, переключения в реальный режим и передачи управления, а не сразу, то все работает нормально.

    Может есть какие нюансы?

    Уже решил сделать так
    Сразу после нажатия , в обработчике делаю CLI, а в загруженном коде первым делом STI, все равно не работает.

    может неправильно читаю с клавиатуры?

    keyboard_handler:
    pushad

    in al, 60h ;read

    ; тут обрабатываю

    ;in al, 0x61 ; 'этот код не на что не влияет
    ;or al, 0x80
    ;out 0x61, al
    ;xor al, 0x80
    ;out 0x61, al

    popad

    jmp int_EOI

    int_EOI:
    push eax
    mov al, 0x20
    out 0x20, al
    out 0xA0, al
    pop eax
    iretd
     
  7. Phantom_84

    Phantom_84 New Member

    Публикаций:
    0
    Регистрация:
    6 июн 2007
    Сообщения:
    820
    Не понятно, восстанавливаешь ли при возврате в RM базовый вектор (8), обработчик BIOS. Также непонятно, зачем в клавиатурном обработчике слать EOI в 0xA0.
     
  8. GLEB

    GLEB New Member

    Публикаций:
    0
    Регистрация:
    12 ноя 2007
    Сообщения:
    83
    восстанавливаю, без этого вообще никак не работает

    если не слать ничего меняется (
     
  9. Phantom_84

    Phantom_84 New Member

    Публикаций:
    0
    Регистрация:
    6 июн 2007
    Сообщения:
    820
    Надеюсь, при входе в PM ты не делал переинициализацию клавиатурного контроллера (что в принципе делать нужно, но видимо не в данном случае). Попробуй для начала при возврате в RM переинициализировать данные BIOS, относящиеся к клавиатуре (2 байта статуса, клавиатурную очередь).
     
  10. GLEB

    GLEB New Member

    Публикаций:
    0
    Регистрация:
    12 ноя 2007
    Сообщения:
    83
    Phantom_84
    нет, не делал

    подскажи как
     
  11. Phantom_84

    Phantom_84 New Member

    Публикаций:
    0
    Регистрация:
    6 июн 2007
    Сообщения:
    820
    См. описание соответствующих полей BDA. Если ты в PM отслеживал удерживание клавиш Alt, Shift, Ctrl, отрази это в статусе. Если ты изменял состояние индикаторов, отрази это в статусе. Очисти клавиатурную очередь BIOS, присвоив указателям начала и конца очереди одинаковые значения.
     
  12. GLEB

    GLEB New Member

    Публикаций:
    0
    Регистрация:
    12 ноя 2007
    Сообщения:
    83
    А может это все лишнее? в PM кроме in al, 60h я ничего не делаю
    Смотрел исходники сислинукса, вроде также все делаю.

    Может быть у меня косяк например со стеком, этот глюк с клавиатурой происходит именно при переключении режимов.

    Кстати немного не в тему, в PM индикаторы клавы перестают реагировать на нажатия caps, num , scroll. Это надо делать самому в обработчике клавиатуры?
     
  13. Phantom_84

    Phantom_84 New Member

    Публикаций:
    0
    Регистрация:
    6 июн 2007
    Сообщения:
    820
    Может и лишнее, но теоретически старое состояние данных BIOS и новое состояние аппаратуры могут привести к описанным эффектам. Если ты ничего кроме in al,60h не делал, это упрощает задачу, но не сильно. К примеру в RM до перехода в PM мог удерживаться Shift. Теперь ты возвращаешься в RM с установленным флагом нажатого Shift'а и BIOS этот флаг не сбросит, пока явно не получит код отпускания Shift'а. Поэтому соответствующий флаг лучше уж обнулить явно, чем оставить в том состоянии, в котором он находился до перехода в PM. Очередь очистить тоже элементарно. Чтобы не ловить клавиши, которые могли быть нажаты давным давно.

    Может и косяк со стеком. Откуда мне знать.

    Естественно, надо делать самому. Давно прошли те времена, когда индикаторы включались/отключались чисто аппаратно.
     
  14. GLEB

    GLEB New Member

    Публикаций:
    0
    Регистрация:
    12 ноя 2007
    Сообщения:
    83
    Phantom_84

    Вроде что-то проясняется )

    Похоже проблема в контроллере прерываний

    загрузку файла в память делаю так: PM -> RM -> INT13 - > PM

    при перключении каждый раз меняю базовый вектор таким кодом:

    Код (Text):
    1. ; DL - primary, DH - secondary
    2. remap_irq:
    3.         mov al, 0x11
    4.         out 0x20, al
    5.         out 0xA0, al
    6.         mov al, dl
    7.         out 0x21, al
    8.         mov al, dh
    9.         out 0xA1, al
    10.         mov al, 0x4
    11.         out 0x21, al
    12.         mov al, 0x2
    13.         out 0xA1, al
    14.         mov al, 0x1
    15.         out 0x21, al
    16.         mov al, 0x1
    17.         out 0xA1, al
    18.         ret
    последовательность такая:

    запрещаю прерывания
    переключаюсь в RM
    mov dx, 0x7008;
    call remap_irq
    разрешаю прерывания
    вызываю int13
    mov dx, 0x2820;
    call remap_irq
    запрещаю прерывания
    переключаюсь в PM
    разрешаю прерывания

    теперь понял делать это совсем не обязательно если при вызове int13 не разрешать прерывания и не менять базовый вектор, то все нормально работает, ну по крайней мере на моем компе, завтра проверю на работе на других машинах.

    Выходит что причина зависания клавиатуры - мнокократная инициализация контроллера прерываний.

    Получается есть какие-то ограничения или я что-то не так делаю?

    На виртуалке и большинстве машин работает нормально, на некоторых ноутах глюк проявляется сразу.
     
  15. Phantom_84

    Phantom_84 New Member

    Публикаций:
    0
    Регистрация:
    6 июн 2007
    Сообщения:
    820
    Я PIC инициализирую так:
    Код (Text):
    1.         mov al,00010001b
    2.         out 20h,al
    3.         out 0A0h,al
    4.  
    5.         mov al,IRQBASE
    6.         out 21h,al
    7.         mov al,IRQBASE+8
    8.         out 0A1h,al
    9.  
    10.         mov al,00000100b
    11.         out 21h,al
    12.         mov al,02h
    13.         out 0A1h,al
    14.  
    15.         mov al,00001101b
    16.         out 21h,al
    17.         mov al,00001001b
    18.         out 0A1h,al
    19.  
    20.         mov al,IRQMASK and 0FFh
    21.         out 21h,al
    22.         mov al,IRQMASK shr 8
    23.         out 0A1h,al
    Если я правильно понял, основная задача твоего кода загрузить что-то в дополнительную память, используя сервис BIOS. Это делается с запрещенными прерываниями в PM путем многократного переключения в PM и обратно или с использованием нереального режима. Т.е. пока явным образом используется BIOS, нужно по минимуму вмешиваться в ее работу. А переинициализировать аппаратуру под себя следует уже при окончательном входе в PM.
     
  16. GLEB

    GLEB New Member

    Публикаций:
    0
    Регистрация:
    12 ноя 2007
    Сообщения:
    83
    Вот так и пытаюсь делать


    На тех компах где не работало заработало, но на некоторых клавиатура попрежнему отказывает (

    Вот код процедуры чтения сектора, Phantom_84, если не трудно глянь может я что-то не так делаю

    Код (Text):
    1. pm_stack dd 0 ; стек защищенного режима
    2.  
    3. use32
    4. ;  PROTECTED MODE ;
    5. read_sector:
    6.  
    7.          pushad
    8.  
    9.         ;disable interrupts
    10.         cli
    11.         in al, 70h
    12.         or al, 80h
    13.         out 70h, al
    14.         in al, 71h
    15.  
    16.         mov dword[pm_stack], esp ; запоминаю вершину стека
    17.  
    18.         lidt [rm_idtr] ; загружаю real mode idt
    19.  
    20.         jmp 00011000b:read_sector_rm_entry ; прыгаем в 16 битный сегмент
    21.  
    22. use16
    23. read_sector_rm_entry:
    24.         mov  ax, 00100000b ; set DATA segment
    25.         mov  ds, ax
    26.         mov  es, ax
    27.         mov  fs, ax
    28.         mov  gs, ax
    29.  
    30.         mov ss, ax
    31.         mov sp, 0x7C00
    32.  
    33.         ; disable protected mode
    34.         mov  eax, cr0
    35.         and  al, 0xFE
    36.         mov  cr0, eax
    37.  
    38.         jmp 0x0:read_sector_rm_start ; прыгаем с сегмент реального режима
    39.  
    40. ;REAL MODE ;
    41. read_sector_rm_start:
    42.  
    43.         xor ax, ax
    44.         mov ax, cs
    45.         mov ds, ax
    46.         mov es, ax
    47.  
    48.         mov ss, ax
    49.         mov sp, 0x7C00
    50.  
    51.         ; remap irq
    52.        ; mov dx, 0x7008
    53.       ;  call remap_irq
    54.  
    55.         ; enable interrupts
    56.         ;in  al, 0x70
    57.         ;and al, 0x7F
    58.         ;out 0x70, al
    59.         ;in al, 0x71
    60.         ;sti
    61.  
    62.          ; читаем данные в 0:7E00
    63.          ; sectors count
    64.         mov eax, [int13_count]
    65.         mov byte [dap + 2], al
    66.         ; sector
    67.         mov eax, [int13_sector]
    68.         mov dword [dap + 8], eax  ; start sector
    69.  
    70.         mov [int13_retval], 0x1 ; no error
    71.  
    72.         mov ah, 0x42
    73.         mov dl, [int13_drive]
    74.         mov si, dap
    75.         int 0x13
    76.         jnc int13_next
    77.  
    78.         mov [int13_retval], 0x0 ; error
    79.  
    80. int13_next:
    81.         ; restore protected mode
    82.  
    83.         ; disable interrupts
    84.         ;cli
    85.         ;in al, 70h
    86.         ;or al, 80h
    87.         ;out 70h, al
    88.         ;in al, 71h
    89.  
    90.        ; mov dx, 0x2820;
    91.        ; call remap_irq
    92.        ; call test_proc
    93.  
    94.         ; load GDTR
    95.         lgdt [gdtr]
    96.  
    97.         ; load IDTR
    98.         lidt [pm_idtr] ; IDT защищенного режима
    99.  
    100.         ; enable protected mode
    101.         mov eax, cr0
    102.         or al, 1
    103.         mov cr0, eax
    104.  
    105.         ; jump to protected mode segment
    106.         jmp 00001000b:read_sector_pm_entry
    107.  
    108. use32
    109. ;  PROTECTED MODE ;
    110. read_sector_pm_entry:
    111.         ; set segments
    112.         mov  ax, 0000000000010000b ; set DATA segment
    113.         mov  ds, ax
    114.         mov  es, ax
    115.         mov  fs, ax
    116.         mov  gs, ax
    117.  
    118.         mov ss, ax
    119.         mov esp, dword[pm_stack] ; восстанавливаем стек
    120.  
    121.         ; enable interrupts
    122.         in  al, 70h
    123.         and al, 7Fh
    124.         out 70h, al
    125.         in al, 71h
    126.         sti
    127.  
    128.         ; copy data   копируем прочитанные данные из 0:7E00 в область выше мегабайта
    129.         cld
    130.         mov esi, 0x7E00
    131.         mov edi, [int13_buffer]
    132.         mov ecx, [int13_count]
    133.         shl ecx, 9 ; mul 512
    134.         rep movsb
    135.  
    136.         popad
    137.  
    138.         ret
    Вызов происходит из Сишного кода

    Код (Text):
    1. ulong read_sector( uchar drive, ulong sector, ulong count, ulong *address )
    2. {
    3.     asm_code->int13_drive = drive;
    4.     asm_code->int13_sector = sector;
    5.     asm_code->int13_count  = count;
    6.     asm_code->int13_buffer = (ulong)address;
    7.    
    8.     __asm("call [%0]" : : "m"(asm_code->int13_proc));
    9.    
    10.     return asm_code->int13_retval;
    11. }
     
  17. Phantom_84

    Phantom_84 New Member

    Публикаций:
    0
    Регистрация:
    6 июн 2007
    Сообщения:
    820
    Ты не понял. В PM (до определенной поры) вообще нужно работать только с запрещенными прерываниями. А ты в PM их запрещаешь, т.е. видимо до этого момента они были разрешены.
     
  18. GLEB

    GLEB New Member

    Публикаций:
    0
    Регистрация:
    12 ноя 2007
    Сообщения:
    83
    А что не так?

    Я изначально при загрузке переключился в PM настроил обработку прерываний, теперь разрешаю их, рисую на экране меню, по нажатию клавиши, вызываю read_sector которая запрещает прерывания, переключается в RM, вызвает INT13, опять переключается в PM, копирует прочитанное из первого мегабайта в второй, разрещает прерывания и возвращается в вызывающую функцию, далее мне снова надо обрабатывать меню для выполнения дальнейших действий.

    Вот поле этих многократных переключений отказывает ввод с клавиатуры, нашелся комп накотором вообще все зависает еще до того как файл полностью загрузится
     
  19. Phantom_84

    Phantom_84 New Member

    Публикаций:
    0
    Регистрация:
    6 июн 2007
    Сообщения:
    820
    В том-то и дело, что было бы более надежным реализовать первичный пользовательский интерфейс в реальном режиме, а в PM переключаться только для переноса очередной порции данных в дополнительную память (с запрещенными прерываниями). По-моему нет особой необходимости делать интерфейс в PM, тем более когда планируется возврат в RM. Я бы вообще при использовании такого интерфейса функции BIOS стал бы вызывать только в виртуальной машине (V86).
     
  20. GLEB

    GLEB New Member

    Публикаций:
    0
    Регистрация:
    12 ноя 2007
    Сообщения:
    83
    Ну а GRUB, SYSLINUX и прочие загрузчики, установщик винды (на этапе начальной загрузки), они все постоянно прыгают из PM в RM и обратно.