Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Asm для Windows/Dos > Защищённый режим


Автор: JAPH 4.2.2007, 16:46
Привожу программку, которая умудряется перевести процессор в защищённый режим, вывести на экран энное количество восклицательных знаков, перевестись обратно в реальный режим и корректно передать управление обратно DOSу.
Код

        .486p        ;Тестируется на Pentium MMX. Компилятор TASM
sseg    segment stack    ;Сегмент стэка, используемый и в реальном (RM), и в защищённом (PM) режимах
        db      0400h dup (?)
sseg    ends
dseg    segment        ;Сегмент, содержащий GDT и IDT
; GDT
gdts    db      8 dup (0)    ;Нулевой дескриптор
    ;Дескриптор сегмента кода, в котором будет осуществляться выход из PM
        db      0FFh, 0FFh, 0, 0, 0, 10011010b, 00000000b, 0 ;cseg
    ;Дескриптор сегмента кода, используемого в PM
        db      0FFh, 0FFh, 0, 0, 0, 10011010b, 11001111b, 0 ;codes for cs
    ;Дескриптор сегмента видеопамяти. К лимиту не придираться
        db      0FFh, 0FFh, 0, 80h, 0Bh, 10010010b, 01000000b, 0 ;B800
    ;Дескриптор сегмента стэка с точки зрения PM
        db      00h, 0FCh, 0, 0, 0, 10010110b, 01000000b, 0 ;sseg for pm
    ;Дескриптор сегмента стэка с точки зрения RM
        db      0FFh, 0FFh, 0, 0, 0, 10010010b, 01000000b, 0 ;sseg for rm
    ;Дескриптор стартового TSS
        db      067h, 0, 0, 0, 0, 10001001b, 00000000b, 0 ;stss
gdtlim  dw      0037h
gdtad   dd      0
idts    dw      20h dup (small offset here, 10h, 1000111000000000b, 0)    ;Все прерывания - на выход из PM
idtlim  dw      00FFh
idtad   dd      0
stss    db      68h dup (0)
dseg    ends
codes   segment use32
        assume  cs:codes, ds:dseg
got:    mov     byte ptr fs:[0], '2'    ;Это - отладочное. Кое-как показывает работу программы
        mov     ecx, 05000000h
@1:     dec     ecx
        jnz     @1
        mov     ax, 20h        ;Инициализация стэка
        mov     ss, ax
        xor     esp, esp
        push    ax        ;И проверка его работоспособности
        pop     ax
        mov     byte ptr fs:[0], '3'
        mov     ecx, 05000000h
@4:     dec     ecx
        jnz     @4
        mov     ax, 30h        ;Инициализация единственного TSS
        ltr     ax
       ;sti             Очень хотелось бы
        mov     ax, 18h        ;Вывод, с которого всё начиналось :)
        mov     es, ax
        mov     ecx, 20
        mov     eax, 07200721h
        xor     edi, edi
        cld
    rep stosd
        mov     ecx, 05000000h
@3:     dec     ecx
        jnz     @3
here:  ;cli             Выход из PM
        mov     ax, 28h        ;Регистру SS нужно дать предел 0FFFFh
        mov     ss, ax
        db      0EAh
        dd      offset back
        dw      8
codes   ends
cseg    segment use16
        assume  cs:cseg, ds:dseg
start:  xor     eax, eax    ;Настройка GDT
        mov     ax, 0B800h
        mov     fs, ax
        mov     ax, dseg    ;Вычисление адреса GDT
        mov     ds, ax
        shl     eax, 4
        mov     gdtad, eax
        xor     eax, eax    ;Настройка дескриптора 2
        mov     ax, codes
        shl     eax, 4
        mov     word ptr gdts + 12h, ax
        bswap   eax
        mov     byte ptr gdts + 14h, ah
        mov     byte ptr gdts + 17h, al
        xor     eax, eax    ;Вычисление базы дескрипторов 4 и 5
        mov     ax, sseg
        shl     eax, 4
        mov     word ptr gdts + 22h, ax
        mov     word ptr gdts + 2Ah, ax
        bswap   eax
        mov     byte ptr gdts + 24h, ah
        mov     byte ptr gdts + 2Ch, ah
        mov     byte ptr gdts + 27h, al
        mov     byte ptr gdts + 2Fh, al
        xor     eax, eax    ;Настройка дескриптора 6
        mov     ax, dseg
        shl     eax, 4
        add     eax, offset stss
        mov     word ptr gdts + 32h, ax
        bswap   eax
        mov     byte ptr gdts + 34h, ah
        mov     byte ptr gdts + 37h, al
        xor     eax, eax    ;Настройка дескриптора 1
        mov     ax, cseg
        shl     eax, 4
        mov     word ptr gdts + 0Ah, ax
        bswap   eax
        mov     byte ptr gdts + 0Ch, ah
        mov     byte ptr gdts + 0Fh, al
        mov     eax, gdtad    ;Вычисление адреса IDT
        add     eax, offset idts
        mov     idtad, eax
        lgdt    fword ptr gdtlim
        lidt    fword ptr idtlim
        in      al, 92h        ;Открытие линии A20
        or      al, 02h
        out     92h, al
        cli            ;Запрет маскируемых
        in      al, 70h        ;   и немаскируемых прерываний
        or      al, 80h
        out     70h, al
        mov     byte ptr fs:[0], '1'
        mov     ecx, 05000000h
@2:     dec     ecx
        jnz     @2
        mov     eax, cr0    ;Поехали!
        or      al, 1
        mov     cr0, eax
        db      66h
        db      0EAh
        dd      offset got
        dw      10h
;----------------------------------
idtr    dw      03FFh        ;IDTR для RM
        dd      0
back:   mov     byte ptr fs:[0], '4'
        mov     ecx, 05000000h
@5:     dec     ecx
        jnz     @5
        mov     eax, cr0    ;Прилетели
        and     al, 0FEh
        mov     cr0, eax
        db      0EAh
        dw      $ + 4
        dw      cseg
        lidt    fword ptr cs:idtr
        mov     byte ptr fs:[0], '5'
        mov     ecx, 05000000h
@6:     dec     ecx
        jnz     @6
        mov     ax, cs
        mov     ds, ax
        mov     es, ax
        mov     ax, sseg
        mov     ss, ax
        mov     esp, 00000400h
        push    ax        ;Работоспособность стэка в RM
        pop     ax
        mov     byte ptr fs:[0], '6'
        mov     ecx, 05000000h
@7:     dec     ecx
        jnz     @7
        in      al, 92h        ;Закрытие A20
        and     al, 0FDh
        out     92h, al
        in      al, 70h        ;Разрешение прерываний
        and     al, 7Fh
        out     70h, al
        sti
        mov     ax, 4C00h    ;Выход в DOS
        int     21h
cseg    ends
        end     start


Так вот. Хочется раскомментировать строку ;sti, чтоб в PM обрабатывать прерывания таймера и клавиатуры (для начала по векторам 8 и 9). Но все мои попытки как-то это организовать проваливались.
Даже такой безобидный вариант: в IDT заменить 8 и 9 шлюзы прерываний на нечто, указывающее на код (в сегменте codes)
Код

mov  al, 20h
out  20h, al
iret

Так как повела себя прога: не дойдя до вывода восклицательных знаков, прошла шаги 4, 5, 6 (в смысле, показала эти цифры) и перезагрузила комп (вероятно, из-за sti). Что это было? Что сделала iret? iretd тоже не помогла - перезагрузка и всё тут. Как правильно?
Если убрать первые две строки в обработчике, прога отрабатывает и даже передаёт управление DOS, но клавиатура в результате просто игнорируется.

Итак, просьба-вопрос: написать простейший обработчик прерываний 8 и 9 (желательно использовать шлюзы прерываний), так, чтобы: прерывание 8 не выполняло никакой полезной работы - пример пустого обработчика; прерывнаие 9 выводило по адресу dword ptr 000B80A0h (через fs) scan-код клавиши-причины прерывания в hex-виде.
Хочется увидеть полный код.

Автор: MAKCim 4.2.2007, 18:34
эх, написал бы, но только на GAS  smile 

Автор: JAPH 4.2.2007, 20:12
Напишите, объясните отличия от TASM, может, уловлю и синтаксис, и идеи. smile
А если не уловлю, наверняка найдётся кто-нибудь, способный перевести код на TASM.

Автор: MAKCim 4.2.2007, 22:41
Код

.code32
.text
head_handler:
    addl    $4, %esp /* код ошибки */
    iret

keyboard_handler:
    iret

timer_handler:
    iret

startup_32:
    movw    $2 << 3, %ax
    movw    %ax, %ds
    movw    %ax, %ss
    movl    $0x90200, %esp    /* стек 512 байт */
/* перепрограммирование primary контроллера на 0x20, slave - на 0x28 */
    movb    $0x15, %al
    outb    %al, $0x20
    outb    %al, $0xa0
    movb    $0x20, %al
    outb    %al, $0x21
    movb    $0x28, %al
    outb    %al, $0xa1
    movb    $0x04, %al
    outb    %al, $0x21
    movb    $0x02, %al
    outb    %al, $0xa1
    movb    $0x0d, %al
    outb    %al, $0x21
    movb    $0x09, %al
    outb    %al, $0xa1
/* отключение всех прерываний кроме IRQ0 и IRQ1 */
        movb   $~0 << 2, %al
        outb    %al, $0x21
        movb   $~0, %al
        outb    %al, $0xa1
    sti
/* дальше любой код */

.code16
.section .boot, "ax", @progbits /* при линковке указываем адрес секции .boot = 0 */
.globl boot
boot:
    ljmp    $0x07C0, $1f  /* дальний jump на метку 1 (с изменением CS на 0x07C0) */
1:
    cli
    lgdt    gdtr
    lidt    idtr
    movl    %cr0, %eax
    orb        $1, %al
    movl    %eax, %cr0   /* переход в protected mode ... */
.code32
    ljmp    $1 << 3, $startup_32 + 0x7C00 /* ... и прыжок на startup_32 (физически находится сразу за .boot) 
           но в памяти по адресу 0x7C00 + startup_32 */
idtr:
    .word BOOT_IDT_SIZE - 1
    .long 0x7C00 + idt
idt:
.rept 32 /* 32 исключения (для всех один обработчик head_handler) */
        .word head_handler + 0x7C00
        .word 0x0008
        .word 0x8F00 /* вместо .word 0x8E00, т. е для исключений - шлюз ловушки */
        .word 0
.endr 
    .word timer_handler + 0x7C00 /* адрес обработчика таймера */
    .word 0x0008 /* селектор сегмента кода (1 << 3) */
    .word 0x8E00 /* DPL = 0, P = 1, type = E */
    .word 0
/* дальше аналогично для клавиатуры... */
    .word keyboard_handler + 0x7C00
    .word 0x0008
    .word 0x8E00
    .word 0
BOOT_IDT_SIZE = . - idt
gdtr:
    .word BOOT_GDT_SIZE - 1
    .long 0x7C00 + gdt
gdt:
    .quad 0x0000000000000000
    .quad 0x00CF98000000FFFF /* сегмент кода */
    .quad 0x00CF92000000FFFF /* сегмент данных */
BOOT_GDT_SIZE = . - gdt

Автор: JAPH 5.2.2007, 00:02
Пытаюсь что-нибудь понять...
Вопросы такие:
1. Можно код обратного перепрограммирования контроллера прерываний? То же самое, только в строках 22-25
Код

mov al, 08h  ;movb $0x08, %al
out 21h, al  ;outb %al, $0x21
mov al, 70h  ;movb $0x70, %al
out 0A1h, al ;outb %al, $0xA1

так? (Задно проверяйте понимание синтаксиса)
2. Почему в строке 19 именно 15h, а не 11h, как у Пирогова?
Что есть остальное? Как контроллер отличает различные ICW/OCW, или они посылаются в определённом порядке, тогда в каком? Может, поясните именно этот пример, описание самих CW у меня есть, но связей между ними - нет.
3. Можно ли обойтись без перепрограммирования, то есть можно ли различить, прерывание 8 вызвано из-за таймера или двойной ошибки? По младшему биту кода ошибки? Хотя прерывание таймера не помещает код ошибки в стэк, не должно, так ведь? Может, пользоваться шлюзом задачи и отслеживать ESP - есть код ошибки или нет?
4. В 17ой строке опечатка?

Автор: MAKCim 5.2.2007, 10:55
отвечу с конца  smile 
4.
нет, не опечатка, просто в пределах 1-го мегабайта память в пространстве адресов между
0x500 и 0x9FBFF свободна (нет данных BIOS и пр.), поэтому и отводим под стек 512 байт от 0x90200 до 0x90000
(так как мы используем flat 32-х разрядный сегмент данных с базой 0 и лимитом 0xFFFFFFFF)
3.
Код ошибки помещается в стек только для исключений. Это раз. Во-вторых обработчик исключения вызывается через шлюз ловушки, в то время как обработчики аппаратных прерываний - через шлюзы прерываний (автоматический вызов cli после записи EFLAGS). Я точно не уверен, будет ли #GP, если их подменить (т. е прерывания обрабатывать через шлюз ловушки)
Цитата

Может, пользоваться шлюзом задачи и отслеживать ESP - есть код ошибки или нет?

как вариант, только не шлюзом задачи, а TSS сегментом  smile 
Код

timer_handler:
    push    ebx
    xor    ebx, ebx
    str    bx ; селектор дескриптора TSS
    push    eax
    sgdt    [esp - 6]
    mov    eax, dword ptr [esp - 4] ; базовый адрес GDT
    lea    eax, [eax + ebx * 8] ; находим дескриптор TSS
; вычисляем базу сегмента TSS
    mov    bh, byte ptr [eax + 7]
    mov    bl, byte ptr [eax + 4]
    shl    ebx, 16
    mov    bx, word ptr [eax]
    mov    eax, [ebx + 4] ; находим esp для CPL = 0
; дальше код с учетом, непереключения стека при вызове обработчика исключения
    sub    eax, 18 ; esp - eflags (4 байта) - cs (2 байта) - eip (4 байта) - ebx (см. начало обработчика) (4 байта)  - eax (аналогично 4 байта)
    cmp    eax, esp
    jz    @@L1 ; нет кода ошибки
    ; есть код ошибки => исключение
...
@@L2:
...

(надеюсь, написал правильно, если не забыл tasm)
но как видишь, код будет излишне длинным (т. е сам обработчик будет выполняться через хз сколько команд), что неприемлемо для обработчиков прерываний/исключений
при этом у тебя также должен быть валидный дескриптор TSS в GDT и TSS сегмент
2.
15h = 00010101b
11h = 00010001b
2-ой бит - размер вектора прерывания
если он - 1 => размер 4 байта, иначе - 8 байт
Цитата(JAPH @  5.2.2007,  00:02 Найти цитируемый пост)
Что есть остальное? Как контроллер отличает различные ICW/OCW, или они посылаются в определённом порядке, тогда в каком? Может, поясните именно этот пример, описание самих CW у меня есть, но связей между ними - нет.

да, они посылаются в определенном порядке
ICW1 -> ICW2 -> [ICW3] -> [ICW4]
Код

movb    $0x15, %al /* старшие биты 0x15 - 0001 показывают, что будет запись ICW1 */
    outb    %al, $0x20 /* запись в ICW1 primary */
    outb    %al, $0xa0 /* запись в ICW1 slave */
    movb    $0x20, %al /* IRQ0 - IRQ7 перенаправляются на 0x20 - 0x28 */
    outb    %al, $0x21
    movb    $0x28, %al /* IRQ0 - IRQ7 перенаправляются на 0x28 - 0x28 + 8 */
/* далее идет запись в ICW3-4, значения взяты из справочника */
    outb    %al, $0xa1
    movb    $0x04, %al
    outb    %al, $0x21
    movb    $0x02, %al
    outb    %al, $0xa1
    movb    $0x0d, %al
    outb    %al, $0x21
    movb    $0x09, %al
    outb    %al, $0xa1

Цитата(JAPH @  5.2.2007,  00:02 Найти цитируемый пост)
так? (Задно проверяйте понимание синтаксиса)

ну так, только опять же, зачем так делать?

Автор: JAPH 5.2.2007, 13:12
Ну, как это зачем? Когда прога выйдет из PM, она должна корректно передать управление DOS. А тут по первому прерыванию от таймера INT 20h!

Насчёт #GP при подмене шлюза прерывания на ловушки - судя по тому, что они отличаются друг от друга только разрешением/запретом прерываний во время работы обработчика, не будет.

По поводу стэка - получается, что никто не контролирует, выйдем мы за 512 байт или нет. Вот я и удивился.

По поводу
Цитата(MAKCim @  5.2.2007,  10:55 Найти цитируемый пост)
только не шлюзом задачи, а TSS сегментом

Я читал, что IDT может содержать только шлюзы прерываний, ловушек и задач. А что на самом деле?

Автор: MAKCim 5.2.2007, 13:23
Цитата(JAPH @  5.2.2007,  13:12 Найти цитируемый пост)
Ну, как это зачем? Когда прога выйдет из PM, она должна корректно передать управление DOS. А тут по первому прерыванию от таймера INT 20h!

а, ну если в этом смысле, тогда да
Цитата(JAPH @  5.2.2007,  13:12 Найти цитируемый пост)
По поводу стэка - получается, что никто не контролирует, выйдем мы за 512 байт или нет. Вот я и удивился.

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

Я читал, что IDT может содержать только шлюзы прерываний, ловушек и задач. А что на самом деле? 

так оно и есть
просто если тебе надо узнать, произошло исключение или прерывание, то нужно узнать ESP для CPL = 0, а он находится в TSS текущей задачи

Автор: JAPH 5.2.2007, 14:09
Прицепил перепрограммирование контроллера до и после. Теперь проблема такая: после возврата в DOS набрать что-либо в командной строке не удаётся - клавиатура игнорируется. Причём раскомментирование sti и/или комментирование mov al, 20h | out 20h, al исхода не меняет. Чего я недоглядел?
Код

        .486p
sseg    segment stack
        db      0400h dup (?)
sseg    ends
dseg    segment
gdts    db      8 dup (0)
        db      0FFh, 0FFh, 0, 0, 0, 10011010b, 00000000b, 0 ;cseg
        dw      small codeslim
        db      0, 0, 0, 10011010b, 01001111b, 0 ;codes in pm
        db      0FFh, 0FFh, 0, 80h, 0Bh, 10010010b, 01000000b, 0 ;B800
        db      00h, 0FCh, 0, 0, 0, 10010110b, 01000000b, 0 ;sseg in pm
        db      0FFh, 0FFh, 0, 0, 0, 10010010b, 01000000b, 0 ;sseg in rm
        db      067h, 0, 0, 0, 0, 10001001b, 00000000b, 0 ;stss
gdtlim  dw      0037h
gdtad   dd      0
idts    dw      20h dup (small offset here, 10h, 1000111000000000b, 0)
        dw      small offset timer, 10h, 1000111000000000b, 0
        dw      small offset keyb, 10h, 1000111000000000b, 0
idtlim  dw      010Fh
idtad   dd      0
stss    db      68h dup (0)
dseg    ends
codes   segment use32
        assume  cs:codes, ds:dseg
got:    mov     byte ptr fs:[0], '2'
        mov     ecx, 05000000h
@1:     dec     ecx
        jnz     @1
        mov     ax, 20h
        mov     ss, ax
        xor     esp, esp
        push    ax
        pop     ax
        mov     byte ptr fs:[0], '3'
        mov     ecx, 05000000h
@4:     dec     ecx
        jnz     @4
        mov     ax, 30h
        ltr     ax
        mov     al, 15h
        out     20h, al
        out     0A0h, al
        mov     al, 20h
        out     21h, al
        mov     al, 28h
        out     0A1h, al
        mov     al, 04h
        out     21h, al
        mov     al, 02h
        out     0A1h, al
        mov     al, 0Dh
        out     21h, al
        mov     al, 09h
        out     0A1h, al
        mov     al, 0FCh
        out     21h, al
        mov     al, 0FFh
        out     0A1h, al
       ;sti
        mov     ax, 18h
        mov     es, ax
        mov     ecx, 20
        mov     eax, 07200721h
        xor     edi, edi
        cld
    rep stosd
        mov     ecx, 05000000h
@3:     dec     ecx
        jnz     @3
here:   cli
        mov     ax, 28h
        mov     ss, ax
        db      0EAh
        dd      offset back
        dw      8
timer:  nop
keyb:   mov     al, 20h
        out     20h, al
        iretd
codeslim = $ - 1
codes   ends
cseg    segment use16
        assume  cs:cseg, ds:dseg
start:  xor     eax, eax
        mov     ax, 0B800h
        mov     fs, ax
        mov     ax, dseg
        mov     ds, ax
        shl     eax, 4
        mov     gdtad, eax
        xor     eax, eax
        mov     ax, codes
        shl     eax, 4
        mov     word ptr gdts + 12h, ax
        bswap   eax
        mov     byte ptr gdts + 14h, ah
        mov     byte ptr gdts + 17h, al
        xor     eax, eax
        mov     ax, sseg
        shl     eax, 4
        mov     word ptr gdts + 22h, ax
        mov     word ptr gdts + 2Ah, ax
        bswap   eax
        mov     byte ptr gdts + 24h, ah
        mov     byte ptr gdts + 2Ch, ah
        mov     byte ptr gdts + 27h, al
        mov     byte ptr gdts + 2Fh, al
        xor     eax, eax
        mov     ax, dseg
        shl     eax, 4
        add     eax, offset stss
        mov     word ptr gdts + 32h, ax
        bswap   eax
        mov     byte ptr gdts + 34h, ah
        mov     byte ptr gdts + 37h, al
        xor     eax, eax
        mov     ax, cseg
        shl     eax, 4
        mov     word ptr gdts + 0Ah, ax
        bswap   eax
        mov     byte ptr gdts + 0Ch, ah
        mov     byte ptr gdts + 0Fh, al
        mov     eax, gdtad
        add     eax, offset idts
        mov     idtad, eax
        lgdt    fword ptr gdtlim
        lidt    fword ptr idtlim
        in      al, 92h
        or      al, 02h
        out     92h, al
        cli
        in      al, 70h
        or      al, 80h
        out     70h, al
        mov     byte ptr fs:[0], '1'
        mov     ecx, 05000000h
@2:     dec     ecx
        jnz     @2
        mov     eax, cr0
        or      al, 1
        mov     cr0, eax
        db      66h
        db      0EAh
        dd      offset got
        dw      10h
;----------------------------------
idtr    dw      03FFh
        dd      0
back:   mov     byte ptr fs:[0], '4'
        mov     ecx, 05000000h
@5:     dec     ecx
        jnz     @5
        mov     eax, cr0
        and     al, 0FEh
        mov     cr0, eax
        db      0EAh
        dw      $ + 4
        dw      cseg
        lidt    fword ptr cs:idtr
        mov     byte ptr fs:[0], '5'
        mov     ecx, 05000000h
@6:     dec     ecx
        jnz     @6
        mov     ax, cs
        mov     ds, ax
        mov     es, ax
        mov     ax, sseg
        mov     ss, ax
        mov     esp, 00000400h
        push    ax
        pop     ax
        mov     al, 15h
        out     20h, al
        out     0A0h, al
        mov     al, 08h
        out     21h, al
        mov     al, 70h
        out     0A1h, al
        mov     al, 04h
        out     21h, al
        mov     al, 02h
        out     0A1h, al
        mov     al, 0Dh
        out     21h, al
        mov     al, 09h
        out     0A1h, al
        mov     al, 00h
        out     21h, al
        out     0A1h, al
        mov     byte ptr fs:[0], '6'
        mov     ecx, 05000000h
@7:     dec     ecx
        jnz     @7
        in      al, 92h
        and     al, 0FDh
        out     92h, al
        in      al, 70h
        and     al, 7Fh
        out     70h, al
        sti
        mov     ax, 4C00h
        int     21h
cseglim = $ - 1
cseg    ends
        end     start

Автор: MAKCim 5.2.2007, 17:46
Цитата(JAPH @  5.2.2007,  14:09 Найти цитируемый пост)
Чего я недоглядел?

так ты sti делаешь только перед int 21h, а в here: делаешь cli

Автор: JAPH 5.2.2007, 18:59
А что тут такого? Раскомментировать строку 59? Не поможет. Так как надо?
Почему DOS после отрабатывания программы не воспринимает клавиатуру? Куда делся обработчик INT 09h?
Если убрать перепрограммирование, всё в порядке.

Автор: MAKCim 5.2.2007, 19:06
Цитата(JAPH @  5.2.2007,  18:59 Найти цитируемый пост)
А что тут такого? Раскомментировать строку 59? Не поможет. Так как надо?

причем тут строка 59
насколько я понял
переход в реальный режим тут
Код

here:   cli
        mov     ax, 28h
        mov     ss, ax
        db      0EAh
        dd      offset back
        dw      8

далее в back (читай комментарии)
Код

back:   mov     byte ptr fs:[0], '4'
        mov     ecx, 05000000h
@5:     dec     ecx
        jnz     @5
        mov     eax, cr0
        and     al, 0FEh
        mov     cr0, eax  ; собственно переход в real-mode
        db      0EAh
        dw      $ + 4
        dw      cseg
        lidt    fword ptr cs:idtr  ; зачем?
        mov     byte ptr fs:[0], '5'
        mov     ecx, 05000000h
@6:     dec     ecx
        jnz     @6
        mov     ax, cs
        mov     ds, ax
        mov     es, ax
        mov     ax, sseg
        mov     ss, ax
        mov     esp, 00000400h
        push    ax
        pop     ax
; тут возврат на 08h и 70h
        mov     al, 15h
        out     20h, al
        out     0A0h, al
        mov     al, 08h
        out     21h, al
        mov     al, 70h
        out     0A1h, al
        mov     al, 04h
        out     21h, al
        mov     al, 02h
        out     0A1h, al
        mov     al, 0Dh
        out     21h, al
        mov     al, 09h
        out     0A1h, al
        mov     al, 00h
        out     21h, al
        out     0A1h, al
        mov     byte ptr fs:[0], '6'
        mov     ecx, 05000000h
@7:     dec     ecx
        jnz     @7
        in      al, 92h
        and     al, 0FDh
        out     92h, al
        in      al, 70h
        and     al, 7Fh
        out     70h, al
        sti ; а вот тут только разрешаем прерывания, пред самым выходом
        mov     ax, 4C00h
        int     21h


Автор: JAPH 5.2.2007, 20:03
Если оставить только конечное перепрограммирование, та же проблема.

Что касается последнего lidt, он должен загрузить в IDTR его значение в реальном режиме, то есть базу 0 и предел 03FFh. Я так понял, тут то же, что заставляет прописывать в CS и SS нечто с лимитом 0FFFFh для выхода из PM. (Я сначала забыл про это - заработал перезагрузку)

И всё же, чем мешает cli? Это не должно влиять на контроллер. Разрешить прерывания я решаюсь только после закрытия A20 и разрешения маскируемых прерываний. Конечно, можно перенести перепрограммирование поближе к sti, но что это изменит?

Автор: MAKCim 5.2.2007, 20:36
Цитата

Что касается последнего lidt, он должен загрузить в IDTR его значение в реальном режиме, то есть базу 0 и предел 03FFh.

в реальном режиме процессор регистр LDTR вообще не смотрит а обращается напрямую к таблице векторов прерываний по 0000:0000h, такова логика
Цитата

И всё же, чем мешает cli? Это не должно влиять на контроллер

Нет, конечно на контроллер это не влияет
однако, сделав cli, процессор не реагирует на сообщения контроллера о возникновении прерываний => процессор не начинает их обработку

Автор: JAPH 5.2.2007, 20:41
Ну дык перед выходом из программы происходит sti. По идее, ОС уже должна реагировать на прерывания?

Автор: MAKCim 5.2.2007, 20:47
Цитата(JAPH @  5.2.2007,  20:41 Найти цитируемый пост)
Ну дык перед выходом из программы происходит sti. По идее, ОС уже должна реагировать на прерывания? 

ну и?
программа то завершается, о каких тогда нажатиях на клавиатуре идет речь? (или я чего-то не понимаю)
Кстати, такой вопрос, как сей код ты запускаешь?

Автор: JAPH 5.2.2007, 21:11
Итак. Загружаюсь под голым DOS-ом, т.е. комп работает в реальном режиме. В командной строке
Код

tasm /m opit.asm
tlink /x /3 opit.obj
opit.exe

Прога отрабатывает, появляется
Код

C:\TP>

но набрать "win" не удаётся - клава игнорируется!

Автор: MAKCim 6.2.2007, 13:05
покажи участок кода, который должен выполняться в момент генерации прерывания

Автор: JAPH 6.2.2007, 13:28
В какой момент какой генерации прерывания? На протяжении всей работы программы прерывания запрещены - от cli в строке 131 до sti перед самым выходом! Привожу полный текст ошибочной программы:

Код

        .486p    
sseg    segment stack     
        db      0400h dup (?)    
sseg    ends    
dseg    segment    
gdts    db      8 dup (0)    
        db      0FFh, 0FFh, 0, 0, 0, 10011010b, 00000000b, 0 ;cseg    
        dw      small codeslim    
        db      0, 0, 0, 10011010b, 01001111b, 0 ;codes in pm    
        db      0FFh, 0FFh, 0, 80h, 0Bh, 10010010b, 01000000b, 0 ;B800    
        db      00h, 0FCh, 0, 0, 0, 10010110b, 01000000b, 0 ;sseg in pm    
        db      0FFh, 0FFh, 0, 0, 0, 10010010b, 01000000b, 0 ;sseg in rm    
        db      067h, 0, 0, 0, 0, 10001001b, 00000000b, 0 ;stss    
gdtlim  dw      0037h    
gdtad   dd      0    
idts    dw      20h dup (small offset here, 10h, 1000111000000000b, 0)    
        dw      small offset timer, 10h, 1000111000000000b, 0    
        dw      small offset keyb, 10h, 1000111000000000b, 0    
idtlim  dw      010Fh    
idtad   dd      0    
stss    db      68h dup (0)    
dseg    ends    
codes   segment use32    
        assume  cs:codes, ds:dseg    
got:    mov     byte ptr fs:[0], '2'    
        mov     ecx, 05000000h    
@1:     dec     ecx    
        jnz     @1    
        mov     ax, 20h    
        mov     ss, ax    
        xor     esp, esp    
        push    ax    
        pop     ax    
        mov     byte ptr fs:[0], '3'    
        mov     ecx, 05000000h    
@4:     dec     ecx    
        jnz     @4    
        mov     ax, 30h    
        ltr     ax    
       ;mov     al, 15h    
       ;out     20h, al    
       ;out     0A0h, al    
       ;mov     al, 20h    
       ;out     21h, al    
       ;mov     al, 28h    
       ;out     0A1h, al    
       ;mov     al, 04h    
       ;out     21h, al    
       ;mov     al, 02h    
       ;out     0A1h, al    
       ;mov     al, 0Dh    
       ;out     21h, al    
       ;mov     al, 09h    
       ;out     0A1h, al    
       ;mov     al, 0FCh    
       ;out     21h, al    
       ;mov     al, 0FFh    
       ;out     0A1h, al    
       ;sti    
        mov     ax, 18h    
        mov     es, ax    
        mov     ecx, 20    
        mov     eax, 07200721h    
        xor     edi, edi    
        cld    
    rep stosd    
        mov     ecx, 05000000h    
@3:     dec     ecx    
        jnz     @3    
here:   cli    
        mov     ax, 28h    
        mov     ss, ax    
        db      0EAh    
        dd      offset back    
        dw      8    
timer:  nop    
keyb:   mov     al, 20h    
        out     20h, al    
        iretd    
codeslim = $ - 1    
codes   ends    
cseg    segment use16    
        assume  cs:cseg, ds:dseg    
start:  xor     eax, eax    
        mov     ax, 0B800h    
        mov     fs, ax    
        mov     ax, dseg    
        mov     ds, ax    
        shl     eax, 4    
        mov     gdtad, eax    
        xor     eax, eax    
        mov     ax, codes    
        shl     eax, 4    
        mov     word ptr gdts + 12h, ax    
        bswap   eax    
        mov     byte ptr gdts + 14h, ah    
        mov     byte ptr gdts + 17h, al    
        xor     eax, eax    
        mov     ax, sseg    
        shl     eax, 4    
        mov     word ptr gdts + 22h, ax    
        mov     word ptr gdts + 2Ah, ax    
        bswap   eax    
        mov     byte ptr gdts + 24h, ah    
        mov     byte ptr gdts + 2Ch, ah    
        mov     byte ptr gdts + 27h, al    
        mov     byte ptr gdts + 2Fh, al    
        xor     eax, eax    
        mov     ax, dseg    
        shl     eax, 4    
        add     eax, offset stss    
        mov     word ptr gdts + 32h, ax    
        bswap   eax    
        mov     byte ptr gdts + 34h, ah    
        mov     byte ptr gdts + 37h, al    
        xor     eax, eax    
        mov     ax, cseg    
        shl     eax, 4    
        mov     word ptr gdts + 0Ah, ax    
        bswap   eax    
        mov     byte ptr gdts + 0Ch, ah    
        mov     byte ptr gdts + 0Fh, al    
        mov     eax, gdtad    
        add     eax, offset idts    
        mov     idtad, eax    
        lgdt    fword ptr gdtlim    
        lidt    fword ptr idtlim    
        in      al, 92h    
        or      al, 02h    
        out     92h, al    
        cli    
        in      al, 70h    
        or      al, 80h    
        out     70h, al    
        mov     byte ptr fs:[0], '1'    
        mov     ecx, 05000000h    
@2:     dec     ecx    
        jnz     @2    
        mov     eax, cr0    
        or      al, 1    
        mov     cr0, eax    
        db      66h    
        db      0EAh    
        dd      offset got    
        dw      10h    
;----------------------------------    
idtr    dw      03FFh    
        dd      0    
back:   mov     byte ptr fs:[0], '4'    
        mov     ecx, 05000000h    
@5:     dec     ecx    
        jnz     @5    
        mov     eax, cr0    
        and     al, 0FEh    
        mov     cr0, eax    
        db      0EAh    
        dw      $ + 4    
        dw      cseg    
        lidt    fword ptr cs:idtr    
        mov     byte ptr fs:[0], '5'    
        mov     ecx, 05000000h    
@6:     dec     ecx    
        jnz     @6    
        mov     ax, cs    
        mov     ds, ax    
        mov     es, ax    
        mov     ax, sseg    
        mov     ss, ax    
        mov     esp, 00000400h    
        push    ax    
        pop     ax    
        mov     al, 15h    
        out     20h, al    
        out     0A0h, al    
        mov     al, 08h    
        out     21h, al    
        mov     al, 70h    
        out     0A1h, al    
        mov     al, 04h    
        out     21h, al    
        mov     al, 02h    
        out     0A1h, al    
        mov     al, 0Dh    
        out     21h, al    
        mov     al, 09h    
        out     0A1h, al    
        mov     al, 00h    
        out     21h, al    
        out     0A1h, al    
        mov     byte ptr fs:[0], '6'    
        mov     ecx, 05000000h    
@7:     dec     ecx    
        jnz     @7    
        in      al, 92h    
        and     al, 0FDh    
        out     92h, al    
        in      al, 70h    
        and     al, 7Fh    
        out     70h, al    
        sti    
        mov     ax, 4C00h    
        int     21h    
cseglim = $ - 1    
cseg    ends    
        end     start

Автор: MAKCim 6.2.2007, 13:42
Цитата(JAPH @  6.2.2007,  13:28 Найти цитируемый пост)
На протяжении всей работы программы прерывания запрещены - от cli в строке 131 до sti перед самым выходом!

блин
ну и чего ты тогда хочешь, каким макаром у тебя будет ловится IRQ1, если IF = 0
после перехода в protected mode и перерограммирования контроллера делай sti, перед возвратом в real mode делай cli, далее переходи в real mode, обратно перепрограммируй контроллер и сразу делай опять sti

Автор: JAPH 6.2.2007, 14:00
Так надо правильно перепрограммировать контроллер! Если даже просто отдельной программой перепрограммировать его на прерывания 8 и 70h, клавиатура перестанет распознаваться, процессор перестанет реагировать на IRQ1 и наверняка на IRQ0 тоже! Ошибка в строках 173-189. Если их убрать, всё нормально.

Я добиваюсь того, чтоб после работы программы (неважно, что конкретно она творит, главное, что перепрограммирует контроллер) операционная система распознавала INT 9!

На вашем компьютере этот код не вызывает таких проблем?

Автор: MAKCim 6.2.2007, 14:40
Цитата(JAPH @  6.2.2007,  14:00 Найти цитируемый пост)
На вашем компьютере этот код не вызывает таких проблем? 

на моем компьютере нет DOS  smile 
у вас к тому же еще и не загрузочный модуль, так что проверить не могу

Автор: JAPH 6.2.2007, 16:32
Контроллер прерываний у вас есть? Вы код перепрограммирования проверяли? Работает? Корректно?

Автор: MAKCim 6.2.2007, 17:15
Цитата(JAPH @  6.2.2007,  16:32 Найти цитируемый пост)
Контроллер прерываний у вас есть? Вы код перепрограммирования проверяли? Работает? Корректно? 

не проверял
но сведения взяты из Зубкова, не думаю, что там ошибка
если хотите вот http://pdos.csail.mit.edu/6.828/2005/readings/hardware/8259A.pdf на оригинальную документацию Intel по 8259 I/O APIC

Автор: JAPH 6.2.2007, 20:39
Прочитал документацию. Действительно, всё верно. Так что sorry, ошибка и правда не здесь.
Попробовал навесить обработчик для прерываний защищённого режима - заработал! Но DOS по-прежнему упрямится.
Попробовал после второго перепрограммирования поменять обработчики реального режима на свои - работают! Но DOSу на это наплевать.
Сохранил всю таблицу прерываний в начале программы и восстановил её перед выходом - никакого эффекта. Клавиатура по-прежнему не влияет на командную строку DOS. Ну что с этим делать!

Итак, вопрос. Как восстановить работоспособность DOS после запуска следующего кода?


Код

        .486p
sseg    segment stack
        db      0400h dup (?)
sseg    ends
dseg    segment
retdata dd      100h dup (?)
gdts    db      8 dup (0)
        db      0FFh, 0FFh, 0, 0, 0, 10011010b, 00000000b, 0 ;cseg
        dw      small codeslim
        db      0, 0, 0, 10011010b, 01001111b, 0 ;codes in pm
        db      0FFh, 0FFh, 0, 80h, 0Bh, 10010010b, 01000000b, 0 ;B800
        db      00h, 0FCh, 0, 0, 0, 10010110b, 01000000b, 0 ;sseg in pm
        db      0FFh, 0FFh, 0, 0, 0, 10010010b, 01000000b, 0 ;sseg in rm
        db      067h, 0, 0, 0, 0, 10001001b, 00000000b, 0 ;stss
gdtlim  dw      0037h
gdtad   dd      0
idts    dw      20h dup (small offset here, 10h, 1000111000000000b, 0)
        dw      small offset timer, 10h, 1000111000000000b, 0
        dw      small offset keyb, 10h, 1000111000000000b, 0
idtlim  dw      010Fh
idtad   dd      0
stss    db      68h dup (0)
dseg    ends
codes   segment use32
        assume  cs:codes, ds:dseg
got:    mov     byte ptr fs:[0], '2'
        mov     ecx, 05000000h
@1:     dec     ecx
        jnz     @1
        mov     ax, 20h
        mov     ss, ax
        xor     esp, esp
        push    ax
        pop     ax
        mov     byte ptr fs:[0], '3'
        mov     ecx, 05000000h
@4:     dec     ecx
        jnz     @4
        mov     ax, 30h
        ltr     ax
        mov     al, 15h
        out     20h, al
        mov     al, 15h
        out     0A0h, al
        mov     al, 20h
        out     21h, al
        mov     al, 28h
        out     0A1h, al
        mov     al, 04h
        out     21h, al
        mov     al, 02h
        out     0A1h, al
        mov     al, 0Dh
        out     21h, al
        mov     al, 09h
        out     0A1h, al
        mov     al, 0FCh
        out     21h, al
        mov     al, 0FFh
        out     0A1h, al
        sti
        mov     ax, 18h
        mov     es, ax
        mov     ecx, 20
        mov     eax, 07200721h
        xor     edi, edi
        cld
    rep stosd
        mov     ecx, 05000000h
@3:     dec     ecx
        jnz     @3
here:   cli
        mov     ax, 28h
        mov     ss, ax
        db      0EAh
        dd      offset back
        dw      8
timer:  nop
keyb:   push    eax
        mov     byte ptr fs:[0A0h], '?'
        mov     al, 20h
        out     20h, al
        pop     eax
        iretd
codeslim = $ - 1
codes   ends
cseg    segment use16
        assume  cs:cseg, ds:dseg
start:  mov     ax, 0B800h
        mov     fs, ax
        mov     ax, dseg
        mov     ds, ax
        lea     di, retdata
        mov     ax, 3500h
        mov     cx, 0100h
@rept:  int     21h
        inc     al
        mov     [di], bx
        mov     [di + 2], es
        add     di, 4
        loop    @rept
        xor     eax, eax
        mov     ax, ds
        shl     eax, 4
        add     eax, offset gdts
        mov     gdtad, eax
        xor     eax, eax
        mov     ax, codes
        shl     eax, 4
        mov     word ptr gdts + 12h, ax
        bswap   eax
        mov     byte ptr gdts + 14h, ah
        mov     byte ptr gdts + 17h, al
        xor     eax, eax
        mov     ax, sseg
        shl     eax, 4
        mov     word ptr gdts + 22h, ax
        mov     word ptr gdts + 2Ah, ax
        bswap   eax
        mov     byte ptr gdts + 24h, ah
        mov     byte ptr gdts + 2Ch, ah
        mov     byte ptr gdts + 27h, al
        mov     byte ptr gdts + 2Fh, al
        xor     eax, eax
        mov     ax, dseg
        shl     eax, 4
        add     eax, offset stss
        mov     word ptr gdts + 32h, ax
        bswap   eax
        mov     byte ptr gdts + 34h, ah
        mov     byte ptr gdts + 37h, al
        xor     eax, eax
        mov     ax, cseg
        shl     eax, 4
        mov     word ptr gdts + 0Ah, ax
        bswap   eax
        mov     byte ptr gdts + 0Ch, ah
        mov     byte ptr gdts + 0Fh, al
        mov     eax, gdtad
        add     eax, offset idts - offset gdts
        mov     idtad, eax
        lgdt    fword ptr gdtlim
        lidt    fword ptr idtlim
        in      al, 92h
        or      al, 02h
        out     92h, al
        cli
        in      al, 70h
        or      al, 80h
        out     70h, al
        mov     byte ptr fs:[0], '1'
        mov     ecx, 05000000h
@2:     dec     ecx
        jnz     @2
        mov     eax, cr0
        or      al, 1
        mov     cr0, eax
        db      66h
        db      0EAh
        dd      offset got
        dw      10h
;----------------------------------
idtr    dw      03FFh
        dd      0
back:   mov     byte ptr fs:[0], '4'
        mov     ecx, 05000000h
@5:     dec     ecx
        jnz     @5
        mov     eax, cr0
        and     al, 0FEh
        mov     cr0, eax
        db      0EAh
        dw      offset @goon
        dw      cseg
@goon:  lidt    fword ptr cs:idtr
        mov     byte ptr fs:[0], '5'
        mov     ecx, 05000000h
@6:     dec     ecx
        jnz     @6
        mov     ax, cs
        mov     ds, ax
        mov     es, ax
        mov     ax, sseg
        mov     ss, ax
        mov     esp, 00000400h
        push    ax
        pop     ax
        mov     al, 15h
        out     20h, al
        out     0A0h, al
        mov     al, 08h
        out     21h, al
        mov     al, 70h
        out     0A1h, al
        mov     al, 04h
        out     21h, al
        mov     al, 02h
        out     0A1h, al
        mov     al, 0Dh
        out     21h, al
        mov     al, 09h
        out     0A1h, al
        mov     al, 00h
        out     21h, al
        out     0A1h, al
        mov     byte ptr fs:[0], '6'
        mov     ecx, 05000000h
@7:     dec     ecx
        jnz     @7
        mov     ax, 2500h
        lea     si, retdata
        mov     cx, 0100h
        push    dseg
        pop     es
@rest:  lds     dx, es:[si]
        add     si, 4
        int     21h
        inc     al
        loop    @rest
        in      al, 92h
        and     al, 0FDh
        out     92h, al
        in      al, 70h
        and     al, 7Fh
        out     70h, al
        sti
        mov     ax, 4C00h
        int     21h
cseg    ends
        end     start

Автор: MAKCim 6.2.2007, 22:04
JAPH, 
а точно ли DOS ставит обработчики на 08h и 70h?
есть подозрения, что причина в этом

Автор: JAPH 7.2.2007, 12:53
Что IRQ0 на 08h - это точно. Насчёт 70h не знаю, но всюду написано, что на 70h.
Цитирую:
Цитата
Прерывания 00h-1Fh и 70h-77h присутствуют в PC независимо от типа установленной операционной системы


Автор: MAKCim 7.2.2007, 16:09
Цитата

Попробовал после второго перепрограммирования поменять обработчики реального режима на свои - работают! Но DOSу на это наплевать.

в реальном режиме попробуй заменить обработчик IRQ1 на свой, а из него вызвать оригинальный по адресу, записанному в  0000:0020h
если не прокатит, есть подозрение, что код оригинального обработчика чем-то затирается в процессе работы твоей программы

Автор: JAPH 7.2.2007, 19:24
Не прокатило. smile

Автор: MAKCim 8.2.2007, 00:17
Цитата(JAPH @  7.2.2007,  19:24 Найти цитируемый пост)
Не прокатило.

тогда проведи такой тест
перед переходом в protected mode сохрани первые 50 байт (или по своему усмотрению) обработчика IRQ9 в надежное место
Код

xor ax, ax
mov es, ax
mov si, word ptr es:[024h] ; offset
mov ax, word ptr es:[026h] ; segment
push ds
mov ds, ax
pop es
lea di, <надежное место>
mov cx, 50
rep
movsb

перед выходом твоей программы просканируй на идентичность кода сохраненного обработчика и кода того обработчика который находится по адресу 0000:0024h

Автор: JAPH 8.2.2007, 14:58
Первые 256 байт по адресу обработчика IRQ1 не изменились.

Кстати, если перед выходом из программы заставить её ждать нажатия клавиши
Код

mov ah, 01h
int 21h
; ИЛИ
mov ah, 10h
int 16h

система виснет.

Автор: MAKCim 9.2.2007, 18:35
Цитата(JAPH @  8.2.2007,  14:58 Найти цитируемый пост)
Первые 256 байт по адресу обработчика IRQ1 не изменились.

не знаю тогда  smile, прямо мистика  smile 

Автор: JAPH 9.2.2007, 19:14
Нда. Может, проблема в самой DOS и переустановка что-нибудь даст? Но до неё далеко.
Может, кто-нибудь ещё потестирует код на своей DOS и расскажет о впечатлениях.
А так, я думаю, вопрос исчерпан - в защищённом режиме всё идеально работает. Спасибо за участие smile

Автор: MAKCim 9.2.2007, 20:24
Цитата(JAPH @  9.2.2007,  19:14 Найти цитируемый пост)
Может, кто-нибудь ещё потестирует код на своей DOS

если у кого такой раритет будет  smile 

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)