Autor Thema: [Erledigt] Port-Verwaltung  (Gelesen 14850 mal)

Programm Noob

  • Gast
Gespeichert
« am: 09. August 2010, 16:15 »
Moin

Ich möchte die Hardware Ports verwalten, so das nicht jeder Prozess auf jeden Port zugreifen kann sondern nur die, die er auch registriert hat.
Eine Möglichkeit, die mir aber nicht so gefällt.(Weshalb später mehr.) Wäre eine Bitmap. Also für jeden Port ein Bit. Dazu taucht eine Frage auf, wie viele Ports kann es geben? Die adresse ist ja ein 16 Bit wert. Gehen also alle Adressen von 0x0000 bis 0xFFFF?
Nun was mir an dieser lösung nicht gefällt. Wenn ein Port von einem Prozess registriert wurde und ein anderer Prozess diesen auch gerne hätte. Dachte ich mir, das ich dann den Prozess frage, der den Port registriert hat, ob er diesen noch braucht oder ob der andere Prozess ihn haben könnte.
Also:
Prozess A registriert sich Port 0x11
Prozess B registriert sich Port 0x11

In diesem fall würde register_port(Die Port registrier-funktion) false zurück geben.

Ich fände es aber schöner, wenn es so ginge:
Prozess A registriert sich Port 0x11
Prozess B registriert sich Port 0x11
register fragt jetzt über IPC Prozess A ob der port noch benötigt wird, wenn nicht, dann wird der Port auf Prozess B übertragen. Wenn der Port noch benötigt wird, dann gibt register_port false zurück.

Da ich IPC über die PID machem wollte, müsste die Recourcen verwaltung aber wissen, welche Ports zu welcher PID gehören. Wie kann man das am besten machen?

Programm Noob
« Letzte Änderung: 11. August 2010, 20:56 von Programm Noob »

Cjreek

  • Beiträge: 104
    • Profil anzeigen
Gespeichert
« Antwort #1 am: 09. August 2010, 16:50 »
Ich war bisher leider nicht so weit fortgeschritten, dass ich mir um sowas Gedanken machen musste. Aber rein ausm Gefühl her finde ich es generell riskant mehr als 1 Programm einen Port registrieren zu lassen. (Diese Programme sind ja wahrscheinlich dann Treiber). Selbst wenn Programm A den Port X gerade nicht braucht, ist es schon beschissen, wenn B irgendwas rumpfuscht, von dem A dann später nichts weiß.
"Programmers talk about software development on weekends, vacations, and over meals not because they lack imagination,
but because their imagination reveals worlds that others cannot see."

FlashBurn

  • Beiträge: 844
    • Profil anzeigen
Gespeichert
« Antwort #2 am: 09. August 2010, 16:55 »
Also erstmal, deine Bedenken (bezüglich der Bitmap) sprechen absolut nicht gegen die Bitmap!

Ich z.B. nutze auch eine Bitmap dafür bzw. musst du eh eine nutzen (je nach dem wie du den eigentlichen Port-Zugriff machst), wenn du die Ports über die IO-Bitmap des TSS freigeben möchtest.

Welche Situation kannst du dir denn vorstellen, wo ein Prozess einen Port zu kurz bräuchte? Denn an und für sich sollten nur Treiber zugriff auf Ports haben und die werden die auch nicht wieder freigeben, es sei denn sie werden beendet.

Wenn du die IO-Bitmap des TSS nutzt, dann weißt du doch welcher Prozess welche Ports "hat". Du musst dann nur noch an einer globalen Stelle speichern (mach ich auch über ne Bitmap) welche Ports "frei" und welche "besetzt" sind.

Nächste Frage wäre, ob du einen reinen monolithen Kernel, einen halb monolithen Kernel (mit User-Mode-Treibern) oder nen Mikrokernel schreiben willst?

Programm Noob

  • Gast
Gespeichert
« Antwort #3 am: 09. August 2010, 17:25 »
@Cjreek natürlich wird ein port nicht doppelt registriert. Und ein anderer Prozess bekommt nur das ja, wenn Prozess A egal ist, was mit dem Port gemacht wird.

@Flashburn Ich benutze nicht die TSS-BitMap sondern will etwas eigenes machen. Es soll ein Microkernel werden.


Ich glaube ich habe mich ein wenig undeutlich ausgedrückt und habe einen vesentlichen Punkt vergessen. Und zwar soll diese IPC abfrage natürlich nicht den Prozess direkt fragen, sondern es gibt eine funktion, zum freigeben von Ports, diese soll jedoch nicht wie die registrierfunktion einen Syscall auslösen sondern nur eine variable setzen, um zu signalisieren, das dieser port frei ist. So gibt es nur dann einen Syscall, wenn a Ein anderes Programm diesen Port möchte oder b das Programm beendet wird. Ein Programm kann in diesem falle auch ein Treiber sein. Ich hoffe ihr vesteht das so.

Programm Noob

FlashBurn

  • Beiträge: 844
    • Profil anzeigen
Gespeichert
« Antwort #4 am: 09. August 2010, 17:59 »
Also wie gesagt, welche Situation stellst du dir vor das ein Treiber (ein Programm sollte wirklich keinen Zugriff auf Ports haben, sondern nur Treiber) einen Port nicht mehr nutzen möchte?

Ich meine warum sollte Prozess A nen Port anfordern und dann ist es ihm mit einmal egal was mit ihm passiert?

Desweiteren würde ich, aus Sicherheitstechnischen Gründen, nicht den Prozess entscheiden lassen welchen Port er bekommt, sondern würde dem Prozess nur bestimmte Ports geben, von denen du weißt das er sie braucht! Denn ansonsten kann ich mir als Prozess einfach versuchen alle Ports zu holen und dann können keine neuen Treiber mehr gestartet werden!

Wie willst du sicherstellen das ein Treiber nur die Ports nutzt die es auch nutzen darf (ich kenne da nur noch eine Möglichkeit außer der IO-Bitmap des TSS)?

Gut ein Mikrokernel, aber wie "mikro" soll der werden ;) Ich meine damit, das ich z.B. ne Art "Device Server" machen will, der die ganze Port-/Hardwareverwaltung dann regelt. Die meisten Mikrokernels machen das aber im Kernel.

Da ich die Ports von einem Server verwalten lasse, muss ich auch sowas wie einen Port an einen anderen Prozess abgeben machen. Bei funktioniert das dann so (wenns denn dann mal fertig ist), dass der Kernel am Anfang alle Ports besitzt. Wird der Device Server gestartet bekommt dieser alle Ports.
Wenn der Device Server dann einen Treiber startet gibt er die rechte für die nötigen Ports an den Treiber weiter.
Was ich noch nicht gemacht habe, ist dass die Ports wenn der Treiber  beendet wird wieder an den Device Server übergehen, aber das kann man ganz einfach machen, indem die Ports beim Beenden an den Parent gegeben werden.

Also zusammengefasst würde ich die globale Verwaltung welcher Port frei ist und welche nicht im Kernel über eine Bitmap machen. Wie du dann die Ports weitergibts ist eine andere Sache.

Programm Noob

  • Gast
Gespeichert
« Antwort #5 am: 09. August 2010, 18:20 »
Ich habe einen Dienst, der sich nur um die verwaltung von Ports und Speicherbereichen kümmert. Also z.B. Der PCI registriert sich den Daten un Commandport. Danach sucht der PCI Treiber alle Geräte inlusive der BAR's und meldet diese den Dienst meldet. Wenn sich jetztz ein Treiber beim Treiberinterface registriert, dann fragt das Treiberinterface beim Recourcen Dienst nach den BAR's

So und hier haben wir eine schöne Situation, wo es dem Prozess egal ist, was mit dem Command und dem Daten Port passiert.

Programm Noob

FlashBurn

  • Beiträge: 844
    • Profil anzeigen
Gespeichert
« Antwort #6 am: 09. August 2010, 20:32 »
Du meinst aber nicht den PCI Daten und Commandport oder? Denn das sollte deinem Dienst nicht egal sein, was mit dem passiert!

Der Dienst sollte immer Herr über diese beiden Ports sein. Denn stell dir mal vor was passiert wenn jeder macht was er will mit diesen Ports!

Also ich würd einfach für jeden Prozess der Ports anfordert ne Bitmap anlegen (die ist dann jedes Mal 8KiB groß) und da die Ports "markieren" die er nutzen darf.

Wenn du dann die Ports von einem Prozess zu einem anderen weiter geben willst, dann markierst du sie in dem gebenden Prozess als nicht nutzbar und in dem empfangenden Prozess als nutzbar.

Programm Noob

  • Gast
Gespeichert
« Antwort #7 am: 09. August 2010, 21:01 »
Doch ich meinte die PCI Ports. Hab aber gerade selber gemerkt, das es murks ist. Eine Bitmap pro Prozess ist eine gute idee. Aber 2 Fragen bleiben noch:

 We viele io-Ports gibt es?
Wie kann ich in der Portverwaltung eine übersichtbekommen, welcher IO-Port von welchem Prozess benutzt wird. Alle einzelnen Bitmaps zu durchsuchen finde ich ein wenig umständlich. Hat da jemand einen guten Vorschlag? Es geht nur darum die Portnummer und dir Pid zu verknüpfen.

Programm Noob

FlashBurn

  • Beiträge: 844
    • Profil anzeigen
Gespeichert
« Antwort #8 am: 09. August 2010, 21:11 »
Es gibt 65536 (= 0x10000) Ports.

Was willst du denn genau erreichen/machen? Wieso musst du wissen welcher Port "zu" welchem Prozess gehört?

Eine Idee (aber Speicher verschwenderisch) wäre ein Array: uint32t ports2pid[0x10000].

Aber wie gesagt was willst du machen?

Programm Noob

  • Gast
Gespeichert
« Antwort #9 am: 09. August 2010, 21:45 »
Ich möchte das Wissen, um mir die zu Debug zwecken und später bei der Prozess-Übersicht ausgeben zu lassen

Programm Noob

FlashBurn

  • Beiträge: 844
    • Profil anzeigen
Gespeichert
« Antwort #10 am: 09. August 2010, 21:51 »
Naja, zu debug Zwecken reicht die Bitmap vollkommen aus und auch bei einer Art TaskManager dürfte das noch reichen, es sei denn deine Prozesse gehen in die tausende.

Ich weiß ja nicht wie gut deine Programmierkenntnisse sind, aber der SlabAllocator im Solaris OS (ich bin mir nicht sicher, aber kann sein, dass das auch im Linux Kernel so genutzt wird) nutzt was interessantes für IDs und Bereiche, das wäre für Ports auch genau richtig.
Ich habe leider noch nicht die Zeit gefunden mir das mal näher anzugucken, zumal meine momentane Implementierung für meine Zwecke noch ausreicht.

Programm Noob

  • Gast
Gespeichert
« Antwort #11 am: 09. August 2010, 22:14 »
Also meine Programmierkenntnisse sind meiner Persönlichen Einschätzung nach Ausreichend fürs OS-DEV, auch wenn einige mr was anderes weiß machen wollten. Aber von diesem SlabAllocator hab ich bisher noch nichts gehört. Kannst du mir da ein paar Infos zu geben?

Wenn alle Treiber und Dienste laufen, werden es sicherlich mehr als 500 Prozesse und wenn ich alle Bitmaps überprüfen soll, das wären dann 500*65536 = 32768000 Bit-operationen. Und das, ja nicht nur einmal, wenn der user die Ansicht Aktualisiert, müssen wieder alle abgefragt werden und ich verschenke lieber 256kb Speicher als das ich 32768000 Bit-Operationen durchführe, selbst wenn man das optimiert und ports die ein Prozess schon belegt nicht mehr bei den anderen überprüft, sind es zu viele. Was meinst du, wie schnell das dann auf nem AMD k6 oder so laufen soll?

Programm Noob

Jidder

  • Administrator
  • Beiträge: 1 625
    • Profil anzeigen
Gespeichert
« Antwort #12 am: 10. August 2010, 01:10 »
Wenn alle Treiber und Dienste laufen, werden es sicherlich mehr als 500 Prozesse und wenn ich alle Bitmaps überprüfen soll, das wären dann 500*65536 = 32768000 Bit-operationen.
Soviele werden es vermutlich nicht, aber natürlich sollte man den Worst Case auch betrachten. Der ist allerdings weniger drastisch, als du es darstellst. Die meisten Prozesse brauchen keinen direkten Portzugriff. Du kannst also mit einem einzigen Bit pro Prozess abbilden, ob überhaupt irgendwelche Ports für den Prozess freigegeben sind, und dir die Suche in der Bitmap komplett sparen.

Aber mal angenommen, 500 Prozesse haben jeweils einen I/O-Port reserviert. Dann solltest du den Durchlauf über die Bitmap zunächst so gestalten, dass du sie als DWORD-Array betrachtest. Du kannst durch einen Vergleich mit 0 testen, ob in einem DWORD überhaupt ein Bit gesetzt ist. Dann brauchst du im Worst Case nur 500*65536/32 = 1024000 Operationen. Ist natürlich immer noch viel.1) Aber 500 Prozesse sind auch viel. Da wirst du noch viel mehr Taktzyklen verbrauchen, wenn du deren Details auflisten willst.

1) Verglichen mit dem theoretisch besten Verhalten im Worst Case von 65536 Operationen (pro Port 1 Operation). Der wäre wohl erreichbar, wenn du an jedem Prozess eine verkette Liste mit Ports hast. Davon würde ich allerdings sehr abraten, weil du damit Informationen duplizierst (die Bitmap brauchst du ja eh). Den Rattenschwanz an Ärger, den das mit sich zieht sind die paar Taktzyklen nicht wert.
Dieser Text wird unter jedem Beitrag angezeigt.

FlashBurn

  • Beiträge: 844
    • Profil anzeigen
Gespeichert
« Antwort #13 am: 10. August 2010, 10:30 »
Also auf 500 Treiber (ich benutze mit absicht nicht das Wort Prozesse) wirst du nicht haben, selbst 100 währen noch viel.

Was mich aber viel mehr interessiert ist, wie du es nun realisieren willst, das ein Treiber auch nur auf die Ports zugreifen kann, die für ihn freigegeben sind?

Noch was zu den Bitmaps. Auf keinen Fall für jeden Prozess eine solche Bitmap anlegen!

Es reicht vollkommen aus, wenn du diese Bitmap nur für die Prozesse anlegst die auch Ports nutzen (den Speicher den du dadurch sparst kannst du dann in die 256KiB für das Array stecken).

Was den SlabAllocator betrifft, musst du mal nach googlen, wenn ich nachher Zeit finde, dann kann ich dir mal nen Link raussuchen. Ich kann dir nur so viel sagen, den Allocator hab ich implementiert, da ich ihn verstanden habe, aber das Zeug mit den Bereichen/IDs hab ich nicht verstanden und hab mir auch keinen Code angesehen.

Obwohl wenn der Algorithmus hält was die versprechen, dann wäre er ne gute allgemeine Lösung für viele Probleme die bei einem OS anfallen.

Ansonsten empfehle ich dir dich mal mit dem SlabAllocator zu beschäftigen, da er ne verdammt gute Lösung ist, wenn es darum geht "Objekte" (und nichts anderes sind deine ganzen Datenstrukturen) zu allozieren.

Programm Noob

  • Gast
Gespeichert
« Antwort #14 am: 10. August 2010, 14:27 »
Alle Ring 3 Task haben nicht die möglichkeit mithilfe der out und in asm Befehle auf die Ports zuzugreifen, sondern die müssen die von mir bereitgestellten Funktionen benutzen, die rufen dann einen Syscall auf und der prüft dann anhand der PortBitmap, ob der Entsprechende Port die brerechtigung hat, wenn ja dann fürt er den asm befehl aus, wenn nicht dann bricht er den Prozess mit der passenden Fehlermeldung ab.

FlashBurn

  • Beiträge: 844
    • Profil anzeigen
Gespeichert
« Antwort #15 am: 10. August 2010, 14:38 »
die 3. Möglichkeit wäre das ganze über eine Exception zu lösen, aber das ist meiner Meinung nach die schlechteste Möglichkeit.

Warum willst du nicht die IO-Bitmap des TSS nutzen? Ne Bitmap hast du ja eh schon.

Hier die Links (der 1. ist leider PostScript, habe auf die schnelle kein PDF gefunden)

http://www.usenix.org/publications/library/proceedings/bos94/full_papers/bonwick.ps 1994
http://www.usenix.org/event/usenix01/full_papers/bonwick/bonwick.pdf 2001

Programm Noob

  • Gast
Gespeichert
« Antwort #16 am: 10. August 2010, 23:48 »
Moin

Also Flashburn ich habe das jetzt mit dem Array gemacht, wobei ich statt uint32_t erstmal uint16_t genommen habe, bis 16 Bit als PID nicht mehr ausreichen, vergeht glaube ich noch viel Zeit. Stimmt ihr habt natürlich recht, es benutzen ja nur trTeiber Ports, alle anderen benötigen diese ja nicht. Daher bekommen jetzt die treiber ne ctr1.o als erweiterung, der crt0.o in der crt0.o wird alles initialisirt, was für normale Programme und Treiber initialisiert werden muss und die crt1.o legt die Port Bitmap an und registriert sich als Treiber beim Treiberinterface und ruft dann die initialisierungs routine des Treibers auf.

Frage: Warum benutzt du nicht die  bitmap der tss?
Antwort: Weil ich lieber solche Sachen selber implementiere und somit vieles besser kontrollieren kann.

Programm Noob

FlashBurn

  • Beiträge: 844
    • Profil anzeigen
Gespeichert
« Antwort #17 am: 11. August 2010, 08:15 »
Was meinst du damit das du die Sachen so besser kontrollieren kannst?

Zumal die IO-Bitmap des TSS von der Performance wesentlich besser sein sollte (ich habe keinen Beweis dafür, aber es sollte eigentlich so sein). Denn du musst jedes mal in den Kernel wenn der Treiber etwas mit einem IO-Port (schreiben/lesen) machen will.
Da ich bisher noch nicht wirklich Treiber programmiert habe weiß ich nicht ob es relevant ist, aber es gibt ja auch die Möglichkeit einen "insb" oder "outsb" zu machen, sprich mehrere "Wörter" auf einmal zu transferieren. Das müsstest du dann auch über deinen Syscall implementieren und dort holst du dir dann entweder Probleme in den Kernel oder die Performance sinkt noch weiter.
Denn du müsstest nämlich jedes Mal bevor du aus dem UserSpace lesen oder schreiben kannst, prüfen ob der Speicher vorhanden ist und ob der Prozess die nötigen Rechte hat (lesen/schreiben).

Aus diesen Gründen wäre es halt besser das alles im UserSpace gemacht wird (außer der Bitmap).

Wenn ich dich jetzt richtig verstanden habe, dann liegt die Bitmap bei dir im UserSpace und wird auch noch von diesem verwaltet?
Wenn dem so sein sollte, dann ist das ne ganz schlechte Idee! Denn das heißt auch, dass sie einfach geändert werden kann ohne das du das (als Kernel) willst.

erik.vikinger

  • Beiträge: 1 277
    • Profil anzeigen
Gespeichert
« Antwort #18 am: 11. August 2010, 12:12 »
Hallo,


Zum einen verstehe ich nicht warum ein Treiber Ressourcen wieder frei geben sollte außer wenn er beendet wird. Zu den Dingen die mehrfach benutzt werden könnten zählt IMHO der ISA-DMA-Controller, da könnte man theoretisch auf die Idee kommen einzelne Ports an den Treiber für das betreffende Gerät (welches einen oder mehrere bestimmte ISA-DMA-Kanäle benutzen will) abzugeben, da bin ich aber eher der Meinung das der Treiber für den ISA-DMA-Controller ein ordentliches Interface anbieten sollte um darüber den anderen Treibern (für Geräte die ISA-DMA benutzen) passende Dienste anzubieten.

Das mit der Verwaltungs-Bit-Map halte ich auch eher für Quatsch. Pro Gerät werden höchstens eine Hand voll Ports in wenigen zusammenhängenden Bereichen angeboten, siehe auch hier die IO-Bereiche der ISA-DMA-Controller. Ich persönlich würde eine Liste mit allen vorhandenen Geräten anlegen (diese Liste muss nicht hochperformant sein da ja nur sehr selten zur Laufzeit Hardware dazu kommt oder entfernt wird) und jede Geräte-Struktur zeigt auf eine Liste, mit konstanter Größe, in der alle Ressourcen (Speicher/Ports/IRQs) des betreffenden Gerätes, der der Form "Type/Basis/Länge", drin sind (diese Liste dürfte, außer bei GraphigKarten, kaum mehr als 5 Einträge haben). Wenn ein Treiber ein Gerät für sich beansprucht dann kann er anschließend die betreffenden Ressourcen für sich freischalten (Ports) oder einblenden (Speicher) oder Call-Back-Funktion registrieren (IRQs). Ich würde Treibern nicht erlauben irgendwelche beliebigen Ressourcen für sich zu allozieren sondern nur das Treiber komplette Geräte bekommen (oder auch nicht falls das Gerät schon in Benutzung ist).

Für Debug-Zwecke wäre es gut wenn das OS sagen könnte welche Geräte ein bestimmtes Programm (Treiber) zugeordnet bekommen hat und dann eben die Ressourcen auflisten (was bei den kurzen Ressourcen-Listen recht effizient sein sollte).

Für die Zugriffsrechte bei den IO-Ports würde ich schon die Bit-Map vom TSS nehmen (ich glaube sogar das die nicht volle Länge haben muss sondern nur bis zum letzten zulässigen Port reichen muss) damit kann eine x86-CPU die Zugriffsrechte sehr schnell prüfen (deutlich schneller als jeder SW-Mechanismus) und löst daher nur bei verbotenen Ports eine Exception aus.


Grüße
Erik
Reality is that which, when you stop believing in it, doesn't go away.

Programm Noob

  • Gast
Gespeichert
« Antwort #19 am: 11. August 2010, 14:49 »
Moin
Jeder treiber hat eine eigene Bitmap, wenn ein Port erfolgreich registriert wurde, dann trägt der Kernel die Pid in seine Master Map ein und der Treiber in die eigene Bitmap, beim drauf zugreifen, wird erst im Userspace nachgesehen, ob dort das entsprechende Bit gesetzt ist, wenn nicht bricht er ab und wenn ja, dann löst er einen Syscall aus, der guckt dan in der Master Map nach, ob der Port wirklich für die Pid registriert wurde, wenn nein, dann wird der Prozess gekillt, wenn ja, dann wird der Befehl ausgeführt.
Ich hoffe die fragen sind jetzt geklärt.

 

Einloggen