Pevný disk

Keď sa váš OS trochu rozrastie tak sa hneď začnete obzerať kamže by ste si svoje veľactené dáta mohli uložiť. Pevný disk je tým najlepším riešením. Avšak na jeho používanie ho najprv musíte vytvoriť, potom zadetekovať a až potom doňho môžete písať alebo čítať. Našťastie je to jednoduché a tak to budete mať cobydup.

Klaykap

Vytváranie pevného disku

Pevný disk bude predstavovať nejaký súbor ktorý na to určíte. Najjednoduchšie riešenie ako ho vytvoriť je použíť program ktorý si stiahnete spolu s qemu a to qemu-img. Súbor vytvoríte pomoocu qemu-img -f raw nazov.img velkost čiže v praxi:

    qemu-img -f raw harddisc.img 10MB
    

Stlačte enter a na svete sa ocitne nový súbor harddisc.img ktorý má veľkosť 10MB(to je ale prekvapenie) a je celý plný núl. No proste presne to čo potreujeme. Ale to že sme taký úchvatný súbor vytvorili nám bude houby platné pokiaľ o tom qemu nebude vedieť. Preto budeme musieť odteraz spúťať qemu aj s -hda harddisc.img a samozrejme musíme mať otvorený terminál v priečinku kde náš harddisc.img.

Detekovanie pevného disku

Pevný disk používa takzvané IDE rozhranie. To znamená že existuje takzvané Primárny IDE kontrolér a Sekundárny IDE kontrolér a na každom je Master a Slave. A na každom z týchto štyroch môže byť pevný disk! Ako prvé teda musíme vyzistiť či vôbec Primárny alebo sekundárny kontrolér existuje. Primárny kontrolér používa porty 0x1F0 až 0x1F7 a sekundárny 0x170 až 0x177(toto nie je úplne presné, tieto porty sú podporované v emulátoroch ale v reálnom hardvéri nemusia, na reálnom hardvéri si musiíte základný port zistiť cez PCI). Nuž a keď chcete zadetekovať primárny kontrolér tak na port 0x1F3(0x173 pre sekundárny) pošlite číslo 0x88 a prečítajte si ten istý prot. Ak v ňom bude tiež 0x88, daný kontrolór existuje. A potom v kontroléri treba zadetekovať jeho master alebo slave. To je jednoduché, stačí do portu 0x1F6(0x176 pre sekundárny) napísať buď 0xA0 pre detekciu master alebo 0xB0 pre detekciu slave a prečítať si port 0x1F7(alebo 0x177 pre sekundárny, odteraz už pre sekundárny nebudem písať lebo to je to isté ako pre primárny iba F je nahradené 7) a ak je na ňom 83, pevný disk na ňom podporuje PIO48, ak iná hodnota tak PIO28 a ak je na ňom 0 tak tam žiaden pevný disk nie je.

Čítanie a písanie

Takže už sme si náš pevný disk aj zadetekovali a vieme kdeže sa nachádza. Väčšinou býva na Primárnom master ale niekedy to neplatí. Nuž a teraz už môžeme začať čítať aleo písať. Ibaže pevné disky podporujú buď spôsob PIO28 ktorý je starší alebo PIO48 ktorý umožňuje prácu s omnoho viac sektormi. Tento kód pre PIO28 píšem pre porty primárneho IDE ale určite vám nebude robiť problém prepísať F na 7 a získať tak proty sekundárneho IDE - napr port 0x1F0 je pre primárne IDE a 0x170 pre sekundárne IDE. Takže dosť tlachov, ideme na to!

Ako prvé musíme vybrať či pracujeme s master alebo slave. To sa robí zapísaním hodnoty do 0x1F6. Pre master to je 0xE0 a pre slave 0xF0.

    outb(0x1F6, 0xE0);
    

Teraz musíme poslať číslo sektoru ktorý chceme prečítať. To sa robí cez porty 0x1F1 až 0x1F5. Premenná sector je veľkosti uint32_t(alebo unsigned int).

    outb(0x1F1, 0x00);
    outb(0x1F2, 0x01);
    outb(0x1F3, (unsigned char)sector);
    outb(0x1F4, (unsigned char)(sector >> 8));
    outb(0x1F5, (unsigned char)(sector >> 16));
    

Teraz treba povedať či chceme písať aleo čítať. O to sa stará port 0x1F7 a pre čítanie je hodnota 0x20 a pre písanie 0x30.

    outb(0x1F7, 0x20);
    

Ďaľším krokom je počkať kým bude pevný disk pripravený. Na to treba čítať statusový port 0x1F7 a vyzistiť či bit 0x08 ktorý sa volá aj DRQ bit je nastavený(čiže je v ňom 1). Keby však olo čosi zle, DRQ bit sa nenastaví a tak musíme spraviť cyklus for. Každé čítanie totiž chviľku času zaberie a tak bude cyklus for bežať po určitú dobu. Pokiaľ sa dovtedy DRQ bit nenastaví niečo je zle a musíme skončiť.

    cycle=0;
    for(int i=0; i<10000; i++) {
        if( (inb(0x1F7) & 0x08)==0x08 ) {
            cycle=1;
            break;    
        }    
    }
    if(cycle==0) {  //DRQ bit sa nenastavil, volaco sa spackalo, takze musime ukoncit metodu
        return 0;
    }
    

A pokiaľ sa DRQ bit nastavil môžme konečne čítať či písať do dátového portu 0x1F0. Pozor! Pracujeme s ním príkazmi outw/inw nie outb/inb! Preto aj pole buffer musí byť zadefinované uint16_t buffer[256].

    for (int idx = 0; idx < 256; idx++)
    {
        if(type==ATA_READ) {  //Ak citame
            buffer[idx] = inw(base + ATA_PORT_DATA);
        }
        else {  //Ak piseme
            outw(base + ATA_PORT_DATA, buffer[idx]);
        }
    }

    return 1;  //citanie/pisanie sa podarilo
    

Hotovo! Vyskúšajte si prečítať sektor nula a ak máte výstup samé nuly, všetko je v poriadku. Majte na pamäti že jeden sektor má velkoť pol kilobajtu.

Modernejšie pevné disky používajú spôsob PIO48. Musím sa priznať že som ho netestoval, ale podľa všetkého by mal tento kód fungovať. Základné odlišnosti sú že master sa vyberá 0x40 a slave 0x50 a čítačí príkaz je 0x24 a písací 0x34. Inak kód nebudem rozpisovať nakoľko je veľmi podobné PIO28 a tak ho určíte rýchlo rozlúštite.

    if(drive==ATA_MASTER) {
    outb(base+ATA_PORT_DRV, 0x40);
    }
    else { // ATA_SLAVE
    outb(base+ATA_PORT_DRV, 0x50);
    }

    //PIO48
    outw(base+ATA_PORT_FEATURES, 0x00);
    outw(base+ATA_PORT_FEATURES, 0x00);
    outw(base+ATA_PORT_SCT_COUNT, 0x00);
    outw(base+ATA_PORT_SCT_NUMBER, (unsigned char)(addr >> 24));
    outw(base+ATA_PORT_CYL_LOW, (unsigned char)(addr >> 32));
    outw(base+ATA_PORT_CYL_HIGH, (unsigned char)(addr >> 40));
    outw(base+ATA_PORT_SCT_COUNT, 0x01);
    outw(base+ATA_PORT_SCT_NUMBER, (unsigned char)addr);
    outw(base+ATA_PORT_CYL_LOW, (unsigned char)(addr >> 8));
    outw(base+ATA_PORT_CYL_HIGH, (unsigned char)(addr >> 16));
    //type
    if(type==ATA_READ) {
    outb(base+ATA_PORT_COMMAND, 0x24);  // Send command
    }
    else {
    outb(base+ATA_PORT_COMMAND, 0x34);
    }

    //wait
    cycle=0;
    for(int i=0; i<10000; i++) {
        if( (inb(0x1F7) & 0x08)==0x08 ) {
            cycle=1;
            break;    
        }    
    }
    if(cycle==0) {  //DRQ bit sa nenastavil, volaco sa spackalo, takze musime ukoncit metodu
        return 0;
    }

    for (int idx = 0; idx < 256; idx++)
    {
        if(type==ATA_READ) {
            buffer[idx] = inw(base + ATA_PORT_DATA);
        }
        else {
            outw(base + ATA_PORT_DATA, buffer[idx]);
        }
    }
    

A je to! To je naozaj všetko! Práve ste dokončili svoj ovládač pre pevný disk! Ak by vám voľačo nefunguvalo alebo bolo niečo nejasné, môžete ma kontaktovať na klaykap[]yandex.com.


os development vytvoril Klaykap
www.000webhost.com