2011-12-27 5 views
3

일부 타이머와 함께 사용하기 위해 int 70h와 IRQ8을 사용하는 RTC로 인한 인터럽트를 처리해야하는 인터럽트 서비스 루틴을 작성하고 있습니다. 불행하게도, 나는 많은 문제를 겪어 왔기 때문에 문제를 몇 가지 작은 문제로 분리하고 각각을 독립적으로 해결하기로 결정했습니다. 처음에는 하드웨어 부분을 포기하고 먼저 소프트웨어에서 인터럽트를 구현하기로 결정했습니다.인터럽트 서비스 루틴의 이상한 동작

지금 당장 NASM과 DosBox를 사용하고 있습니다.

segment .code 
; ---------------------------------------------- 
; writes a message on the screen 
; every time interrupt is called 
; ---------------------------------------------- 

INT_CODE equ 070h 

my_int: 
    pusha   ;saves all registers on stack so they get preserved 

    ;EDIT1 
    xor ax, ax  ;sets ax to zero 
    mov es, ax  ;puts zero into extra segment register 
    mov bx, [es:INT_CODE*4+2] ;this should give us the sergment of the ISR 
    mov ds, bx  ;the segment is now in ds 
    ;END OF EDIT1 

    ;mov ax, 0  ;cleans any garbage in ax 

    ;mov ah, 09h ;preparing to call DOS system call, remove later 
    mov ax, string_s 
    mov si, ax 
    call _print_string 


    ;int 021h  ;this should hopefully work 

    mov al, 0Ch  ; Accessing RTC 
    out 070h, al ; register C should be read 
    in al, 071h  ;or there won't be any new interrupts (or so it's supposed to be) 

    ;mov ax, 0  ; again we clear anything left in ax, just in case 
    ;mov ah, 09h ; preparing to write string 
    mov ax, string_e 
    mov si, ax 
    call _print_string 
    ;int 021h  ; this should work 

    mov al, 20h  ;we're letting PICs know the interrupt ended 
    out 0A0h, al ;notifying second PIC 
    out 020h, al ;notifying first PIC 

    popa   ;application gets its registers back 

    iret 

_inst_70: 
    cli    ;hardware interrupts are now stopped 
    xor  ax, ax 
    mov  es, ax 
    mov  bx, [es:INT_CODE*4] 
    mov  [old_int70_off], bx 
    mov  bx, [es:INT_CODE*4+2] 
    mov  [old_int70_seg], bx 

; adding our routine to interrupt vector table 
    mov  dx, my_int 
    mov  [es:INT_CODE*4], dx 
    mov  ax, cs 
    mov  [es:INT_CODE*4+2], ax 
    sti 

    ;mov ah, 09h 

    mov ax, string_inst 
    mov si, ax 
    call _print_string 
    ;int 021h 

    ret 

; ----------------------------------------------------------------------------- 
; return old int 70 h 

_uninst_70: 
    cli 
    xor  ax, ax 
    mov  es, ax 
    mov  ax, [old_int70_seg] 
    mov  [es:INT_CODE*4+2], ax 
    mov  dx, [old_int70_off] 
    mov  [es:INT_CODE*4], dx 
    sti 
    ret 

_print_string: 

    pusha 
    mov  ah, 0Eh      ; BIOS INT 10h teletype (TTY) function 
.Repeat: 
    lodsb        ; takes one character from a string 
    cmp  al, 0 
    je  .End       ; If it's zero, end of string 
    int  10h       ; if not, call BIOS 
    jmp .Repeat      ; and go to next character 
.End: 
    popa 
    ret 

segment .data 

string_s: db 'We're in ISR',0 
string_e: db 'It's working',0 
string_inst: db 'Installed',0 

old_int70_seg: dw 0 
old_int70_off: dw 0 

나는 다음과 같은 프로그램을 사용하여이 인터럽트를 테스트하고 있습니다 :

;myint 
org 100h;installs the interrupt 
segment .code 

main: 
    call _inst_70 

    ;call _uninst_70 ; THIS IS ON PURPOSE! 
    ret 

%include "myint.asm" 

;int70h 
org 100h   ;calls the interrupt 
segment .code 
    mov ah, 09h  ; getting ready to print string 
    mov dx, string1 
    int 21h 

    ;mov ax, 0  ;getting rid of the last message 
    ;mov dx, 0 

    int 070h  ;calling the interrupt 

    mov ah, 09h 
    mov dx, string2; 
    int 21h 

    ret 

segment .data 
string1: db 'Testing!',0 
string2: db 'int 70h working',0 
_print_string: 

     pusha 
     mov  ah, 0Eh   ; BIOS INT 10h teletype (TTY) function 
.Repeat: 
     lodsb     ; takes one character from a string 
     cmp  al, 0 
     je  .End    ; If it's zero, end of string 
     int  10h    ; if not, call BIOS 
     jmp .Repeat   ; and go to next character 
.End: 
     popa 
     ret 

이제 우리는 흥미를 얻고을 여기

는 ISR 코드입니다 부품.

설치 프로그램을 호출하면 인터럽트가 설치되었다는 메시지가 나타나고 프로그램이 정상적으로 종료 된 것처럼 보입니다.

INT70H.COM을 호출하면 메모리 영역을 덤프하는 것으로 나타납니다. 읽을 수있는 유일한 것들은 Testing!Testing!int 70h workingC:\NASM-DOS\NASM.EXE입니다.

INT70H에서 mov ax, 0mov dx, 0 행의 주석을 제거하면 Testing!이 표시되고 DosBox가 중단되고 때때로 충돌합니다. VMware와 VirtualBox도 마찬가지입니다.

내가 INT70H에서 두 개의 movs와 RTC의 레지스터 C를 읽고있는 줄을 주석으로 처리하면 Testing!Testing!int 70h working이되고 DosBox가 중단됩니다. 버추얼 박스와 VMware에서도 똑같은 일이 일어납니다. INT70H에서 두 개의 mov 파일의 주석 처리가 해제 된 경우 Testing!이 표시되고 멈 춥니 다.

이것은 일부 DOS 시스템 호출 (최종 제품에서 사용하지 않아야 함)이 나쁘다고 생각할 수도 있지만 INT70H를 실행할 때 주석 처리 된 경우에도 컴퓨터 멈 춥니 다.

내 주요 문제는 바로 지금이 문제에 대한 작업을 시작하는 방법을 전혀 모른다는 것입니다.

+2

전체 답변을 드릴 시간이 없지만 프로그램을 [TSR] (http://en.wikipedia.org/wiki/Terminate_and_Stay_Resident)으로 만들어야합니다. – interjay

+0

@interjay 그건 내가 프로그램을 쓰고 있음을 암시합니다. 나중에 운영 체제 스케줄러의 일부가 될 것이며 PIT를 사용하지 않고 100ms 타임베이스를 얻으려고합니다. 그래서 최종 결과에 DOS 기능을 의지 할 수는 없습니다. :) – AndrejaKo

+0

하드웨어 인터럽트 처리기에서 DOS 인터럽트를 사용할 수 없으며 재진입이 불가능합니다. –

답변

0

이것은 정말 이상한 버그였습니다. 도움을 주신 모든 분들께 고마워요.하지만 결국 RTC를 설정할 때 출력하기 전에 출력 레지스터를 B로 설정하지 않았습니다. 이제 제대로 작동합니다.

1

인터럽트 서비스 루틴은 세그먼트 레지스터를 설정 한 후에 세그먼트 레지스터를 설정해야합니다. 인터럽트가 호출되면 시스템에 절대적으로 아무 것도없는 컨텍스트를 가질 수 있습니다. 문자열 인쇄에 대한 호출은 특히 문자열 주소에 대해 ds:dx을 사용하기 때문에 문제가 발생하지만 ds은 설정되지 않습니다.

이외의 외형은 외관상으로 좋아 보입니다. ds을 설정하면 중단 문제가 해결되는지 확인하십시오. 그렇지 않으면 후속 조치를 취하십시오.

+0

중요한 개선점은 INT70H의 'mov ax, 0'이 주석 처리되고 서비스 루틴의 첫 번째 'mov ax, 0'이 아닌 경우 메모리 내용을 인쇄 한 다음 중단됩니다. 전에는 그렇게하지 않았습니다. – AndrejaKo

1

인터럽트 서비스 루틴 (ISR)은 사용하는 레지스터를 저장하고 복원해야합니다 (인터럽트 된 소프트웨어가 임의로 휴지통에있는 레지스터를 볼 수 없도록). 여기에는 세그먼트 레지스터 (예 : DS 및 ES)가 포함됩니다. "push ds"과 "push es"이 ISR의 시작 부분에 해당 "팝"지침이 "iret"앞에 있어야합니다.

BIOS 기능은 모두 재진입 중이므로 ISR에서 이들 중 하나를 사용하는 것이 안전하지 않습니다. 다른 코드에서 실행될 가능성이 없다는 것을 보장 할 수 없다면 말입니다. 여기에는 "int 0x10, ah = 0x0E"함수 (주 코드에서 사용하는 ISR 및 주 코드에서 인터럽트하는 함수)가 포함됩니다. 그것이 테스트를 위해서만 존재한다면; 대신 디스플레이 메모리에 직접 쓰기를 시도하십시오 (예 : 텍스트 모드의 경우 "mov ax,0xB800; mov es,ax; inc word [es:0]").

OS 코드를 테스트 할 때 종종 OS 코드를 테스트하는 것이 더 쉽습니다. 예를 들어, 의도적으로 반환하지 않은 부트 섹터에 구현 된 경우 (잠김). 이전 IVT 항목을 저장/복원하거나 DOS 및/또는 TSR이 테스트를 방해 할 수있는 백그라운드에서 수행하는 것에 대해 걱정할 필요가 없습니다. Bochs와 같이 가상 머신 안에 DOS/FreeDOS를 먼저 설치하지 않고 디버깅 할 수 있습니다. 추가 보너스로 나중에 16 비트 리얼 모드 코드를 다시 작성하는 대신 대상 작동 모드 (예 : 32 비트 보호 모드)에서 수행 할 수 있습니다.