Lowlevel

Lowlevel => Lowlevel-Coding => Thema gestartet von: bitmaster am 11. December 2005, 12:54

Titel: Diskette: int 13h im PM
Beitrag von: bitmaster am 11. December 2005, 12:54
Hi,

also ich habe mein OS jetzt im PM mit Multitasking laufen. Jetzt möchte ich einen Diskettentreiber schreiben. Also z.B. um Sektore zu lesen, zu schreiben. Das habe ich im RM mit dem int 13h gemacht. Wie mache ich das im PM? Welche Ports benötige ich. Kennt ihr ein gutes Tutorial oder so dazu?

Danke!!!
Titel: Diskette: int 13h im PM
Beitrag von: C#ris am 11. December 2005, 17:06
Hi!

Das Ding heißt Intel 82078 Floppy Controller. Ich hab mal angefangen einen Treiber für zu schreiben.


; Driver for Intel 82078 Floppy Controller
; (C)Copyright 2004 by NucleusKL Team & Authors
; Authors: Christian Lins
; Published under GPL - General Public License
; Last change: 17.02.2004

;; Primary
Port0SRB db 3F1h ; R/W Status Register B
Port0DOR db 3F2h ; R/W Digital Output Register
Port0TDR db 3F3h ; R/W Tape Drive Register
Port0MSR db 3F4h ; R Main Status Register
Port0DSR db 3F4h ; W Data Rate Select Register
Port0FIFO db 3F5h ; R/W Data (FIFO)
Port0DIR db 3F7h ; R Digital Input Register
Port0CCR db 3F7h ; W Configuration Control Register

;; Secondary
Port1SRB db 371h ; R/W Status Register B
Port1DOR db 372h ; R/W Digital Output Register
Port1TDR db 373h ; R/W Tape Drive Register
Port1MSR db 374h ; R Main Status Register
Port1DSR db 374h ; W Data Rate Select Register
Port1FIFO db 375h ; R/W Data (FIFO)
Port1DIR db 377h ; R Digital Input Register
Port1CCR db 377h ; W Configuration Control Register

ActiveDrive dw 0000h ; Nummer des aktiven Laufwerks

;; Initialisiert den FC82078
_fc82078_init:
; Paramter ActiveDrive 0, 1, 2, 3
pop ax ;ActiveDrive

call _fc82078_read_msr

; Bit 2 im DOR für Reset setzen
mov dx, Port0DOR
mov al, 00000100b
out dx, al

call _fc82078_read_msr
ret


;; Aktiviert den Motor des aktiven Laufwerks
_fc82078_motor_on:
mov dx, Port0DOR
mov al, 00010000b
out dx, al ; TODO: Drive 0 gewählt, ActiveDrive sollte gewählt werden

call _fc82078_read_msr
push 0
ret


;; Deaktiviert den Motor des aktiven Laufwerks
_fc82078_motor_off:
mov dx, Port0DOR
mov al, 0x0
out dx, al ; TODO: Drive 0 gewählt, ActiveDrive sollte gewählt werden

call _fc82078_read_msr
push 0
ret


;; Wählt die Übertragungsgeschwindigkeit
_fc82078_datarate:
push ax
mov dx, Port0DSR
mov al, 00000010b
out dx, al ; TODO: 250 kbps gewählt, andere Geschwindigkeiten sollten möglich sein
push 0
ret


;; Liest das Status Register und speichert es in al
_fc82078_read_msr:
xor al, al
mov dx, Port0MSR
in al, dx
;mov MSR, al
ret


;; Liest 16 Bytes aus dem FIFO (ohne DMA)
_fc82078_read_fifo:
mov dx, Port0FIFO
__readfifo_loop:
in al, dx ; Liest ein Byte
mov ah, al
in al, dx ; Liest noch ein Byte
push ax ; Speichert das Word auf dem Stack
call _fc82078_read_msr
cmp al, 80h ; Vergleicht ob das Lesen nun zu Ende ist
jne __readfifo_loop

push 0
ret


;; Schreibt 16 Bytes in das FIFO Register (ohne DMA)
_fc82078_write_fifo:
mov dx, Port0FIFO
__writefifo_loop:
pop ax
xchg al, ah
out dx, al
xchg al, ah
out dx, al
call _fc82078_read_msr
cmp al, 80h
jne __writefifo_loop

push 0
ret


;; Schreibt einen Befehl



Zumindest das Anschalten und Ausschalten sollte funktionieren. Vielleicht hilft dir das.

C#ris
Titel: Diskette: int 13h im PM
Beitrag von: [MM] am 11. December 2005, 17:31
Hallo, ich hab mal ein Modul in ASM geschrieben, mit dem man auch lesen und schreiben auf Disketten kann (funktionierte auch). Ist zwar etwas lang, aber ich wollt es dir nicht per Mail schicken, falls eventuell noch jemand Anderes Interesse daran hat...
Also, hier der Code (sind eigentlich 2 Dateien), interessant dürften die Funktionen FDD_WRITE_BLOCK und FDD_READ_BLOCK bzw stdfdc_read_block und stdfdc_write_block sein:

;***************************************************************************
;*** FDD                                                                 ***
;***************************************************************************
; Enth„lt Funktionen f?r den Zugriff auf das Floppylaufwerk.

; Maximale L„nge einer Path-Angabe (inclusive 0):
#define MAX_PATH_LEN 100

; Struktur mit allen Daten ?ber das FDD:
#struct_start FDD_DATA_STRUCT
  installed db 0 ; Merker, ob ein FDD installiert ist.
  user dw 0 ; TSS des aktuellen Nutzers (0 wenn keiner).
  floppy_sectors_per_fat dw 0 ; Anzahl der Sektoren pro FAT.
  floppy_root_entrys dw 0 ; Maximale Anzahl an Eintr„gen im Root.
  floppy_root_startblock dw 0 ; Startblock des Root.
  floppy_fat_startblock dw 0 ; Startblock der 1. FAT.
  buffer_blocks dw #dup(0,8) ; Nummern der Blocks in den einzelnen Buffern (bei -1 unbenutzt).
  next_buffer dw 0 ; Nummer des n„chsten Bufferers zum ?berschreiben.
#struct_end
FDD_DATA_STRUCT fdd_data

;----------------------------------------------------------------------------
; FDD_INIT
;----------------------------------------------------------------------------
; Initialisiert das Floppylaufwerk.
; (cl<- = 0 - Fehler, 1 - OK)
@fdd_init(){
; Pr?fen, ob ?berhaupt ein FDD installiert ist:
        cmp     byte ptr [hw_fdc],0
        jz      .not_installed
        cmp     byte ptr [hw_floppys],0
        jz      .not_installed

        mov     byte ptr [fdd_data_installed],1

; Den FDC zur?cksetzen (auch ohne eingelegte Disk):
        push    bx
        call    fdc_reset
        pop     bx
; Alle Daten ?ber die Floppy zur?cksetzen (auch ohne eingelegte Disk):
        call    fdd_init_floppy_disk_changed

; Alle Buffer l”schen:
        push    cx
        push    edi
        mov     cx,8
        mov     edi,fdd_data_buffer_blocks
.reset_buffer_loop:
        mov     word ptr [edi],-1
        add     edi,2
        loop    .reset_buffer_loop
        pop     edi
        mov     cx,[stdfdc_dma_buffer_base]
        mov     [stdfdc_dma_buffer],cx
        mov     word ptr [fdd_data_next_buffer],0
        pop     cx

        mov     cl,1
        ret

.not_installed:
        mov     byte ptr [fdd_data_installed],0
        @add_error(dword num ERROR_FDD_NOT_INSATLLED)
       
.error:
        mov     cl,0
        ret
}

;----------------------------------------------------------------------------
; FDD_INIT_FLOPPY
;----------------------------------------------------------------------------
; Initialisiert alle Werte nach dem Wechsel einer Diskette.
; (cl<- = 0 - Fehler, 1 - OK)
fdd_init_floppy:
        @fdd_login()
        or      cl,cl
        jz      fdd_init_floppy_in_use
; Testen, ob die Diskette gewechselt wurde:
        call    check_diskchange
        or      cl,cl
        jnz     fdd_init_floppy_disk_changed
; Die Diskette wurde nicht gewechselt, neuladen der Daten daher unn”tig.
        mov     cl,1
        @fdd_logout()
        ret

fdd_init_floppy_disk_changed:
        push    ax
        push    bx
        push    dx
        push    gs
        push    edi
        mov     ax,[_des_global_]
        mov     gs,ax

; Alle Buffer l”schen:
        push    cx
        mov     cx,8
        mov     edi,fdd_data_buffer_blocks
.reset_buffer_loop:
        mov     word ptr [edi],-1
        add     edi,2
        loop    .reset_buffer_loop
        mov     cx,[stdfdc_dma_buffer_base]
        mov     [stdfdc_dma_buffer],cx
        pop     cx

; Den Bootsektor laden (in den ersten Buffer):
        @stdfdc_read_block(word num 0)
        or      cl,cl
        jz      fdd_init_floppy_error

        xor     edi,edi
        mov     di,[stdfdc_dma_buffer]
        ; Rooteintr„ge:
        gs:
        mov     ax,[edi+11]
        mov     [fdd_data_floppy_root_entrys],ax
        ; Sektoren/FAT:
        gs:
        mov     ax,[edi+16]
        mov     [fdd_data_floppy_sectors_per_fat],ax
        ; Root-Startblock (FATs*Size of FAT)+hidden sectors+reserved sectors:
        xor     bx,bx

        gs:
        mov     bl,[edi+10] ; Anzahl der FATs.
        mul     bx
        gs:
        add     ax,[edi+0E]
        gs:
        add     ax,[edi+1C]
        mov     [fdd_data_floppy_root_startblock],ax
        ; FAT-Startblock:
        gs:
        mov     ax,[edi+0E]
        mov     [fdd_data_floppy_fat_startblock],ax

        ; Block Nummer 0 nun im 1. Buffer:
        mov     word ptr [fdd_data_buffer_blocks],0
        add     word ptr [stdfdc_dma_buffer],200
        mov     word ptr [fdd_data_next_buffer],1

        pop     edi
        pop     gs
        pop     dx
        pop     bx
        pop     ax
        mov     cl,1
        @fdd_logout()
        ret

fdd_init_floppy_error:
        pop     edi
        pop     gs
        pop     dx
        pop     bx
        pop     ax
        xor     cl,cl
        @fdd_logout()
        ret

fdd_init_floppy_in_use:

        @add_error(dword num ERROR_FDD_IN_USE)
        xor     cl,cl
        ret

;----------------------------------------------------------------------------
; FDD_LOGIN
;----------------------------------------------------------------------------
; Pr?ft, ob die Floppy gerade von jemand anderen benutzt wird. Wenn nicht,
; dann wird das aktuelle TSS eingetragen.
; (cl<- = 0 - Fehler, 1 - OK)
fdd_login_count: dd 0 ; Z„hler, wie oft der Benutzer sich einloggt.
@fdd_login(){
        push    cx
        str     cx
        ; Schon eingeloggt:
        cmp     [fdd_data_user],cx
        jz      .is_logged_in
        cli     ; Keine Interrupts, damit jetzt kein Taskwechesl kommt.
        ; Nein, ist das FDD frei:
        cmp     word ptr [fdd_data_user],0
        jnz     .error
        mov     [fdd_data_user],cx
        sti
        mov     dword ptr [fdd_login_count],0
        pop     cx
        mov     cl,1
        ret
.is_logged_in:
        inc     dword ptr [fdd_login_count]
        pop     cx
        mov     cl,1
        ret
.error:
        sti
        pop     cx
        xor     cl,cl
        ret
}

;----------------------------------------------------------------------------
; FDD_LOGOUT
;----------------------------------------------------------------------------
; Gibt die Floppy wieder frei, wenn man der rechtm„áige Benutzer war.
@fdd_logout(){
        push    cx
        str     cx
        cmp     [fdd_data_user],cx
        jz      .logout
        pop     cx
        ret
.logout:
        cmp     dword ptr [fdd_login_count],0
        jz      .now_logout
        dec     dword ptr [fdd_login_count]
        pop     cx
        ret

.now_logout:
        mov     word ptr [fdd_data_user],0
        pop     cx
        ret
}

;----------------------------------------------------------------------------
; FDD_READ_BLOCK
;----------------------------------------------------------------------------
; Liest den gew?nschten Block von der Disktette und kopiert ihn nach dest.
; (cl<- = 0 - Fehler, 1 - OK)
@fdd_read_block(word block,word dest_seg,dword dest_off){
~word is_block_in_buffer ; Gibt an, ob der Block tats„chlich geladen wurde.

        @fdd_login()
        or      cl,cl
        jz      .in_use

        call    fdd_init_floppy
        or      cl,cl
        jnz     .next
        @fdd_logout()
        ret
.next:

        mov     byte ptr [.is_block_in_buffer],1
        ; Testen, ob der Block im Buffer steht:
        push    ax
        mov     ax,[.block]
        call    fdd_find_block_buffer
        pop     ax
        or      cl,cl
        jnz     .no_load

        mov     byte ptr [.is_block_in_buffer],0

        ; Den Block lesen:
        @stdfdc_read_block(word word ptr [.block])

        or      cl,cl
        jz      .error
.no_load:
        @fdd_logout() ; Das FDD wird nun nicht mehr ben”tigt.

; Nun den Block nach dest kopieren:
        push    es
        push    ax
        push    edi

        mov     ax,[.dest_seg]
        mov     es,ax
        mov     edi,[.dest_off]

        push    ecx
        push    esi
        push    ds
        xor     esi,esi
        mov     si,[stdfdc_dma_buffer]
        mov     ecx,80 ; (4 Bytes auf einmal)
        mov     ax,[_des_global_]
        mov     ds,ax

        rep ; Achtung benutzt hier ecx!
        movsd ; ds:esi -> es:edi

        pop     ds

        cmp     byte ptr [.is_block_in_buffer],1
        jz      .no_buffer_overrun

        ; Den erfolgreich gelesenen Block in den Buffer eintragen:
        xor     edi,edi
        mov     di,[fdd_data_next_buffer]
        shl     di,1 ; *= 2
        add     edi,fdd_data_buffer_blocks
        mov     ax,[.block]
        mov     [edi],ax
        ; Next Buffer um 1 erh”hen:
        inc     word ptr [fdd_data_next_buffer]
        cmp     word ptr [fdd_data_next_buffer],8
        jnz     .no_buffer_overrun
        mov     word ptr [fdd_data_next_buffer],0

.no_buffer_overrun:

        pop     esi
        pop     ecx
        pop     edi
        pop     ax
        pop     es

        mov     cl,1
        ret

.error:

        @fdd_logout()
        xor     cl,cl
        ret

.in_use:
        @add_error(dword num ERROR_FDD_IN_USE)
        xor     cl,cl
        ret
}

;----------------------------------------------------------------------------
; FDD_WRITE_BLOCK
;----------------------------------------------------------------------------
; Schreibt 512 Bytes von scr in den gew?nschten Block.
; (cl<- = 0 - Fehler, 1 - OK)
@fdd_write_block(word block,word scr_seg,dword scr_off){
        @fdd_login()
        or      cl,cl
        jz      .in_use

        call    fdd_init_floppy
        or      cl,cl
        jnz     .next
        @fdd_logout()
        ret
.next:

; Die 512 Byte von scr in den dma-Buffer kopieren:
        push    ds
        push    es
        push    ax
        push    edi
        push    ecx
        push    esi
        xor     edi,edi

        ; Den richtigen Buffer einstellen:
        mov     di,[fdd_data_next_buffer]
        shl     di,9
        add     di,[stdfdc_dma_buffer_base]
        mov     [stdfdc_dma_buffer],di
       
        mov     di,[stdfdc_dma_buffer]
        mov     ecx,80 ; (4 Bytes auf einmal)
        mov     ax,[_des_global_]
        mov     es,ax

        mov     esi,[.scr_off]
        mov     ax,[.scr_seg]
        mov     ds,ax

        rep ; Achtung benutzt hier ecx!
        movsd ; ds:esi -> es:edi

        ; Den Block schreiben:
        @stdfdc_write_block(word word ptr [.block])
        or      cl,cl
        jz      .error
        @fdd_logout() ; Das FDD wird nun nicht mehr ben”tigt.

        ; Den erfolgreich geschriebenen Block in den Buffer eintragen:
        xor     edi,edi
        mov     di,[fdd_data_next_buffer]
        shl     di,1 ; *= 2
        add     edi,fdd_data_buffer_blocks
        mov     ax,[.block]
        mov     [edi],ax
        ; Next Buffer um 1 erh”hen:
        inc     word ptr [fdd_data_next_buffer]
        cmp     word ptr [fdd_data_next_buffer],8
        jnz     .no_buffer_overrun
        mov     word ptr [fdd_data_next_buffer],0
.no_buffer_overrun:

        pop     esi
        pop     ecx
        pop     edi
        pop     ax
        pop     es
        pop     ds

        mov     cl,1
        ret

.error:
        @fdd_logout()
        pop     esi
        pop     ecx
        pop     edi
        pop     ax
        pop     es
        pop     ds

        xor     cl,cl
        ret

.in_use:
        @add_error(dword num ERROR_FDD_IN_USE)
        xor     cl,cl
        ret
}

;----------------------------------------------------------------------------
; FDD_FIND_BLOCK_BUFFER
;----------------------------------------------------------------------------
; Testet, ob der Block in ax schon im Buffer steht, wenn ja wird in cl 1
; zur?ckgegeben, und stdfdc_dma_buffer wird auf den entsprechenden Buffer
; gelegt, ansonsten wird in cl 0 zur?ckgegeben und stdfdc_dma_buffer wird
; auf den n„chsten Buffer zum šberschreiben gelegt.
; (->ax = Block Nr,
;  cl<- = 0 - nicht im Buffer)
fdd_find_block_buffer:
        push    cx
        push    edi
        mov     cx,8
        mov     edi,fdd_data_buffer_blocks
fdd_find_block_buffer_loop:
        cmp     [edi],ax
        jz      fdd_find_block_buffer_found
        add     edi,2
        loop    fdd_find_block_buffer_loop

        mov     di,[fdd_data_next_buffer]
        shl     di,9
        add     di,[stdfdc_dma_buffer_base]
        mov     [stdfdc_dma_buffer],di

        pop     edi
        pop     cx
        xor     cl,cl
        ret

fdd_find_block_buffer_found:

        sub     edi,fdd_data_buffer_blocks
        shl     di,8 ; *= 256
        add     di,[stdfdc_dma_buffer_base]
        mov     [stdfdc_dma_buffer],di

        pop     edi
        pop     cx
        mov     cl,1
        ret

;***************************************************************************
;*** STDFDC                                                              ***
;***************************************************************************
; Enth„lt Funktionen zum Steuern des FDC.
; ALLE FUNKTIONEN NUR ZUM INTERNEN GEBRAUCH!

; *** Drive Geometry ***
#define DG144_HEADS    2 ; heads per drive (1.44M)
#define DG144_TRACKS  50 ; number of tracks (1.44M) (80d)
#define DG144_SPT     12 ; sectors per track (1.44M) (18d)
#define DG144_GAP3FMT 54 ; gap3 while formatting (1.44M)
#define DG144_GAP3RW  1B ; gap3 while reading/writing (1.44M)

; *** I/O ports ***
#define FDC_DOR    3F2 ; Digital Output Register.
#define FDC_DRS    3F4 ; Data Rate Select Register (output).
#define FDC_MSR    3F4 ; Main Status Register (input).
#define FDC_DATA   3F5 ; Data Register.
#define FDC_DIR    3F7 ; Digital Input Register (input).
#define FDC_CCR    3F7 ; Configuration Control Register (output)

; *** Commands ***
#define CMD_SENSEI  08 ; sense interrupt status.
#define CMD_SPECIFY 03 ; specify drive timings.
#define CMD_SEEK    0F ; seek track.
#define CMD_RECAL   07 ; recalibrate.
#define CMD_VERSION 10 ; FDC version.
#define CMD_WRITE  0C5 ; write data (+ MT,MFM)
#define CMD_READ   0E6 ; read data (+ MT,MFM,SK)
#define CMD_FORMAT 04D ; format track (+ MFM)

; Adresse des DMA-Buffers (nur 16 Bit):
stdfdc_dma_buffer: dw 0
stdfdc_dma_buffer_base: dw 0
; Wenn der Counter 0 erreicht wird der Motor ausgeschaltet und der Counter
; wird auf -1 (FFFF) gesetzt (der Timerinterrupt z„hlt den Counter runter).
motor_kill_counter: dw 0

; *** Aktuelle drive geometry ***
drvgeom_heads:   db      00 ; heads
drvgeom_tracks:  db      00 ; tracks
drvgeom_spt:     db      00 ; sectors per track

; *** DATEN ***
irq_0E_done:   db 00 ; Gibt an, ob der IRQ 0E aufgerufen wurde.
motor_running: db 01 ; Motorstatus.
disk_changed:  db 00 ; Gibt an, ob die Diskette gewechselt wurde.
status:        db 00,00,00,00,00,00,00 ; Command-Result Bytes.
sr0:           db 00 ; Status Register 0.
fdc_track:     db 0FF ; Track, ?ber dem der Lesekopf gerade ist.

;----------------------------------------------------------------------------
; FDC_RESET
;----------------------------------------------------------------------------
; Den FDC zur?cksetzen.
; (bl<- = success)
fdc_reset:
        pusha
; IRQ/DMA aus:
        xor     ax,ax
        mov     dx,FDC_DOR
        out     dx,al

; Motor sofort aus:
        call    motoroff_now

; Datenrate einstellen (500K/s):
        mov     dx,FDC_DRS
        out     dx,al

; Interrupts wieder aktivieren:
        mov     ax,0C
        mov     dx,FDC_DOR
        out     dx,al

; Der Reset erzeugt einen Interrupt. Diesen handeln:
        mov     bl,1
        call    waitfdc
        cmp     bl,0
        jz      reset_error

; Die Drive-Timings einstellen (aus dem BIOS entnommen):
        mov     bl,CMD_SPECIFY
        call    sendbyte
        mov     bl,0DF ; SRT = 3ms, HUT = 240ms
        call    sendbyte
        mov     bl,02 ; HLT = 16ms, ND = 0
        call    sendbyte

; Den "disk change" Status l”schen:
        mov     bl,1
        call    seek
        cmp     bl,0
        jz      reset_error
       
        call    recalibrate
        cmp     bl,0
        jz      reset_error

        mov     byte ptr [disk_changed],0
        popa
        mov     bl,1
        ret
reset_error:
        call    motoroff
        popa
        mov     bl,0
        ret

;----------------------------------------------------------------------------
; WAITFDC
;----------------------------------------------------------------------------
; (->bl = sense interrupt status / bl<- = Status)
; Wartet auf einen Interrupt vom FDC.
waitfdc:
        pusha
        mov     di,bx
        and     di,0FF

; Warten bis der Interrupt vom FDC kommt:

        sti
        push    eax
        push    ebx
        mov     ebx,[timer_tick]
waitfdc_loop:
        cmp     byte ptr [irq_0E_done],0
        jnz     waitfdc_weiter

        ; Auf Timeout pr?fen (max 500ms):
        @calc_ticks(dword ebx)
        cmp     eax,50xD
        jb      waitfdc_loop
        ; Timeout:
        pop     ebx
        pop     eax
        cli
        popa
        mov     bl,0
        ret

waitfdc_weiter:
        pop     ebx
        pop     eax
        cli

; Command-Result Bytes einlesen (7 Bytes):
        xor     bx,bx
waitfdc_loop2:
        mov     dx,FDC_MSR
        in      al,dx
        and     al,10
        cmp     al,0
        jz      waitfdc_weiter2
        cmp     bx,7
        jae     waitfdc_weiter2

        push    bx
        call    getbyte
        mov     al,bl
        pop     bx
        mov     byte ptr [bx+status],al

        inc bx
        jmp     waitfdc_loop2
waitfdc_weiter2:

        cmp     di,0
        jz      waitfdc_no_sensei

; Das Sense-Interrupt-Status Kommando senden:
        mov     bl,CMD_SENSEI
        call    sendbyte
        call    getbyte
        mov     byte ptr [sr0],bl
        call    getbyte
        mov     byte ptr [fdc_track],bl
waitfdc_no_sensei:

        mov     byte ptr [irq_0E_done],0

; Testen ob es einen Diskchange gab:
        mov     dx,FDC_DIR
        in      al,dx
        and     al,80
        cmp     al,0
        jz      waitfdc_weiter3
        mov     byte ptr [disk_changed],1

        popa
        mov     bl,0
        ret
waitfdc_weiter3:

        popa
        mov     bl,1
        ret

;----------------------------------------------------------------------------
; SENDBYTE
;----------------------------------------------------------------------------
; (->bl = Byte to send)
; Sendet das Byte in bl an den FDC.
sendbyte:
        push    cx
        push    dx
        push    ax
        mov     cx,80
        mov     dx,FDC_MSR
sendbyte_loop:
        in      al,dx
        and     al,0C0
        cmp     al,80
        jnz     sendbyte_weiter
        mov     dx,FDC_DATA
        mov     al,bl
        out     dx,al
        pop     ax
        pop     dx
        pop     cx
        ret
sendbyte_weiter:
        in      al,80 ; delay
        loop    sendbyte_loop
        pop     ax
        pop     dx
        pop     cx
        ret

;----------------------------------------------------------------------------
; GETBYTE
;----------------------------------------------------------------------------
; (bl<- = received Byte ( FF = Timeout ))
; Empf„ngt in bl ein Byte vom FDC.
getbyte:
        push    cx
        push    dx
        push    ax
        mov     cx,80
        mov     dx,FDC_MSR
getbyte_loop:
        in      al,dx
        and     al,0D0
        cmp     al,0D0
        jnz     getbyte_weiter
        mov     dx,FDC_DATA
        in      al,dx
        mov     bl,al
        pop     ax
        pop     dx
        pop     cx
        ret
getbyte_weiter:
        in      al,80 ; delay
        loop    getbyte_loop
        pop     ax
        pop     dx
        pop     cx
        mov     bl,0FF ; Timeout
        ret

;----------------------------------------------------------------------------
; RECALIBRATE
;----------------------------------------------------------------------------
; Den FDC rekalibrieren
; (bl<- = success)
recalibrate:
; Motor an:
        call    motoron
   
; Das Kommando zum Rekalibrieren sende:
        mov     bl,CMD_RECAL
        call    sendbyte
        mov     bl,0
        call    sendbyte

; Warten bis das Kommando ausgef?hrt wurde:
        mov     bl,1
        call    waitfdc ; Die R?ckgabe von waitfdc bleibt erhalten.
   
; Motor aus:
        call    motoroff
        ret

;----------------------------------------------------------------------------
; MOTORON
;----------------------------------------------------------------------------
; Den Motor anschalten:
motoron:
; L„uft der Motor schon:
        cmp     byte ptr [motor_running],0
        jz      motoron_weiter
        ret
motoron_weiter:
        push    ax
        push    dx
        push    bx

; Den Motor starten:
        mov     dx,FDC_DOR
        mov     al,1C
        out     dx,al

; Den Kill-Counter nicht weiter runterz„hlen:
        mov     word ptr [motor_kill_counter],0FFFF

; Warten damit der Motor anlaufen kann:
        @wait(dword num 50xD) ; 1/2 Sekunde.

        mov     byte ptr [motor_running],1
        pop     bx
        pop     dx
        pop     ax
        ret

;----------------------------------------------------------------------------
; MOTOROFF
;----------------------------------------------------------------------------
; Den Motor stoppen:
motoroff:
; Steht der Motor schon:
        cmp    byte ptr [motor_running],0
        jz     motoroff_ende

; ca. 3 Sekunden warten und dann den Motor aus:
        mov     word ptr [motor_kill_counter],300xD

motoroff_ende:
         ret

;----------------------------------------------------------------------------
; MOTOROFF_NOW
;----------------------------------------------------------------------------
; Den Motor SOFORT stoppen:
motoroff_now:
        push    ax
        push    dx
        mov     ax,0C
        mov     dx,FDC_DOR
        out     dx,al
        mov     byte ptr [motor_running],0
        pop     dx
        pop     ax
        ret

;----------------------------------------------------------------------------
; SEEK
;----------------------------------------------------------------------------
; (->bl = track / bl<- = success)
; Den Lesekopf zum Track bl bewegen.
seek:
        cmp     byte ptr [fdc_track],bl
        jnz     seek_weiter
        mov     bl,1 ; Der Kopf ist schon da.
        ret
seek_weiter:
        push    di
        mov     di,bx

; Den Motor starten:
        call    motoron

; Das Seek Kommando senden:
        mov     bl,CMD_SEEK
        call    sendbyte
        mov     bl,0
        call    sendbyte
        mov     bx,di
        call    sendbyte

; Warten bis das Seek Kommando ausgef?hrt ist:
        mov     bl,1
        call    waitfdc
        cmp     bl,0
        jnz     seek_weiter2
        pop     di
        mov     bl,0 ; Timeout!
        ret
seek_weiter2:

; Den Kopf etwas Zeit geben:

        @wait(dword num 50xD) ; 1/2 Sekunde warten.
; Motor aus:
        call    motoroff
   
; Testen ob der Kopf auch angekommen ist:
        cmp     byte ptr [sr0],20
        jnz     seek_error
        mov     bx,di
        cmp     byte ptr [fdc_track],bl
        jnz     seek_error
        pop     di
        mov     bl,1
        ret
seek_error:
        pop     di
        mov     bl,0
        ret

;----------------------------------------------------------------------------
; BLOCK2HTS
;----------------------------------------------------------------------------
; (->bx = Block
;  bx<- = Head
;  cx<- = Track
;  dx<- = Sektor)
; Konvertiert die Eingabe von Blocks in head, track und sector.
block2hts:
; head = (block % (geometry.spt * geometry.heads)) / (geometry.spt);
; track = block / (geometry.spt * geometry.heads);
; sector = block % geometry.spt + 1;
        push    ax
        push    bp
        pushw   0 ; head (bp+4)
        pushw   0 ; track (bp+2)
        pushw   0 ; sector (bp)
        mov     bp,sp

        mov     ah,0
        mov     al,[drvgeom_heads]
        mov     ch,0
        mov     cl,[drvgeom_spt]
        mul     cx
        mov     cx,ax
; *** ax = (geometry.spt * geometry.heads) ***
        mov     ax,bx
        xor     dx,dx
        div     cx
; *** ax = blocks / spt*heads dx = blocks % spt*heads ***
        mov     [bp+2],ax
        mov     ax,dx
        mov     ch,0
        mov     cl,[drvgeom_spt]
        xor     dx,dx
        div     cx
        mov     [bp+4],ax
; *** Errechnen des Sektors ***
        mov     ax,bx
        div     cl
        add     dx,1
        mov     [bp],dx

        pop     dx
        pop     cx
        pop     bx
        pop     bp
        pop     ax      
        ret

;----------------------------------------------------------------------------
; FDC_RW
;----------------------------------------------------------------------------
; (->bx = block nr
;  ->cl = 1-read 0-write
;  bl<- = 1 success)
; Liest oder Schreibt den Block Nr bx.
fdc_rw:
        pusha
        pushw   0 ; read/write (bp+6)
        pushw   0 ; head (bp+4)
        pushw   0 ; track (bp+2)
        pushw   0 ; sector (bp)
        mov     bp,sp
        mov     [bp+6],cl
; Die logische Adresse in eine physikalische Adresse umwandeln:
        call    block2hts
        mov     [bp],dx
        mov     [bp+2],cx
        mov     [bp+4],bx
; Motor an:
        call    motoron

        mov     di,3 ; Max 3 Male probieren.
fdc_rw_loop:
; Testen, ob die Diskette gewechselt wurde:
        mov     dx,FDC_DIR
        in      al,dx
        and     al,80
        cmp     al,0
        jz      fdc_rw_no_diskchange
; Fehlgeschlagen, da die Diskette gewechselt wurde:
        mov     byte ptr [disk_changed],1
        mov     bl,1
        call    seek ; Disk Changed Staus ausschalten.
        call    recalibrate
        call    motoroff
        add     bp,8
        mov     sp,bp
        popa
        mov     bl,0
        @add_error(dword num ERROR_FD_CHANED_WHILE_RW)
        ret
fdc_rw_no_diskchange:

; Den Kopf zum richtigen Track bewegen:
        mov     bl,[bp+2]
        call    seek
        cmp     bl,1
        jz      fdc_rw_seek_success
; Seek fehlgeschlagen:
        call    motoroff
        add     bp,8
        mov     sp,bp
        popa
        mov     bl,0
        @add_error(dword num ERROR_FD_SEEK_FAILED)
        ret
fdc_rw_seek_success:

; Datenrate (500K/s) einstellen:
        mov     dx,FDC_CCR
        mov     bl,0
        out     dx,al

; Feststellen, was gemacht werden soll:
        cmp     byte ptr [bp+6],1
        jnz     fdc_rw_send_command_write

; Lesen:
        mov     bl,0 ; read
        mov     cx,200 ; 512 Bytes
        call    dma_xfer

        mov     bl,CMD_READ
        call    sendbyte        
        jmp     fdc_rw_send_command_next        
fdc_rw_send_command_write:

; Schreiben:
        mov     bl,1 ; write
        mov     cx,200 ; 512 Bytes
        call    dma_xfer

        mov     bl,CMD_WRITE
        call    sendbyte
fdc_rw_send_command_next:

; Alle Informationen ?ber die Position des Blocks ?bertragen:
        mov     bl,[bp+4] ; head
        shl     bl,2
        call    sendbyte
        mov     bl,[bp+2] ; track
        call    sendbyte
        mov     bl,[bp+4] ; head
        call    sendbyte
        mov     bl,[bp] ; sector
        call    sendbyte
        mov     bl,2 ; 512 Bytes/Sector
        call    sendbyte
        mov     bl,[drvgeom_spt]
        call    sendbyte
        mov     bl,DG144_GAP3RW ; gap 3 size for 1.44M read/write
        call    sendbyte
        mov     bl,0FF ; DTL = unused
        call    sendbyte

; Warten bis das Kommando ausgef?hrt wurde:
; (read/write braucht keinen sense interrupt status)
        mov     bl,0
        call    waitfdc
        cmp     bl,0
        jnz     fdc_rw_no_timeout

        add     bp,8
        mov     sp,bp
        popa
        mov     bl,0 ; Timeout !
        @add_error(dword num ERROR_FD_TIMEOUT_WHILE_RW)
        ret
fdc_rw_no_timeout:

        mov     al,[status]
        and     al,0C0
        cmp     al,0
        jz      fdc_rw_worked

; Es hatt nicht funktioniert, nochmal:
        call    recalibrate
        dec     di
        cmp     di,0
        jnz     fdc_rw_loop
; *** ERROR ***
        call    motoroff

        add     bp,8
        mov     sp,bp
        popa
        mov     bl,0
        @add_error(dword num ERROR_FD_RW_FAILED)
        ret
fdc_rw_worked:

; *** SUCCESS ***
        call    motoroff

        add     bp,8
        mov     sp,bp
        popa
        mov     bl,1
        ret

;----------------------------------------------------------------------------
; LOG_DISK
;----------------------------------------------------------------------------
; (bl<- = 1 = 1.44 Disk / 0 not supported)
; Feststellen um was f?r einen Diskettentyp es sich handelt.
log_disk:
        push    cx
        call    fdc_reset
        cmp     bl,0
        jz      log_disk_no_144

; Davon ausgehen, das es eine 1.44mb Diskette ist und Block 17 auf dem 1.
; Track lesen:
        mov     byte ptr [drvgeom_heads],DG144_HEADS
        mov     byte ptr [drvgeom_tracks],DG144_TRACKS
        mov     byte ptr [drvgeom_spt],DG144_SPT

        mov     bx,11 ; Block 17.
        mov     cl,1 ; Lesen.
        call    fdc_rw
        cmp     bl,0
        jz      log_disk_no_144
        pop     cx

        mov     bl,1
        ret
log_disk_no_144:
        pop     cx

        mov     bl,0
        @add_error(dword num ERROR_FD_TYP_NOT_SUPPORTED)
        ret

;----------------------------------------------------------------------------
; DMA_XFER
;----------------------------------------------------------------------------
; (->bl = 1-read / 0-write
;  ->cx = length)
; Aktiviert den DMA.
dma_xfer:
        pusha

        mov     al,14 ; DMA1 deaktivieren
        out     08,al

        cmp     bl,0
        jnz     dma_xfer_read
; *** Modus: Einzeltransfer, Adressinkrementierung, Schreiben, Kanal 2 ***
        mov     al,56
        out     0B,al
        jmp     dma_xfer_weiter
dma_xfer_read:
; *** Modus: Einzeltransfer, Adressinkrementierung, Lesen, Kanal 2 ***
        mov     al,5A
        out     0B,al
dma_xfer_weiter:

        mov     ax,[stdfdc_dma_buffer]
        mov     bx,[stdfdc_dma_buffer]
        shr     bx,4
        shr     bh,04
        out     0C,al ; Flip-Flop zur?ckstellen

        out     04,al ; Niederwertige Adresse ausgeben
        mov     al,ah
        out     04,al ; H”herwertige Adresse ausgeben
        mov     al,bh
        out     81,al ; Segment ausgeben

        out     0C,al ; Flip-Flop zur?cksetellen

; *** Length -1 ***
        dec     cx
        mov     al,cl ; Low-Byte
        out     05,al
        mov     al,ch ; High-Byte
        out     05,al

        mov     al,02 ; Kanal 2 freigeben
        out     0A,al
        mov     al,10 ; DMA 1 aktivieren
        out     08,al

        popa
        ret

;***************************************************************************
;*** FUNKTIONEN                                                          ***
;***************************************************************************

;----------------------------------------------------------------------------
; STDFDC_IRQ_HANDLER
;----------------------------------------------------------------------------
; Wird vom FDC-IRQ ausgel”st.
stdfdc_irq_handler:
        cli
        push    ax
        push    ds

        cs:
        mov     ax,[_des_kernel_data_]
        mov     ds,ax
        mov     byte ptr [irq_0E_done],1

        push es
        mov ax,[_des_vram_]
        mov es,ax
        es:
        mov byte ptr [(160xD*4)],'H'
        es:
        inc byte ptr [(160xD*4+2)]
        pop es

        ; Dem Controller mitteilen, dass der IRQ bearbeitet wurde:
        mov     al,20
        out     20,al
        pop     ds
        pop     ax
        sti
        iret

;----------------------------------------------------------------------------
; STDFDC_READ_BLOCK
;----------------------------------------------------------------------------
; Liest einen Block (512 Byte) in den aktuellen DMA Buffer ein..
; Gibt in cl 1 zur?ck wenn es funktioniert hat, sonst 0.
@stdfdc_read_block(word block){
        push    ax
        push    bx
        push    dx
        cli     ; Bei FDC Funktionen besser keine Interrupts.

; Testen, ob die Diskette gewechselt wurde:
        call    check_diskchange
        or      cl,cl
        jnz     .log_disk ; Diskette wurde gewechselt.

; Ggf die Diskette testen:
        cmp     byte ptr [drvgeom_tracks],0
        jnz     .no_log_disk
.log_disk:
        call    log_disk
        cmp     bl,0
        jz      .error
.no_log_disk:

; Den Block lesen:
        mov     bx,[.block] ; Block nr.
        mov     cl,1 ; read
        call    fdc_rw
        cmp     bl,0
        jz      .error

        sti
        pop     dx
        pop     bx
        pop     ax
        mov     cl,1
        ret

.error:
        sti
        pop     dx
        pop     bx
        pop     ax
        mov     cl,0
        ret
}

;----------------------------------------------------------------------------
; STDFDC_WRITE_BLOCK
;----------------------------------------------------------------------------
; Schreibt 512 Bytes aus dem aktuellen DMA Buffer auf den angegebenen Block.
; Gibt in cl 1 zur?ck wenn es funktioniert hat, sonst 0.
@stdfdc_write_block(word block){
        push    ax
        push    bx
        push    dx
        cli     ; Bei FDC Funktionen besser keine Interrupts.

; Testen, ob die Diskette gewechselt wurde:
        call    check_diskchange
        or      cl,cl
        jnz     .log_disk ; Diskette wurde gewechselt.

; Ggf die Diskette testen:
        cmp     byte ptr [drvgeom_tracks],0
        jnz     .no_log_disk
.log_disk:
        call    log_disk
        cmp     bl,0
        jz      .error
.no_log_disk:

; Den Block schreiben:
        mov     bx,[.block] ; Block nr.
        mov     cl,0 ; write
        call    fdc_rw
        cmp     bl,0
        jz      .error

        sti
        pop     dx
        pop     bx
        pop     ax
        mov     cl,1
        ret

.error:
        sti
        pop     dx
        pop     bx
        pop     ax
        mov     cl,0
        ret
}

;----------------------------------------------------------------------------
; CHECK_DISKCHANGE
;----------------------------------------------------------------------------
; ->cl = Gibt eine 1 zur?ck, wenn die Diskette gewechselt wurde.
check_diskchange:
        push    dx
        push    ax

; Kommando senden, damit das DIR die Informationen ?ber den Diskchange hat:
        call    motoron
        call    motoroff

        mov     dx,FDC_DIR
        in      al,dx
        and     al,80
        mov     cl,al

        pop     ax
        pop     dx
        ret


Nicht wundern über die seltsame Syntax, hab ich für meinen eigenen Assembler, den MMASM geschrieben (man arbeitet doch am liebsten mit den eigenen Werkzeugen, nich  :wink: ).
Bei Bedarf hab ich sowas ähnliches auch noch in C.

MM
Titel: Diskette: int 13h im PM
Beitrag von: SSJ7Gohan am 11. December 2005, 17:49
Wenn der C Code auch in der Lage ist, zu lesen und zu schreiben wär er ganz interessant :D
Titel: Diskette: int 13h im PM
Beitrag von: Mihail121 am 11. December 2005, 18:59
Grüß dich, lies dir das hier mal an:

http://www.xaff.org/GI/floppy.html
Titel: Diskette: int 13h im PM
Beitrag von: [MM] am 11. December 2005, 19:02
Meine Version des C Codes finde ich irgendwie grad nicht, aber dafür hab ich hier nen Link zu nem netten Democode, mit dem man sogar Disketten formatieren kann (aus dem FreeDOS32):
http://www.koders.com/c/fidCACDE05FE2F07441CF52B2104E08993FF8E8D8B5.aspx

Mir ist das zwar etwas zu unübersichtlich, aber eventuell hilft es weiter.
Ich hatte meinen Code übrigends nach der folgenden FDC Referenz geschrieben:
http://www.isdaman.com/alsos/hardware/fdc/floppy.htm

Eventuell finde ich meinen C Code ja nochmal wieder...
MM
Titel: Diskette: int 13h im PM
Beitrag von: bitmaster am 17. December 2005, 17:10
Vielen dank für eure Informationen. Also der IRQ6 und die Ports 3F0h-3F7h und 370h-377h benötige ich um mit der Diskette zu komonizieren. Aber ich habe das leider nicht so ganz verstanden. Was muss der Code des IRQ6 denn machen? Und wie lese/schreibe ich Sektoren. Beispiel:
Ich möchte den Sektor 3 der Diskette im ersten Diskettenlaufwerk in den Arbeitsspeicher an Adresse 20000h schreiben. Wie würde der Code dafür aussehen? Gibt es dazu eigentlich auch deutsche Seiten? So wie ich das sehe, werden also max. 4 Diskettenlaufwerke unterstützt. Wann benötige ich den ersten Kontroller (3F0-3F7) und wann den zweiten (370-377)?

Danke!!!

PS:
Zitat von: Mihail121
Grüß dich, lies dir das hier mal an:

http://www.xaff.org/GI/floppy.html
Der Link funktioniert nicht.
Titel: Diskette: int 13h im PM
Beitrag von: Osbios am 17. December 2005, 19:47
Zitat von: bitmaster
Wann benötige ich den ersten Kontroller (3F0-3F7) und wann den zweiten (370-377)?

Naja, den ersten Kontroller benutzt du fürs erste Floppy und den zweiten Kontroller fürs zweite Floppy.  :|
Titel: Diskette: int 13h im PM
Beitrag von: bitmaster am 17. December 2005, 20:07
Zitat von: Osbios
Zitat von: bitmaster
Wann benötige ich den ersten Kontroller (3F0-3F7) und wann den zweiten (370-377)?

Naja, den ersten Kontroller benutzt du fürs erste Floppy und den zweiten Kontroller fürs zweite Floppy.  :|
Und fürs dritte und Vierte Floppy?
Titel: Diskette: int 13h im PM
Beitrag von: Osbios am 17. December 2005, 20:47
Nein, vergiss was ich gesagt habe. :/
Die max. 4 Floppys steuert man ja alle über die selben Register an.

Zitat
The base port address used for the controller is dependant on whether the controller is configured as the primary or secondary controller


Mehr kann ich dir dazu leider nicht sagen als das was in den Docs steht.

[edit]Das ist so wie: Die größe des Speichers hängt von der eingebauten Menge des Speicher ab.[/edit]
Titel: Diskette: int 13h im PM
Beitrag von: joachim_neu am 18. December 2005, 12:03
Ich hab meins jetzt auch zum Laufen gebracht. Fehler war, dass ich nicht lange genug gewartet hab, bis das Teil fertig hatte. ;)
An dieser Stelle möchte ich nocheinmal ein herzliches Dankeschön an die Entwickler von Intel für diesen grandiosen Anti-Logik-Test richten. Sie haben ihr Ziel erreicht und es geschaft, einen Baustein zu entwickeln, der eine Unlogik enthält, wie sie noch nie gesehen wurde.
Titel: Diskette: int 13h im PM
Beitrag von: Osbios am 18. December 2005, 13:50
@[MM]: Ich habe mir mal deinen Code angeschaut. Schon in denn ersten Zeilen gibt es eine Variable/Pointerkonstante (hw_fdc) die nirgends deklariert wurde!?

Fehlt da eventuell noch was?
Titel: Diskette: int 13h im PM
Beitrag von: [MM] am 18. December 2005, 21:27
hw_fdd und hw_floppys sind Variablen aus der Hardwareerkennung, in hw_fdd steht glaub ich die Versionsnummer des FDD-Controllers und in hw_floppys die Anzahl der Floppys.
Wie das initialisiert wurde dürfte für dieses Thema unerheblich sein.

MM
Titel: Diskette: int 13h im PM
Beitrag von: Osbios am 18. December 2005, 22:30
Ich denke die Hardwareerkennung der Floppy ist hier schon relevant.
Ok, meistens ist nur eine einziges 3 1/2 Floppy am PC angeschlossen aber ein OS sollte doch auch mit allen anderen Fällen zurechtkommen.
Und wenn ein OS sich beim Booten aufhängt nur weil dem Floppytreiber kein formgerechtes Standardgerät vor die Nase gesetzt wurde...   :?

Währe also nett wenn Du eventuell auch deinen Hrdwareerkennungscode für die Floppy postest.  :D
Titel: Diskette: int 13h im PM
Beitrag von: [MM] am 18. December 2005, 23:43
Gna, immer diese Extrawünsche...
Aber gut, hier der Code mit dem bei diesem Projekt der Floppy-Controller gesucht wurde:
detect_basic_hw_string: db "detecting basic hardware: ",0A,0D,0
create_temp_pmode_env: db "creating temporary pmode environment... ",0
start_pmode: db "starting protected mode... ",0

hw_start:
hw_cpu_id_string: dd 0,0,0 ; Prozessor ID-String (o0 l13).
db 0
hw_cpu_version: dd 0 ; Informationen ?ber die Version (o13 l4).
hw_cpu_features: dd 0 ; Informationen ?ber die Features (o17 l4).
hw_cpu_speed: dd 0 ; ungef„hre MHz Zahl (o21 l4).
hw_memory: dd 0 ; KB an Speicher (o25 l4).
hw_fdc: db 0 ; 0=none / 1=extended fdc (o29 l1).
hw_floppys: db 0 ; Anzahl der Floppylaufwerke (o30 l1).
; Path des Bootscripts (o31 l72).
bootscript_path: db ".......................................................................",0

#define HW_SIZE 103xD

; *** PREPARE_KERNEL ***
prepare_kernel:
; Hardware suchen:
        mov     si,detect_basic_hw_string
        call    print_string

        call    detect_processor
        call    detect_memory
        call    detect_fdc
        call    detect_floppys

; Den Temp-Pmode vorbereiten:
        mov     si,create_temp_pmode_env
        call    print_string
        jmp     temp_pm

; *** DETECT_FDC ***
#define FDC_DATA   3F5 ; Data Register.
#define FDC_MSR    3F4 ; Main Status Register (input).
#define CMD_VERSION 10 ; FDC version.
detect_fdc_string: db " floppy disk controller: ",0
detect_fdc_ec_found: db "extended controller",0A,0D,0
detect_fdc_no_ec_found: db "none",0A,0D,0
detect_fdc:
        mov     bl,COLOR_WHITE
        mov     si,detect_fdc_string
        call    print_string_color

; Testet, welche FDC-Version installiert ist:
        mov     bl,CMD_VERSION
        call    sendbyte_fdc
        call    getbyte_fdc
        cmp     bl,90
        jnz     detect_fdc_no_ec

        mov     si,detect_fdc_ec_found
        call    print_string
        mov     byte ptr [hw_fdc],1
        ret
detect_fdc_no_ec:
        mov     si,detect_fdc_no_ec_found
        call    print_string
        mov     byte ptr [hw_fdc],0
        ret

; *** SENDBYTE_FDC ***
; (->bl = Byte to send)
; Sendet das Byte in bl an den FDC.
sendbyte_fdc:
        push    cx
        push    dx
        push    ax
        mov     cx,80
        mov     dx,FDC_MSR
sendbyte_fdc_loop:
        in      al,dx
        and     al,0C0
        cmp     al,80
        jnz     sendbyte_fdc_weiter
        mov     dx,FDC_DATA
        mov     al,bl
        out     dx,al
        pop     ax
        pop     dx
        pop     cx
        ret
sendbyte_fdc_weiter:
        in      al,80 ; delay
        loop    sendbyte_fdc_loop
        pop     ax
        pop     dx
        pop     cx
        ret

; *** GETBYTE_FDC ***
; (bl<- = received Byte ( FF = Timeout ))
; Empf„ngt in bl ein Byte vom FDC.
getbyte_fdc:
        push    cx
        push    dx
        push    ax
        mov     cx,80
        mov     dx,FDC_MSR
getbyte_fdc_loop:
        in      al,dx
        and     al,0D0
        cmp     al,0D0
        jnz     getbyte_fdc_weiter
        mov     dx,FDC_DATA
        in      al,dx
        mov     bl,al
        pop     ax
        pop     dx
        pop     cx
        ret
getbyte_fdc_weiter:
        in      al,80 ; delay
        loop    getbyte_fdc_loop
        pop     ax
        pop     dx
        pop     cx
        mov     bl,0FF ; Timeout
        ret

; *** DETECT_PROCESSOR ***
detect_processor_string: db " processor: ",0
detect_processor_speed_string1: db " ~",0
detect_processor_speed_string2: db "MHz",0A,0D,0
detect_processor:
        mov     si,detect_processor_string
        mov     bl,COLOR_WHITE
        call    print_string_color
       
; Den ID-String holen (12 Bytes in ebx,edx,ecx):
        xor     eax,eax
        cpuid
        mov     [hw_cpu_id_string],bl
        shr     ebx,8
        mov     [(hw_cpu_id_string+1)],bl
        shr     ebx,8
        mov     [(hw_cpu_id_string+2)],bl
        shr     ebx,8
        mov     [(hw_cpu_id_string+3)],bl
        shr     ebx,8
        mov     [(hw_cpu_id_string+4)],dl
        shr     edx,8
        mov     [(hw_cpu_id_string+5)],dl
        shr     edx,8
        mov     [(hw_cpu_id_string+6)],dl
        shr     edx,8
        mov     [(hw_cpu_id_string+7)],dl
        shr     edx,8
        mov     [(hw_cpu_id_string+8)],cl
        shr     ecx,8
        mov     [(hw_cpu_id_string+9)],cl
        shr     ecx,8
        mov     [(hw_cpu_id_string+0A)],cl
        shr     ecx,8
        mov     [(hw_cpu_id_string+0B)],cl

        mov     si,hw_cpu_id_string
        call    print_string

; Erweiterte Informationen holen:
        xor     eax,eax
        inc     ax
        cpuid
        mov     [hw_cpu_version],eax
        mov     [hw_cpu_features],edx

; CPU Geschwindigkeit ermitteln:

        call    detect_cpu_speed
        mov     si,detect_processor_speed_string1
        call    print_string
        mov     eax,[hw_cpu_speed]
        mov     ebx,10xD
        call    print_number
        mov     si,detect_processor_speed_string2
        call    print_string
        ret

detect_cpu_speed_lo: dd 0
detect_cpu_speed_hi: dd 0
detect_cpu_speed_delay: dd 0
detect_cpu_speed:
; Aktuelle Cycle Zahl holen:
        db 0F,31 ; RDTSC
        mov     [detect_cpu_speed_lo],eax
        mov     [detect_cpu_speed_hi],edx

; Delay von ca. 500ms:
        xor     ax,ax
        int     1A
        shl     ecx,16xD
        mov     cx,dx
        mov     [detect_cpu_speed_delay],ecx
        add     dword ptr [detect_cpu_speed_delay],9

        detect_cpu_speed_delay_loop:
        int     1A
        shl     ecx,16xD
        mov     cx,dx

        cmp     [detect_cpu_speed_delay],ecx
        jg      detect_cpu_speed_delay_loop

; Jetzt aktuelle Cycle Zahl holen und die alte davon abziehen:
        db 0F,31 ; RDTSC
        sub     eax,[detect_cpu_speed_lo]
        sbb     edx,[detect_cpu_speed_hi]

; Einen kleinen Korrekturwert hinzuf?gen:
        add     eax,600000
        adc     edx,0
       
; Nun ausrechnen wie viele Cycle der Rechner in 1000 Sekunden macht (MHz):
        mov     ecx,7A120
        div     ecx
        mov     [hw_cpu_speed],eax
        ret

; *** DETECT_MEMORY ***
detect_memory_string1: db " memory: ",0
detect_memory_string2: db "kb",0A,0D,0
detect_memory:
        mov     si,detect_memory_string1
        mov     bl,COLOR_WHITE
        call    print_string_color

; Dieser Interrupt gibt die Menge an Erweiterungsspeicher in kb zur?ck:
        mov     eax,0E801
        int     15

; Es kann sein, dass „ltere BIOS-Versionen diese Funktion noch nicht haben:
        jc      detect_memory_noE801

        and     eax,0FFFF ; 16-Bit mem unter 16mb in 1kb Bl”cken.
        and     ebx,0FFFF ; 16-bit mem ?ber 16mb in 64kb Bl”cken.
        shl     ebx, 6 ; Auf 1kb Bl”cke bringen.
        add     eax,ebx
        mov     [hw_memory],eax
        jmp     detect_memory_ende

detect_memory_noE801:
; Die SpeichergrӇe aus dem CMOS lesen:
        mov     al,17
        out     70,al
        in      al,71
        mov     [hw_memory],al
        mov     al,18
        out     70,al
        in      al,71
        mov     [(hw_memory+1)],al

detect_memory_ende:
; Den gesammten Speicher nicht nur den Erweiterten (also +1mb):
        add     dword ptr [hw_memory],1024xD
        mov     eax,[hw_memory]
        mov     ebx,10xD
        call    print_number
        mov     si,detect_memory_string2
        call    print_string
        ret

; *** DETECT_FLOPPYS ***
detect_floppys_string: db " floppy disks: ",0
detect_floppys:

        mov     si,detect_floppys_string
        mov     bl,COLOR_WHITE
        call    print_string_color

; Floppy 1 testen:
        push    es
        mov     ax,800
        xor     dx,dx
        int     13
        pop     es
        jc      detect_floppys_done ; Error.
        cmp     cx,0
        je      detect_floppys_done ; Nicht installiert.

        inc     byte ptr [hw_floppys]

; Floppy 2 testen:
        push    es
        mov     ax,800
        mov     dx,1
        int     13
        pop     es
        jc      detect_floppys_done ; Error.
        cmp     cx,0
        je      detect_floppys_done ; Nicht installiert.

        inc     byte ptr [hw_floppys]
detect_floppys_done:
        xor     eax,eax
        mov     al,[hw_floppys]
        mov     ebx,10xD
        call    print_number
        mov     si,new_line
        call    print_string
        ret


detect_fdc wird prüfen, ob eine Floppy da ist und detect_floppys prüft, ob 1 oder 2 Laufwerke installiert sind (glaub ich). Die anderen Funktionen sind für so Zeug wie Prozessorerkennung usw...

MM
Titel: Diskette: int 13h im PM
Beitrag von: bitmaster am 19. December 2005, 12:14
Wäre gut wenn jemand ein Tutorial dazu schreiben würde. ;)
Titel: Diskette: int 13h im PM
Beitrag von: bitmaster am 21. December 2005, 23:42
Ich habe oft gelesen, dass man DMA nicht benutzen sollte. Ich verstehe aber nicht warum. Hat das einen Nachteil? Geht das überhaupt ohne? Und dann hätte ich noch eine Frage. Was muss im IRQ6 passieren? Also was muss der IRQ6 machen wenn er aufgerufen wird?

Danke!!!
Titel: Diskette: int 13h im PM
Beitrag von: bitmaster am 22. December 2005, 11:47
Zitat von: T0ast3r
Nun den, IRQ & DMA haben einen Nachteil:
Du kannst nur die ersten 16 MB (physikalisch) addressieren, zudem ist es viel zu aufwendig.
Vor allem ist die implementierung ziemlich schwierig...
DMA kann zu dem nicht 32 Bit arbeiten, nur die Register 0-5 oder so...
verstehe ich nicht  :(
Titel: Diskette: int 13h im PM
Beitrag von: Osbios am 22. December 2005, 12:45
Auch wenn man mit dem DMA für floppy nur im unteren Speicherbereich arbeiten kann würde ich diese Methode vorziehen, denn PIO mit dem FDC ist ein CPU fresser und nichts im Vergleich zu dem was benötigt wird um ein par KB von A nach B zu kopieren.
Titel: Diskette: int 13h im PM
Beitrag von: bitmaster am 22. December 2005, 13:04
Also mal konkret bitte. Welcher vorteile hat DMA und welche Nachteile hat DMA. Und was muss der Code des IRQ6 machen?

Danke!!!
Titel: Diskette: int 13h im PM
Beitrag von: joachim_neu am 22. December 2005, 14:17
Vorteile:

- der Übertragungsvorgang verläuft automatisch
- du musst den Übertragungsvorgang nicht überwachen
- du kannst während der Übertragung andere Tasks an den Prozessor lassen

Nachteile:

- du kannst nur die unteren 16 MB im Speicher adressieren, sodass du in den meisten Fällen den Sektor in einen gesicherten Bereich kopieren und von dort aus dann in den Programmbereich kopieren musst
Titel: Diskette: int 13h im PM
Beitrag von: SSJ7Gohan am 22. December 2005, 14:59
Man sollte auf jeden Fall DMA verwenden, das hat den Vorteil, das man wärend der Datenübertragung noch andere Sachen mit der CPU machen kann, und es viel schneller ist als PIO.
Man kann ja die ersten 16 MB für DMA reservieren, dann hat man kein Problem mit den 16 MB. Wenn diese 16 MB bereits voll sind, kann man ja immernoch PIO als Alternative benutzen. Selbst das kopieren in den oberen Speicherbereich ist eventuell schneller, da man beim kopieren in DWORDs verarbeiten kann, beim PIO kann man aber meist nur einzelne Bytes lesen.
Titel: Diskette: int 13h im PM
Beitrag von: bitmaster am 22. December 2005, 18:01
Vielen dank, ich werde also DMA verwenden (ich arbeite sowieso im 16 Bit PM, also max. 16 MByte ;) )

Aber was muss der Code des IRQ6 machen?

Danke!!!
Titel: Diskette: int 13h im PM
Beitrag von: joachim_neu am 22. December 2005, 20:19
Zitat von: SSJ7Gohan
Man sollte auf jeden Fall DMA verwenden, das hat den Vorteil, das man wärend der Datenübertragung noch andere Sachen mit der CPU machen kann, und es viel schneller ist als PIO.
Man kann ja die ersten 16 MB für DMA reservieren, dann hat man kein Problem mit den 16 MB. Wenn diese 16 MB bereits voll sind, kann man ja immernoch PIO als Alternative benutzen. Selbst das kopieren in den oberen Speicherbereich ist eventuell schneller, da man beim kopieren in DWORDs verarbeiten kann, beim PIO kann man aber meist nur einzelne Bytes lesen.


Ich würds auch verwenden (tu ich auch ;)), auch, weil bei der Übertragung per DMA keine Daten verlohren gehen. Bei dem anderen kann es sein, dass, wenn der Task durch einen Taskwechsel unterbrochen wird (was fast immer so sein sollte), Daten verlohren gehen, weil der FDC sich nicht kümmert, ob seine Daten ankommen. (Soweit ich weiß...)
Titel: Diskette: int 13h im PM
Beitrag von: Osbios am 22. December 2005, 21:32
Nicht wenn man es ordentlich programmiert.
Aber dann wird für jedes Byte ein Int aufgerufen was die ganze sache ja so langsam macht. Z. B. Win95 (glaube auch 98  ) benutzt kein DMA für die Floppy, das kann man auch gut erkennen wenn das System ausgelastet ist  nur weil man was mit der Floppy macht.

Damals bei "Betriebssystemen" wie Dos war das kein Problem denn man musste sowieso warten bis alle Daten gelesen oder geschrieben waren.
Aber bei Multitaskingsystemen kam erschwerend die komplexere Int  verarbeitung des PM hinzu.

Ich hab mal ausprobiert wie schnell eine fd daten lesen kann.
Für eine ganze fd benötigt ich 42 Sec.
1440 KB = 1474560 Byte
1474560 / 42 = ~35108 Ints. pro Sec.
Titel: Diskette: int 13h im PM
Beitrag von: bitmaster am 22. December 2005, 22:08
OK, wie gesagt werde ich es auch mit DMA machen. Ich habe herausgefunden, dass der IRQ6 Code ledinglich zeigen soll das er aufgerufen wurde. Dies kann er z.B. in dem er den Wert 1 in einer Variable abspeichert. Dann kann man später mit cmp variable,1 prüfen ob der IRQ6 aufgerufen wurde. Dann habe ich auch herausgefunden das ich neun Bytes an dem 3F5h senden muss, um Sektoren schreiben/lesen zu können. Aber wie genau mach ich das jetzt mit DMA? Ich meine wo muss ich die Adresse angeben, wo er mir den Sektor hinkopieren soll?

Danke!!!

PS: Und warum gibt es zwei Controller?
Titel: Diskette: int 13h im PM
Beitrag von: Osbios am 23. December 2005, 08:55
Um DMA zu benutzen musst du den DMA Chip ansprechen. Ich habe hier mal ein bisel Code meines "Treibers" herausgesucht, aber das meiste habe ich nur irgendwoher Copy&Past.  :roll:
;DMA channel 0-3 command register
 mov al,00010100b
       ;|||||1=controller; 0=memory-to-memory
       ;||||1=compressed timing; 0=normal timing
       ;|||1=rotating priority; 0=fixed priority
       ;||1=extended write selection; 0=late write selection
       ;|1=DREQ sense active high; 0=low
       ;1=DACK sense active high; 0=low
 out 0x8,al

;DMA channel 0-3 mode register
 mov al,01010110b
       ;||||||XX:channel select 0..3
       ;||||XX:00=Verify transfer; 01=Write transfer; 10=Read transfer
       ;|||1=NonAutoinitialized
       ;||X:Address increment(0=+;1=-)
       ;XX:00=Demand mode; 01=Single mode; 10=Block mode; 11=Cascade mode
 out 0xB,al

 out 0xC,al ;DMA clear byte pointer flip-flop(only write something)

 mov eax,floppy_buffer+0x500 ;0x10000?
 out 0x4,al  ;linear @ 0-7
 shr eax,8
 out 0x4,al  ;linear @ 8-15
 shr eax,8
 out 0x81,al ;linear @ 16-23

 out 0xC,al ;DMA clear byte pointer flip-flop
 
 mov al,0xff
 out 0x5,al
 mov al,0x1
 out 0x5,al ;load 511 into count register (to read one sector)
 ; it should be noted that for multiple transfers, the
 ; second value output to port 05h is equivalent to
 ; (2*number of sectors)-1

 mov al,0x2
 out 0xa,al ;release channel 2

 ;enable DMA 1
 mov al,0x10
 out 0x8,al ;this is the value for enabling the DMA for the mode required


Zusätzlich muss man dem FDC noch sagen das er DMA benutzen soll:

mov al,3;= Fix Drive Data
 call floppy_write
 mov al,0x0F
       ;  |x=head unload time
       ;  x = step rate
 call floppy_write
       
       ;head unload time
       ;|   1M  500k  300k  250k (Data Transfer Rate)
       ;0  128   256   426   512
       ;1    8    16  26.7    32
       ;2   16    32  53.3    64
       ;. ....  ....  ....  ....
       ;E  112   224   373   448
       ;F  120   240   400   480
       
       ;step rate
       ;|   1M  500k  300k  250k (Data Transfer Rate)
       ;0  8.0    16  26.7    32
       ;1  7.5    15  25.0    30
       ;2  7.0    14  23.3    28
       ;. ....  ....  ....  ....
       ;E  1.0     2   3.3     4
       ;F  0.5     1   1.7     2

       
 mov al,00000010b
       ;|||||||x 0=DMA 1=noDMA
       ;xxxxxxx = head load time
 call floppy_write
       
       ;head load time
       ; |   1M  500k  300k  250k (Data Transfer Rate)
       ; 0  128   256   426   512
       ; 1    1     2   3.3     4
       ; 2    2     4   6.6     8
       ;.. ....  ....  ....  ....
       ;7E  126   252   420   504
       ;7F  127   254   423   508
       


Das was da steht muss nicht umbeding Fehlerfrei sein, aber wir sollten alle Informationen zusammentragen um das Geheimniss FDC zu lüften.   : D

*denktübereingroßestuorialnach*
Titel: Diskette: int 13h im PM
Beitrag von: bitmaster am 23. December 2005, 12:08
danke

Also der Obere Code zur DMA steht auch so in meinem PC Hardwarebuch. Das werde ich mir jetzt genaustens durchlesen. Das mit dem DMA an FDC: Und was ist mit der Funktion "floppy_write"?

Zitat
*denktübereingroßestuorialnach*

Das wäre echt super.

Danke!!!
Titel: Diskette: int 13h im PM
Beitrag von: joachim_neu am 23. December 2005, 12:18
Zitat von: bitmaster

Zitat
*denktübereingroßestuorialnach*

Das wäre echt super.


So eins habe ich vor längerer Zeit einmal angefangen, mal sehen, ob ich das weitermache. Wenn jemand ein Tut schreiben will, kann ich ihm gerne meine Anfänge als Stütze geben.
Titel: Diskette: int 13h im PM
Beitrag von: Osbios am 23. December 2005, 14:42
Zitat von: bitmaster
Also der Obere Code zur DMA steht auch so in meinem PC Hardwarebuch. Das werde ich mir jetzt genaustens durchlesen. Das mit dem DMA an FDC: Und was ist mit der Funktion "floppy_write"?

Zitat
*denktübereingroßestuorialnach*

Das wäre echt super.

Danke!!!


Ich unterschlagen halt auch mal was.  8)

floppy_write: ;data port=al
 push ax
 mov dx,0x3F4
 .loop1:
  in  al,dx
 and al,11000000b
 cmp al,10000000b
       ;|X:1=FDC to CPU; 0=CPU to FDC
       ;X :data reg ready
 jne .loop1

 inc dx
 pop ax
 out dx,al
ret


@joachim_neu:
Ja, alles was man an Infos sammel kann ist gut. Wenn es zu groß zum posten ist bitte als Email: osbios at web . de

Ich habe mir schon mal Gedanken über den Inhalt gemacht:

-BIOS Diskettenfunktionen
-Programmierbeispiele (Mit Ablaufdiagram?)
-Sonstiges (Tipps, Bugs, Besonderheiten, ...)
-Befehlsliste der BIOS-Funktionen

-direkte Programmierung des Diskettenlaufwerkkontrollers
-Kontroller Modele
-Register/Ports
-Interrupt
-DMA
-Programmierbeispiele (Mit Ablaufdiagram?)
-Sonstiges (Tipps, Bugs, Besonderheiten, ...)
-Befehlsliste für den FDC

Also eine ausführliche Dok. für Programmierer. Oder soll man gleich in die Vollen gehen und alles was man zu Floppys finden kann als THE ULTIMATIVFLOPPYDOKU titulieren? ^^

Auf jeden fall will ich auch solche sachen wie DMA soweit erklähren, dass man deren Benutzung im Zusammenhang mit der Floppy ohne extra Tuts verstehen kann.

Eventuell noch Ideen was fehlt?
Titel: Diskette: int 13h im PM
Beitrag von: joachim_neu am 23. December 2005, 16:02
Wenn du schon DMA machst, dann auch richtig ausführlich. Du kannst es ja 2teilig machen, wenn du Lust hast. Erst DMA und dann FDC mit Benutzung von DMA.
Titel: Diskette: int 13h im PM
Beitrag von: Osbios am 24. December 2005, 11:47
Ich habe schon darüber nachgedacht nicht alles in eine Dokumentation reinzustopfen, aber aus Sicht eines Programmierers der die Floppy programmieren will ist ein einzelne Dok. mit allen nötigen Infos natürlich nicht schlecht. Der Programmierer hat daduch auch mehr Übersicht, da z.B. für Floppy mit DMA nicht alles über DMA-Programmiererung enthalten sein muss.

Naja, dann werde ich micht mal selber ransetzn und ersteinmal Informationen zusammensuchen. Wenn ich einen besseren Überblick habe kann ich die einzelnen Bereiche besser abgrenzen.
Titel: Diskette: int 13h im PM
Beitrag von: bitmaster am 24. December 2005, 21:58
Also ich wäre wirklich sehr dankbar für ein ausführliches Tutorial zu diesem Thema. Im Moment verstehe ich nämlich nur Bahnhof.
Titel: Diskette: int 13h im PM
Beitrag von: bitmaster am 28. December 2005, 15:42
@[MM]: Also ich glaube das bei deinem Code irgendwie was fehlt. Z.b. bei motoroff. Wo wird denn da der Motor ausgeschalten? Und ca. 3 Sekunden wird dort auch nicht gewartet. motoroff_now verstehe ich ja aber motoroff nicht. Da felt doch was, richtig?
Titel: Diskette: int 13h im PM
Beitrag von: joachim_neu am 28. December 2005, 23:02
Nur, um es mal gesagt zu haben:
Es ist theoretisch auch möglich, das RM Int 13 im PM weiterzuverwenden. Wie? Nun, man macht sich einen Task, schaltet den in den VM86, mappt ihm alles, wie ers im RM hätte und öffnet die notwendigen FDC-Ports im IO-Bitmap des TSS. So kann ein RM-Treiber in einem emulierten RM weiterhin die RM-Ints benutzen und man erspart sich das Programmieren.
Titel: Diskette: int 13h im PM
Beitrag von: bitmaster am 28. December 2005, 23:25
Zitat von: joachim_neu
Nur, um es mal gesagt zu haben:
Es ist theoretisch auch möglich, das RM Int 13 im PM weiterzuverwenden. Wie? Nun, man macht sich einen Task, schaltet den in den VM86, mappt ihm alles, wie ers im RM hätte und öffnet die notwendigen FDC-Ports im IO-Bitmap des TSS. So kann ein RM-Treiber in einem emulierten RM weiterhin die RM-Ints benutzen und man erspart sich das Programmieren.
Das will ich aber nicht. ;)
Titel: Diskette: int 13h im PM
Beitrag von: Jidder am 29. December 2005, 00:29
Zitat von: joachim_neu
Nur, um es mal gesagt zu haben:
Es ist theoretisch auch möglich, das RM Int 13 im PM weiterzuverwenden. Wie? Nun, man macht sich einen Task, schaltet den in den VM86, mappt ihm alles, wie ers im RM hätte und öffnet die notwendigen FDC-Ports im IO-Bitmap des TSS. So kann ein RM-Treiber in einem emulierten RM weiterhin die RM-Ints benutzen und man erspart sich das Programmieren.

ich kenn eine einfachere methode: man schreibt einen RM-Code->PM-Code konverter, der auf binärcode-ebene arbeitet. den jagt man dann vor dem ersten benutzen des int 13h über eben diesen rüber. dann muss man den interrupt nur noch in die IDT eintragen. so einfach ist das :P
Titel: Diskette: int 13h im PM
Beitrag von: bitmaster am 29. December 2005, 13:37
Hi,

ich habe noch eine Frage. Ich kann mit dem 3F4h und 3F7h die Datenrate einstellen. Aber was ist da der unterschied bzw. wann sollte ich welches Register benutzen.

Danke!!!
Titel: Diskette: int 13h im PM
Beitrag von: joachim_neu am 29. December 2005, 15:07
Zitat von: bitmaster
Zitat von: joachim_neu
Nur, um es mal gesagt zu haben:
Es ist theoretisch auch möglich, das RM Int 13 im PM weiterzuverwenden. Wie? Nun, man macht sich einen Task, schaltet den in den VM86, mappt ihm alles, wie ers im RM hätte und öffnet die notwendigen FDC-Ports im IO-Bitmap des TSS. So kann ein RM-Treiber in einem emulierten RM weiterhin die RM-Ints benutzen und man erspart sich das Programmieren.
Das will ich aber nicht. ;)

Ich habs nur der Vollständigkeit wegen gesagt. Es soll ja auch andere Leute geben, die vor dem Problem stehen (werden) und die Such-Funktion benutzen. ;)
Zitat von: PorkChicken
Zitat von: joachim_neu
Nur, um es mal gesagt zu haben:
Es ist theoretisch auch möglich, das RM Int 13 im PM weiterzuverwenden. Wie? Nun, man macht sich einen Task, schaltet den in den VM86, mappt ihm alles, wie ers im RM hätte und öffnet die notwendigen FDC-Ports im IO-Bitmap des TSS. So kann ein RM-Treiber in einem emulierten RM weiterhin die RM-Ints benutzen und man erspart sich das Programmieren.

ich kenn eine einfachere methode: man schreibt einen RM-Code->PM-Code konverter, der auf binärcode-ebene arbeitet. den jagt man dann vor dem ersten benutzen des int 13h über eben diesen rüber. dann muss man den interrupt nur noch in die IDT eintragen. so einfach ist das :P

Das wird nicht so einfach sein. Du musst die ganzen Adressen neu berechnen und den Code manipulieren. Außerdem musste (wie schon gesagt) alles von 16 bit zu 32 bit bringen. Da finde ich das andere einfacher, auch, weils sicherer ist. ;)
Titel: Diskette: int 13h im PM
Beitrag von: SSJ7Gohan am 29. December 2005, 15:13
Ich würde generell vermeiden, den VM86 Mode zu nutzen, und ihn nur dann nutzen, wenn es unbedingt nötig ist (VESA Framebuffer z.B.). Er ist unportabel (x86_64 unterstützt ihn nicht mehr), switches zurück in den Realmode sind leichter, und das BIOS ist meistens auch nicht gerade bugfrei.
Titel: Diskette: int 13h im PM
Beitrag von: joachim_neu am 29. December 2005, 22:50
Zitat von: SSJ7Gohan
Ich würde generell vermeiden, den VM86 Mode zu nutzen, und ihn nur dann nutzen, wenn es unbedingt nötig ist (VESA Framebuffer z.B.). Er ist unportabel (x86_64 unterstützt ihn nicht mehr), switches zurück in den Realmode sind leichter, und das BIOS ist meistens auch nicht gerade bugfrei.


1. Wenn du nach Portabilität gehst, kannst du den PM vergessen, den gibt es auch nicht in 64Bit-Ausführung. Da musst du deinen Kernel eh umschreiben (GDT, IDT, ...)
2. Kann man doch nicht für einen Treiber in den RM wechseln. Wo kommen wir da hin, dann könnte jeder Treiber die volle Macht übers System übernehmen.
3. Ich denke das BIOS ist bugfreier als der Code, den wir produzieren...
Titel: Diskette: int 13h im PM
Beitrag von: bitmaster am 29. December 2005, 23:14
Zitat von: joachim_neu
Zitat von: SSJ7Gohan
Ich würde generell vermeiden, den VM86 Mode zu nutzen, und ihn nur dann nutzen, wenn es unbedingt nötig ist (VESA Framebuffer z.B.). Er ist unportabel (x86_64 unterstützt ihn nicht mehr), switches zurück in den Realmode sind leichter, und das BIOS ist meistens auch nicht gerade bugfrei.


1. Wenn du nach Portabilität gehst, kannst du den PM vergessen, den gibt es auch nicht in 64Bit-Ausführung. Da musst du deinen Kernel eh umschreiben (GDT, IDT, ...)
2. Kann man doch nicht für einen Treiber in den RM wechseln. Wo kommen wir da hin, dann könnte jeder Treiber die volle Macht übers System übernehmen.
3. Ich denke das BIOS ist bugfreier als der Code, den wir produzieren...
Das sehe ich ganz genau so.
Titel: Diskette: int 13h im PM
Beitrag von: SSJ7Gohan am 30. December 2005, 11:43
1. Naja, stimmt, wie der Kernel intern aufgebaut ist, ist egal. Und ob ich jetzt in den RM wechsele oder den VM86 Mode nutze ist dafür auch egal.
2. Ja, stimmt, das ist ein Vorteil des VM86 Modes. Allerdings ist der VM86 Mode auch nicht sehr sicher, ausser wenn du sehr viel emulierst. Du weißt z.B. nicht, auf welche Ports das Video-BIOS zugreifen muss, um VBE einzuschalten, daher musst du den Zugriff auf alle Ports erlauben, wodurch auch jeder Treiber die volle Macht übers System übernehmen könnte. (Über APM das System ausschalten usw.)
3. Naja, wenn in unserem Code Bugs sind, können wir sie beheben, beim BIOS müssen wir uns darauf verlassen, das alles klappt. Ausserdem will ich nicht alles vom BIOS machen lassen, sondern meine eigenen Treiber benutzen, ausser wenn es halt nicht möglich ist.
Titel: Diskette: int 13h im PM
Beitrag von: joachim_neu am 30. December 2005, 12:29
Zitat von: SSJ7Gohan

2. Ja, stimmt, das ist ein Vorteil des VM86 Modes. Allerdings ist der VM86 Mode auch nicht sehr sicher, ausser wenn du sehr viel emulierst. Du weißt z.B. nicht, auf welche Ports das Video-BIOS zugreifen muss, um VBE einzuschalten, daher musst du den Zugriff auf alle Ports erlauben, wodurch auch jeder Treiber die volle Macht übers System übernehmen könnte. (Über APM das System ausschalten usw.)


Das kannst du einfach herausfinden. Du sperrst alle Ports und lässt dir von den auftretenden Protected Faults zeigen, auf welche Ports zugegriffen wird. Die kannst du dann beim nächsten Durchlauf aufmachen, bis keine Faults mehr auftreten.
Titel: Diskette: int 13h im PM
Beitrag von: SSJ7Gohan am 30. December 2005, 13:00
Die Ports, auf die zugegriffen wird können aber je nach System unterschiedlich sein.
Titel: Diskette: int 13h im PM
Beitrag von: Osbios am 30. December 2005, 21:08
Zitat von: SSJ7Gohan

2. Ja, stimmt, das ist ein Vorteil des VM86 Modes. Allerdings ist der VM86 Mode auch nicht sehr sicher, ausser wenn du sehr viel emulierst. Du weißt z.B. nicht, auf welche Ports das Video-BIOS zugreifen muss, um VBE einzuschalten, daher musst du den Zugriff auf alle Ports erlauben, wodurch auch jeder Treiber die volle Macht übers System übernehmen könnte. (Über APM das System ausschalten usw.)


Also meines Wissens nach haben Treiber in den meisten Betriebssystemen sowieso die volle Kontrolle über das System.

Zitat von: joachim_neu

Das kannst du einfach herausfinden. Du sperrst alle Ports und lässt dir von den auftretenden Protected Faults zeigen, auf welche Ports zugegriffen wird. Die kannst du dann beim nächsten Durchlauf aufmachen, bis keine Faults mehr auftreten.


Wofür sollte man dann noch Ports sperre, wenn man sowieso alle Ports sofort wieder freigibt wenn sie benutzt werden?
Titel: Diskette: int 13h im PM
Beitrag von: Legend am 30. December 2005, 21:59
Zitat von: Osbios
Zitat von: SSJ7Gohan

2. Ja, stimmt, das ist ein Vorteil des VM86 Modes. Allerdings ist der VM86 Mode auch nicht sehr sicher, ausser wenn du sehr viel emulierst. Du weißt z.B. nicht, auf welche Ports das Video-BIOS zugreifen muss, um VBE einzuschalten, daher musst du den Zugriff auf alle Ports erlauben, wodurch auch jeder Treiber die volle Macht übers System übernehmen könnte. (Über APM das System ausschalten usw.)


Also meines Wissens nach haben Treiber in den meisten Betriebssystemen sowieso die volle Kontrolle über das System.


Ja, in Linux sowieso und in Windows haben es auch die meisten. Das ist aber kein Zeichen von einem gutem (möglichts stabilem) Kerneldesign (auch wenn es ein paar wenige % Performance bringt).
Titel: Diskette: int 13h im PM
Beitrag von: elfish_rider am 31. December 2005, 12:16
Zitat von: bitmaster
Ich habe oft gelesen, dass man DMA nicht benutzen sollte. Ich verstehe aber nicht warum. Hat das einen Nachteil? Geht das überhaupt ohne?


Das interessiert mich auch! Welches Register müsste man dann auslesen, um über P I/O an Daten zu kommen? 0x03F5?
Titel: Diskette: int 13h im PM
Beitrag von: SSJ7Gohan am 31. December 2005, 15:56
Naja, DMA ist recht langsam (maximal 4MB/s) und kann nur die ersten 16 MB addressieren, er ist aber besser für Multitasking Umgebungen geeignet (wärend die Daten übertragen werden, kann die CPU was anderes machen.) und AFAIK kommt man beim FDC nicht um den DMA rum.
Titel: Diskette: int 13h im PM
Beitrag von: joachim_neu am 31. December 2005, 17:21
Zitat von: Osbios
Zitat von: SSJ7Gohan

2. Ja, stimmt, das ist ein Vorteil des VM86 Modes. Allerdings ist der VM86 Mode auch nicht sehr sicher, ausser wenn du sehr viel emulierst. Du weißt z.B. nicht, auf welche Ports das Video-BIOS zugreifen muss, um VBE einzuschalten, daher musst du den Zugriff auf alle Ports erlauben, wodurch auch jeder Treiber die volle Macht übers System übernehmen könnte. (Über APM das System ausschalten usw.)


Also meines Wissens nach haben Treiber in den meisten Betriebssystemen sowieso die volle Kontrolle über das System.


Heißt nicht, dass wir so dumm sein müssen, und es auch machen. ;)

Zitat von: Osbios

Zitat von: joachim_neu

Das kannst du einfach herausfinden. Du sperrst alle Ports und lässt dir von den auftretenden Protected Faults zeigen, auf welche Ports zugegriffen wird. Die kannst du dann beim nächsten Durchlauf aufmachen, bis keine Faults mehr auftreten.


Wofür sollte man dann noch Ports sperre, wenn man sowieso alle Ports sofort wieder freigibt wenn sie benutzt werden?


Warum alle freigeben? Man gibt nur die frei, die gebraucht werden.

Zitat von: SSJ7Gohan
Die Ports, auf die zugegriffen wird können aber je nach System unterschiedlich sein.


Nein, FDC und DMA gehen immer über die gleichen Ports (zumindest bei x86), oder hast du schonmal was anderes gesehen? Und wenn: Wie soll man dann herausfinden, wo die sich verstecken?
Titel: Diskette: int 13h im PM
Beitrag von: SSJ7Gohan am 31. December 2005, 17:43
Das bezog sich nicht auf DMA und FDC, sondern auf VBE.
Titel: Diskette: int 13h im PM
Beitrag von: joachim_neu am 01. January 2006, 01:57
Achso, ja, das kann sein. Aber wenn man VESA im RM mit LFB aktiviert, dann braucht man dafür eg. nichtmehr zurück in den RM.
Titel: Diskette: int 13h im PM
Beitrag von: bitmaster am 04. January 2006, 16:38
Also ich komm da einfach nicht weiter. Ich habe alles mögliche versucht, aber nicht funktioniert. Das einzige was funktioniert ist: Motot an und Motor aus. Aber ich möchte jetzt aus testzwecken nur einen Sektor (Sektor 4, sprich den dritten Sektor) mit Daten beschreiben. Aber VMware zeigt mir eine Fehlermeldung an und Bochs macht gar nichts mehr. Der Sektor wurde auch nicht beschrieben. Was mache ich da falsch? Hier mein Code:

xor al,al
call fdc_activate_motor
mov bl,0Fh
call fdc_sendbyte
xor bl,bl
call fdc_sendbyte
xor bl,bl
call fdc_sendbyte
mov bl,01h
call fdc_wait
xor cl,cl
mov dx,07C0h
xor bx,bx
call dma_xfer ;bis hier mache ich glaube ich alles richtig
mov bl,0C5h ;jetzt komt der Fehler
call fdc_sendbyte
xor bl,bl
call fdc_sendbyte
xor bl,bl
call fdc_sendbyte
xor bl,bl
call fdc_sendbyte
mov bl,03h
call fdc_sendbyte
mov bl,02h
call fdc_sendbyte
mov bl,18
call fdc_sendbyte
mov bl,1Bh
call fdc_sendbyte
mov bl,0FFh
call fdc_sendbyte
xor bl,bl
call fdc_wait
jmp $


Hier mal die Funktionen von denen ich ausgehe das dort ein Fehler sein kann:

;input:  bl, 0=ohne sensei, 1=mit sensei
;output: -
fdc_wait proc near
cmp irq6_done,1
jne fdc_wait
pusha
push bx
cli
mov cx,0007h
fdc_wait_loop:
mov dx,03F4h
in al,dx
and al,10h
or al,al
jz fdc_wait_weiter
dec cx
jz fdc_wait_weiter
call fdc_getbyte
jmp fdc_wait_loop

fdc_wait_weiter:
pop bx
or bl,bl
jz fdc_wait_no_sensei
mov bl,08h
call fdc_sendbyte
call fdc_getbyte
call fdc_getbyte
fdc_wait_no_sensei:

mov irq6_done,0
sti
popa
ret
fdc_wait endp

;input:  bl = Byte das gesendet werden soll
;output: -
fdc_sendbyte proc near
pusha
mov cx,0080h
mov dx,03F4h
fdc_sendbyte_loop:
in al,dx
and al,0C0h
cmp al,80h
jne fdc_sendbyte_weiter
mov dx,03F5h
mov al,bl
out dx,al
popa
ret
fdc_sendbyte_weiter:
in al,80h
loop fdc_sendbyte_loop
popa
ret
fdc_sendbyte endp

;input:  -
;output: bl = Byte aus dem Datenregister
fdc_getbyte proc near
push ax
push cx
push dx
mov cx,0080h
mov dx,03F4h
fdc_getbyte_loop:
in al,dx
and al,0D0h
cmp al,0D0h
jne fdc_getbyte_weiter
mov dx,03F5h
in al,dx
mov bl,al
pop dx
pop cx
pop ax
ret
fdc_getbyte_weiter:
in al,80h
loop fdc_getbyte_loop
pop dx
pop cx
pop ax
ret
fdc_getbyte endp

Es wäre wirklich nett wenn ihr euch das mal anschaut. Ich finde den Fehler einfach nicht.

Danke!!!
Titel: Diskette: int 13h im PM
Beitrag von: bitmaster am 06. January 2006, 23:36
So, ich habe es nun entlich geschafft. Es funktioniert. Ich hatte das lesen/schreiben beim DMA Code vertauscht und den Kopf nicht zur richtigen Spur positioniert. Also wunderbar alles funktioniert. Aber jetzt habe ich immer noch ein kleines Problem. Was ist wenn jemand eine nicht 1,44 MByte Diskette mit meinem OS benutzen will? Würde es dann abstürtzen? Also im RM macht der int 13h das ja alles automatisch (außer natürlich die Anzahl der Heads, Sectors a Track usw.). Aber ich muss dem FDC genau die Formate angeben die er zu lesen hat. Also bitte ich um Informationen der verschiedenen Diskettenformate. Z.B. Wird bei 1,44 MByte als Länge der GAP3, 1Bh angegeben. Wie heißt es bei den anderen Formaten. Welche Datenrate brauchen die Formate? Wann kommt FM und wann MFM zu tragen? Also im Prinzip würde ich gerne alle Informationen über den Verschiedensten Diskettenformaten (natürlich nur die für den PC) haben. Danke!!!

bitmaster
Titel: Diskette: int 13h im PM
Beitrag von: bitmaster am 10. January 2006, 16:04
Zitat von: [MM]
@fdd_login(){
        push    cx
        str     cx
        ; Schon eingeloggt:
        cmp     [fdd_data_user],cx
        jz      .is_logged_in
        cli     ; Keine Interrupts, damit jetzt kein Taskwechesl kommt.
        ; Nein, ist das FDD frei:
        cmp     word ptr [fdd_data_user],0
        jnz     .error
        mov     [fdd_data_user],cx
        sti
        mov     dword ptr [fdd_login_count],0
        pop     cx
        mov     cl,1
        ret
.is_logged_in:
        inc     dword ptr [fdd_login_count]
        pop     cx
        mov     cl,1
        ret
.error:
        sti
        pop     cx
        xor     cl,cl
        ret
}
Und was ist wenn genau nach dem jz      .is_logged_in (bedingung nicht erfüllt) ein Taskwechsel stattfindet? Also das cli erst gar nicht ausgeführt wird?

bitmaster
Titel: Diskette: int 13h im PM
Beitrag von: bitmaster am 10. January 2006, 23:36
MFM ist gültig bei High Density Disks, oder? Was macht das Bit7 beim schreib/lese Befehl? In einem Doku steht das dann die gewünschte Operation auf beiden Seiten ausgeführt wird. Aber es wird nicht von beiden Seiten gelesen/geschrieben obwohl ich das Bit7 gesetzt habe. Wäre auch irgendwie unlogisch. Aber wofür ist Bit7 denn dann wirklich?

bitmaster
Titel: Diskette: int 13h im PM
Beitrag von: bitmaster am 27. January 2006, 16:10
Hallo,

wie gesagt funktioniert eigentlich alles. Nur habe ich festgestellt, dass es beim echten PC ziemlich langsam ist (das lesen und schreiben vom/auf Diskette). Also unter den Emulatoren läuft es ziemlich schnell bzw. normal. Aber wenn ich es auf einem wirklichen PC ohne Emulator laufen lasse, dauern 64 KByte lesen oder schreiben ca. 1,5 Minuten. Das ist viel zu lange. Auch hört man das Laufwerk kaum gegenüber das lesen im RM mit dem int 13h. Muss ich eigentlich bei jedem lesen/schreiben eines Sektors das Laufwerk rest(en)? Muss ich auch jedes mal die Drive-Timings setzten? Ich warte auch nirgendwo die 1/2 sekunden. Muss man das unbedingt? Warum und wo genau?

Danke!!!

bitmaster