Vage topictitel, weet het niet anders te verwoorden, maar het gaat om het volgende probleem:
Het is mij eindelijk gelukt om een goed werkende set routines te schrijven in assembly waarmee ik vanuit 32-bits protected mode stukjes realmodecode kan uitvoeren, zodat ik BIOS-functies kan aanroepen. Werkt goed, zo kan ik via interrupt 13h lezen van alle door het BIOS ondersteunde schijven. De V86-monitor heeft ook de mogelijkheid om realmode IRQ's uit te voeren, zelfs als de PC alweer protectedmode code uitvoert, zodat de BIOS-routines altijd goed werken. Zo kan het BIOS bijvoorbeeld op de achtergrond een toetsenbordbuffer bijhouden omdat de IRQ's altijd uitgevoerd kunnen worden.
Nu het probleem: 32-bit native drivers voor apparatuur hebben natuurlijk de voorkeur. Dit geldt zeker voor schijven. De performance van een driver die int13h gebruikt is namelijk zeer laag. Ik zou dus kunnen beginnen aan het schrijven van een ATA-driver. De interrupt 13h driver moet dan natuurlijk niet werken, anders gebeuren dingen door elkaar. Dit geldt metname voor gebruik van de IRQ: Als de IRQ nog is ingesteld op uitvoeren van de realmode BIOS interrupt-routine, terwijl mijn driver die IRQ ook gebruikt, dan zit die driver maar te wachten op de gegevens.. Het is dus of het een of het ander.
Soms is het echter niet altijd wenselijk om de interrupt 13h-driver helemaal niet meer te gebruiken. Dit is het geval als er schijven in het systeem zitten die (nog) niet door een eigen driver kunnen worden benaderd en schijven die juist wel door een eigen driver kunnen worden benaderd. Zodra je dan toch via interrupt 13h schijven benadert waarvoor al een eigen driver aanwezig is, dan gaat het mis. Dus moet de interrupt 13h driver bepaalde schijven niet meer benaderen, het OS/kernel/loader/whatever moet 'weten' welke schijven door de native drivers moeten worden benaderd en welke door interrupt 13h. Hiervoor is echter vereist dat het (eventuele) bios disknummer (waarde van DL bij aanroep van int 13h functies), van een disk die via een eigen driver wordt banaderd, achterhaald wordt. De grote vraag is hoe dit kan.
Methode 1.
Functie 48h van interrupt 13h biedt de mogelijkheid om het ISA base-adress of de PCI-gegevens bus/device/function op te vragen. Deze zaken zijn ook bij een eigen driver die de controller rechtstreeks benadert bekend, en zo kan achterhaald worden dat deze schijf de schijf is die al door de eigen driver benaderd wordt.
Nadeel: Deze functie behoort tot de IBM/MS int 13h extensions. Wat oudere BIOSsen ondersteunen deze functie niet, en de gegevens van de ISA-interface of PCI-interface waar de schijf aan hangt, zijn pas vanaf versie 3.0 van deze extensies beschikbaar. Zelfs niet alle Pentium BIOSsen kunnen deze gegevens achterhalen
Methode 2.
Fysieke gegevens vergelijken. Werkt niet, want je kunt identieke schijven aan verschilende controllers hangen. Interrupt 13h kan geen serienummers e.d. opvragen om een schijf te identificeren.
Methode 3.
De eerste reeks sectoren lezen en vergelijken. Zijn ze gelijk? Dan aannemen dat het om dezelfde schijf gaat. Nadeel: Als je een stel schijven neemt, allemaal gevuld met nullen (dd if=/dev/zero of=/dev/hda) dan denkt die driver met identieke schijven te maken te hebben terwijl dit niet zo hoeft te zijn.
Methode 4.
Een ID-wegschrijven op de eerste sector. Microsoft pakt het volgens mij sinds Windows 2000 zo aan, aangezien vanaf deze Windows versie een 64-bit nummer in het MBR, vlak voor de partitietabel, wordt geplaatst. Vervelende aan deze methode is het feit dat je tegen de standaarden ingaat. Geen enkele standaard garandeert dat er in het MBR op de 8 bytes voor de partitietabel geen code of andere data staat. Microsoft gaat alleen van haar eigen MBR's uit.. Daarnaast is het zo dat een harddisk geen partitietabel hoeft te bevatten. De eerste sector kan ook een bootsector zijn, als je gewoon een grote data partitie wilt. Unix OS-es kunnen daar prima mee uit de voeten. Ook kan een int 13h device een soort van bijzondere floppy zijn die een BIOS-nummer > 127 krijgt toegewezen dus op een harddisk lijkt maar het stiekum niet is. Kortom, de enige garantie t.a.v. de eerste sector van een schijf is de magische ID 0xAA55 aan het einde. Zomaar waardes gaan schrijven is riskant. Je kunt weliswaar tijdelijke ID's schrijven en de oorspronkelijke bytes later weer netjes terugzetten, maar als midden in het detectie-proces de stroom uitvalt dan zit de gebruiker met verziekte bootsectoren of MBR's. Onwenselijke methode dus vanuit het oogpunt van betrouwbaarheid.
Methode 2 is ook onwenselijk, omdat BIOS-en gegevens van schijven nog al eens anders presenteren als de gegevens die je terugkrijgt bij rechtstreekse benadering van een controller. Berucht zijn natuurlijk de 8 GB en 32 GB grenzen, maar ook geeft het BIOS wel eens een iets kleinere omvang van de schijf terug (een cylinder minder). Conclusie: deze methode is niet betrouwbaar.
Bijven methode 1 en 3 over.
Methode 1 is echter alleen geschikt voor nieuwere BIOSsen en methode 3 is weliswaar betrouwbaar als het gaat om het feilloos detecteren van verschillende schijven maar als de methode detecteert dat een schijf identiek is hoeft dit nog niet zo te zijn. Het kan heel goed zijn dat toevallig de eerste reeks sectoren gelijk aan elkaar zijn. Meerdere megabytes uitlezen is onwenselijk, duurt te lang.
Kortom, het blijft behelpen.
Zijn er hier nog mensen die met hobby OS-en bezig zijn en hier ook mee te maken hebben? Hoe heb je het aangepakt? Of ga je gewoon uit van of alles int 13h of alles via een driver (waarbij dus de kans bestaat dat bepaalde schijven niet kunnen worden benaderd als er een niet-ondersteunde controller tussen zit).
De meeste OSdev-tutorials komen helaas niet verder dan een printf("Wh000t me kernel doet ut");
Het is mij eindelijk gelukt om een goed werkende set routines te schrijven in assembly waarmee ik vanuit 32-bits protected mode stukjes realmodecode kan uitvoeren, zodat ik BIOS-functies kan aanroepen. Werkt goed, zo kan ik via interrupt 13h lezen van alle door het BIOS ondersteunde schijven. De V86-monitor heeft ook de mogelijkheid om realmode IRQ's uit te voeren, zelfs als de PC alweer protectedmode code uitvoert, zodat de BIOS-routines altijd goed werken. Zo kan het BIOS bijvoorbeeld op de achtergrond een toetsenbordbuffer bijhouden omdat de IRQ's altijd uitgevoerd kunnen worden.
Nu het probleem: 32-bit native drivers voor apparatuur hebben natuurlijk de voorkeur. Dit geldt zeker voor schijven. De performance van een driver die int13h gebruikt is namelijk zeer laag. Ik zou dus kunnen beginnen aan het schrijven van een ATA-driver. De interrupt 13h driver moet dan natuurlijk niet werken, anders gebeuren dingen door elkaar. Dit geldt metname voor gebruik van de IRQ: Als de IRQ nog is ingesteld op uitvoeren van de realmode BIOS interrupt-routine, terwijl mijn driver die IRQ ook gebruikt, dan zit die driver maar te wachten op de gegevens.. Het is dus of het een of het ander.
Soms is het echter niet altijd wenselijk om de interrupt 13h-driver helemaal niet meer te gebruiken. Dit is het geval als er schijven in het systeem zitten die (nog) niet door een eigen driver kunnen worden benaderd en schijven die juist wel door een eigen driver kunnen worden benaderd. Zodra je dan toch via interrupt 13h schijven benadert waarvoor al een eigen driver aanwezig is, dan gaat het mis. Dus moet de interrupt 13h driver bepaalde schijven niet meer benaderen, het OS/kernel/loader/whatever moet 'weten' welke schijven door de native drivers moeten worden benaderd en welke door interrupt 13h. Hiervoor is echter vereist dat het (eventuele) bios disknummer (waarde van DL bij aanroep van int 13h functies), van een disk die via een eigen driver wordt banaderd, achterhaald wordt. De grote vraag is hoe dit kan.
Methode 1.
Functie 48h van interrupt 13h biedt de mogelijkheid om het ISA base-adress of de PCI-gegevens bus/device/function op te vragen. Deze zaken zijn ook bij een eigen driver die de controller rechtstreeks benadert bekend, en zo kan achterhaald worden dat deze schijf de schijf is die al door de eigen driver benaderd wordt.
Nadeel: Deze functie behoort tot de IBM/MS int 13h extensions. Wat oudere BIOSsen ondersteunen deze functie niet, en de gegevens van de ISA-interface of PCI-interface waar de schijf aan hangt, zijn pas vanaf versie 3.0 van deze extensies beschikbaar. Zelfs niet alle Pentium BIOSsen kunnen deze gegevens achterhalen
Methode 2.
Fysieke gegevens vergelijken. Werkt niet, want je kunt identieke schijven aan verschilende controllers hangen. Interrupt 13h kan geen serienummers e.d. opvragen om een schijf te identificeren.
Methode 3.
De eerste reeks sectoren lezen en vergelijken. Zijn ze gelijk? Dan aannemen dat het om dezelfde schijf gaat. Nadeel: Als je een stel schijven neemt, allemaal gevuld met nullen (dd if=/dev/zero of=/dev/hda) dan denkt die driver met identieke schijven te maken te hebben terwijl dit niet zo hoeft te zijn.
Methode 4.
Een ID-wegschrijven op de eerste sector. Microsoft pakt het volgens mij sinds Windows 2000 zo aan, aangezien vanaf deze Windows versie een 64-bit nummer in het MBR, vlak voor de partitietabel, wordt geplaatst. Vervelende aan deze methode is het feit dat je tegen de standaarden ingaat. Geen enkele standaard garandeert dat er in het MBR op de 8 bytes voor de partitietabel geen code of andere data staat. Microsoft gaat alleen van haar eigen MBR's uit.. Daarnaast is het zo dat een harddisk geen partitietabel hoeft te bevatten. De eerste sector kan ook een bootsector zijn, als je gewoon een grote data partitie wilt. Unix OS-es kunnen daar prima mee uit de voeten. Ook kan een int 13h device een soort van bijzondere floppy zijn die een BIOS-nummer > 127 krijgt toegewezen dus op een harddisk lijkt maar het stiekum niet is. Kortom, de enige garantie t.a.v. de eerste sector van een schijf is de magische ID 0xAA55 aan het einde. Zomaar waardes gaan schrijven is riskant. Je kunt weliswaar tijdelijke ID's schrijven en de oorspronkelijke bytes later weer netjes terugzetten, maar als midden in het detectie-proces de stroom uitvalt dan zit de gebruiker met verziekte bootsectoren of MBR's. Onwenselijke methode dus vanuit het oogpunt van betrouwbaarheid.
Methode 2 is ook onwenselijk, omdat BIOS-en gegevens van schijven nog al eens anders presenteren als de gegevens die je terugkrijgt bij rechtstreekse benadering van een controller. Berucht zijn natuurlijk de 8 GB en 32 GB grenzen, maar ook geeft het BIOS wel eens een iets kleinere omvang van de schijf terug (een cylinder minder). Conclusie: deze methode is niet betrouwbaar.
Bijven methode 1 en 3 over.
Methode 1 is echter alleen geschikt voor nieuwere BIOSsen en methode 3 is weliswaar betrouwbaar als het gaat om het feilloos detecteren van verschillende schijven maar als de methode detecteert dat een schijf identiek is hoeft dit nog niet zo te zijn. Het kan heel goed zijn dat toevallig de eerste reeks sectoren gelijk aan elkaar zijn. Meerdere megabytes uitlezen is onwenselijk, duurt te lang.
Kortom, het blijft behelpen.
Zijn er hier nog mensen die met hobby OS-en bezig zijn en hier ook mee te maken hebben? Hoe heb je het aangepakt? Of ga je gewoon uit van of alles int 13h of alles via een driver (waarbij dus de kans bestaat dat bepaalde schijven niet kunnen worden benaderd als er een niet-ondersteunde controller tussen zit).
De meeste OSdev-tutorials komen helaas niet verder dan een printf("Wh000t me kernel doet ut");