INT 13, 2 hanging on x86 real mode when trying to read sectors from floppy drive

前端 未结 1 1898
死守一世寂寞
死守一世寂寞 2020-12-21 10:41

I\'m writing a DOS clone for a school project and I\'m trying to read some sectors from a floppy drive (mainly the root directory of a FAT12 file system, sector 19) using BI

相关标签:
1条回答
  • 2020-12-21 11:15

    Your code isn't working because the int 0x13 BIOS call is returning a 0x80 status code (timeout). This is because you are doing the disk read BIOS call inside an interrupt handler (ISR).

    When the CPU transfers control to your ISR in real mode it clears the IF flag. This causes the CPU to ignore maskable external interrupts. Even if you were to enable interrupts with STI you won't get any more interrupts sent from the PICs that are of lower or equal priority to the current interrupt. In essence IRQ0 (higher priority interrupt than IRQ1) is the only interrupt you could get until you send an EOI. You won't get the floppy disk controller interrupts that the BIOS call needs to properly complete a request. This is likely the cause of the timeout.

    The best idea for doing ISRs is to limit them to doing the bare minimum and do it in the least amount of time possible. You should avoid making other BIOS calls from your ISR unless you know what you are doing.

    In a keyboard ISR you can read keystrokes into a buffer and defer processing them until later. A ring buffer is often used by kernels for handling keyboard data. Once the character is read into the buffer you can send the EOI and exit your ISR. Replace the JMP $ that is your kernel's main loop with a loop that processes the keys stored by the keyboard ISR. You can then take whatever actions are appropriate. You could replace your JMP $ with something like:

    main_loop:
        hlt                 ; Halt processor until next interrupt occurs
    
        [check for characters in the keyboard buffer and process them as needed]
        ...
        jmp main_loop
    

    Since this is done outside an ISR you are not constrained by the issues you had running inside an ISR.


    An example implementation of an interrupt safe lockless ring buffer that can work with one consumer and producer is shown below. The example has a keyboard ISR that takes each scancode and places it into a buffer if the buffer isn't full. The main loop checks each iteration if there is a scancode available (buffer isn't empty). If one is available it is translated to ASCII and printed to the console.

    KBD_BUFSIZE equ 32                 ; Keyboard Buffer length. **Must** be a power of 2
                                       ;     Maximum buffer size is 2^15 (32768)
    KBD_IVT_OFFSET equ 0x0024          ; Base address of keyboard interrupt (IRQ) in IVT
    
    bits 16
    org 0x7c00
    
    start:
        xor ax, ax
        mov ds, ax                     ; DS=0 since we use an ORG of 0x7c00.
                                       ;     0x0000<<4+0x7C00=0x07C00
        mov ss, ax
        mov sp, 0x7c00                 ; SS:SP stack pointer set below bootloader
    
        cli                            ; Don't want to be interrupted when updating IVT
        mov word [KBD_IVT_OFFSET], kbd_isr
                                       ; 0x0000:0x0024 = IRQ1 offset in IVT
        mov [KBD_IVT_OFFSET+2], ax     ; 0x0000:0x0026 = IRQ1 segment in IVT
        sti                            ; Enable interrupts
    
        mov ax, 0xb800
        mov es, ax                     ; Set ES to text mode segment (page 0)
        xor di, di                     ; DI screen offset = 0 (upper left)
        mov ah, 0x1F                   ; AH = White on Blue screen attribute
        mov bx, keyboard_map           ; BX = address of translate table used by XLAT
        cld                            ; String instructions set to forward direction
    
    .main_loop:
        hlt                            ; Halt processor until next interrupt
        mov si, [kbd_read_pos]
        cmp si, [kbd_write_pos]
        je .main_loop                  ; If (read_pos == write_pos) then buffer empty and
                                       ;     we're finished
    
        lea cx, [si+1]                 ; Index of next read (tmp = read_pos + 1)
        and si, KBD_BUFSIZE-1          ; Normalize read_pos to be within 0 to KBD_BUFSIZE
        mov al, [kbd_buffer+si]        ; Get next scancode
        mov [kbd_read_pos], cx         ; read_pos++ (read_pos = tmp)
        test al, 0x80                  ; Is scancode a key up event?
        jne .main_loop                 ;     If so we are finished
    
        xlat                           ; Translate scancode to ASCII character
        test al, al
        je .main_loop                  ; If character to print is NUL we are finished
        stosw                          ; Display character on console in white on blue
    
        jmp .main_loop
    
    ; Keyboard ISR (IRQ1)
    kbd_isr:
        push ax                        ; Save all registers we modify
        push si
        push cx
    
        in al, 0x60                    ; Get keystroke
    
        mov cx, [cs:kbd_write_pos]
        mov si, cx
        sub cx, [cs:kbd_read_pos]
        cmp cx, KBD_BUFSIZE            ; If (write_pos-read_pos)==KBD_BUFSIZE then buffer full
        je .end                        ;    If buffer full throw char away, we're finished
    
        lea cx, [si+1]                 ; Index of next write (tmp = write_pos + 1)
        and si, KBD_BUFSIZE-1          ; Normalize write_pos to be within 0 to KBD_BUFSIZE
        mov [cs:kbd_buffer+si], al     ; Save character to buffer
        mov [cs:kbd_write_pos], cx     ; write_pos++ (write_pos = tmp)
    
    .end:
        mov al, 0x20
        out 0x20, al                   ; Send EOI to Master PIC
    
        pop cx                         ; Restore all registers modified
        pop si
        pop ax
        iret
    
    align 2
    kbd_read_pos:  dw 0
    kbd_write_pos: dw 0
    kbd_buffer:    times KBD_BUFSIZE db 0
    
    ; Scancode to ASCII character translation table
    keyboard_map:
        db  0,  27, '1', '2', '3', '4', '5', '6', '7', '8'    ; 9
        db '9', '0', '-', '=', 0x08                           ; Backspace
        db 0x09                                               ; Tab
        db 'q', 'w', 'e', 'r'                                 ; 19
        db 't', 'y', 'u', 'i', 'o', 'p', '[', ']', 0x0a       ; Enter key
        db 0                                                  ; 29   - Control
        db 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';'   ; 39
        db "'", '`', 0                                        ; Left shift
        db "\", 'z', 'x', 'c', 'v', 'b', 'n'                  ; 49
        db 'm', ',', '.', '/', 0                              ; Right shift
        db '*'
        db 0                                                  ; Alt
        db ' '                                                ; Space bar
        db 0                                                  ; Caps lock
        db 0                                                  ; 59 - F1 key ... >
        db 0,   0,   0,   0,   0,   0,   0,   0
        db 0                                                  ; < ... F10
        db 0                                                  ; 69 - Num lock
        db 0                                                  ; Scroll Lock
        db 0                                                  ; Home key
        db 0                                                  ; Up Arrow
        db 0                                                  ; Page Up
        db '-'
        db 0                                                  ; Left Arrow
        db 0
        db 0                                                  ; Right Arrow
        db '+'
        db 0                                                  ; 79 - End key
        db 0                                                  ; Down Arrow
        db 0                                                  ; Page Down
        db 0                                                  ; Insert Key
        db 0                                                  ; Delete Key
        db 0,   0,   0
        db 0                                                  ; F11 Key
        db 0                                                  ; F12 Key
        times 128 - ($-keyboard_map) db 0                     ; All other keys are undefined
    
    times 510 - ($-$$) db 0                                   ; Boot signature
    dw 0xAA55
    

    Note: This implementation is a demonstration. A real OS would likely have a queue of events that the main loop would check for. The ISRs would push an event into a queue, and the main loop would pop each off and process them. The demonstration is inefficient since it is always checking for scancodes in the buffer whether a keyboard event occurred or not.

    The code is based on a ring buffer implementation that would look like this in pseudo-code:

    buffer[BUFSIZE]; /* BUFSIZE has to be power of 2 and be <= 32768 */
    uint16_t read_pos = 0;
    uint16_t write_pos = 0;
    
    normalize(val)   { return val & (BUFSIZE - 1); }
    saveelement(val) { buffer[normalize(write_pos++)] = val; }
    getelement()     { return buffer[normalize(read_pos++)]; }
    numelements()    { return write_pos - read_pos; }
    isfull()         { return numelements() == BUFSIZE; }
    isempty()        { return write_pos == read_pos; }
    

    Before using saveelement you must call isfullto make sure the buffer isn't full. Before using getelement you must call isempty to make sure there is a value to read.

    0 讨论(0)
提交回复
热议问题