Lowlevel

Lowlevel => OS-Design => Thema gestartet von: erik.vikinger am 12. February 2011, 12:54

Titel: Was genau ist eigentlich ein "Hardware Abstraction Layer" in einem OS?
Beitrag von: erik.vikinger am 12. February 2011, 12:54
Hallo,


ich habe in den letzten Tagen versucht die Frage aus dem Betreff für mich persönlich zu beantworten und bin dabei leider nicht zu einem ordentlichen/eindeutigen Ergebnis gekommen.

In den entsprechenden Wikipedia-Artikeln (deutsch wie englisch) finden sich teilweise widersprüchliche aber auch teilweise sehr weit gefasste Erklärungen.

Zählt schon ein Mechanismus der einem Treiber die physische Adresse von Geräte-Speicher verrät (so das der Treiber dann direkt mit seiner HW sprechen kann) als HAL oder muss ein richtiger HAL wirklich als "Vermittler" zwischen Treiber und Hardware fungieren (so das der Treiber für jeden HW-Zugriff durch den HAL muss)? Oder zählt eher der OS-Kernel zusammen mit den Treibern als HAL auf dem dann die normalen Programme laufen können ohne sich um HW-Details sorgen zu müssen?


Ich würde dazu gerne mal Eure Meinungen lesen.
Was muss ein HAL Eurer Meinung nach mindestens können damit er diesen Namen verdient?


Grüße
Erik
Titel: Re:Was genau ist eigentlich ein "Hardware Abstraction Layer" in einem OS?
Beitrag von: kevin am 12. February 2011, 13:31
Keine Ahnung. Meine Systeme hatten deswegen auch nie einen Teil, der HAL heißt. ;)
Titel: Re:Was genau ist eigentlich ein "Hardware Abstraction Layer" in einem OS?
Beitrag von: Svenska am 12. February 2011, 16:45
Für mich ist der HAL der Teil eines Kernels, der ihn portierbar macht. Sieht ungefähr so aus:
               << Benutzer
+-----------+
| Anwendung |
+-----------+
               << Userspace-API (z.B. POSIX)
+-----------+
| Kernel    |
+-----------+
               << Kernel-API (z.B. CDI)
+-----------+
| Treiber   |
+-----------+
               << HAL
+-----------+
| Hardware  |
+-----------+
               << Halbleiter
Ein Beispiel ist die Abstraktion eines Bussystems, so dass ein einziger NE2000-Treiber für ISA-, MCA-, PCMCIA-, CardBus- und PCI-Varianten dieser Netzwerkkarten verwendet werden kann.

Der HAL muss nicht als Extrastück existieren, sondern kann auch im Kernel selbst drin sein, ohne so genannt zu werden; es geht auch komplett ohne HAL, dann ist Kernel bzw. Treiber halt nicht ohne weiteres portabel.

Gruß,
Svenska
Titel: Re:Was genau ist eigentlich ein "Hardware Abstraction Layer" in einem OS?
Beitrag von: erik.vikinger am 12. February 2011, 20:19
Hallo,


Keine Ahnung.
Ich muss zugeben das mich diese Antwort etwas beruhigt, ich bin also nicht der einzigste der das nicht weiß.


Für mich ist der HAL der Teil eines Kernels, der ihn portierbar macht. Sieht ungefähr so aus: .....
Ein hübsches Diagramm, aber es sagt mir leider nicht was der HAL genau macht. Gibt er nur ne physische Adresse an den Treiber oder muss der Treiber für alle Zugriffe den HAL benutzen?
(das der Kernel zwischen den Anwendungen und den Treibern sitzt ist wohl Deinem eher monolithischem Welt-Bild zuzuschreiben ;) )

Ein Beispiel ist die Abstraktion eines Bussystems, so dass ein einziger NE2000-Treiber für ISA-, MCA-, PCMCIA-, CardBus- und PCI-Varianten dieser Netzwerkkarten verwendet werden kann.
Mit "Abstraktion eines Bussystems" meinst Du wohl "gibt nur ne physische Adresse an den Treiber" oder?
Aber was nützt das? Welche HW (außer die NE2000) gibt es mit identischer Ansteuerung für unterschiedliche Bus-Systeme?

Der HAL muss nicht als Extrastück existieren, sondern kann auch im Kernel selbst drin sein, ohne so genannt zu werden; es geht auch komplett ohne HAL, dann ist Kernel bzw. Treiber halt nicht ohne weiteres portabel.
Also zumindest das "gibt nur ne physische Adresse an den Treiber" sollte man IMHO nicht weglassen, wenn die Treiber anfangen würden selber z.B. im PCI-Config-Space rum zu murkeln dürfte es recht schnell Probleme geben (auf den PCI-Config-Space kann üblicherweise nicht parallel zugegriffen werden).


Grüße
Erik
Titel: Re:Was genau ist eigentlich ein "Hardware Abstraction Layer" in einem OS?
Beitrag von: bluecode am 12. February 2011, 20:32
Zählt schon ein Mechanismus der einem Treiber die physische Adresse von Geräte-Speicher verrät (so das der Treiber dann direkt mit seiner HW sprechen kann) als HAL oder muss ein richtiger HAL wirklich als "Vermittler" zwischen Treiber und Hardware fungieren (so das der Treiber für jeden HW-Zugriff durch den HAL muss)?
Inwiefern ist der Unterschied relevant?

Zitat
Oder zählt eher der OS-Kernel zusammen mit den Treibern als HAL auf dem dann die normalen Programme laufen können ohne sich um HW-Details sorgen zu müssen?
Das kann man sicher auch so verwenden, aber sicher nicht beim OSDev, sondern eben aus Userspacesicht.
Titel: Re:Was genau ist eigentlich ein "Hardware Abstraction Layer" in einem OS?
Beitrag von: Svenska am 12. February 2011, 21:12
Hallo,

Ein hübsches Diagramm, aber es sagt mir leider nicht was der HAL genau macht. Gibt er nur ne physische Adresse an den Treiber oder muss der Treiber für alle Zugriffe den HAL benutzen?
Das ist ein Implementierungsdetail. Der HAL ist eine Abstraktionsschicht, kein festgelegtes Protokoll. Für verschiedene Ebenen kann es auch unterschiedlich aufgebaut sein; bei ISA-/PCMCIA-Geräten wirst du neben "Adressraum" auch "I/O-Raum" und "DMA-Leitung" abstrahieren müssen, was bei PCI natürlich nicht zielführend ist.

(das der Kernel zwischen den Anwendungen und den Treibern sitzt ist wohl Deinem eher monolithischem Welt-Bild zuzuschreiben ;) )
Meinetwegen reden die Anwendungen auch direkt mit dem Treiber, aber der muss irgendwie auf die Hardware zugreifen. Und das tut er über den HAL, wie ist egal. Wenn er es direkt tut (weil Treiber privilegiert sein können), dann ist dein HAL eben ein Dummy/nicht existent.

Mit "Abstraktion eines Bussystems" meinst Du wohl "gibt nur ne physische Adresse an den Treiber" oder?
Aber was nützt das? Welche HW (außer die NE2000) gibt es mit identischer Ansteuerung für unterschiedliche Bus-Systeme?
Ich weiß, dass du Bussysteme nicht abstrahieren möchtest, wie es fast keiner tut. Grundsätzlich gehört aber mehr dazu als die physische Adresse, nämlich auch die Adresse des Gerätes auf dem Bus (bei I²C eine 7-Bit-Zahl, bei PCI-Geräten Busnummer usw., bei ISA-Geräten die I/O-Leitungen). Dann brauchst du Sende- und Empfangsmöglichkeiten, da nicht jedes Bussystem über MMIO verfügt. Für manche Bussysteme gibt es noch obskure Parameter (Taktgeschwindigkeit bei I²C/SPI) usw.

Für den PCI-Bus läuft das auf einen physischen Speicherbereich hinaus, wenn du den PCI-Adressraum mittels MMIO ansprechen kannst.

Identische Ansteuerung bei verschiedenen Bussystemen hast du inzwischen nur noch selten. Beispiele sind am Parallelport angeschlossene SCSI-Geräte (Scanner, CD-Laufwerke, früher auch Festplatten). Ansonsten betrifft das jegliche Hardware, die über einen Buswandler angeschlossen wird.

In die andere Richtung bringt Busabstraktion auch was, denn eine andere Hardwarearchitektur hat auch einen PCI-Bus, der aber vielleicht ganz anders angesprochen werden muss. Abstrahierst du an der Stelle, funktionieren plötzlich alle Treiber trotzdem. Für dein komplett anders aufgebautes Betriebssystem auf deiner einen komplett anders aufgebauten Hardwareplattform ist alles das natürlich nicht relevant, da brauchst du auch nichts, was sich irgendwie HAL nennen könnte.

Gruß,
Svenska
Cheftheoretiker
Titel: Re:Was genau ist eigentlich ein "Hardware Abstraction Layer" in einem OS?
Beitrag von: FlashBurn am 12. February 2011, 22:44
Ich würde sogar soweit gehen, bestimmte Treiber mit in den HAL zu packen. So wäre ein Bsp. für nen HAL der Timer-Treiber. Ich will immer das selbe Interface haben und was dahinter passiert ist mir egal.
Das würde dann also eigentlich auf alle Standard-Geräte-Treiber zutreffen (Grafik, Sound, Eingabe, Speichermedien usw.).

Ansonsten wüsste ich auch nicht wie ich nen HAL definieren würde.
Titel: Re:Was genau ist eigentlich ein "Hardware Abstraction Layer" in einem OS?
Beitrag von: kevin am 13. February 2011, 10:34
Bleiben dann überhaupt noch Treiber übrig? ;)
Titel: Re:Was genau ist eigentlich ein "Hardware Abstraction Layer" in einem OS?
Beitrag von: FlashBurn am 13. February 2011, 11:23
Nicht wirklich ;)

Im Endeffekt ist ein HAL auch "nur" ein Interface, was halt immer gleich bleibt, egal was für Hardware dahinter steckt.
Noch ein Bsp. wäre das Mappen einer Page. Denn es ist egal wieviele Page-Level dahinter stecken, ist immer das gleiche Interface.
Titel: Re:Was genau ist eigentlich ein "Hardware Abstraction Layer" in einem OS?
Beitrag von: erik.vikinger am 13. February 2011, 11:41
Hallo,


Inwiefern ist der Unterschied relevant?
Zum einen beeinflusst das sicher massiv die Performance und zum anderen ist es IMHO schon ein wesentlicher konzeptioneller Unterschied ob Speicher einfach eingeblendet (in den Treiber-Kontext reingemappt) wird um dann damit direkt zu arbeiten oder ob man für jeden Zugriff durch eine Art Service muss. Da IMHO heute jede Architektur auf linearem Speicher basiert bringt es also absolut nichts den Speicher wegzuabstrahieren so das es offensichtlich praktischer ist ihn einfach in den Treiber einzublenden.

Das kann man sicher auch so verwenden, aber sicher nicht beim OSDev, sondern eben aus Userspacesicht.
Ist mir klar, aber es ist eben meine Frage ob dann das gesamte OS (zumindest die niederen Schichten bestehend aus Kernel und Treibern) als ne Art HAL zu betrachten ist.


Das ist ein Implementierungsdetail. Der HAL ist eine Abstraktionsschicht, kein festgelegtes Protokoll.
Hm, das ist richtig aber irgendwie keine Antwort auf meine Frage. Gerade um dieses Implementierungsdetail geht es mir ja eigentlich, was genau ist es das einen HAL definiert oder darf das jeder nach eigenem Geschmack und Bedarf frei festlegen?
In allen relevanten OSen gibt es etwas das HAL genannt wird und so weit ich das überblicken kann ist das meistens recht dünn aufgebaut (also eher die Variante "gibt nur ne physische Adresse an den Treiber").

Meinetwegen reden die Anwendungen auch direkt mit dem Treiber, aber der muss irgendwie auf die Hardware zugreifen. Und das tut er über den HAL, wie ist egal.
Nein, mir ist das für diese Frage nicht egal. Gerade um dieses wie geht es mir doch.

Wenn er es direkt tut (weil Treiber privilegiert sein können), dann ist dein HAL eben ein Dummy/nicht existent.
Für direkten Zugriff auf Speicher muss kein Programm privilegiert sein es reicht wenn das OS ihm die gewünschten Speicherbereiche zugänglich macht (was zwar auch wieder eine Art von Privileg ist aber eben rein in SW und nicht in HW in Form von Ring 0 o.ä.).

Ich weiß, dass du Bussysteme nicht abstrahieren möchtest
Ich würde das anders formulieren: ich möchte nichts machen das mir keinen Vorteil bringt und das Abstrahieren von BUS-Systemen bringt eben keinen. Selbst auf einem klassischen PC (von Heute) ist der Floppy-Controller die absolut letzte Komponente die noch auf ISA (inklusive ISA-DMA) basiert so das ich persönlich ganz klar empfehlen würde den ganzen ISA-Kram (inklusive ISA-DMA) direkt in den Floppy-Treiber zu integrieren und das ganze als einen Blob zu betrachten.

wie es fast keiner tut.
Ja eben, wozu auch. Die NE2000 ist die einzigste mir bekannte HW die es auf mehr als einem BUS-System gab und zwar so das man mit dem selben Treiber arbeiten konnte. Ich kenne keine weitere HW auf die das zutrifft. Gemessen daran erscheint mir (und wohl auch anderen) der Aufwand die Busse zu abstrahieren dann doch zu hoch.

Grundsätzlich gehört aber mehr dazu als die physische Adresse, nämlich auch die Adresse des Gerätes auf dem Bus (bei I²C eine 7-Bit-Zahl, bei PCI-Geräten Busnummer usw., bei ISA-Geräten die I/O-Leitungen).
Das ist ein sehr schönes Beispiel. PCI ist wimre der einzigste Bus der es mit standardisierten On-Board-Mitteln erlaubt die physische Position (also die reale Slot-Nummer auf dem Main-Board) zu ermitteln, sogar über mehrere Gehäuse hinweg (für PCI gibt es ja solche tollen externen PCI-Erweiterungs-Boxen wo man noch ein paar zusätzliche Karten unterbringen kann). Aber die SW kann mit diesen Informationen üblicherweise kaum was anfangen so dass das wohl nicht ganz dem entspricht worauf ich mit meiner Frage hinaus wollte.

Dann brauchst du Sende- und Empfangsmöglichkeiten, da nicht jedes Bussystem über MMIO verfügt.
Prominentes Beispiel wäre der USB. Aber alle diese Busse die nicht direkt für die CPU erreichbar sind stellen doch eh eine ganz andere Kategorie dar. Eben weil sie nicht für die CPU (und der darauf laufenden SW) erreichbar sind müssen die mit einem Host-Controller-Treiber abstrahiert werden. Ist das dann eine Art von HAL?

In die andere Richtung bringt Busabstraktion auch was, denn eine andere Hardwarearchitektur hat auch einen PCI-Bus, der aber vielleicht ganz anders angesprochen werden muss. Abstrahierst du an der Stelle, funktionieren plötzlich alle Treiber trotzdem.
Ich nehme an Du meinst den Zugriff auf den PCI-Config-Space. Ja der sollte immer über einen Service vom OS-Kernel laufen und zwar nicht nur wegen der Portabilität sondern auch weil diese Zugriffe serialisiert werden müssen. Ich denke für PCI ist das die minimalste Anforderung an einen HAL, aber reicht das damit der Name HAL auch berechtigt ist?

Cheftheoretiker
Genau deswegen hatte ich gehofft das auch Du Dich an dieser Frage beteiligst. ;)
Ich möchte eher eine akademische Antwort auf meine Frage als eine Aufzählung praktischer Umsetzungen.


Ich würde sogar soweit gehen, bestimmte Treiber mit in den HAL zu packen. So wäre ein Bsp. für nen HAL der Timer-Treiber....
Auch der "Treiber" für den Interrupt-Controller gehört in diese Kategorie. Es gibt also einige Geräte die so elementar sind das sie direkt im OS-Kernel bzw. dessen HAL-Schicht behandelt werden müssen.

Ansonsten wüsste ich auch nicht wie ich nen HAL definieren würde.
Da sind wir hier wohl recht viele. ;)


Mein ersten Fazit (nach weniger als 24 Stunden): wirklich genau weiß das hier wohl auch keiner.
Offensichtlich ist die Antwort auf meine Frage dermaßen akademisch das sie in der hier gelebten Praxis keine Rolle spielt.


Grüße
Erik
Titel: Re:Was genau ist eigentlich ein "Hardware Abstraction Layer" in einem OS?
Beitrag von: FlashBurn am 13. February 2011, 11:56
Das Problem ist wahrscheinlich auch, aus welcher Sicht willst du wissen was der HAL ist? Denn z.B. aus Kernel-sicht wäre es halt, das du viele Sachen immer über das selbe Interface (z.B. Timer, Irqs) nutzen kannst. Aus Sicht der Treiber ist es wichtig, das sie auch immer das selbe Interface haben, ob nun z.B. per USB oder per PCI angebunden (ob das so möglich ist, bin ich mir gar nicht so sicher).

Aber der eigentliche Grund sowas wie nen HAL zu haben, ist portabilität (und auch Einfachheit für z.B. den Treiber-Programmierer)! Wenn du das nicht brauchst, kannst du ihn dir eigentlich auch sparen.
Titel: Re:Was genau ist eigentlich ein "Hardware Abstraction Layer" in einem OS?
Beitrag von: Svenska am 13. February 2011, 15:10
Hallo,

Das ist ein Implementierungsdetail. Der HAL ist eine Abstraktionsschicht, kein festgelegtes Protokoll.
Gerade um dieses Implementierungsdetail geht es mir ja eigentlich, was genau ist es das einen HAL definiert oder darf das jeder nach eigenem Geschmack und Bedarf frei festlegen?
Dann hast du die falsche Frage gestellt: Du willst nicht wissen, was ein HAL ist, sondern wie du es konkret implementieren musst. ;-)

Gerade um dieses wie geht es mir doch.

Selbst auf einem klassischen PC (von Heute) ist der Floppy-Controller die absolut letzte Komponente die noch auf ISA (inklusive ISA-DMA) basiert so das ich persönlich ganz klar empfehlen würde den ganzen ISA-Kram (inklusive ISA-DMA) direkt in den Floppy-Treiber zu integrieren und das ganze als einen Blob zu betrachten.
An der Stelle ist dein HAL für ISA-DMA nicht existent, der Treiber muss die Privilegien besitzen, um auf dem Bus seine Dinge tun zu dürfen.

PCI ist wimre der einzigste Bus der es mit standardisierten On-Board-Mitteln erlaubt die physische Position (also die reale Slot-Nummer auf dem Main-Board) zu ermitteln, sogar über mehrere Gehäuse hinweg (für PCI gibt es ja solche tollen externen PCI-Erweiterungs-Boxen wo man noch ein paar zusätzliche Karten unterbringen kann).
Du vergisst den MCA, dort ging das auch. Aber es gab m.W. keine MCA-auf-MCA-Brücken.

Aber alle diese Busse die nicht direkt für die CPU erreichbar sind stellen doch eh eine ganz andere Kategorie dar.
Es sind trotzdem Busse. Und wenn du eine USB-PCI-Bridge haben könntest, dann liegt dahinter irgendwo trotzdem ein PCI-Bus.

Eben weil sie nicht für die CPU (und der darauf laufenden SW) erreichbar sind müssen die mit einem Host-Controller-Treiber abstrahiert werden. Ist das dann eine Art von HAL?
Um mal das Beispiel der USB-PCI-Bridge zu nehmen: Wenn du soetwas anschließt und dieses Teil als PCI-Bus an dein Betriebssystem einbindest und alle Treiber für PCI-Geräte funktionieren damit, dann hast du eine Busabstraktion (Hardwareabstraktion für PCI), also ein HAL, den du im Gerätetreiber für diese Bridge implementierst. Eine weitere Implementation des gleichen HALs liegt dann im Kernel für den normalen, CPU-erreichbaren, MMIO-addressierbaren PCI-Bus.

Ich nehme an Du meinst den Zugriff auf den PCI-Config-Space. Ja der sollte immer über einen Service vom OS-Kernel laufen und zwar nicht nur wegen der Portabilität sondern auch weil diese Zugriffe serialisiert werden müssen.
Damit hast du schlagartig ein HAL für PCI erfunden. Es abstrahiert zwar nur PCI, aber es macht PCI-Gerätetreiber (theoretisch) unabhängig von der Hardware, in der der PCI-Bus verbaut ist.

Ich denke für PCI ist das die minimalste Anforderung an einen HAL, aber reicht das damit der Name HAL auch berechtigt ist?
Wenn du es dann HAL nennst, ja. Nennst du es anders, nein.

HAL ist nur eine Abstraktion für dich. Je portabler dein Betriebssystem sein muss, desto dicker muss diese Schicht sein, umso mehr potentielle Unterschiede muss sie abstrahieren können.

Oder ein anderes Beispiel; ich habe einen Microcontroller (STM32) für USB-Host-Operation programmiert. Der Treiber für diesen Controller (kein *HCI, sondern USB_OTG_FS), hatte im Kopf eine Menge #defines, welche die Pins und die GPIOs angeben, an denen der Baustein angeschlossen ist. Prinzipiell ist das auch schon ein "HAL". Denn es macht den USB-Treiber unabhängig von den konkreten Pins des Microcontrollers. Mehr ist als HAL auch nicht nötig, da es eine CPU-interne Logik ist, die nur auf ähnlichen Controllern existieren kann.

In deinem konkreten Fall brauchst du keine extra deklarierte HAL, da du genau eine Architektur hast. Und da bei dir ja alles MMIO-adressierbar ist, reicht also ein Syscall "gib mir physischen Speicher" für die systemweise HAL aus.

Die HAL für USB wird bei dir schon etwas dicker werden; optimalerweise ist sie sämtlicher Code, der in jedem Treiber vorhanden sein muss. Ich hoffe, die Ausführungen helfen...

Ich würde sogar soweit gehen, bestimmte Treiber mit in den HAL zu packen. So wäre ein Bsp. für nen HAL der Timer-Treiber....
Treiber sind kein HAL - HAL ist eine Hardwareabstraktionsschicht.

Die API, wie man einen Treiber anspricht und wie man Informationen über dessen Fähigkeiten (Auflösung, Zählweite, Interruptfähigkeit) bekommt, ist eine Hardwareabstraktion eines Timers. Für Interruptcontroller ist das ähnlich; welche Interrupts gibt es, wie sind sie geroutet, wie registriert/entfernt man einen Interrupthandler und was muss man in einem solchen beachten gehören in eine API. Diese API abstrahiert dann Interrupts.

Die Summe aller solcher APIs, die jeweils ein Stückchen Hardware abstrahieren, ist der HAL.
Und ob man den jetzt so nennt oder nicht, ist unerheblich.

Gibt es dazu Einwände/Widersprüche?

Offensichtlich ist die Antwort auf meine Frage dermaßen akademisch das sie in der hier gelebten Praxis keine Rolle spielt.
Wie willst du eine Abstraktion allgemein erklären? Es geht schließlich auch ohne...

Gruß,
Svenska
Titel: Re:Was genau ist eigentlich ein "Hardware Abstraction Layer" in einem OS?
Beitrag von: erik.vikinger am 13. February 2011, 15:13
Hallo,


Das Problem ist wahrscheinlich auch, aus welcher Sicht willst du wissen was der HAL ist?
Es geht mir eher um die akademische/theoretische Sicht: Was ist ein HAL? Was sind seine Aufgaben?

Aber der eigentliche Grund sowas wie nen HAL zu haben, ist portabilität (und auch Einfachheit für z.B. den Treiber-Programmierer)! Wenn du das nicht brauchst, kannst du ihn dir eigentlich auch sparen.
Ich denke ein HAL dient zu mehr als nur zur Portabilität. Wozu hat Windows einen HAL?
Wenn ein Treiber über eine zentrale Stelle die Ressourcen seines Gerätes holen kann dann ist das IMHO besser als wenn der Treiber selber anfangen müsste z.B. im PCI-Config-Space nach seinen Geräten und deren Ressourcen zu suchen (das wäre ja quasi wie ein Rückschritt in die Zeit als proben noch angesagt war). Also steht da auch ganz klar Einfachheit für den Treiberprogrammierer und die Vermeidung von doppelten Code ganz vorne.
Auch das Abstrahieren des Interrupt-Controllers ist eigentlich unumgänglich weil sonst der Kernel den Überblick verliert (vor allem bei geshareten IRQs). Darüber das wir nicht mehr (so wie zu seligen DOS-Zeiten) mit jedem Programm in der IDT rummurkseln und wild Interrupts hooken müssen sind wir doch eigentlich sehr froh. Oder?


@Svenska:
Zu Deinem Diagramm von gestern Nachmittag hab ich noch eine Frage: Wieso ist der Benutzer (ich nehme mal an das Du damit den Menschen meinst) ganz oben und kommuniziert direkt mit den Anwendungen (ich nehme mal an das Du damit die normalen User-Space-Applikationen meinst)? Ich persönlich habe noch nie mit einer Anwendung direkt kommuniziert, ich konnte bisher immer nur mit der Hardware eines Computers interagieren. Eigentlich müsste Dein Diagramm komplett andersherum aufgebaut sein bis auf den Benutzer der muss oben bleiben. IMHO sind die Applikationen die am tiefsten versteckteste Komponente in einem Computer.



Grüße
Erik
Titel: Re:Was genau ist eigentlich ein "Hardware Abstraction Layer" in einem OS?
Beitrag von: Svenska am 13. February 2011, 15:32
Ich denke ein HAL dient zu mehr als nur zur Portabilität. Wozu hat Windows einen HAL?
Der Windows NT-Kernel ist unglaublich portabel. Er läuft auf mehreren Prozessorarchitekturen mit jeweils darunterliegenden Systemarchitekturen. Und weil er dafür ursprünglich mal erdacht wurde, gibt es eine entsprechend ausgezeichnete Hardwareabstraktion. Bei NetBSD ist das ähnlich.

Auf der anderen Seite steht Linux, welches nie für Portabilität entwickelt wurde. Dort gibt es ursprünglich auch keinen HAL, sondern jedes Subsystem selbst bringt eine eigene Hardwareabstraktion mit. Die Summe aller Teile ist dann trotzdem ein HAL, aber es gibt keine Stelle, wo du ihn finden könntest.

Also steht da auch ganz klar Einfachheit für den Treiberprogrammierer und die Vermeidung von doppelten Code ganz vorne.
Das ist der Sinn einer jeden Abstraktion. ;-)

Auch das Abstrahieren des Interrupt-Controllers ist eigentlich unumgänglich weil sonst der Kernel den Überblick verliert (vor allem bei geshareten IRQs).
Naja, eher nicht. Ein Treiber für den Interruptcontroller führt einfach zu sauberer Programmierung; der Kernel selbst (als privilegiertes Medium; ja ich weiß, monolithisches Denken) könnte ja auch ständig direkt in dessen Registern rumpfuschen und fröhlich Interrupts hooken, ohne den Überblick zu verlieren. (So ähnlich funktioniert mein System auf dem Microcontroller, aber da gibt es nur drei relevante Interrupts, kein IRQ-Sharing und nur 64K RAM. Und der Code ist von der Menge her noch erträglich.)

Wenn du einen Interrupt-Controllertreiber schreibst, dann hast du die Möglichkeit, mehrere identische dieser zu verwenden (2 PICs), außerdem kannst du es auf eine andere Architektur portieren, die z.B. andere Interruptmechanismen benutzt.

Zu Deinem Diagramm von gestern Nachmittag hab ich noch eine Frage: Wieso ist der Benutzer (ich nehme mal an das Du damit den Menschen meinst) ganz oben und kommuniziert direkt mit den Anwendungen (ich nehme mal an das Du damit die normalen User-Space-Applikationen meinst)?
Das ist eine Frage der Richtung, aus der du auf ein System draufguckst. Der typische Benutzer sieht ein Fenster mit Word drin und der Computer ist "der graue Kasten unterm Tisch". Es geht ihm nicht darum, die Maus zu bewegen, sondern er "klickt auf den Druckerbutton und dann kommt bedrucktes Papier aus dem Drucker".

Ich persönlich habe noch nie mit einer Anwendung direkt kommuniziert, ich konnte bisher immer nur mit der Hardware eines Computers interagieren.
Dein Ziel ist es aber, die Anwendung zu bedienen. Die Anwendung wiederum stellt die Schnittstelle zwischen dem Benutzer und dem Betriebssystem dar. Das Betriebssystem steuert die Hardware an (oder sitzt der Benutzer mit einem Taktgeber vorm Bildschirm und taktet die Pixel da rein? :-P) und um das zu tun, bedient sich das Betriebssystem eines Treibers.

Das ist die Sichtweise des Systems.

Eigentlich müsste Dein Diagramm komplett andersherum aufgebaut sein bis auf den Benutzer der muss oben bleiben. IMHO sind die Applikationen die am tiefsten versteckteste Komponente in einem Computer.
Der Benutzer bedient Hardware, die wiederum einen Treiber erfordert, damit sie mit dem Betriebssystem kommunizieren kann und am Ende der Kette sitzt die Anwendung, die dann die entsprechende Aktion ausführt.

Das ist die Sichtweise des Datenflusses.

Gruß,
Svenska
Titel: Re:Was genau ist eigentlich ein "Hardware Abstraction Layer" in einem OS?
Beitrag von: kevin am 13. February 2011, 22:08
Ist also CDI der HAL von tyndur?
Titel: Re:Was genau ist eigentlich ein "Hardware Abstraction Layer" in einem OS?
Beitrag von: Svenska am 13. February 2011, 22:35
CDI ist, soweit ich das verstehe, die API, über die das Betriebssystem mit Treibern kommuniziert. Die Treiber selbst nutzen den HAL, um mit der Hardware zu kommunizieren. Also ist CDI erstmal kein HAL für Tyndur.

Ein CDI-Treiber für PCI wäre somit Teil des HAL, ein CDI-Treiber für Netzwerkkarten nicht.
Titel: Re:Was genau ist eigentlich ein "Hardware Abstraction Layer" in einem OS?
Beitrag von: kevin am 13. February 2011, 22:39
Hm, es gibt zwei Teilaspekte, würde ich sagen: Zum einen abstrahiert CDI für das OS die Hardware, die der Treiber ansteuert weg, so dass das OS einfach nur eine Netzwerkkarte statt einer e1000 ansteuert (das geht wohl in die Richtung dessen, was oben genannt wurde, nämlich dass das ganze OS ein HAL für Programme ist), zum anderen abstrahiert es aber auch für den Treiber wiederum die tieferen Schichten. Wenn ein Treiber z.B. Speicher braucht oder einen IRQ haben will, ruft er wieder eine CDI-Funktion auf.
Titel: Re:Was genau ist eigentlich ein "Hardware Abstraction Layer" in einem OS?
Beitrag von: erik.vikinger am 14. February 2011, 11:01
Hallo,


Dann hast du die falsche Frage gestellt: Du willst nicht wissen, was ein HAL ist, sondern wie du es konkret implementieren musst. ;-)
Nein nein, wie ich in meinem konkreten Projekt den Treibern ermöglichen möchte ihre Geräte zu finden und anzusprechen weiß ich recht genau, die Frage die sich mir stellt: "ist das was ich in meinem OS haben möchte wirklich ein HAL oder ganz was anderes oder eine Mischform?" und deswegen hätte ich gerne eine möglichst allgemeingültige Definition was genau ein HAL in einem typischen OS ist.

Du vergisst den MCA, dort ging das auch. Aber es gab m.W. keine MCA-auf-MCA-Brücken.
Hä, was willst Du damit sagen? Ich vermute das wir beide in diesem Forum (fast) die einzigsten sind die überhaupt eine einigermaßen konkrete Vorstellung vom MCA haben wobei ich ehrlich sagen muss das ich noch nie in meinem Leben MCA-Hardware mit eigenen Augen gesehen oder mit eigenen Händen berührt hab (im Gegensatz zu EISA). Ein seit 20 Jahren totes Bussystem als Gegenbeispiel aufzuführen ist IMHO nicht zweckdienlich. Nebst dessen das MCA zwar P&P hatte aber wimre nicht in der Lange war die Karten ihrer realen physischen Position auf dem Main-Board (Slot-Nummer o.ä.) zuzuordnen.

Es sind trotzdem Busse. Und wenn du eine USB-PCI-Bridge haben könntest, dann liegt dahinter irgendwo trotzdem ein PCI-Bus.
Ich finde Du klammerst Dich zu arg an dem Wort Bus fest. ;)
Nur weil USB und PCI beides als Busse bezeichnet werden (obwohl beides, zumindest seit PCI-Express, nur reine geswitchte Punkt-zu-Punkt-Verbindungen sind) heißt das noch lange nicht das es dort konzeptionelle Gemeinsamkeiten gibt! PCI kennst Speicher- und IO-Ressourcen und jeder Teilnehmer kann welche anbieten aber auch selbstständig auf die Angebote anderer Teilnehmer zugreifen (der nicht PCI-konforme Teil des PC, also CPUs und Haupt-Speicher, wird hinter der Host-Bridge wegabstrahiert, aus Sicht der restlichen PCI-Komponenten). USB hingegen kennt nur Kommunikations-Pipelines die auch immer mit einem Ende bei einem Host-Controller (quasi der Wurzel des USB-Baums) enden müssen und auch nur der Host kann von sich aus aktiv werden alle Devices müssen grundsätzlich auf das Polling vom Host warten (ja ich weiß es gibt noch USB-2-Go aber das macht wimre auch nicht so viele Änderungen an den USB-Grundkonzepten). Zwischen PCI und USB gibt es IMHO keine funktionalen Übereinstimmungen so das es wohl absoluter Blödsinn ist beide hinter einer gemeinsamen Abstraktion zu verstecken, nebst dessen das es keine Geräte mit identischer Ansteuerung für PCI und USB gibt (geht einfach nicht da die Konzepte zu unterschiedlich sind). Noch nicht einmal die Vendor-IDs sind identisch vergeben so das man schon bei den elementarsten P&P-Funktionen zwischen PCI und USB unterschieden muss.
PCI mit I²C oder SPI in einen Topf zu werfen macht IMHO noch viel weniger Sinn da die Unterschiede nur noch mehr werden.

Um mal das Beispiel der USB-PCI-Bridge zu nehmen: Wenn du soetwas anschließt und dieses Teil als PCI-Bus an dein Betriebssystem einbindest und alle Treiber für PCI-Geräte funktionieren damit, dann hast du eine Busabstraktion (Hardwareabstraktion für PCI), also ein HAL, den du im Gerätetreiber für diese Bridge implementierst. Eine weitere Implementation des gleichen HALs liegt dann im Kernel für den normalen, CPU-erreichbaren, MMIO-addressierbaren PCI-Bus.
Wenn man wirklich PCI über USB tunneln möchte (was sicher irgendwie funktionieren könnte wenn auch nicht sonderlich gut) dann wäre dieser Tunnel für die PCI-Hardware und die Treiber völlig transparent (also aus PCI-Sicht unsichtbar), anders lassen sich Dinge wie Busmasterring oder klassische Interrupts der Geräte hinter dem Tunnel nicht realisieren. Klar benötigt dieser Tunnel eine Konfiguration aber ein HAL ist das IMHO absolut nicht (weil ja für die PCI-Geräte und PCI-Treiber alles so bleibt wie es die PCI-Spec festlegt).

Ich nehme an Du meinst den Zugriff auf den PCI-Config-Space. Ja der sollte immer über einen Service vom OS-Kernel laufen und zwar nicht nur wegen der Portabilität sondern auch weil diese Zugriffe serialisiert werden müssen.
Damit hast du schlagartig ein HAL für PCI erfunden. Es abstrahiert zwar nur PCI, aber es macht PCI-Gerätetreiber (theoretisch) unabhängig von der Hardware, in der der PCI-Bus verbaut ist.
Das ist maximal ein HAL für den PCI-Config-Space aber nicht für PCI als ganzes.

hatte im Kopf eine Menge #defines, welche die Pins und die GPIOs angeben, an denen der Baustein angeschlossen ist. Prinzipiell ist das auch schon ein "HAL". Denn es macht den USB-Treiber unabhängig von den konkreten Pins des Microcontrollers.
Hm, also wenn das schon als HAL zählt dann ist der HAL wirklich einfach eine recht freie Sache die jedes OS für sich individuell definieren kann.
Das soll keine Wertung des Mikrocontroller-Codes sein, so oder so ähnlich hätte ich das sicher auch realisiert, aber es zeigt eben dass das was man unter einem HAL versteht doch sehr differenziert sein kann.

In deinem konkreten Fall brauchst du keine extra deklarierte HAL, da du genau eine Architektur hast. Und da bei dir ja alles MMIO-adressierbar ist, reicht also ein Syscall "gib mir physischen Speicher" für die systemweise HAL aus.
Falls ich mein OS jemals auf x86 portieren sollte (was sich nicht lohnt weil Segmentierung im 64Bit-Modus ja leider abgeschafft wurde also nur ein reines 32Bit-System entstehen kann) dann sehe ich momentan keine konzeptionellen Hindernisse, ich denke das alles was ich bis jetzt an Konzepten entwickelt habe auch auf x86 funktionieren würde (wenn auch vieles davon nicht so elegant wie auf einer HW die speziell nach meinen Wünschen designt wurde).

Die HAL für USB wird bei dir schon etwas dicker werden; optimalerweise ist sie sämtlicher Code, der in jedem Treiber vorhanden sein muss.
Ich hoffe nicht das ich identischen Code in allen Treibern haben muss (automatisch generierte IPC-Stubs zählen da jetzt mal nicht), das ist ja gerade das was ich mit einer Abstraktion vermeiden will.


Ich würde sogar soweit gehen, bestimmte Treiber mit in den HAL zu packen. So wäre ein Bsp. für nen HAL der Timer-Treiber....
Treiber sind kein HAL - HAL ist eine Hardwareabstraktionsschicht.
Das heißt also der HAL abstrahiert z.B. den PCI-Config-Space aber benutzt seinerseitz wieder einen austauschbaren Treiber der dann den Zugriff tatsächlich durchführt? Aber was bleibt dann für den HAL selber übrig?


Die Summe aller solcher APIs, die jeweils ein Stückchen Hardware abstrahieren, ist der HAL.
Das trifft aber auch auf Treiber zu oder auf das OS als ganzes (aus Sicht der Applikationen).

Wie willst du eine Abstraktion allgemein erklären? Es geht schließlich auch ohne...
Nur weil man ohne eine Abstraktion auskommen kann heißt das IMHO nicht das man eine Abstraktion nicht erklären könnte. ;) Aber ich merke das meine Frage einen ungeahnten Schwierigkeitsgrad hat.


Ein Treiber für den Interruptcontroller führt einfach zu sauberer Programmierung; der Kernel selbst (als privilegiertes Medium; ja ich weiß, monolithisches Denken) könnte ja auch ständig direkt in dessen Registern rumpfuschen und fröhlich Interrupts hooken, ohne den Überblick zu verlieren.
Der eigentliche Kernel hat aber für die HW-IRQs gar keine Verwendung, der muss diese an die Treiber weiter vermitteln und mit einer möglichst guten API anbieten. IRQs müssen IMHO auf allen größeren CPU-Architekturen durch den Kernel gehen weil die ja immer einen Modus-Wechsel verursachen (ja ich weiß das x86 da mit seinen Task-Gates eine Sonderrolle einnimmt).

So ähnlich funktioniert mein System auf dem Microcontroller, aber da gibt es nur drei relevante Interrupts, kein IRQ-Sharing und nur 64K RAM. Und der Code ist von der Menge her noch erträglich.
Klar, weil Du ein sauber abgetrenntes System hast, aber das ist nicht mit einem General-Purpose-OS vergleichbar.

Der typische Benutzer sieht ein Fenster mit Word drin und der Computer ist "der graue Kasten unterm Tisch". Es geht ihm nicht darum, die Maus zu bewegen, sondern er "klickt auf den Druckerbutton und dann kommt bedrucktes Papier aus dem Drucker".
Sorry, aber das kannst Du Deiner Oma so erklären, hier sind wir auf lowlevel.eu und da ist diese Art von Erklärung IMHO weniger geeignet.  ;)  SCNR

Dein Ziel ist es aber, die Anwendung zu bedienen.
Absolut richtig, trotzdem kann ich als OS-Dever nicht den langen und komplizierten Weg der Informationen vom User bis zur eigentlichen Applikation und zurück ignorieren.

Der Benutzer bedient Hardware, die wiederum einen Treiber erfordert, damit sie mit dem Betriebssystem kommunizieren kann und am Ende der Kette sitzt die Anwendung, die dann die entsprechende Aktion ausführt.
Exakt.


Hm, es gibt zwei Teilaspekte ....
Eben genau deswegen ist es offensichtlich so enorm schwierig den HAL als Einzel-Komponente exakt zu definieren. Was wir als HAL betrachten das hängt sehr davon ab aus welcher Richtung wir schauen und wie das umgebende OS aufgebaut ist.


Es erscheint mir wirklich so das die Definition des HAL eine sehr subjektive und dehnbare Angelegenheit ist. Ich bin also einer Antwort auf meine ursprüngliche Frage nicht wirklich näher gekommen, schade. Ich danke Euch trotzdem für Eure Mithilfe.


Grüße
Erik
Titel: Re:Was genau ist eigentlich ein "Hardware Abstraction Layer" in einem OS?
Beitrag von: kevin am 14. February 2011, 11:28
Damit sind wir also zum Ergebnis gekommen, dass Namen Schall und Rauch sind. Nichts neues eigentlich. ;)
Titel: Re:Was genau ist eigentlich ein "Hardware Abstraction Layer" in einem OS?
Beitrag von: erik.vikinger am 14. February 2011, 12:43
Hallo,


Damit sind wir also zum Ergebnis gekommen, dass Namen Schall und Rauch sind. Nichts neues eigentlich. ;)
Tja, offensichtlich. :(


Und was ist nun die Moral von der Geschicht? Den HAL den gibt es nicht!


Grüße
Erik
Titel: Re:Was genau ist eigentlich ein "Hardware Abstraction Layer" in einem OS?
Beitrag von: kevin am 14. February 2011, 12:45
Und wer fixt jetzt http://www.lowlevel.eu/wiki/HAL (http://www.lowlevel.eu/wiki/HAL)? ;)
Titel: Re:Was genau ist eigentlich ein "Hardware Abstraction Layer" in einem OS?
Beitrag von: erik.vikinger am 14. February 2011, 13:35
Hallo,


Und wer fixt jetzt http://www.lowlevel.eu/wiki/HAL (http://www.lowlevel.eu/wiki/HAL)? ;)
Eigentlich wollte ich ja auf den Fragesteller verweisen aber ich hab dann doch mal schnell ein paar Zeilen dazu gepackt. Ich hoffe das ist so richtig.


Grüße
Erik
Titel: Re:Was genau ist eigentlich ein "Hardware Abstraction Layer" in einem OS?
Beitrag von: Svenska am 14. February 2011, 21:52
Nachdem wir uns einig sind, dass ein HAL eine Abstraktion ohne Code ist, kann ich ja noch ein bisschen Senf draufkippen.

Du vergisst den MCA, dort ging das auch. Aber es gab m.W. keine MCA-auf-MCA-Brücken.
Nebst dessen das MCA zwar P&P hatte aber wimre nicht in der Lange war die Karten ihrer realen physischen Position auf dem Main-Board (Slot-Nummer o.ä.) zuzuordnen.
Die Ressourcen einer MCA-Karte sind m.W. von ihrer physischen Slot-Position abhängig.

Es sind trotzdem Busse. Und wenn du eine USB-PCI-Bridge haben könntest, dann liegt dahinter irgendwo trotzdem ein PCI-Bus.
Ich finde Du klammerst Dich zu arg an dem Wort Bus fest. ;)
Eine Frage der Sichtweise. Ein Bus ist für mein Verständnis das Teil, wo ich Daten auf einer Seite reingebe und Daten auf der anderen Seite rauskommen. Das schließt I²C, SPI und USB mit ein.

Dass du unter Bus etwas PCI-artiges verstehst, ist eine andere Sichtweise. Wenn du nur hochgezüchtete Bussysteme als Bus bezeichnen möchtest, fallen die simplen µC-Busse natürlich aus dem Rahmen.

Ich betrachte den ganzen Krempel eher aus Sicht der Software, also schaue ich durch die Abstraktion auf den physischen Teil. Und da besteht ein Bus in erster Linie aus Daten, die hindurchgehen, die ein Ziel (oder eine Quelle) haben. Dazu kommt dann noch ein Anteil durch die Abstraktion rein, der die Unterschiede zwischen den Bussen wegabstrahiert. Also Erkennung angeschlossener Geräte (Probing oder harte Konfiguration eingeschlossen), die Konfiguration der Ressourcen (auf Hardwareseite), Übermittlung von Ereignissen (HotPnP, Überspannung) und so weiter.

Am Ende ist der Bus nur ein Medium, wo du Daten reinkippen und rausholen kannst.

PCI kennst Speicher- und IO-Ressourcen und jeder Teilnehmer kann welche anbieten aber auch selbstständig auf die Angebote anderer Teilnehmer zugreifen.
USB hingegen kennt nur Kommunikations-Pipelines die auch immer mit einem Ende bei einem Host-Controller (quasi der Wurzel des USB-Baums) enden müssen und auch nur der Host kann von sich aus aktiv werden alle Devices müssen grundsätzlich auf das Polling vom Host warten.
Das sind Unterschiede, die durch eine gute Abstraktion vernichtet werden sollten.

Zwischen PCI und USB gibt es IMHO keine funktionalen Übereinstimmungen so das es wohl absoluter Blödsinn ist beide hinter einer gemeinsamen Abstraktion zu verstecken, nebst dessen das es keine Geräte mit identischer Ansteuerung für PCI und USB gibt.
Aha. Datenübertragung, der Sinn eines jeden Bussystems, ist also keine Gemeinsamkeit von PCI und USB. Das ist mir neu.

Noch nicht einmal die Vendor-IDs sind identisch vergeben so das man schon bei den elementarsten P&P-Funktionen zwischen PCI und USB unterschieden muss.
PCI mit I²C oder SPI in einen Topf zu werfen macht IMHO noch viel weniger Sinn da die Unterschiede nur noch mehr werden.
Du verstehst, glaube ich nicht, was ich mit Abstraktion meine.

Eine Abstraktion für Bussysteme ist eine Sammlung von Funktionen, also eine API, die der Treiber benutzen kann, um mit der am Bus angeschlossenen Hardware zu reden. Das heißt nicht, dass du einen großen, gemeinsamen Treiber für PCI und I²C entwickeln sollst!

Das heißt nur, dass dein PCI-, USB- und auch I²C-Treiber eine einheitliche Sammlung von Funktionen bereitstellen - die dann von den jeweiligen Hardwaretreibern genutzt wird. Jeder Treiber für eine Bus-Bridge stellt ebenfalls diese API bereit und schon funktioniert dein Temperatursensor für I²C, wenn du ihn an eine USB-I²C-Bridge anschließt, aber der gleiche Treiber kann auch die Temperatur vom Mainboard lesen oder vom DDC-Teil des VGA-Anschlusses.

Für jedes Bussystem hast du trotzdem einen eigenen Treiber. Alles andere ist Blödsinn.

Wenn man wirklich PCI über USB tunneln möchte (was sicher irgendwie funktionieren könnte wenn auch nicht sonderlich gut) dann wäre dieser Tunnel für die PCI-Hardware und die Treiber völlig transparent (also aus PCI-Sicht unsichtbar), anders lassen sich Dinge wie Busmasterring oder klassische Interrupts der Geräte hinter dem Tunnel nicht realisieren.
Ich rede nicht von einem Tunnel. Ich rede von einer Bridge. Dass diese für USB->PCI extrem aufwendig ist, weil die Bussysteme physisch gesehen große Unterschiede aufweisen, steht nicht zur Debatte.

Eine recht simple Schaltung baut dir einen ISA-Bus (8-Bit) an den Parallelport. Das geht recht einfach, wenn du auf Interrupts verzichten kannst. Es wird geringfügig schwieriger, wenn du den ISA-Bus komplett nachbilden möchtest. Du kannst auch I²C-Busse problemlos an einen Parallelport, an einen USB-Anschluss oder an einen PCI-Bus hängen, all das gibt es. Und PCI-PCI-Bridges ist auch kein Thema, siehe CardBus (obwohl die physische Schicht dort trotzdem anders aussieht).

Klar benötigt dieser Tunnel eine Konfiguration aber ein HAL ist das IMHO absolut nicht (weil ja für die PCI-Geräte und PCI-Treiber alles so bleibt wie es die PCI-Spec festlegt).
Eine Abstraktion ist eine Softwareschnittstelle, keine Hardwareschnittstelle. Dem Temperatursensor ist total egal, wie der I²C-Bus mit dem Rechner verbunden ist, er sieht nur I²C. Und PCI-Hardware sieht nur einen PCI-Bus. Logisch, sonst funktioniert die Hardware ja nicht.

Der Unterschied (mit/ohne HAL) liegt darin, ob dein Hardwaretreiber weiß, wo das Gerät angeschlossen ist, oder nicht. Und ob es prinzipiell einen Unterschied macht, ob da eine Bridge zwischen ist, oder nicht. Das ist alles.

Im Falle von USB ist es meinem Microcontroller nicht egal, ob ich einen Hub angeschlossen habe. Der kann nämlich mit Hubs nichts anfangen (und auch sonst nur exakt ein einziges Gerät verwalten, dessen Treiber ich zudem bei der Initialisierung des USB-Stacks mit angeben muss).

Und wenn du nicht "Bussystem" abstrahieren möchtest, weil dir das widerstrebt, dann ist eine Abstraktion für "USB-Bus" trotzdem ein Teil des HAL (oder ein Teil deines USB-Stacks, oder des EHCI-Treibers, Implementierungsdetail). Im Endeffekt sollte es dem Gerätetreiber egal sein, ob ein USB-Hub unterwegs auftaucht oder nicht, ob du den Anschluss gewechselt hast oder nicht oder ob das Hardwareprotokoll nun USB 1.1 oder USB 2.0 kann.

Die Summe aller solcher APIs, die jeweils ein Stückchen Hardware abstrahieren, ist der HAL.
Das trifft aber auch auf Treiber zu oder auf das OS als ganzes (aus Sicht der Applikationen).
Der HAL abstrahiert Hardware für Treiber, im Gegensatz zu den Treibern, die für das Betriebssystem abstrahieren. Und das Betriebssystem als Ganzen abstrahiert für Anwendungen.

Leg die Dinge nicht immer so aus, wie ich sie gerade nicht gemeint habe. ;-)

Der typische Benutzer sieht ein Fenster mit Word drin und der Computer ist "der graue Kasten unterm Tisch". Es geht ihm nicht darum, die Maus zu bewegen, sondern er "klickt auf den Druckerbutton und dann kommt bedrucktes Papier aus dem Drucker".
Sorry, aber das kannst Du Deiner Oma so erklären, hier sind wir auf lowlevel.eu und da ist diese Art von Erklärung IMHO weniger geeignet.  ;)
Es geht um die Sichtweise, und für gewisse Anwendungsfälle ist eine gewisse Sichtweise vorteilhaft, eine andere wiederum untauglich.

Ich glaube, wenn ich "Festplatte" sage, denkst du in erster Linie auch ein Kästchen mit SATA-/IDE-/USB-Anschluss und bist der Meinung, dass da Daten in Form von Sektoren draufgepresst werden. Das ist aus Sichtweise des Betriebssystems eine hinreichend gute Abstraktion. Da fallen übrigens auch SSDs (und im weiteren Sinne USB-Sticks oder CF-Karten) drunter.

Für Anwendungsprogramme ist eine Festplatte etwas, wo ein Pfad dransteht und Dateien drauf sind.

Für Datenrettungsunternehmen und Festplattenhersteller ist eine Festplatte etwas, was aus rotierenden, beschichteten Metallscheiben besteht, die entsprechend physischer Gesetze magnetisiert werden und den Magnetisierungszustand mit halbleitertechnologischen Mitteln rein- & rausschieben können. Für einen OS-Entwickler ist diese Sichtweise natürlich blödsinnig.

Dein Ziel ist es aber, die Anwendung zu bedienen.
Absolut richtig, trotzdem kann ich als OS-Dever nicht den langen und komplizierten Weg der Informationen vom User bis zur eigentlichen Applikation und zurück ignorieren.
Du kannst aus Sicht der Anwendungen schauen, du kannst es aber auch aus Sicht der Hardware tun. Im einen Fall ist die Hardware das Ende der Kette, im anderen Fall in der Mitte.

Man nimmt sich immer nur die Teilaspekte raus, die man gebrauchen kann, das solltest du wissen. Und für meine Betrachtung eines HAL ist mein Bild nunmal recht gut geeignet. Wenn du von einer ganz anderen Sicht auf die Dinge ausgehst, ist es ungleich schwieriger, da noch was zu sehen.

Eben genau deswegen ist es offensichtlich so enorm schwierig den HAL als Einzel-Komponente exakt zu definieren.
Der HAL ist keine Einzelkomponente, sondern er definiert das Zusammenspiel verschiedener Komponenten.

Gruß,
Svenska
Titel: Re:Was genau ist eigentlich ein "Hardware Abstraction Layer" in einem OS?
Beitrag von: erik.vikinger am 15. February 2011, 15:50
Hallo,


Die Ressourcen einer MCA-Karte sind m.W. von ihrer physischen Slot-Position abhängig.
Echt, hm, wusste ich gar nicht.
Für einen kurzen Moment war ich versucht mir die MCA-Spec im iNetz zu suchen aber da bleibe ich doch lieber bei meinem Totschlagargument das der MCA bereits vor über 20 Jahren ausgestorben ist und daher nicht zählt. :P

Es sind trotzdem Busse. Und wenn du eine USB-PCI-Bridge haben könntest, dann liegt dahinter irgendwo trotzdem ein PCI-Bus.
Ich finde Du klammerst Dich zu arg an dem Wort Bus fest. ;)
Eine Frage der Sichtweise. ....
Natürlich ist es eine Frage der Sichtweise. Ich glaube ich verstehe jetzt warum wir da so gänzlich aneinander vorbei schreiben, deswegen möchte ich das noch mal etwas anders erklären und hoffe das Du mich dann auch besser verstehst.

Du gehst zu erst von den Gemeinsamkeiten aus, da ist im wesentlichen das Durchleiten von Daten, und versuchst dann die Unterschiede, das sind ne ganze Menge, hinter einer Abstraktion zu verstecken.
Ich hingegen schaue mir die verschiedenen Busse im Detail an und versuche dann anhand der jeweiligen Eigenschaften/Fähigkeiten zu kategorisieren und da fallen PCI, USB und I²C alle in unterschiedliche Kategorien. ISA ist zu PCI sehr ähnlich (EISA und MCA auch), von den unterstützten Konzepten wie IO, MMIO, Interrupts usw., und würde deswegen von mir mit in den PCI-Topf reingeworfen werden. Obwohl bei ISA ein paar Sonderdinge wie DMA-Kanäle zu beachten sind aber da diese in der realen Praxis keine echte Rolle mehr spielen (weil ja der Floppy-Controller in heutigen PCs der einzigste und letzte Nutzer der ISA-DMA-Kanäle ist) kann ich sie recht gut ignorieren. Was anderes wäre es wenn ich viele vollwertige ISA-Komponenten managen müsste und ich die Besonderheiten von ISA auch wirklich anständig verwalten müsste, dann würde ich wohl ISA nicht in den PCI-Topf werfen sondern lieber eine extra ISA-Kategorie aufmachen. Mir ist klar das meine Vorgehensweise aus akademischer Sicht nicht ganz korrekt ist aber ich persönlich empfinde sie als praktisch und zweckdienlich.
Wenn ich versuchen würde PCI, USB und I²C auf eine gemeinsame Basis zu stellen dann wäre die extrem klein (weil es eben nur sehr wenige Gemeinsamkeiten gibt, eigentlich nur eine nämlich das Durchleiten von Daten) so das ich für jede Unterkategorie einen recht großen Funktionsumfang bieten muss (für PCI benötige ich MMIO, Busmastering, Interrupts; für USB benötige ich Device-IDs, Endpunkte und Pipes; für I²C benötige ich die 7-Bit-Adressen und Baudraten). Es würde aus meiner Sicht schlicht nichts bleiben was wirklich in eine gemeinsame Basis-API kommen könnte, nebst dessen das es für diese Basis-API einfach keine Verwendung gibt weil es eben keine HW-Komponenten gibt die sich auch nur theoretisch mit einem Treiber über verschiedene Busse ansprechen lassen (von NE2000 mal abgesehen aber ISA und PCI sind sich eben doch noch recht ähnlich was z.B. auf ISA, USB und SPI nicht mehr zutrifft). Als HW-Entwickler nehme ich die Anforderungen die das Gerät erfüllen muss und suche mir dann das geeignete Bus-Interface aus (die Wahl wird natürlich für einen Temperatur-Sensor anders ausfallen als für ein 10GB-Ethernet-Interface), danach entwickle ich diese HW so das sie aus den spezifischen Fähigkeiten und Eigenheiten des gewählten Busses das Maximum raus holt. Ich persönlich finde das sich eine gemeinsame Basis nur dann lohnt wenn sie auch groß genug ist und es auch genügend Anwender dafür gibt und genau das trifft auf die Abstraktion von unterschiedlichen Bussen eben nicht zu.

Es ist nicht meine Absicht Deine Sichtweise in irgendeiner Form zu bewerten (schon gar nicht als falsch denn das ist sie nicht), ich bin nur der Meinung das Deine Sichtweise für OS-Dev nicht so ganz passend ist.

Alle von uns genannten Bussysteme sind wichtig und nützlich und keiner ist besser oder schlechter als ein anderer aber sie sind eben für komplett unterschiedliche Anwendungen konzipiert und haben daher auch gänzlich unterschiedliche Fähigkeiten und Eigenheiten. Wenn Du diese Unterschiede wegabstrahierst dann tust Du in meinen Augen den Bussystemen unrecht, lass ihnen doch ihre Individualität und erfreue Dich an der Vielfalt. ;)

Wenn du nur hochgezüchtete Bussysteme als Bus bezeichnen möchtest, fallen die simplen µC-Busse natürlich aus dem Rahmen.
Da hast Du mich wohl missverstanden. Das ich so auf PCI aus bin liegt einfach daran das er für die CPU und der darauf laufenden Software direkt erreichbar ist. In C kann man den MMIO-Speicherbereich einer PCI-Karte mit einem simplen Pointer (ist elementarer Teil der Programmiersprache) ansprechen, für die Ressourcen einer USB/I²C/SPI-Hardware gilt das erstmal nicht (da wird immer eine Art Library benötigt). PCI ist in heutigen Computern nunmal der Haupt-Bus und alles andere hängt dahinter (per Host-Controller o.ä. zugänglich).

PCI kennt Speicher- und IO-Ressourcen und jeder Teilnehmer kann welche anbieten aber auch selbstständig auf die Angebote anderer Teilnehmer zugreifen.
USB hingegen kennt nur Kommunikations-Pipelines die auch immer mit einem Ende bei einem Host-Controller (quasi der Wurzel des USB-Baums) enden müssen und auch nur der Host kann von sich aus aktiv werden alle Devices müssen grundsätzlich auf das Polling vom Host warten.
Das sind Unterschiede, die durch eine gute Abstraktion vernichtet werden sollten.
Wie?

Aha. Datenübertragung, der Sinn eines jeden Bussystems, ist also keine Gemeinsamkeit von PCI und USB. Das ist mir neu.
Natürlich ist das eine Gemeinsamkeit (noch nicht mal die einzigste) von PCI und USB aber wie willst Du das hinter einer gemeinsamen API verstecken? Einer PCI-Karte schicke ich Daten indem ich über einen Pointer auf Speicher zugreife (oder die Karte sich die Daten gleich selber aus dem Haupt-Speicher holt) und für USB muss man eine Funktion/Syscall/o.ä. aufrufen, da gibt es aus Sicht der Software keine gemeinsame Basis.

Das heißt nur, dass dein PCI-, USB- und auch I²C-Treiber eine einheitliche Sammlung von Funktionen bereitstellen - die dann von den jeweiligen Hardwaretreibern genutzt wird.
Was soll in diese einheitliche API denn rein?

Jeder Treiber für eine Bus-Bridge stellt ebenfalls diese API bereit und schon funktioniert dein Temperatursensor für I²C, wenn du ihn an eine USB-I²C-Bridge anschließt, aber der gleiche Treiber kann auch die Temperatur vom Mainboard lesen oder vom DDC-Teil des VGA-Anschlusses.
So in der Art hab ich mir das vorgestellt. Es gibt einen I²C-Master-Manager an den von unten die verschiedenen Host-Controller-Treiber andocken (egal ob der I²C nun von einem USB-basierten Host-Controller, einem PCI-basierten Host-Controller, irgendwelchen SMB-Registern im Chipsatz oder von der GPU kommt) und von oben die eigentlichen Geräte-Treiber die ein einfaches/einheitliches Interface bekommen so das sie mit jeder I²C-Implementierung umgehen können. Vergleichbare Instanzen gibt es für USB, SPI und auch für PCI (jeweils mit einem Funktionsumfang der genau zu dem entsprechenden Bus passt) aber diese APIs haben (fast) keine Gemeinsamkeiten so das es IMHO nichts bringt sie auf einer gemeinsamen Basis aufzusetzen (nebst dessen das es für diese Basis nach wie vor niemanden gibt der sich dafür interessieren würde).

Für jedes Bussystem hast du trotzdem einen eigenen Treiber. Alles andere ist Blödsinn.
Also doch keine gemeinsame API? Ja was denn nun?

Wenn man wirklich PCI über USB tunneln möchte (was sicher irgendwie funktionieren könnte wenn auch nicht sonderlich gut) dann wäre dieser Tunnel für die PCI-Hardware und die Treiber völlig transparent (also aus PCI-Sicht unsichtbar), anders lassen sich Dinge wie Busmasterring oder klassische Interrupts der Geräte hinter dem Tunnel nicht realisieren.
Ich rede nicht von einem Tunnel. Ich rede von einer Bridge. Dass diese für USB->PCI extrem aufwendig ist, weil die Bussysteme physisch gesehen große Unterschiede aufweisen, steht nicht zur Debatte.
Ich glaube nicht das eine echte Bridge zwischen USB und PCI wirklich realisierbar ist. Anderes Beispiel: wenn man normale Straßenfahrzeuge (aka Autos) mit der Bahn transportiert dann werden die nicht in Schienenfahrzeuge umgewandelt sondern in einem Waggon versteckt (für die Bahn-Gleise ist nur dieser Waggon sichtbar), dieses Konzept entspricht dem Tunneln. Der Grund warum man das so macht ist der das die konzeptionellen Unterschiede einfach zu groß sind (auch wenn beide auf runden Rädern basieren und noch viele andere Gemeinsamkeiten haben) und das selbe trifft auch auf USB und PCI zu. Unüberbrückbare Unterschiede können auch nicht von noch so vielen Gemeinsamkeiten überwunden werden.

Eine recht simple Schaltung baut dir einen ISA-Bus (8-Bit) an den Parallelport. Das geht recht einfach, wenn du auf Interrupts verzichten kannst.
Da müsste man noch auf sehr viel mehr verzichten als nur Interrupts, z.B. auf DMA. Nebst dessen das ISA-Karten einen Takt erwarten der mit konstanter Frequenz arbeiten muss (ohne Unterbrechungen u.ä.) und sich die Datentransfers an diesen Takt halten müssen. So simpel dürfte diese Schaltung mit Sicherheit nicht werden (ich würde sagen einen kleinen FPGA kann man damit schon füllen und mit einem mittleren FPGA sollte man sogar ISA komplett unterstützen können).

Du kannst auch I²C-Busse problemlos an einen Parallelport, an einen USB-Anschluss oder an einen PCI-Bus hängen, all das gibt es.
Hab ich alles schon selber benutzt. I²C ist auch was anderes als ISA, u.a. ist das Timing recht flexibel bei I²C.

Der Unterschied (mit/ohne HAL) liegt darin, ob dein Hardwaretreiber weiß, wo das Gerät angeschlossen ist, oder nicht. Und ob es prinzipiell einen Unterschied macht, ob da eine Bridge zwischen ist, oder nicht. Das ist alles.
Aha, das musst Du bitte etwas ausführlicher erklären.

Und wenn du nicht "Bussystem" abstrahieren möchtest, weil dir das widerstrebt
Es widerstrebt mir nicht sondern es erscheint mir nicht sinnvoll für den OS-Dever.

dann ist eine Abstraktion für "USB-Bus" trotzdem ein Teil des HAL (oder ein Teil deines USB-Stacks, oder des EHCI-Treibers, Implementierungsdetail).
Womit der Begriff HAL wieder zu einer recht frei definierbaren Angelegenheit wird.

Im Endeffekt sollte es dem Gerätetreiber egal sein, ob ein USB-Hub unterwegs auftaucht oder nicht, ob du den Anschluss gewechselt hast oder nicht oder ob das Hardwareprotokoll nun USB 1.1 oder USB 2.0 kann.
Ja, genau so stelle ich mir das für USB vor. Und auch für I²C oder SPI sollte es genau so sein.

Der HAL abstrahiert Hardware für Treiber
Hm, wie soll das gehen und vor allem wie weit soll das gehen?

Leg die Dinge nicht immer so aus, wie ich sie gerade nicht gemeint habe. ;)
Dann schreibe bitte auch so wie Du es gerade meinst. ;)

Ich glaube, wenn ich "Festplatte" sage, denkst du in erster Linie auch ein Kästchen ....
Nö, ganz so simpel mach ich mir das nun auch wieder nicht, mir sind die verschiedenen Abstraktionsebenen durchaus bewusst.

Dein Ziel ist es aber, die Anwendung zu bedienen.
Absolut richtig, trotzdem kann ich als OS-Dever nicht den langen und komplizierten Weg der Informationen vom User bis zur eigentlichen Applikation und zurück ignorieren.
Du kannst aus Sicht der Anwendungen schauen, du kannst es aber auch aus Sicht der Hardware tun.
Beide Sichtweisen kommen bei mir zum selben Ergebnis. Die Applikation benötigt zum Fenster malen eine GUI-Library und diese setzt wieder auf einem Fenstermanager u.ä. auf welcher wiederum auf Treiber zugreift die dann schlussendlich die Hardware ansteuern mit der der User interagiert (in dem Fall der Monitor dessen Bild durch die menschlichen Augen wahrgenommen wird), auch die HW sieht nur die Treiber aber nicht die Applikation(en). Ich kann das drehen und wenden wie ich will, so wie ich das sehe sind User und Applikationen immer die zwei entferntesten Enden der Kette. Das einzigste was mir jetzt beim nochmaligen nachdenken aufgefallen ist ist das es auch HW gibt mit der der User nicht interagiert (z.B. eine Festplatte oder die Netzwerkkarte).


Der HAL ist keine Einzelkomponente, sondern er definiert das Zusammenspiel verschiedener Komponenten.
Der Satz gefällt mir wirklich, ist bis jetzt die beste Antwort auf meine ursprüngliche Frage. Danke!


Grüße
Erik
Titel: Re:Was genau ist eigentlich ein "Hardware Abstraction Layer" in einem OS?
Beitrag von: Svenska am 15. February 2011, 17:13
Hallo,

Mir ist klar das meine Vorgehensweise aus akademischer Sicht nicht ganz korrekt ist aber ich persönlich empfinde sie als praktisch und zweckdienlich.
Ich glaube, das trifft es recht gut.

Wenn ich versuchen würde PCI, USB und I²C auf eine gemeinsame Basis zu stellen dann wäre die extrem klein (weil es eben nur sehr wenige Gemeinsamkeiten gibt, eigentlich nur eine nämlich das Durchleiten von Daten) so das ich für jede Unterkategorie einen recht großen Funktionsumfang bieten muss (für PCI benötige ich MMIO, Busmastering, Interrupts; für USB benötige ich Device-IDs, Endpunkte und Pipes; für I²C benötige ich die 7-Bit-Adressen und Baudraten).
Der Sinn einer guten Abstraktion ist es doch, auch noch in Unterschieden die Gemeinsamkeiten zu finden. Die Baudrate eines I²C kannst du mit der Geschwindigkeit des USB-Gerätes (oder -Busses) gleichsetzen, die 7-Bit-Adresse des I²C entspricht der Vendor-/Device-ID (evtl. auch dem Endpoint) von PCI/USB. Und so weiter.

Ich finde das gut, du findest das nicht gut. Aber das wussten wir beide schon vorher. ;-)

Wenn Du diese Unterschiede wegabstrahierst dann tust Du in meinen Augen den Bussystemen unrecht, lass ihnen doch ihre Individualität und erfreue Dich an der Vielfalt. ;)
Es gibt für beide Varianten recht weit verbreitete Beispiele (NetBSD mit, Linux und Windows ohne Busabstraktion).

Das heißt nur, dass dein PCI-, USB- und auch I²C-Treiber eine einheitliche Sammlung von Funktionen bereitstellen - die dann von den jeweiligen Hardwaretreibern genutzt wird.
Was soll in diese einheitliche API denn rein?
Hatte ich schonmal beschrieben, siehe weiter oben.

Für jedes Bussystem hast du trotzdem einen eigenen Treiber. Alles andere ist Blödsinn.
Also doch keine gemeinsame API? Ja was denn nun?
Mein Gedanke: Es gibt Treiber für Bussysteme. Alle diese Treiber implementieren eine gemeinsame API, die die Unterschiede zwischen den Bussystemen wegabstrahiert und somit jedem Hardwaretreiber einen "Bus" zur Verfügung stellt. Der Treiber selbst weiß das garnicht (oder nur peripher).

Du sollst nicht einen einzelnen Treiber bauen, der gleichzeitig PCI- und USB-Hostcontroller unterstützt.

Ich glaube nicht das eine echte Bridge zwischen USB und PCI wirklich realisierbar ist. Anderes Beispiel: wenn man normale Straßenfahrzeuge (aka Autos) mit der Bahn transportiert dann werden die nicht in Schienenfahrzeuge umgewandelt sondern in einem Waggon versteckt (für die Bahn-Gleise ist nur dieser Waggon sichtbar), dieses Konzept entspricht dem Tunneln.
Genau. Und die Fahrzeuge, die sowohl Straßen als auch Schienen befahren können, die sind in dem Zusammenhang Bridges. (Solche Teile gibt es im Baugewerbe.)

Unüberbrückbare Unterschiede können auch nicht von noch so vielen Gemeinsamkeiten überwunden werden.
Keine Unterschiede sind Unüberbrückbar. Im schlimmsten Fall hast du einen Rechner mit PCI-Schnittstelle, einen weiteren Rechner mit USB-Schnittstelle und baust einen TCP/IP-Tunnel dazwischen. Ich sage ja nicht, dass eine USB-PCI-Bridge ohne weiteres herstellbar ist (der umgekehrte Fall ist wesentlich einfacher und heißt *HCI).

Eine recht simple Schaltung baut dir einen ISA-Bus (8-Bit) an den Parallelport...
Da müsste man noch auf sehr viel mehr verzichten als nur Interrupts, z.B. auf DMA. Nebst dessen das ISA-Karten einen Takt erwarten der mit konstanter Frequenz arbeiten muss (ohne Unterbrechungen u.ä.) und sich die Datentransfers an diesen Takt halten müssen.
So die Theorie.

So simpel dürfte diese Schaltung mit Sicherheit nicht werden (ich würde sagen einen kleinen FPGA kann man damit schon füllen und mit einem mittleren FPGA sollte man sogar ISA komplett unterstützen können).
Ich verweise auf diesen Link (http://www-user.tu-chemnitz.de/~heha/bastelecke/Rund%20um%20den%20PC/LPTISA/). Viel Spaß beim Basteln. ;-)

Der Unterschied (mit/ohne HAL) liegt darin, ob dein Hardwaretreiber weiß, wo das Gerät angeschlossen ist, oder nicht. Und ob es prinzipiell einen Unterschied macht, ob da eine Bridge zwischen ist, oder nicht. Das ist alles.
Aha, das musst Du bitte etwas ausführlicher erklären.
Entweder, der NE2000-Treiber weiß, dass er es jetzt mit einer ISA/PCI/USB/PCMCIA-Karte zu tun hat (weil er mit dem entsprechenden Bustreiber quatschen muss) oder er weiß es nicht, weil alle Busse für ihn gleich aussehen und er vom Betriebssystem z.B. ein "struct bus_info" bekommt, in dem eine abstrakte Adresse drinsteht.

Und reg dich über die NE2000 nicht auf, die ist ein einfach zu schönes Beispiel. ;-)

dann ist eine Abstraktion für "USB-Bus" trotzdem ein Teil des HAL (oder ein Teil deines USB-Stacks, oder des EHCI-Treibers, Implementierungsdetail).
Womit der Begriff HAL wieder zu einer recht frei definierbaren Angelegenheit wird.
Ist es ja auch.

Der HAL abstrahiert Hardware für Treiber
Hm, wie soll das gehen und vor allem wie weit soll das gehen?
Das definierst du als OS-Entwickler.

Gruß,
Svenska
Titel: Re:Was genau ist eigentlich ein "Hardware Abstraction Layer" in einem OS?
Beitrag von: erik.vikinger am 15. February 2011, 21:08
Hallo,


Mir ist klar das meine Vorgehensweise aus akademischer Sicht nicht ganz korrekt ist aber ich persönlich empfinde sie als praktisch und zweckdienlich.
Ich glaube, das trifft es recht gut.
Dann sind wir uns ja einig. Ein OS muss eben vor allem in der Praxis funktionieren und nicht nur in der akademischen Theorie. ;)

Der Sinn einer guten Abstraktion ist es doch, auch noch in Unterschieden die Gemeinsamkeiten zu finden. Die Baudrate eines I²C kannst du mit der Geschwindigkeit des USB-Gerätes (oder -Busses) gleichsetzen, die 7-Bit-Adresse des I²C entspricht der Vendor-/Device-ID (evtl. auch dem Endpoint) von PCI/USB. Und so weiter.
Grundsätzlich hast Du ja Recht aber die von Dir gewählten Beispiele sind noch die einfachsten.
Wie möchtest Du das Übermitteln von Daten (bekannter weise der eigentliche Zweck eines jeden Bussystems) hinter einer einheitlichen API verstecken wenn die PCI-Karte die Daten selber per Busmastering aus dem RAM holen möchte, die ISA-Karte die über MMIO (also über ne Art memcpy) bekommen will und die USB/I²C/SPI-Geräte die Daten eben manuell verpackt übergeben brauchen?
Des weiteren stört mich an Deinen Beispielen das Du z.B. Vendor-/Device-ID und I²C-7-Bit-Adresse in einen Topf werfen möchtest, da geht doch beim programmieren die Typ-Sicherheit verloren. In was für einen Datentyp würdest Du das denn reinpacken wollen? Schon aus der Sicht eines Programmierers finde ich diese Gleichmacherei gar nicht gut.

Ich finde das gut, du findest das nicht gut. Aber das wussten wir beide schon vorher. ;-)
Die Welt wäre ja auch fürchterlich öde wenn wir alle der selben Meinung wären! Siehst Du doch genauso oder?

Mein Gedanke: Es gibt Treiber für Bussysteme. Alle diese Treiber implementieren eine gemeinsame API, die die Unterschiede zwischen den Bussystemen wegabstrahiert und somit jedem Hardwaretreiber einen "Bus" zur Verfügung stellt. Der Treiber selbst weiß das garnicht (oder nur peripher).
Hm, bis auf die gemeinsame API für alle Busse klingt das eigentlich nicht verkehrt.

Du sollst nicht einen einzelnen Treiber bauen, der gleichzeitig PCI- und USB-Hostcontroller unterstützt.
Das geht auch gar nicht in einem Bus-Treiber. Während bei PCI die Geräte eine für die CPU direkt erreichbare Ressource zugewiesen bekommen (und noch ein wenig Routing konfiguriert werden muss) und dann die Geräte-Treiber direkt mit ihrem Gerät kommunizieren können müssen bei USB alle Datentransfers durch den Treiber-Stapel durchgeschleust werden. Ich sehe einfach nicht wie Du das hinter einer einheitlichen API verstecken möchtest.

Und die Fahrzeuge, die sowohl Straßen als auch Schienen befahren können, die sind in dem Zusammenhang Bridges. (Solche Teile gibt es im Baugewerbe.)
Wenn Du das mit einer Bridge (wie z.B. einer PCI-2-ISA-Bridge) vergleichst dann haben wir ein Kommunikationsproblem. Dieses Baufahrzeug ist ein Hybrid weil es die Fähigkeiten beider Systeme vereint, einer Bridge würde entsprechen wenn man ein beliebiges Fahrzeug der einen Kategorie in ein Fahrzeug der anderen Kategorie umwandeln könnte (so wie eine PCI-2-ISA-Bridge einen PCI-Transfer entgegen nimmt und einen ISA-Transfer weiter leitet ohne den Inhalt zu ändern).

Im schlimmsten Fall hast du einen Rechner mit PCI-Schnittstelle, einen weiteren Rechner mit USB-Schnittstelle und baust einen TCP/IP-Tunnel dazwischen.
Das entspricht aber auch nicht dem was man unter einer Bus-Bridge versteht.

Ich sage ja nicht, dass eine USB-PCI-Bridge ohne weiteres herstellbar ist (der umgekehrte Fall ist wesentlich einfacher und heißt *HCI).
Ich sage schon das eine USB-PCI-Bridge nicht so ohne weiteres herstellbar ist. Und die andere Richtung (*HCI) ist auch keine Bridge sondern eine Komponente die von der CPU als reines PCI-Gerät angesprochen wird und die mit Hilfe der so empfangenen Daten den USB betreibt. Die USB-Daten werden quasi von der HW in PCI-Transfers verpackt (versteckt, so wie bei dem Waggon für Autos) und von dem USB-Treiber wieder entpackt.

Ich verweise auf diesen Link (http://www-user.tu-chemnitz.de/~heha/bastelecke/Rund%20um%20den%20PC/LPTISA/). Viel Spaß beim Basteln. ;-)
Okay, es scheint tatsächlich ISA-Karten zu geben die kein Takt-Signal benötigen (B20 ist in beiden Versionen unbeschaltet), aber die anderen Einschränken sind auch so extrem das nur sehr wenige ISA-Karten wirklich damit laufen könnten. Die als lauffähig genannten Karten basieren alle auf simplen IO-Registern um eben ein paar Ausgänge anzusteuern bzw. ein paar Eingänge abzufragen, ich würde wetten die Schaltung wäre nicht aufwendiger wenn man die Funktionalität der Karten gleich direkt nachbaut. Trotzdem bleibe ich bei der Meinung das da kein echter ISA-Bus raus kommt (irgendeiner ISA-Spezifikation entspricht das auf jeden Fall nicht).

Entweder, der NE2000-Treiber weiß, dass er es jetzt mit einer ISA/PCI/USB/PCMCIA-Karte zu tun hat (weil er mit dem entsprechenden Bustreiber quatschen muss) oder er weiß es nicht, weil alle Busse für ihn gleich aussehen und er vom Betriebssystem z.B. ein "struct bus_info" bekommt, in dem eine abstrakte Adresse drinsteht.
In Deiner Bus-Liste ist der USB zu viel, es gab mit Sicherheit keine NE2000-USB-Karte, NE2000 basiert auf IO-Registern die es bei USB eben nicht gibt. Ich kann mir problemlos eine NE2000 als HyperTransport-/EISA-/MCA- oder PCI-Express-Gerät vorstellen (weil alle diese Busse IO-Ports und Interrupts unterstützen und damit auch alle existierenden NE2000-Treiber zurecht kommen inklusive solche aus DOS-Zeiten, für diese gab es extra ein Hilfstool das die IO-Basis-Adresse und die Interrupt-Nummer aus dem PCI-Config-Space geholt hat und dann den DOS-Treiber mit den richtigen Parametern gestartet hat) aber ganz sicher nicht für USB, I²C, SPI, OneWire, SATA oder FireWire (es fehlen einfach die IO-Ports und/oder die Interrupts und direkt für die CPU bzw. für die darauf laufende Software sind diese Busse auch nicht erreichbar).

Und reg dich über die NE2000 nicht auf, die ist ein einfach zu schönes Beispiel. ;-)
Dann nenne doch Bitte einfach mal ein anderes Beispiel.


Grüße
Erik
Titel: Bussysteme und deren Abstraktion
Beitrag von: Svenska am 17. February 2011, 21:08
Hallo,

Wie möchtest Du das Übermitteln von Daten (bekannter weise der eigentliche Zweck eines jeden Bussystems) hinter einer einheitlichen API verstecken wenn die PCI-Karte die Daten selber per Busmastering aus dem RAM holen möchte, die ISA-Karte die über MMIO (also über ne Art memcpy) bekommen will und die USB/I²C/SPI-Geräte die Daten eben manuell verpackt übergeben brauchen?
Der ultimative Fall ist der des Busmasterings.

Du übergibst der API also einen Zeiger auf ein Stück physischen Speicher, den die PCI-Karte sich per Busmastering holt. Der PCI-Bus-Treiber hätte also nichts zu tun. Ein ISA-Bustreiber kopiert die Daten dann mittels MMIO in die Karte. Ein USB-Bustreiber verpackt die Daten und schickt sie weg. Ein SPI-Bitbanging-Bustreiber fängt an, die Daten rauszutakten.

Eine gute API (die ich nicht entwickelt habe) orientiert sich am besten (PCI), bezieht aber die Eigenheiten der anderen Dinge mit ein. Und die konkrete Umsetzung obliegt doch dem Treiber.

Des weiteren stört mich an Deinen Beispielen das Du z.B. Vendor-/Device-ID und I²C-7-Bit-Adresse in einen Topf werfen möchtest, da geht doch beim programmieren die Typ-Sicherheit verloren.
Was hat denn das eine mit dem anderen zu tun? Typsicherheit ist ein reines Implementationsdetail, noch dazu stark abhängig von der Programmiersprache. Außerdem: Typsicherheit wofür? Deine API definiert die Datentypen, die dort verwendet werden. Die müssen nicht identisch zu dem sein, was am Ende für die Hardware da ist!

In was für einen Datentyp würdest Du das denn reinpacken wollen? Schon aus der Sicht eines Programmierers finde ich diese Gleichmacherei gar nicht gut.
Wie wäre es mit einer abstrakten 64-Bit langen 'Adresse' des Gerätes 'an einem Bus'? Bei I²C kann diese nur Werte von 0..127 annehmen, bei USB-/PCI-Geräten hast du eine 32-Bit-Adresse, die der PCI- oder USB-Bustreiber entsprechend zerlegt.

Ich sehe einfach nicht wie Du das hinter einer einheitlichen API verstecken möchtest.
*seufz* Ich lass es. Bringt nichts.

In Deiner Bus-Liste ist der USB zu viel, es gab mit Sicherheit keine NE2000-USB-Karte, NE2000 basiert auf IO-Registern die es bei USB eben nicht gibt.
Und? Dann definiert der USB-Controller, der die NE2000 ansteuert, halt zwei Endpoints. Eins für I/O-Register, eins für Speicher. Die Interrupts kannst du direkt nicht nachbilden, aber USB-Interrupt-Transfers haben eine Maximallatenz, womit du sowas nachbilden kannst.

Du sollst doch nicht den NE2000-Baustein direkt an einen USB-Bus hängen. Du gibst ihm eine Umgebung, in der er lebt (Datenein-&ausgabe) und diese Umgebung hängst du an den USB.

Gruß,
Svenska
Titel: Re:Was genau ist eigentlich ein "Hardware Abstraction Layer" in einem OS?
Beitrag von: DeepDancer am 17. February 2011, 23:42
Moinsen zusammen auch

Also wenn man das ganze mal ein wenig "offener" betrachtet, dann ist eigentlich das OS selber auch nur ein HAL - es abstrahiert die komplette Hardware und stellt einheitliche Funktionen zur verfügung welche JEDE Software die so geschrieben wird ansprechen kann, ohne sich Gedanken machen zu müssen was denn hinter diesen Funktionsaufrufen steckt.  :-)

Auch das angesprochene CDI ist in seiner Gesamtheit ein HAL - nur eben nicht direkt unter dem Kernel wie der klassische HAL, den man noch aus WIN-NT oder 2000 oder auch XP kennt.

Wobei es auch in Windows schon so war, dass zum Beispiel DirectX direkt auf den HAL ging und nicht mehr den Umweg über den Kernel nehmen musst und somit eben dann schneller war/ist.


Grüße,
DeepDancer
Titel: Re: Bussysteme und deren Abstraktion
Beitrag von: erik.vikinger am 18. February 2011, 11:12
Hallo,


Svenska, zuerst einmal muss ich Dir meinen Respekt zollen, es ist Dir gelungen meine Fragen zu beantworten ohne sie zu beantworten. Ich bin ein bisschen Ratlos.


Der ultimative Fall ist der des Busmasterings.
Warum? ;) Der ist schnell und CPU-schonend, ja, aber es gibt auch einige konzeptionelle Nachteile wie das die Geräte die Speicherverwaltung der CPU (Paging) verstehen und nachahmen müssen (per Scatter-Gather-Listen).

Du übergibst der API also einen Zeiger auf ein Stück physischen Speicher, den die PCI-Karte sich per Busmastering holt.
Wie soll das gehen? Der Code hinter der API, also der PCI-Bus-Treiber, kennt ja nicht das konkrete PCI-Gerät also weiß er gar nicht was er mit dem Pointer machen muss (wie dieser Pointer dem PCI-Gerät übergeben werden muss bzw. wie diese Scatter-Gather-Listen aufgebaut sein müssen). Das weiß nur der eigentliche Geräte-Treiber.

Genau deswegen ist es auch unmöglich das Ansteuerungskonzept eines PCI-Gerätes auf ein Gerät zu übertragen das an einem Bus hängt der nicht mindestens über die selben Features, wie z.B. Busmastering, wie PCI verfügt und deswegen kann der Geräte-Treiber seine Hardware auch nur als PCI-Gerät ansprechen. Denn wenn wir ein funktional vergleichbares Gerät für z.B. USB entwickeln wird es zwangsläufig ein anderes Ansteuerungskonzept bekommen und deswegen nicht mehr mit dem selben Geräte-Treiber ansprechbar sein. Aus eben diesem Grund bin ich der Meinung das Busabstraktion kaum einen praktischen Nutzwert hat.

Ein ISA-Bustreiber kopiert die Daten dann mittels MMIO in die Karte.
Okay, das ist auf jeden Fall machbar aber es stellt sich die Frage: Warum soll man ein memcpy abstrahieren? Das Konzept des Speicher gibt es immer und wenn nicht dann gibt es auch keine MMIO-basierenden Geräte.

Ein USB-Bustreiber verpackt die Daten und schickt sie weg. Ein SPI-Bitbanging-Bustreiber fängt an, die Daten rauszutakten.
Ja, bei diesen Bussen ist der Aufruf einer API-Funktion absolut nötig und korrekt aber bei Bussen die direkt von der CPU erreichbar sind, z.B. ISA und PCI, ist der Funktionsaufruf IMHO eine Performance-Bremse (und im Fall von gerätespezifischen Busmastering auch völlig unmöglich).

Eine gute API (die ich nicht entwickelt habe) orientiert sich am besten (PCI), bezieht aber die Eigenheiten der anderen Dinge mit ein.
Ich erwarte ja gar nicht das Du hier eine komplette Bus-API entwickelst aber wenigstens mal ein Konzept grob darlegen wäre echt nicht schlecht. Ich habe jetzt einen ganzen Haufen an Gründen genannt warum ich der Meinung bin dass das gar nicht umsetzbar (und auch nicht praktikabel) ist und Du drückst Dich um ein konkretes Beispiel wie es Deiner Meinung nach funktionieren könnte. Das ist frustrierend. :cry:

Typsicherheit ist ein reines Implementationsdetail, noch dazu stark abhängig von der Programmiersprache. Außerdem: Typsicherheit wofür?
Also wenn Du als Programmierer nicht weist wofür Typsicherheit gut ist dann werde ich das wohl auch nicht erklären können. Sorry, wenn das reichlich arrogant klingt aber eigentlich sind wir uns doch einig das wir ein OS nicht mehr in Assembler programmieren wollen sondern in einer Hochsprache und die bringen alle mehr oder weniger Typsicherheit mit (einfach weil sich das als nützliches Programmierparadigma erwiesen hat).

Deine API definiert die Datentypen, die dort verwendet werden. Die müssen nicht identisch zu dem sein, was am Ende für die Hardware da ist!
Aber der Geräte-Treiber muss auch auf diese Informationen anständig zugreifen können. Der benötigt z.B. die genaue PCI-Geräte-ID um sich je nach Produktversion ein klein wenig anders verhalten zu können. Ein gutes Beispiel ist da der e1000-Treiber, diese HW gibt es in sehr vielen Varianten (z.B. mit Kupfer- oder Glasfaser-Anschluss) und trotz dessen dass das Grundansteuerungsprinzip immer gleich ist sind eben doch ein paar Details spezifisch zu erledigen. Es wäre Unsinn für jede e1000-Variante einen eigenen Treiber zu bauen sondern es ist viel zweckmäßiger einen Treiber für alle zu haben der dann eben an ein paar wenigen Stellen im Code eine Fallunterscheidung anhand der Geräte-ID macht.

Wie wäre es mit einer abstrakten 64-Bit langen 'Adresse' des Gerätes 'an einem Bus'?
Was genau meinst Du mit "abstrakt"? Zumindest in C gibt es keine abstrakten Datentypen.

Ich sehe einfach nicht wie Du das hinter einer einheitlichen API verstecken möchtest.
*seufz* Ich lass es. Bringt nichts.
Du hast ja auch noch gar nicht erklärt wie es denn funktionieren könnte. Nimm doch einfach das Beispiel von oben mit dem Übergeben von Daten an ein Gerät (einmal PCI mit Busmastering, einmal ISA mit MMIO und dazu noch USB oder SPI mit ner Sende-Funktion) und zeige wie diese einheitliche API konkret aussehen könnte und wie die von den jeweiligen Bus-Treibern umgesetzt werden müsste.

Du sollst doch nicht den NE2000-Baustein direkt an einen USB-Bus hängen. Du gibst ihm eine Umgebung, in der er lebt (Datenein-&ausgabe) und diese Umgebung hängst du an den USB.
Dann ist es aber kein NE2000 mehr sondern dann hast Du einen Umsetzer von einem neuen USB-basierten Interface nach NE2000 gebaut und der Geräte-Treiber muss mit diesem neuen Interface umgehen können. Daraus folgt das Du einen neuen Treiber (für Dein USB-Interface) programmieren musst (auch wenn Du sicher viele Code-Teile vom NE2000-Treiber übernehmen kannst) und daher bin ich der Meinung das die Bus-Abstraktion in diesem Fall schon mal nicht funktioniert hat. Klar könntest Du die IO-Zugriffe vom System alle abfangen lassen und die dann in einer Emulationsschicht für Dein USB-Interface umsetzen (in der Art wie das diese LPT-ISA-Sache macht) damit der alte NE2000-Treiber noch funktioniert aber das verstehe ich persönlich nicht unter Abstraktion (des entspricht IMHO der Virtualisierung).


Grüße
Erik
Titel: Re: Bussysteme und deren Abstraktion
Beitrag von: Svenska am 18. February 2011, 14:44
Hallo,

Svenska, zuerst einmal muss ich Dir meinen Respekt zollen, es ist Dir gelungen meine Fragen zu beantworten ohne sie zu beantworten. Ich bin ein bisschen Ratlos.
Das liegt unter anderem daran, dass ich den PCI-Bus bei weitem nicht so gut kenne wie du. Eigentlich überhaupt nicht; ich kenne mich ein bisschen mit ISA, I²C und SPI aus. Deswegen beziehe ich die Dinge alle darauf und nicht auf PCI, was du ständig machst.

Der ultimative Fall ist der des Busmasterings.
Warum? ;) Der ist schnell und CPU-schonend, ja, aber es gibt auch einige konzeptionelle Nachteile wie das die Geräte die Speicherverwaltung der CPU (Paging) verstehen und nachahmen müssen (per Scatter-Gather-Listen).
Busmastering ist der eleganteste Fall. Wenn die Busabstraktion das abbilden kann, ist damit ein Zero-Copy möglich. Wenn die höchste Abstraktionsstufe "nur" MMIO hergibt, dann wirst du damit PCI-Geräten keinen Gefallen tun. Das meinte ich. Dazu muss man aber alle Bussysteme kennen und den PCI kenne ich (abgesehen von ein paar Features) nunmal nicht, schon garnicht im Detail.

Genau deswegen ist es auch unmöglich das Ansteuerungskonzept eines PCI-Gerätes auf ein Gerät zu übertragen das an einem Bus hängt der nicht mindestens über die selben Features, wie z.B. Busmastering, wie PCI verfügt und deswegen kann der Geräte-Treiber seine Hardware auch nur als PCI-Gerät ansprechen.
Da kann ich nicht viel zu sagen. Höchstens, dass deine API ja nach der Ansteuerung über den PCI-Bus modelliert sein kann.

Denn wenn wir ein funktional vergleichbares Gerät für z.B. USB entwickeln wird es zwangsläufig ein anderes Ansteuerungskonzept bekommen und deswegen nicht mehr mit dem selben Geräte-Treiber ansprechbar sein.
Naja, es gibt kaum Hardware, die für mehrere völlig verschiedene Bussysteme existiert und wenn sie das tut, dann weiß der Treiber das in der Regel auch (schließlich muss er die Hardware evtl. entsprechend konfigurieren können => NE2000 als NE1000 in einem 8-Bit-Steckplatz).

Wenn die Hardware halt sowohl Speicher- als auch Portzugriffe benötigt, dann wird der Treiber schon so strukturiert sein, dass er zwei Funktionen "send_mem" und "send_io" enthält, die dann entsprechende Funktionen der Busabstraktions-API aufruft oder, wenn du sowas nicht hast, direkt arbeitet. Und wenn die USB-Variante jetzt zwei Endpoints anbietet, die als Speicher- bzw. Portendpunkt funktionieren, dann sind das im Treiber nur wenige Zeilen und ein switch, um das zu implementieren.

Wenn du allerdings keine gemeinsame Busabstraktion hast (sondern dein HAL eine API für PCI implementiert, eine ganz andere API für USB usw.), dann ist das schon wesentlich umständlicher und läuft am Ende auf einen völlig neuen Treiber hinaus, mit identischem, mehrfach vorhandenem Code usw; es sei denn, du faktorisierst den gemeinsamen Anteil heraus. Das ist eine Menge Arbeit und wird meist nicht (oder sehr viel später) gemacht.

Bei Linux sieht man das jetzt wieder für die r300g- und r600g-Treiber, wo komplett verschiedene Shaderimplementierungen benutzt werden und jetzt der r300g-Anteil (den es schon vorher gab und der schneller/besser ist) rausfaktorisiert wird, um ihn in r600g nutzen zu können.

Das Ziel, dass ein identischer Treiber auf Hardware funktioniert, für die er nie geschrieben wurde, ist logischerweise ein Theoretisches. Praktisch hast du sowieso Errata, die du berücksichtigen musst.

Aus eben diesem Grund bin ich der Meinung das Busabstraktion kaum einen praktischen Nutzwert hat.
Das ist mit jeder Theorie so. Am Ende sieht man, was sich bewährt hat und was nicht - und zwar im Kontext von Aufwand gegen Nutzen. Mit dem Argument könnte man übrigens Microkernel komplett einstampfen, schließlich sind alle bekannten, großen System Monolithen (Linux, *BSD, Solaris, Win 9x) oder zumindest nahezu monolithisch (NT als Hybridkernel). Dennoch ist der Microkernel ein schönes theoretisches Konstrukt und funktioniert auch.

Ein ISA-Bustreiber kopiert die Daten dann mittels MMIO in die Karte.
Okay, das ist auf jeden Fall machbar aber es stellt sich die Frage: Warum soll man ein memcpy abstrahieren? Das Konzept des Speicher gibt es immer und wenn nicht dann gibt es auch keine MMIO-basierenden Geräte.
Warum gibt es Datentypen wie "size_t", wenn man auch einfach einen "int" nutzen kann? Zahlen sind schließlich Zahlen.

Der Sinn eines HAL ist es, die Hardware vollständig vom Gerätetreiber abzutrennen. Praktisch ist das nicht umsetzbar, also entfernt man sich mehr oder weniger von diesem Konzept und der HAL wird dementsprechend dünner und du hast mehr gemeinsamen Code in den Treibern.

Ein USB-Bustreiber verpackt die Daten und schickt sie weg. Ein SPI-Bitbanging-Bustreiber fängt an, die Daten rauszutakten.
Ja, bei diesen Bussen ist der Aufruf einer API-Funktion absolut nötig und korrekt aber bei Bussen die direkt von der CPU erreichbar sind, z.B. ISA und PCI, ist der Funktionsaufruf IMHO eine Performance-Bremse (und im Fall von gerätespezifischen Busmastering auch völlig unmöglich).
Gerätespezifisches Busmastering ist, soweit ich das verstehe, ohnehin stark vom verwendeten Bus abhängig. Du kannst Treiber, die sowas nutzen, ja auch unterhalb des HAL ansiedeln und einen Durchgriff durchs Layering definieren. Diese Treiber sind dann halt nicht portabel (und können es auch nicht sein).

Ich erwarte ja gar nicht das Du hier eine komplette Bus-API entwickelst aber wenigstens mal ein Konzept grob darlegen wäre echt nicht schlecht. Ich habe jetzt einen ganzen Haufen an Gründen genannt warum ich der Meinung bin dass das gar nicht umsetzbar (und auch nicht praktikabel) ist und Du drückst Dich um ein konkretes Beispiel wie es Deiner Meinung nach funktionieren könnte. Das ist frustrierend. :cry:
Ich schreibe halt kein OS, du schon. ;-)

Ich habe keine Ahnung von PCI und weiß u.a. nicht, wie man Scatter-Gather konkret benutzt (nur, wozu es gut ist). Eine Abstraktion für kleine Busse könnte ich vielleicht bauen, aber ohne PCI wird dir das nichts nutzen. Mal abgesehen davon sind Gedankenexperimente ohne Implementation wertlos.

Typsicherheit ist ein reines Implementationsdetail, noch dazu stark abhängig von der Programmiersprache. Außerdem: Typsicherheit wofür?
Also wenn Du als Programmierer nicht weist wofür Typsicherheit gut ist dann werde ich das wohl auch nicht erklären können.
Du hast mich missverstanden.

Wofür (für welchen Teil) soll die Typsicherheit denn sein? Zwischen Treiber und Bus-API (HAL)? Die ist zwingend gegeben, schließlich definiert deine API ja den Datentyp. Zwischen HAL und Hardware? Da arbeitest du eh nur mit Zahlen, und für die Typsicherheit muss der HAL sorgen. Zwischen Treiber und Hardware? Da liegt der HAL zwischen.

Das zweite ist, dass Typsicherheit ein Implementationsteil ist, der bei der Definition einer API keine Rolle spielen sollte - dort definierst du Datentypen. Der Compiler, der dir sagt, dass die nicht zusammenpassen, ist in der Betrachtung außen vor.

Der benötigt z.B. die genaue PCI-Geräte-ID um sich je nach Produktversion ein klein wenig anders verhalten zu können. Ein gutes Beispiel ist da der e1000-Treiber, diese HW gibt es in sehr vielen Varianten (z.B. mit Kupfer- oder Glasfaser-Anschluss) und trotz dessen dass das Grundansteuerungsprinzip immer gleich ist sind eben doch ein paar Details spezifisch zu erledigen.
Sehe ich kein Problem. Wenn du eine 64-Bit-Zahl nimmst, und für PCI-Geräte sind die oberen vier Bytes halt null und die unteren 4 Bytes sind Hersteller/Gerätenummer, dann hat der Treiber die IDs ja trotzdem vorrätig. Ansonsten hast du halt ein Typfeld (PCI=0, USB=1, SPI=2, ...) und die abstrakte Geräte-ID sieht halt, je nach Bus, verschieden aus - ist aber trotzdem konstant.

Du hast ja auch noch gar nicht erklärt wie es denn funktionieren könnte. Nimm doch einfach das Beispiel von oben mit dem Übergeben von Daten an ein Gerät (einmal PCI mit Busmastering, einmal ISA mit MMIO und dazu noch USB oder SPI mit ner Sende-Funktion) und zeige wie diese einheitliche API konkret aussehen könnte und wie die von den jeweiligen Bus-Treibern umgesetzt werden müsste.
Für PCI mit Busmastering muss ich passen. Für den Rest hast du eine Funktion zum Senden und jeweils mindestens eine Implementation in den Bustreibern:

Code: (Prototyp) [Auswählen]
int send_data(struct bus_device dev, int endpoint, void *data, int len, int dest_offset);
Code: (ISA/MMIO) [Auswählen]
int send_data_isa(struct bus_device *dev, int endpoint, void *data, int len, int dest_offset) {
  if (endpoint != 0) return -EENDPOINT; /* endpoint muss null sein */

  memcpy(dev->blackbox->mmio_base+dest_offset, data, len);
}

Code: (USB) [Auswählen]
int send_data_usb(struct bus_device *dev, int endpoint, void *data, int len, int dest_offset) {
  if (!(dev->blackbox->ep_dir &= USB_DIR_WRITE)) return -EENDPOINT; /* endpoint muss schreibbar sein */
  if (dest_offset != 0) return -EDEST; /* usb-transfers haben keinen ziel-offset */

  /* sendefunktion des hostcontrollers, untersucht den typ des endpoints und tut das richtige */
  /* blackbox ist ein bus-abhängiger container, auf den der gerätetreiber nicht zugreifen sollte */
  ehci_send_data(dev->blackbox, data, len);
}

Code: (I²C) [Auswählen]
int send_data_i2c(struct bus_device *dev, int endpoint, void *data, int len, int dest_offset) {
  int i;

  if (endpoint != 0) return -EENDPOINT;

  i2c_send_wire( I2C_DIR_WRITE | dev->id, 1 ); /* adresse senden; 1 = warte auf  ACK */
  for( i = 0; i < len-1; i++ )
    i2c_send_wire( data+i, 1 ); /* sende daten mit ACK (fortsetzung folgt) */

  i2c_send_wire( data+len-1, 0); /* sende daten ohne ACK (letztes paket) */
}

I²C ist bei mir schon eine Weile her, ob das mit dem ACK/NACK stimmt, weiß ich gerade nicht. Grundsätzlich hast du hierbei eine Black Box, die den Status für den Bus-Treiber (HAL) enthält, und der nur von den jeweiligen Bustreibern verwaltet wird (werden sollte). Und das ganze hier ist ein Gedankenexperiment.

Ein Treiber darf trotzdem darauf zugreifen, gibt damit aber seine Portabilität auf, ist potentiell abhängig von der Version des Bustreibers - und hat damit die Möglichkeit, direkt auf das Gerät zuzugreifen und Dinge zu tun, die von der Abstraktion nicht erfasst werden.

Um eine Hardware zum Laufen zu kriegen, sollte jeder Treiber mit der Abstraktion auskommen können. Ein maschinenspezifischer Treiber, der irgendwelche tollen Features nutzt, kann sich ja auch direkt mit dem Bustreiber unterhalten, statt über den HAL zu gehen.

Daraus folgt das Du einen neuen Treiber (für Dein USB-Interface) programmieren musst (auch wenn Du sicher viele Code-Teile vom NE2000-Treiber übernehmen kannst) und daher bin ich der Meinung das die Bus-Abstraktion in diesem Fall schon mal nicht funktioniert hat.
Der Treiber muss darüber informiert sein, dass die Ansteuerung hier anders läuft. Also wirfst du in die Sendefunktionen eine Unterscheidung rein, die je nach Zugriff den richtigen Endpoint auswählt und der Treiber funktioniert dann auch mit dieser Hardware. Ich brauche keinen neuen NE2000-Treiber schreiben und ich brauche vor allem nicht aus dem vorhandenen NE2000-Treiber die Einzelteile raussuchen, die ich weiternutzen kann. Siehe oben.

Klar könntest Du die IO-Zugriffe vom System alle abfangen lassen und die dann in einer Emulationsschicht für Dein USB-Interface umsetzen (in der Art wie das diese LPT-ISA-Sache macht) damit der alte NE2000-Treiber noch funktioniert aber das verstehe ich persönlich nicht unter Abstraktion (des entspricht IMHO der Virtualisierung).
Das ist auch ein böser Hack und keine schöne Lösung.

Gruß
Titel: Re: Bussysteme und deren Abstraktion
Beitrag von: erik.vikinger am 19. February 2011, 14:49
Hallo,


dass ich den PCI-Bus bei weitem nicht so gut kenne wie du. Eigentlich überhaupt nicht
Ja, das scheint  mir auch so. Ich könnte Dir ja jetzt die PCI-Spec, die PCI-Express-Spec und die HyperTransport-Spec ans Herz legen damit Du einen Eindruck von PCI und seinen Verwandten bekommst. Damit Du dann noch eine gute Vorstellung davon bekommst wie man mit diesen Möglichkeiten am besten umgeht wären die AHCI-Spec, die EHCI-Spec, die xHCI-Spec und das Driver-Developer-Manual für die e1000-Serie ein guter Rat. Das sind dann so etwa 4000 bis 5000 Seiten aber das Wochenende hat ja gerade erst angefangen. ;)
Und selbst wenn Du das alles komplett gelesen hast (was ich nicht getan habe) hab ich immer noch fast 10 Jahre Vorsprung was die Entwicklung von PCI-Hardware und deren Ansteuerung per Software betrifft.

Ja, ich beziehe mich sehr oft auf PCI, einfach weil dass das ist womit ich mich am besten auskenne und natürlich weil der PCI die mächtigsten Möglichkeiten bietet. Trotzdem bin ich der Meinung selbst wenn man PCI gut im Griff hat heißt das noch nichts für SPI, I²C oder USB da diese Busse anders arbeiten. Bei PCI, ISA und der Gleichen hat man üblicherweise ne Reiche an Registern zur Verfügung (unabhängig davon ob die nun im IO-Adressraum oder im Speicher-Adressraum liegen) über die man die Hardware steuert und deren Status ermittelt. Diese Register lassen sich beliebig (vor allem in beliebiger Reihenfolge) lesen und schreiben. Bei den eher Byte-Strom orientierten Bussen wie eben UBS, SPI usw. versucht man das Ansteuerungskonzept auf Paketen aufzubauen in denen meistens ein Job kodiert ist und auch gleich die Nutzdaten mit dabei sind. Der Paket-Overhead ist meistens zu groß als das man für jedes Bisschen eine eigene Anfrage an das Gerät schickt. Gerade dieser grundlegende Unterschied macht es meiner persönlichen Meinung nach unsinnig diese 2 grundverschiedenen Philosophien in einen Topf zu werfen. Ich hätte kein Problem damit wenn man versucht SPI, I²C, OneWire und Ähnliche Busse hinter einer gemeinsamen Abstraktion zu verbergen, schon weil es für alle sehr ähnliche Geräte (kleine Sensoren für Temperatur u.ä., EEPROMs, AD/DA-Wandler u.a.m.) gibt die auch oft sehr ähnlich angesteuert werden. Hier würde es einfach Sinn ergeben wenn man da Gemeinsamkeiten zusammen fasst, es gibt in dieser Bus-Kategorie eben auch viele Gemeinsamkeiten und nur wenige Unterschiede (die sich vor allem im physischen Protokoll finden). Aber dort Dinge wie ISA, EISA, NuBus, MCA, VLB oder auch PCI mit rein zu packen ist meiner Meinung nach von vorn herein zum Scheitern verurteilt einfach weil die Gemeinsamkeiten zwischen diesen 2 Welten zu wenige bzw. kaum existent sind. Dinge wie Busmastering und MMIO sind bei SPI, I²C usw. einfach nicht realisierbar und die Paketorientierung wird man bei ISA usw. nicht benutzen weil man ja Register hat die direkt von der CPU (bzw. der darauf laufenden SW) angesprochen werden können.

Genau deswegen ist es auch unmöglich das Ansteuerungskonzept eines PCI-Gerätes auf ein Gerät zu übertragen das an einem Bus hängt der nicht mindestens über die selben Features, wie z.B. Busmastering, wie PCI verfügt und deswegen kann der Geräte-Treiber seine Hardware auch nur als PCI-Gerät ansprechen.
Da kann ich nicht viel zu sagen. Höchstens, dass deine API ja nach der Ansteuerung über den PCI-Bus modelliert sein kann.
PCI gibt das Ansteuerungskonzept für die Geräte nicht vor, es werden nur gewisse Rahmenbedingungen vorgegeben. Wie das Busmastering dann realisiert wird ist von PCI-Gerät zu PCI-Gerät völlig anders. Deswegen kann es für PCI keine zentrale Instanz geben die das Busmastering für verschiedene oder gar unbekannte Geräte ansteuert und deswegen kann es für Deinen send_data-Code auch keine PCI-Version geben.

Wenn die Hardware halt sowohl Speicher- als auch Portzugriffe benötigt, dann wird der Treiber schon so strukturiert sein, dass er zwei Funktionen "send_mem" und "send_io" enthält, die dann entsprechende Funktionen der Busabstraktions-API aufruft oder, wenn du sowas nicht hast, direkt arbeitet. Und wenn die USB-Variante jetzt zwei Endpoints anbietet, die als Speicher- bzw. Portendpunkt funktionieren, dann sind das im Treiber nur wenige Zeilen und ein switch, um das zu implementieren.
Sorry, wenn ich das so direkt frage aber viel Erfahrung mit Treiberprogrammierung hast Du nicht oder? In vielen alten Treibern gibt es write_port() und read_port() und diese Funktionen enthalten effektiv nur einen Assemblerbefehl und werden deswegen geinlined (falls es nicht eh bloß Makros sind). Diese Funktionen oder Makros werden demzufolge sehr häufig benutzt, schließlich sind für viele Aufgaben mehrere Register-Zugriffe erforderlich. Wenn man versuchen würde dieses Konzept 1:1 auf einen Byte-Strom orientierten Bus wie USB zu übernehmen käme da nichts sinnvolles bei raus. Dann wären write_port() und read_port() richtige Funktionen die jedes mal einen kompletten Kommunikationsvorgang zwischen Geräte-Treiber und Hardware benötigen und dass das nicht sonderlich zielführend ist dürfte klar sein.

Wenn du allerdings keine gemeinsame Busabstraktion hast (sondern dein HAL eine API für PCI implementiert, eine ganz andere API für USB usw.), dann ist das schon wesentlich umständlicher und läuft am Ende auf einen völlig neuen Treiber hinaus, mit identischem, mehrfach vorhandenem Code usw; es sei denn, du faktorisierst den gemeinsamen Anteil heraus. Das ist eine Menge Arbeit und wird meist nicht (oder sehr viel später) gemacht.
Ja, da hast Du recht. Aber wo stört das? Es gibt keine Geräte die bei PCI und USB in identischer Form vorliegen also gibt es einfach keinen Bedarf für eine gemeinsame API.
Du hast ein paar mal die NE2000 als Beispiel angeführt aber dabei unterschlagen das es das Ansteuerungskonzept, das nur auf ein paar IO-Registern und einem Interrupt basiert, auf all den Bussen, für die es die NE2000 gab, auch identisch zur Verfügung steht. Unter den direkt CPU-erreichbaren Bussen auf der PC-Plattform sind IO-Register, MMIO und Interrupts quasi ne Art kleinster gemeinsamer Nenner und deswegen kann ein Treiber alle NE2000-Implementierungen ansteuern ohne das er sich dafür interessieren muss an welchem Bus diese NE2000 nun konkret hängt. Aber eine PCI-Version der NE2000 funktioniert z.B. nur wenn der zugewiesene Interrupt nicht geshared wird, damit können zumindest die älteren DOS-Treiber nicht umgehen. Für die NE2000 ist eine Busabstraktion quasi nicht erforderlich, von der Beschaffung der IO-Basis-Adresse und der IRQ-Nummer mal abgesehen. Für USB, SPI, I²C, OneWire usw. (also alle Busse die die CPU nicht direkt erreicht) ist immer eine Busabstraktion erforderlich schließlich will der Geräte-Treiber sich nicht auch noch um die konkrete Realisierung der physischen Busansteuerung kümmern müssen. Es wäre ja wohl auch Unsinn wenn der Treiber für USB-Mäuse sich mit OHCI, UHCI, EHCI und xHCI auskennen müsste, das ist der Job für die USB-Abstraktionsschicht. Bei ISA, PCI usw. sorgt die CPU und der Chipsatz dafür das IN und OUT immer gleich funktionieren.

Bei Linux sieht man das jetzt wieder für die r300g- und r600g-Treiber, wo komplett verschiedene Shaderimplementierungen benutzt werden und jetzt der r300g-Anteil (den es schon vorher gab und der schneller/besser ist) rausfaktorisiert wird, um ihn in r600g nutzen zu können.
Dieses Problem liegt aber sicher nicht an einer fehlenden Busabstraktion. Da wurde wohl irgendetwas anderes in den Treibern ungünstig realisiert und das muss wohl nun korrigiert werden. Wenn zwischen 2 unterschiedlichen aber ähnlichen Geräten eine gewisse Menge an Gemeinsamkeiten vorhanden sind dann ist es wohl auch geschickt dafür gemeinsamen Quell-Code zu benutzen.

Um es noch mal ganz klar zu schreiben: für reale Gemeinsamkeiten sollte man auch meiner Meinung nach gemeinsamen Code nutzen.
Das Problem zwischen ISA/EISA/MCA/PCI auf der einen Seite und USB/SPI/I²C/OneWire auf der anderen Seite ist nur das dort keine Gemeinsamkeiten vorhanden sind.
Ein gutes Beispiel für Gemeinsamkeiten ist z.B. das MII-Interface bei Ethernet-Controllern, über dieses in der IEEE-802.3-Spec genormte Interface wird z.B. die Geschwindigkeit und Vollduplex/Halbduplex ausgehandelt. Daher lagert man das üblicherweise in eine extra Library aus die der Ethernet-Geräte-Treiber benutzt um eben diese Informationen zu bekommen mit denen er dann selber seinen Ethernet-Controller passend konfiguriert und zwar unabhängig davon ob der Ethernet-Controller per ISA, PCI, USB oder anders angeschlossen ist. Damit diese MII-Library arbeiten kann muss der Geräte-Treiber aber wieder ein abstraktes/vordefiniertes Interface anbieten über das die MII-HW-Komponente durch den spezifischen Ethernet-Controller hindurch erreichbar ist (wie die physische Verbindung zwischen dem Ethernet-Controller und der MII-Komponente aussieht ist nicht fest vorgegeben, es müssen ja auch nicht unbedingt 2 einzelne Chips sein denn es gibt auch Ethernet-Controller wo der Phy schon mit drin ist).

Gerätespezifisches Busmastering ist, soweit ich das verstehe, ohnehin stark vom verwendeten Bus abhängig. Du kannst Treiber, die sowas nutzen, ja auch unterhalb des HAL ansiedeln und einen Durchgriff durchs Layering definieren. Diese Treiber sind dann halt nicht portabel (und können es auch nicht sein).
Vom Bus ist das Busmastering eher weniger abhängig, der Bus muss das nur grundsätzlich ermöglichen. Mann könnte PCI auch gegen einen ganz anderen Bus austauschen, solange der neue Bus auch Busmastering, MMIO, Interrupts und P&P unterstützt sollten die meisten Geräte-Treiber ohne eine Änderung funktionieren (mal von Dingen abgesehen die von einer konkreten Device-ID anhängig sind). Schon wenn Du mal PCI mit seinen Verwandten vergleicht stellt man schnell fest das die eigentlich nur das höhere Protokoll gemeinsam haben. Ich denke eine der Stärken von PCI ist es das Konzept von der physischen Implementierung zu trennen. Wenn man dann mal das P&P-Zeugs von PCI mit USB vergleicht wird man auch dort sehr viele Gemeinsamkeiten feststellen. Zumindest auf PCI-Express, mit seinen Bridges und reinen Punkt-zu-Punkt-Verbindungen sollte man das USB-P&P übertragen können ohne das die Geräte-Treiber das merken würden (so lange die selben Informationen wie Vendor/Device-ID, BARs usw. zur Verfügung stehen).

Wofür (für welchen Teil) soll die Typsicherheit denn sein? Zwischen Treiber und Bus-API (HAL)? Die ist zwingend gegeben, schließlich definiert deine API ja den Datentyp. Zwischen HAL und Hardware? Da arbeitest du eh nur mit Zahlen, und für die Typsicherheit muss der HAL sorgen. Zwischen Treiber und Hardware? Da liegt der HAL zwischen.
Du hast mich wohl auch missverstanden. Ich meinte die Typsicherheit für den Geräte-Treiber bei der Kommunikation mit dem HAL. Wenn Du Dinge wie die Geräte-Adresse in einen 64Bit-Datentyp verpackst dann muss jeder Treiber das wieder so entpacken wie das für den Bus an dem das Gerät hängt vom HAL benutzt wird. Also wenn ein Geräte-Treiber für ein PCI-Gerät die Bus-Nummer/Device-Nummer/Function-Nummer haben will dann muss er diesen unspezifischen 64Bit-Typ korrekt zerlegen können und das selbe Problem hat auch der Geräte-Treiber für I²C-Geräte der die 7Bit-Adresse haben möchte. Hier ist es IMHO besser wenn der PCI-Geräte-Treiber direkt eine PCI-spezifische HAL-Funktion fragen kann aus der das gewünschte Trio typsicher raus kommt und das selbe für USB wo eine implementierungsspezifische Bus-Nummer und eine 7Bit-Geräte-Adresse als Ergebnis kommen.

Sehe ich kein Problem. Wenn du eine 64-Bit-Zahl nimmst, und für PCI-Geräte sind die oberen vier Bytes halt null und die unteren 4 Bytes sind Hersteller/Gerätenummer, dann hat der Treiber die IDs ja trotzdem vorrätig. Ansonsten hast du halt ein Typfeld (PCI=0, USB=1, SPI=2, ...) und die abstrakte Geräte-ID sieht halt, je nach Bus, verschieden aus - ist aber trotzdem konstant.
Ich sehe da ein Problem. Du kannst dann dieses Detail nie wieder am HAL ändern. Oder der HAL muss für jeden Bus dafür eine Entpack-Funktion anbieten aber dann hätte man sich die gemeinsame Basis IMHO auch gleich sparen können.

Für PCI mit Busmastering muss ich passen. Für den Rest hast du eine Funktion zum Senden und jeweils mindestens eine Implementation in den Bustreibern:

Code: (Prototyp) [Auswählen]
int send_data(struct bus_device dev, int endpoint, void *data, int len, int dest_offset);[......]
Hm, find ich irgendwie nicht so toll. 'endpoint' und 'dest_offset' sind IMHO redundant da wohl kaum beides benötigt wird. Für PCI muss ich ebenfalls passen, einfach weil das so nicht geht.

Um eine Hardware zum Laufen zu kriegen, sollte jeder Treiber mit der Abstraktion auskommen können. Ein maschinenspezifischer Treiber, der irgendwelche tollen Features nutzt, kann sich ja auch direkt mit dem Bustreiber unterhalten, statt über den HAL zu gehen.
Also "zum Laufen zu kriegen" wird oft nicht genug sein, schließlich hat der HW-Designer viel Zeit und Mühe investiert um das Gerät genau so zu bauen damit es maximale Performance/Funktionalität/sonstwas erreicht und der Treiber-Programmierer wird es nicht gerne sehen wenn dann nur ein Bruchteil davon mit dem HAL funktioniert. Wenn die Treiber-Programmierer sich daran gewöhnt haben am HAL vorbei zu entwickeln dann hätte der OS-Programmierer diesen HAL auch gleich ganz bleiben lassen können.

Der Treiber muss darüber informiert sein, dass die Ansteuerung hier anders läuft. Also wirfst du in die Sendefunktionen eine Unterscheidung rein, die je nach Zugriff den richtigen Endpoint auswählt und der Treiber funktioniert dann auch mit dieser Hardware. Ich brauche keinen neuen NE2000-Treiber schreiben und ich brauche vor allem nicht aus dem vorhandenen NE2000-Treiber die Einzelteile raussuchen, die ich weiternutzen kann. Siehe oben.
Ich weiß ja nicht von welcher Ebene Deine "Sendefunktion" ist aber wenn die sich z.B. auf die Ethernet-Frames bezieht dann muss ich Dir sagen das der eigentliche Treiber erst da drunter liegt. Ein Ethernet-Treiber macht nichts anderes als Ethernet-Frames zu versenden und zu empfangen, ist also eine Art packetorientierte serielle Schnittstelle (nur ein kleines bisschen schneller und damit die CPU nicht zum PIO-Flaschenhals wird, so wie bei nem normalen UART, benutzt man heutzutage eben Busmastring wogegen die NE2000 nichts weiter als ein besserer UART mit altbackenem PIO-Interface war).

Das ist auch ein böser Hack und keine schöne Lösung.
Na wenigstens etwas über das wir einer Meinung sind. Das ist doch schon mal ein Anfang. ;)


Grüße
Erik