
Dieser Artikel ist die logische Konsequenz aus einer
Reihe von „Climbing Elbrus“ -Artikeln zur Einführung von
Embox in die
Elbrus-Prozessorarchitektur (E2K) . Warum eine logische Schlussfolgerung, denn als Ergebnis war es möglich, über Telnet eine Anwendung auszuführen, die das Bild auf dem Bildschirm anzeigt, dh, die volle Arbeit von Embox auf dieser Architektur zu erreichen. Weitere Forschungen können kaum als Einführung bezeichnet werden, obwohl natürlich noch vieles unklar bleibt. Und die Architektur selbst hat viele interessante Merkmale, die derzeit auch nicht verstanden werden. In diesem Artikel werden wir uns auf die Organisation des virtuellen Speichers konzentrieren, PCI ansprechen, ein wenig über eine Netzwerkkarte sprechen und eine Grafikkarte auf einer bestimmten Hardware ansprechen, über die wir verfügen.
Für diejenigen, die zu faul sind, um den Artikel zu lesen, werde ich sofort ein kurzes Video mit den Ergebnissen geben.
Und jetzt für diejenigen, die interessiert sind, werden wir die technischen Details enthüllen, die wir in dem Prozess verstehen konnten.
Virtueller Speicher
Unser Stapelfehler
Beginnen wir mit dem virtuellen Speicher. Darauf haben wir uns im vorigen
Artikel der Serie geeinigt. Es lohnt sich, sich sofort daran zu erinnern, warum wir virtuellen Speicher benötigt haben, da Embox ohne diesen arbeiten kann. Es ist ganz einfach: Die Sache ist Caching. Vidyaha funktionierte, aber ich musste dasselbe zweimal im Videospeicher aufzeichnen, um ein zuverlässiges Abrufen von Bildern zu ermöglichen. Natürlich war es möglich, mit dem Cache umzugehen, aber in unseren Beispielen wurde der Videospeicher direkt von einer Benutzeranwendung aus verwendet, ohne dass Kernelemente wie die Cache-Verwaltung erforderlich waren. Daher war es richtig, zu lernen, wie Speicher als nicht cachefähig zugeordnet werden kann. Dasselbe kann unter Linux durch Zuordnen von fb (
Beispiel ) erreicht werden.
Es ist erwähnenswert, dass wir zwar lange nicht über Elbrus geschrieben haben und es den Anschein haben könnte, dass MMU in dieser Architektur eine Art superkomplizierte Sache ist, aber die Sache ist anders. Tatsächlich haben wir im Sommer Unterstützung hinzugefügt, wir haben einfach nicht unsere Hände erreicht, um darüber zu schreiben. Aufgrund unseres blöden Fehlers wurde eine lange Zeit (mehrere Monate) verbracht. Dieser Fehler wurde sogar im Titel des Artikels gemacht ("Oder vergessen Sie nie, was Sie während des Nachrichtendienstes bekommen haben"). Wir sprechen von Stacks, mit denen wir uns ziemlich gut auseinandergesetzt haben und die wir im Artikel Climbing
Elbrus - Reconnaissance beschrieben haben. Technischer Teil 1. Register, Stapel und andere technische Details .
" Wir haben sehr lange gelitten und dabei dummerweise die Tatsache aus den Augen verloren, dass wir den anfänglichen Stapel (auf dem das System initialisiert ist) von irgendwo außerhalb genommen und alles abgebildet haben. Damit Embox funktioniert, haben wir diese Daten nicht zugeordnet.
Unter der Katze gebe ich eine neue Funktion e2k_entry, die im zweiten Artikel des
Artikels in der Reihe beschrieben wird .
Auf Wunsch können Sie vergleichen.
__attribute__ ((__section__(".e2k_entry"))) void e2k_entry(struct pt_regs *regs) { if (entries_count >= CPU_COUNT) { e2k_trap_handler(regs); RESTORE_COMMON_REGS(regs); E2K_DONE; } e2k_wait_all(); entries_count = __e2k_atomic32_add(1, &entries_count); if (entries_count > 1) { while(!sync_count); context_init(&cpu_ctx[0], CONTEXT_PRIVELEGED | CONTEXT_IRQDISABLE, cpu_idle, idle_stack, sizeof(idle_stack)); context_switch(&cpu_ctx_prev[0], &cpu_ctx[0]); } context_init(&cpu_ctx[1], CONTEXT_PRIVELEGED | CONTEXT_IRQDISABLE, e2k_kernel_start, &_stack_top, KERNEL_STACK_SZ); sync_count = __e2k_atomic32_add(1, &sync_count); context_switch(&cpu_ctx_prev[1], &cpu_ctx[1]); }
Ich werde nur erklären, dass wir jetzt die Funktionen context_init () und context_switch () nur verwenden, um den Stapel in den Speicher im Embox-Bereich zu verschieben. Und das tun wir für alle Kerne, auch für solche, die nicht verwendet werden.
MMU-Organisation
Jetzt werde ich ein wenig über die Organisation der MMU in der E2k-Architektur sprechen.
Im Allgemeinen ist die MMU-Architektur recht gewöhnlich und verfügt über Tabellen mit vier Ebenen (oder drei, wenn eine 4-MB-Seite verwendet wird).
In der E2k-Architektur gibt es mehrere Serviceregister, auf die über Zugriffsbefehle auf alternative Bereiche sowie auf den E / A-Bereich zugegriffen werden kann, der im Artikel
„Embox beginnt mit dem Aufstieg auf Elbrus“ kurz beschrieben wird.
Wir werden solche Register brauchen:
#define MMU_REG_CR 0x00 #define MMU_REG_CONT 0x10 #define MMU_REG_CR3_RG 0x20 #define MMU_REG_ELB_PTB 0x30 #define MMU_REG_ROOT_PTB 0x40 /
Tatsächlich ist dies ein Steuerregister, ein Kontextnummernregister, ein Stammregister von Tabellen und ein wenig obskures MMU_REG_ELB_PTB. Beginnen wir damit, dieses Register sollte auf einen bestimmten Wert gesetzt werden, die nächsten 512 GB werden vom Prozessor für die Anforderungen des Geräts verwendet, und diese Adressen stehen dem Programmierer nicht zur Verfügung. Ich werde Erklärungen aus dem Brief des ICST-Spezialisten abgeben, ich kann es kaum besser erklären:
Unter Linux setzen wir MMU_ELB_PTB auf 0xff1 << 39 und dann
oberer Bereich des virtuellen Speichers (0xff8000000000 - 0xffffffffffff)
reserviert für die Bedürfnisse von Geräten, nämlich TLB. Jede Seite
Seitentabelle (TS) erhält seine eindeutige Adresse in diesem Bereich,
Darüber hinaus sind diese Adressen leicht von der Adresse zu erhalten, an der sich das Programm befindet
appellierte an die Erinnerung. Und seitdem TLB speichert virtuelle Adresszuordnungen
physisch, so können Sie im gleichen TLB-Puffer zwischenspeichern
sendet nicht nur für Benutzeradressen, sondern auch für das Fahrzeug selbst.
In solchen Prozessoren / Architekturen, in denen separate TLBs für verschiedene erstellt werden
Seitentabellenebenen wird ein solcher Trick unnötig.
Wenn Sie also den TLB verpassen, ist es möglich, die Suche nicht zu starten
von der Null-Ebene (pgd *) und sofort die letzte Ebene des Fahrzeugs (pte *) prüfen.
Es ist keine Hardware erforderlich, um dieses Gebiet selbst abzubilden, Wirth. Adressen von
Es wird nur als Index für die TLB-Suche benötigt. Im Kern jedoch in
Die letzte Seite in der Null-Ebene der Seitentabelle wird nat geschrieben. die adresse dafür
am Nullpunkt. Infolgedessen nur
die letzten 4 KB des Bereichs ff80'0000'0000 - ffff'ffff'ffff - d. h. genau richtig
Null Fahrzeugniveau. Dies ermöglicht den normalen Zugriff auf pgd *
Lese- / Schreibanweisungen für virtuelle Adressen.
Infolgedessen wurde beschlossen, einfach einen großen Wert in dieses Register zu setzen, der uns nicht stören wird. Schließlich können wir mit der vorgeschlagenen Lösung die Suche nach Seiten optimieren, wir haben uns jedoch noch nicht mit der Optimierung befasst. Wird wie unter Linux ausgeliefert.
Nun das Kontrollregister. Sie müssen MMU dadurch aktivieren. Bekannte Bits sehen folgendermaßen aus:
#define _MMU_CR_TLB_EN 0x0000000000000001 #define _MMU_CR_CD_MASK 0x0000000000000006 #define _MMU_CR_SET1 0x0000000000000008 #define _MMU_CR_SET2 0x0000000000000010 #define _MMU_CR_SET3 0x0000000000000020 #define _MMU_CR_CR0_PG 0x0000000000000040 #define _MMU_CR_CR4_PSE 0x0000000000000080 #define _MMU_CR_CR0_CD 0x0000000000000100 #define _MMU_CR_TLU2_EN 0x0000000000000200 #define _MMU_CR_LD_MPT 0x0000000000000400 #define _MMU_CR_IPD_MASK 0x0000000000000800 #define _MMU_CR_UPT_EN 0x0000000000001000
Wir interessieren uns für das erste Bit, das die Übersetzung von Adressen beinhaltet.
Wir haben auch _MMU_CR_SET3 gesetzt, aber wir haben nicht herausgefunden, in welchen besonderen Fällen dies geschehen soll.
Wettbewerbsregister Wenn einfach, dann ist dies die PID des Prozesses oder des Adressraums. Technisch gesehen ist dies eine 11-Bit-Adresserweiterung. In unserem Fall haben wir alle Seiten zum Kern gemacht, indem wir auf allen unseren Seiten ein bisschen Globalität eingestellt haben, den gleichen Adressraum verwenden und daher in diesem Register Null verwenden können.
Im Register der Root-Tabelle befindet sich ein Zeiger auf die physikalische Adresse des Anfangs der Übersetzungstabelle. Sie können einfach einen Betrug begehen, indem Sie die Tabelle auch der Adresse zuordnen, die im Register MMU_REG_ELB_PTB angegeben ist, aber wie gesagt, wir haben uns nicht auf die Optimierung konzentriert.
Was kann ich noch sagen, die Struktur der Tabellen ist ganz normal, die Flags sind wie folgt:
#define E2K_MMU_PAGE_P 0x0000000000000001ULL #define E2K_MMU_PAGE_W 0x0000000000000002ULL #define E2K_MMU_PAGE_UU2 0x0000000000000004ULL #define E2K_MMU_PAGE_PWT 0x0000000000000008ULL #define E2K_MMU_PAGE_CD1 0x0000000000000010ULL #define E2K_MMU_PAGE_A 0x0000000000000020ULL #define E2K_MMU_PAGE_D 0x0000000000000040ULL #define E2K_MMU_PAGE_HUGE 0x0000000000000080ULL #define E2K_MMU_PAGE_G 0x0000000000000100ULL #define E2K_MMU_PAGE_CD2 0x0000000000000200ULL #define E2K_MMU_PAGE_NWA 0x0000000000000400ULL #define E2K_MMU_PAGE_AVAIL 0x0000000000000800ULL #define E2K_MMU_PAGE_PFN 0x000000fffffff000ULL #define E2K_MMU_PAGE_VALID 0x0000010000000000ULL #define E2K_MMU_PAGE_PV 0x0000020000000000ULL #define E2K_MMU_PAGE_INT_PR 0x0000040000000000ULL #define E2K_MMU_PAGE_NON_EX 0x0000080000000000ULL #define E2K_MMU_PAGE_RES 0x0000f00000000000ULL #define E2K_MMU_PAGE_C_UNIT 0xffff000000000000ULL
Für die Tabelle der 4. Ebene lauten die Adressverschiebungen wie folgt:
#define __MMU_PGD_SHIFT (PAGE_SHIFT + 3 * (PAGE_SHIFT-3)) #define __MMU_PUD_SHIFT (PAGE_SHIFT + 2 * (PAGE_SHIFT-3)) #define __MMU_PMD_SHIFT (PAGE_SHIFT + 1 * (PAGE_SHIFT-3))
Ein bisschen über PCI
Kommunikation über alternative Adressräume
Bevor wir zu Vidyaha und der Netzwerkkarte übergehen, kehren wir kurz zu PCI zurück. Wir haben bereits im ersten Teil von
"Embox beginnt mit dem Aufstieg auf den Elbrus" ein wenig darüber gesprochen. Es wurden Makros für die Kommunikation mit alternativen Adressräumen angezeigt:
#define _E2K_READ_MAS(addr, mas, type, size_letter, chan_letter) \ ({ \ register type res; \ asm volatile ("ld" #size_letter "," #chan_letter " \t0x0, [%1] %2, %0" \ : "=r" (res) \ : "r" ((__e2k_ptr_t) (addr)), \ "i" (mas)); \ res; \ }) #define _E2K_WRITE_MAS(addr, val, mas, type, size_letter, chan_letter) \ ({ \ asm volatile ("st" #size_letter "," #chan_letter " \t0x0, [%0] %2, %1" \ : \ : "r" ((__e2k_ptr_t) (addr)), \ "r" ((type) (val)), \ "i" (mas) \ : "memory"); \ })
Und es gab einen Hinweis auf das Prinzip der Adressräume. Unterschiedliche Adressräume werden mit dem MAS (Memory Address Specifier) definiert. Um beispielsweise auf die E / A zuzugreifen, über die auf die PCI zugegriffen wird, müssen Sie 6 und für MMU 7 verwenden.
Bei genauerer Betrachtung des Makros können Sie jedoch eine Art chan_letter bemerken. Und wenn Sie sich die Beschreibung der e2k-Befehle ansehen, finden wir
LDD ddd Lesen von Doppelwörtern
ldd [adresse] mas, dst
Das heißt, auf den ersten Blick gibt es keine Kanäle. Wenn Sie jedoch den Links folgen, stellt sich heraus, dass der Code für die angegebene Operation ldd 67 ist. 67 ist jedoch nur der Code für ldd für die Kanäle AL0 / AL3 und AL2 / AL5, und für die Kanäle AL1 / AL4 entspricht dieser Code der Operation POPCNTd.
Daher war es nicht möglich, die Kanäle in der Terminologie von Elbrus vollständig zu verstehen. Ich würde den Vorschlag wagen, dass dies bereits mit dem vliw-Prinzip zusammenhängt, wenn Sie angeben können, welches Alu verwendet wird, da bei dieser Art von Architektur eines der Merkmale das Vorhandensein mehrerer unabhängiger Computergeräte ist. Ich kann mich natürlich irren, aber Tatsache ist, dass Sie den zweiten oder fünften Kanal verwenden müssen, um auf die PCI oder MMU zuzugreifen. Somit sieht der Befehl ungefähr so aus:
ldd, 2 0x0, [addr_in_mas] mas_id,% reg
lspci
Jetzt gebe ich das Ergebnis der Ausgabe des Befehls lspci auf dem Gerät, das wir haben:
root @ embox: (null) #lspci
00: 0.0 (PCI-Entwickler E3E3: ABCD) [6 4]
PCI-zu-PCI-Brücke: (null) Elbrus PCIe-Brücke (Rev. 01)
00: 1.0 (PCI dev 8086: E3E3) [6 4]
PCI-zu-PCI-Brücke: Intel Corporation Elbrus Virt PCI-Brücke (Rev. 01)
01: 0.0 (PCI dev 1FFF: 8000) [6 4]
PCI-zu-PCI-Bridge: (null) Elbrus PCI-Bridge (Rev. 05)
01: 1.0 (PCI dev 8086: 4D45) [2 0]
Ethernet-Controller: Intel Corporation MCST ETH1000 Gigabit-Ethernet (Version 01)
01: 2.0 (PCI dev 8086: 4D49) [1 1]
IDE-Controller: Intel Corporation MCST IDE (Version 128)
01: 2.1 (PCI dev 8086: 0002) [7 2]
Einfache komm. Controller: Intel Corporation (null) (Version 05)
01: 2.2 (PCI dev 8086: 8000) [7 128]
Einfache komm. Controller: Intel Corporation Elbrus PCI-Bridge (Version 00)
01: 2.3 (PCI dev 1013: 6005) [4 1]
Multimedia-Gerät: Cirrus Logic Crystal CS4281 PCI Audio (Version 01)
01: 3.0 (PCI dev 8086: 4748) [1 6]
Massenspeicher-Controller: Intel Corporation MCST SATA (Rev. 00)
01: 4.0 (PCI dev 8086: 554F) [12 3]
USB-Gerät: Intel Corporation OHCI für Elbrus (Rev. 00)
01: 4.1 (PCI dev 8086: 5545) [12 3]
USB-Gerät: Intel Corporation EHCI für Elbrus (Rev. 00)
02: 1.0 (PCI dev 126F: 0718) [3 0]
VGA-kompatibler Controller: Silicon Motion, Inc. SM718 LynxSE + (Rev. 160)
root @ embox: (null) #
Hinweis
01: 2.2 (PCI dev 8086: 8000) [7 128]
Einfache komm. Controller: Intel Corporation Elbrus PCI-Bridge (Version 00)
Tatsächlich ist es eine serielle Schnittstelle vom MCST, ähnlich wie am85c30, zumindest über dieses Gerät, das wir über minicom kommunizieren.
Netzwerkkarte
Allgemeine Struktur
Kommen wir nun zur Netzwerkkarte.
Wenn ich das richtig verstehe, ist dies die ursprüngliche Netzwerkkarte, die im Betrieb ein bisschen der e1000 ähnelt, aber nur im Hinblick auf den Betrieb (wie das Vorhandensein von Deskriptoren in den Empfangs- und Sendewarteschlangen).
Nun mehr zu den wichtigen Punkten, auf die wir gestoßen sind.
PCI-VID der Netzwerkkarte: PID 0x8086: 0x4D45. Seien Sie nicht überrascht, dass die VID mit Intel identisch ist. Der MCST verwendet häufig diese spezielle VID. Sehen Sie sich zumindest das oben erwähnte Gerät mit serieller Schnittstelle an.
BAR0 enthält eine Registerbasis. Die Register sind wie folgt:
#define L_E1000_E_CSR 0x00 #define L_E1000_MGIO_CSR 0x04 #define L_E1000_MGIO_DATA 0x08 #define L_E1000_E_BASE_ADDR 0x0c #define L_E1000_DMA_BASE_ADDR 0x10 #define L_E1000_PSF_CSR 0x14 #define L_E1000_PSF_DATA 0x18 #define L_E1000_INT_DELAY 0x1c
Die letzten drei (L_E1000_PSF_CSR, L_E1000_PSF_DATA, L_E1000_INT_DELAY) haben wir nicht verwendet, daher werden wir nicht darüber sprechen. Beginnen wir mit MGIO, alles ist einfach: Lesen und Schreiben mit dem MII-Protokoll, dh Kommunikation mit dem PHY-Chip. Speziell haben wir einen Chip DP83865.
Die Verfahren sind nicht besonders bemerkenswert, ich werde sie einfach auflisten.
Lesen:
static int e1000_mii_readreg(struct net_device *dev, int phy_id, int reg_num) { struct l_e1000_priv *ep = netdev_priv(dev); uint32_t rd; uint16_t val_out = 0; int i = 0; rd = 0; rd |= 0x2 << MGIO_CS_OFF; rd |= 0x1 << MGIO_ST_OF_F_OFF; rd |= 0x2 << MGIO_OP_CODE_OFF; rd |= (phy_id & 0x1f) << MGIO_PHY_AD_OFF; rd |= (reg_num & 0x1f) << MGIO_REG_AD_OFF; e1000_write_mgio_data(ep, rd); rd = 0; for (i = 0; i != 1000; i++) { if (e1000_read_mgio_csr(ep) & MGIO_CSR_RRDY) { rd = (uint16_t)e1000_read_mgio_data(ep); val_out = rd & 0xffff; log_debug("reg 0x%x >>> 0x%x", reg_num, val_out); return val_out; } usleep(100); } log_error("mdio_read: Unable to read from MGIO_DATA reg\n"); return val_out; }
Rekord:
static void e1000_mii_writereg(struct net_device *dev, int phy_id, int reg_num, int val) { struct l_e1000_priv *ep = netdev_priv(dev); uint32_t wr; int i = 0; wr = 0; wr |= 0x2 << MGIO_CS_OFF; wr |= 0x1 << MGIO_ST_OF_F_OFF; wr |= 0x1 << MGIO_OP_CODE_OFF; wr |= (phy_id & 0x1f) << MGIO_PHY_AD_OFF; wr |= (reg_num & 0x1f) << MGIO_REG_AD_OFF; wr |= val & 0xffff; log_debug("reg 0x%x <<< 0x%x", reg_num, val); e1000_write_mgio_data(ep, wr); for (i = 0; i != 1000; i++) { if (e1000_read_mgio_csr(ep) & MGIO_CSR_RRDY) { return; } usleep(100); } log_error("Unable to write MGIO_DATA reg: val = 0x%x", wr); return; }
Nun beschreiben L_E1000_DMA_BASE_ADDR und L_E1000_E_BASE_ADDR tatsächlich einen Parameter, die Adresse des Netzwerkkarten-Beschreibungsblocks. Das heißt, die Adresse in Elbrus ist 64-Bit und die Register sind 32-Bit.
Eigentlich Code:
init_block_addr_part = (uint32_t)((uintptr_t)ep->init_block & 0xffffffff); e1000_write_e_base_addr(ep, init_block_addr_part); log_debug("Init Block Low DMA addr: 0x%x", init_block_addr_part); init_block_addr_part = (uint32_t)(((uintptr_t)(ep->init_block) >> 32) & 0xffffffff); e1000_write_dma_base_addr(ep, init_block_addr_part); log_debug("Init Block High DMA addr: 0x%x", init_block_addr_part);
Daraus ist ersichtlich, dass L_E1000_DMA_BASE_ADDR der obere Teil und L_E1000_DMA_BASE_ADDR der untere Teil der Adresse eines bestimmten Initialisierungsblocks (tatsächlich ein Kartenbeschreibungsblock) ist.
Die Beschreibungsstruktur ist wie folgt:
struct l_e1000_init_block { uint16_t mode; uint8_t paddr[6]; uint64_t laddrf; uint32_t rdra; uint32_t tdra; } __attribute__((packed));
C laddrf - hat nicht verstanden, aus irgendeinem Grund ist es auf Null gesetzt, wir haben das gleiche getan.
paddr - wie Sie sich vorstellen können, ist mac die Adresse der Netzwerkkarte.
rdra und tdra enthalten die Adressen der Ringe von Speicherdeskriptoren, die unteren 4 Bits sind der Größe des Rings zugeordnet, und dies ist der Logarithmus der Größe. Das heißt, wenn es 8 gibt, beträgt die Anzahl der Deskriptoren im Ring 2 ^ 8 (1 << 8 == 256).
mode ist die Betriebsart der Karte, die Bits lauten wie folgt:
#define DRX (1 << 0) #define DTX (1 << 1) #define LOOP (1 << 2) #define DTCR (1 << 3) #define COLL (1 << 4) #define DRTY (1 << 5) #define INTL (1 << 6) #define EMBA (1 << 7) #define EJMF (1 << 8) #define EPSF (1 << 9) #define FULL (1 << 10) #define PROM (1 << 15)
Das heißt, wenn alles konfiguriert ist, müssen Sie Bit 10 setzen. Wenn Sie einen Promiscuous-Modus wünschen, dann auch 15.
Paketdeskriptoren
Nun zum Format der Paketdeskriptoren.
An der rezeption:
struct l_e1000_rx_desc { uint32_t base; int16_t buf_length; int16_t status; int16_t msg_length; uint16_t reserved1; uint32_t etmr; } __attribute__((packed));
base - Verstehe wahrscheinlich, dass dies die Adresse des Puffers für das Paket ist
buf_length - Puffergröße
msg_length - Enthält nach dem Empfang die Länge des empfangenen Pakets
status - Deskriptorstatus. Wenn das Paket vorbereitet und an die DMA (Karte) übergeben wurde, müssen Sie Bit 15 (RD_OWN) setzen. Wenn alles in Ordnung ist, wird dieses Bit nach dem Empfang des Pakets in diesem Deskriptor zurückgesetzt und 9 (RD_STP) und 8 (RD_ENP) werden gesetzt.
Alle Statusbits lauten wie folgt:
#define RD_OWN (1 << 15) #define RD_ERR (1 << 14) #define RD_FRAM (1 << 13) #define RD_OFLO (1 << 12) #define RD_CRC (1 << 11) #define RD_BUFF (1 << 10) #define RD_STP (1 << 9) #define RD_ENP (1 << 8) #define RD_PAM (1 << 6) #define RD_LAFM (1 << 4) #define RD_BAM (1 << 3)
Bei Überweisung:
struct l_e1000_tx_desc { uint32_t base; int16_t buf_length; int16_t status; uint32_t misc; uint32_t etmr; } __attribute__((packed));
Fast wie beim Empfangen lauten die Statusbits wie folgt:
#define TD_OWN (1 << 15) #define TD_ERR (1 << 14) #define TD_AFCS (1 << 13) #define TD_NOINTR (1 << 13) #define TD_MORE (1 << 12) #define TD_ONE (1 << 11) #define TD_DEF (1 << 10) #define TD_STP (1 << 9) #define TD_ENP (1 << 8)
Wenn ein Paket gesendet wird, müssen 15 (TD_OWN), 9 (TD_STP) und 8 (TD_ENP) entsprechend eingestellt werden. Bit 8 bedeutet, dass dies das letzte zu verarbeitende Paket ist. Wenn also ein Paket gesendet wird, müssen Sie nur das letzte Paket installieren.
Ich habe auch ein wichtiges Feature vergessen, die Pufferlänge in Deskriptoren ist mit einem Minuszeichen geschrieben, wahrscheinlich in zusätzlichem Code. Auch in Little-Endian, aber da Elbrus die gleiche Bytereihenfolge haben, ist dies wahrscheinlich nicht wichtig.
Verwaltungsregister
Nun beschreiben wir das letzte nicht zusammengesetzte Register L_E1000_E_CSR:
#define E_CSR_ATME (1 << 24) #define E_CSR_TMCE (1 << 23) #define E_CSR_DRIN (1 << 22) #define E_CSR_DTIN (1 << 21) #define E_CSR_ESLE (1 << 20) #define E_CSR_SLVE (1 << 19) #define E_CSR_PSFI (1 << 18) #define E_CSR_SINT (1 << 16) #define E_CSR_ERR (1 << 15) #define E_CSR_BABL (1 << 14) #define E_CSR_CERR (1 << 13) #define E_CSR_MISS (1 << 12) #define E_CSR_MERR (1 << 11) #define E_CSR_RINT (1 << 10) #define E_CSR_TINT (1 << 9) #define E_CSR_IDON (1 << 8) #define E_CSR_INTR (1 << 7) #define E_CSR_INEA (1 << 6) #define E_CSR_RXON (1 << 5) #define E_CSR_TXON (1 << 4) #define E_CSR_TDMD (1 << 3) #define E_CSR_STOP (1 << 2) #define E_CSR_STRT (1 << 1) #define E_CSR_INIT (1 << 0)
Initialisierung
Es gibt eine etwas ungewöhnliche Initialisierungssequenz:
STOP-> INIT-> IDON-> STRT
In diesem Fall steigen die RXON- und TXON-Bits unabhängig voneinander an.
Weitere Details finden Sie in unserem Treiber.
Grafikkarte
Wie bereits erwähnt, verwendet unser Gerät einen Silicon Motion Vidyah namens SM718 LynxSE +. Daher ist alles einfach, es gibt
Treiberquellen in Linux und es gibt eigentlich nichts zu beschreiben.
Nun, abgesehen davon, dass das Video zeigt, dass es sich als sehr niedrig erwiesen hat, fühlt es sich wie ein langsamer Zugriff auf den Speicher an. Dies ist jedoch ohne Compileroptimierung möglich, und im Allgemeinen ist dies möglicherweise unser Problem, das mit der inkorrekten Verwendung der e2k-Architektur zusammenhängt.
Was soll man noch über Sachalin Elbrus sagen?
Grundsätzlich ist das Wetter normal :)
Anscheinend existieren Elbrus, arbeiten. Persönlich sehe ich das Hauptproblem der Entwicklung dieser interessanten Architektur in ihrer Nähe. Es ist kaum zu glauben, dass ein relativ kleines Unternehmen einen Prozessor, einen Compiler, Support und alles andere erstellen kann. Ja, es tauchten Softwareentwickler von Drittanbietern auf, derselbe Basalt-SPO unterstützt
Alt-Linux, das auf Elbrus installiert werden kann .
Ja, es gab Berichte, dass Drittanbieter Hardware auf der Basis des Elbrus-Prozessors herstellen, zum Beispiel
Fastwel . All dies sind jedoch nur kleine Fortschritte in Richtung Offenheit. Ein sehr einfaches Beispiel, um das zu reproduzieren, was wir hier gesagt und gezeigt haben, brauchen wir einen Compiler, und nur der
MCST hat ihn . Die im Artikel angegebenen Informationen sind eine Ergänzung zu den Informationen, die vom
MCST erhalten wurden , und ich sage es immer noch nicht dass es unwahrscheinlich ist, dass ein Stück Eisen auch im MCST gefunden wird. Es ist ziemlich alt und
ICST bietet neuere Modelle an.
PS Natürlich können Sie alles im
Embox-Repository sehen .
PPS Über Embox (
https://t.me/embox_chat ) gelangen Sie zum russischen Telegrammkanal.
PPS Embox hat die zweite Komponente in der Version aktualisiert, jetzt die aktuelle Version
0.4.0