Universiteit Gent Faculteit Toegepaste Wetenschappen Vakgroep Elektronica en Informatiesystemen Voorzitter: Prof. dr. ir. J. Van Campenhout
Academiejaar 2004–2005
Een VGA-video demonstrator
Nicolas Christiaens
Promotor: Prof. dr. ir. D. Stroobandt Begeleider: Dr. ir. M. Christiaens
Scriptie voorgedragen tot het behalen van de graad van Master in de Toegepaste Informatica
Overzicht Een VGA-video demonstrator door Nicolas Christiaens Scriptie ingediend tot het behalen van de academische graad van Master in de Toegepaste Informatica Academiejaar 2004-2005 Promotor: Prof. dr. ir. D. Stroobandt Scriptiebegeleider: Dr. ir. M. Christiaens Faculteit Toegepaste Wetenschappen Universiteit Gent Vakgroep Elektronica en Informatiesystemen Voorzitter: Prof. dr. ir. J. Van Campenhout
Trefwoorden thesis, eindwerk, scriptie, RESUME, VGA, mmio, nvidia, memory mapping, linux
De toelating tot bruikleen De auteur geeft de toelating deze scriptie voor consultatie beschikbaar te stellen en delen van de scriptie te kopi¨eren voor persoonlijk gebruik. Elk ander gebruik valt onder de beperkingen van het auteursrecht, in het bijzonder met betrekking tot de verplichting de bron uitdrukkelijk te vermelden bij het aanhalen van resultaten uit deze scriptie. 19 mei 2005
Woord vooraf Vooreerst wens ik mijn begeleider, Mark Christiaens, te bedanken voor alle steun tijdens het maken van de scriptie. Zonder zijn wijze raad zou het werk onmogelijk deze vorm gekregen hebben. Verder wens ik Prof. Stroobandt en Prof. De Bosschere te bedanken, die het mogelijk maakten dat ik dit boeiende onderwerp kon behandelen. Mijn dankbetuigingen gaan ook uit naar Philippe Faes en Michiel Ronsse. Ook zij werden van tijd tot tijd lastiggevallen met vage vragen, waarop echter wel een fijn antwoord werd gegeven. Eveneens bedank ik graag de Linux-gemeenschap. Zonder deze mensen was het werk onmogelijk. Ik bedank graag nog mijn taaladviseur en goede vriend, Guido Van Puyenbroeck, voor het nauwgezet nalezen van de geschreven teksten en het verbeteren van de abondante taalblunders. Uiteraard mag ik mijn familie en vriendin niet vergeten, die ook met de niettechnische problemen van de zaak moeten leven hebben, waarvoor mijn oprechte dank en bewondering.
ii
Samenvatting
In de onderzoeksgroep PARIS aan de Universiteit Gent loopt een project waarbij een zelf ontwikkelde video codec in hardware wordt ge¨ımplementeerd. Dit wordt gedaan aan de hand van een Field Programmable Gate Array PCI-bordje. Om de gegenereerde beelden te kunnen visualiseren, is er nood aan video uitvoer. De verzorging van de uitvoer is het onderwerp van deze scriptie. Ze wordt verkregen door het aansturen van een PCI VGA-kaart onder Linux. Meer specifiek werd gevraagd een programma te schrijven dat de beeldkaart kan initialiseren op een gegeven resolutie. Na de initialisatie is het noodzakelijk dat beelden tegen een vaste, vooropgestelde framerate naar de beeldkaart worden gestuurd en vervolgens zichtbaar worden op een scherm. De implementatie maakt gebruik van user-space memory mapping. Hierdoor wordt toegang tot de kernel, en dus belangrijke systeembronnen, ontzegd en is er minder kans op het blokkeren van het besturingssysteem. Door middel van memory mapping kan toegang worden verkregen tot het geheugen van de PCI-kaart in de vorm van een gewone tabel in C/C++.
iii
Abstract
There’s an active project in the research group PARIS at the Ghent University, involving the implementation of a video codec in hardware. The video codec is implemented using a Field Programmable Gate Array PCI-board. To visualize the generated video frames, a need for video output arizes. The subject of this master thesis is the realization of the aforementioned video output. This is achieved by programming a PCI VGA card in Linux. More specifically, the intention is to initialize the graphics card to a certain resolution. After initialization, images must be sent to the graphics card at a given framerate, making them visible on a PC screen. This is implemented in user-space using memory mapping techniques. In this manner, access to the kernel and important system resources is denied, preventing more frequent system crashes. By use of memory mapping, one can gain access to the memory on the PCI card in form of a regular array in C/C++.
iv
Inhoudsopgave Woord vooraf
ii
Samenvatting
iii
Abstract
iv
1 Probleemstelling 1.1
1.2
2
Het RESUME -project . . . . . . . . . . . . . . . . . . . . . . . . . . .
2
1.1.1
De nood aan visualisatie . . . . . . . . . . . . . . . . . . . . . .
3
1.1.2
De uitdaging . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3
Beschikbare apparatuur . . . . . . . . . . . . . . . . . . . . . . . . . .
4
2 Secondaire VGA-kaart 2.1
6
VESA/VGA-conformiteit . . . . . . . . . . . . . . . . . . . . . . . . . .
6
2.1.1
Primitieve visualisatie . . . . . . . . . . . . . . . . . . . . . . .
6
2.1.2
De personal computer . . . . . . . . . . . . . . . . . . . . . . .
7
2.1.3
VGA ontoereikend . . . . . . . . . . . . . . . . . . . . . . . . .
8
2.1.4
Memory mappen . . . . . . . . . . . . . . . . . . . . . . . . . .
8
2.1.5
De toekomst . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
9
2.2
Het ‘nVidia’ mysterie . . . . . . . . . . . . . . . . . . . . . . . . . . . .
9
2.3
Op te lossen problemen . . . . . . . . . . . . . . . . . . . . . . . . . . .
10
2.3.1
Het probleem van de koude start . . . . . . . . . . . . . . . . .
10
2.3.2
Afbeelding van het geheugen . . . . . . . . . . . . . . . . . . . .
13
2.3.3
Initialiseren van een modus . . . . . . . . . . . . . . . . . . . .
13
v
Inhoudsopgave
2.3.4
vi
Beelden schrijven naar de kaart . . . . . . . . . . . . . . . . . .
3 Mogelijkheden in Linux
14 16
3.1
Het ‘proc’ bestandssysteem . . . . . . . . . . . . . . . . . . . . . . . . .
16
3.2
Het geheugen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
17
3.3
BASH-scripting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
17
3.3.1
Gebruikte commando’s . . . . . . . . . . . . . . . . . . . . . . .
17
User-space . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
19
3.4.1
Beschrijving . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
19
3.4.2
Voor- en nadelen . . . . . . . . . . . . . . . . . . . . . . . . . .
20
Kernel-space . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
20
3.5.1
Beschrijving . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
20
3.5.2
Voor- en nadelen . . . . . . . . . . . . . . . . . . . . . . . . . .
20
3.4
3.5
4 Realisatie - Gedeelde bibliotheken 4.1
4.2
4.3
libsoftboot.so . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
23
4.1.1
Exports . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
23
4.1.2
Functiereferentie . . . . . . . . . . . . . . . . . . . . . . . . . .
24
libnvugent.so . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
28
4.2.1
Exports . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
28
4.2.2
Functiereferentie . . . . . . . . . . . . . . . . . . . . . . . . . .
30
Het gebruik van de bibliotheken . . . . . . . . . . . . . . . . . . . . . .
36
4.3.1
Compilatie en installatie . . . . . . . . . . . . . . . . . . . . . .
36
4.3.2
Gebruik . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
36
5 Realisatie - Kernelmodule 5.1
23
Compilatie en gebruik . . . . . . . . . . . . . . . . . . . . . . . . . . .
6 Realisatie - Voorbeeldprogramma
39 40 42
6.1
Softboot voorbeeld . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
42
6.2
Dubbele buffering . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
43
6.3
Aangepaste resolutie . . . . . . . . . . . . . . . . . . . . . . . . . . . .
45
Inhoudsopgave
vii
7 Besluit
48
A De configuratiehoofding
49
B De nVidia registerlocaties
54
C Klassecodes voor PCI
56
C.1 Klassecode tabel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
56
C.2 Klassecodes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
57
D nvugent modi
58
Bibliografie
64
“(with interrupts) the processor doesn’t waste its time looking for work - when there is something to be done, the work comes looking for the processor.” —Peter Norton—
Hoofdstuk 1
Probleemstelling 1.1
Het RESUME -project
Wanneer een nieuw multimediasysteem ontworpen wordt, zal de voorkeur meestal uitgaan naar een software-implementatie draaiende op een multi-purpose processor. Dit bevordert het gemak van implementatie en de flexibiliteit ervan. In veel gevallen echter, worden betere prestaties verkregen door de implementatie in een ASIC 1 . Door het gebrek aan flexibiliteit na implementatie van de ASIC, wordt de voorkeur gegeven aan een derde optie, namelijk een FPGA2 . De FPGA’s hebben echter wel een nadeel, hun klokfrequentie ligt aanzienlijk lager dan die van een ASIC. Hierdoor is het noodzakelijk dat een FPGA-implementatie gebruik maakt van parallelle algoritmes of een additionele processor3 om rendabel te zijn. In de onderzoeksgroep PARIS aan de Universiteit Gent werd met het RESUME 4 project onderzoek verricht naar het nut van FPGA’s in multimediasystemen. Er werd een schaalbare, wavelet gebaseerde, videodecoder gebouwd. Met schaalbaar wordt in deze context bedoeld, de mogelijkheid om de doelresolutie, -beeldsnelheid en de doorvoersnelheid van de data aan te passen zonder het veranderen van de bron datastroom. 1
ASIC is de afkorting van Application-Specific Integrated Circuit. FPGA betekent Field Programmable Gate Array. 3 De delen van het algoritme die niet parallel zijn, kunnen op deze processor sneller worden uitgevoerd dan 2
op de FPGA. 4 RESUME staat voor Reconfigurable Embedded Systems for Use in scalable Multimedia Environments.
2
Hoofdstuk 1. Probleemstelling
3
Door het gebruik van schaalbare videocodecs 5 , moet er maar ´e´enmaal een datastroom worden opgesteld. Bij het afspelen op een lagere beeldkwaliteit worden dan simpelweg enkele blokken data niet gedecodeerd. Voor meer informatie omtrent het RESUMEproject, zie [1]. 1.1.1
De nood aan visualisatie
Om het mogelijk te maken de gedecodeerde videostroom in ware tijd te volgen op een scherm, is er nood aan een programma dat die taak op zich neemt. In deze thesis was het dan ook de bedoeling zo een programma te schrijven in Linux. Het moest in staat zijn verschillende resoluties te ondersteunen en beelden tegen een bepaalde frequentie naar het scherm te schrijven. Eveneens moest zoveel mogelijk geprobeerd worden de applicatie te laten draaien in user-mode 6 . Het programma maakt gebruik van een additionele grafische PCI-kaart7 van het merk AOpen. Het betreft een grafische processor van het type nVidia GeForce FX5200. Door het gebruik van een kaart van het merk nVidia wordt echter een groot probleem ge¨ıntroduceerd. De specificaties van de grafische processoren van het merk zijn niet publiekelijk gedocumenteerd. Aangezien het ook een additionele, niet-primaire kaart betreft, is de communicatie ermee niet conform de VGA8 -standaarden. 1.1.2
De uitdaging
Zoals hierboven reeds werd vermeld, was de grootste uitdaging het uitzoeken van de manier waarop de kaart moest worden geconfigureerd. De primaire VGA-kaart wordt ge¨ınitialiseerd door de BIOS 9 tijdens het opstarten van de PC om gebruik te maken van gekende standaardadressen. Hierdoor wordt het mogelijk de kaart te configureren zoals wordt voorgeschreven door de VGA-standaard. Alle problemen en hun oplossingen 5 6
Codec is het samenvoegsel van Codeerder en Decodeerder. In user-mode kunnen slechts bepaalde geheugengebieden worden geadresseerd. Hierdoor wordt toegang tot
kernel bronnen ontzegd, zodat er minder kans is op de corruptie ervan (en de daaruit volgende systeemcrash). 7 PCI betekent Peripheral Component Interconnect 8 VGA is de afkorting van Video Graphics Array. 9 BIOS staat voor Basic Input Output System.
Hoofdstuk 1. Probleemstelling
4
worden gedetailleerd beschreven in puntje 2.3.
1.2
Beschikbare apparatuur
Zoals voorheen aangehaald, werd een videocodec in hardware ge¨ımplementeerd op een FPGA-bord.
Het betreft een Altera PCI development kit met een Altera
EP1S25F1020C5 en 256MiB on-board DDR-geheugen dat aan 133MHz werkt. De PCI-bus draait aan 33MHz in 32bit mode. De grafische kaart die werd voorzien voor het maken van de scriptie is een AOpen PCI-kaart met de nVidia GeForce FX5200 chip. Deze wordt ook nog de NV34-chip genoemd en intern bij nVidia ge¨ıdentificeerd als chip nummer 0x322. Ze bevat 128MiB on-board DDR-geheugen dat werkt aan 200MHz, een GPU 10 aan 250MHz en een RAMDAC 11 aan 350MHz. De interne busbreedte is 128bits. De PC waarin de kaart zat tijdens het maken van de thesis is een Pentium 4, 2,67MHz met 1GiB Dual DDR RAM. De primaire grafische kaart in deze PC is een AGP 4× nVidia Quadro4 750XGL gemaakt door Fujitsu-Siemens. Dit is een NV25 GPU (0x259) met 128MiB DDR SDRAM aan 550MHz, 275MHz core-clock en dubbele RAMDAC aan 350MHz elk. De Linux-distributie op deze PC was Suse Linux Professional 9.2.
10 11
GPU staat voor Graphical Processing Unit. RAMDAC is de afkorting van Random Access Memory Digital-to-Analog Convertor.
“The real danger is not that computers will begin to think like men, but that men will begin to think like computers.” —Sydney J. Harris—
Hoofdstuk 2
Secondaire VGA-kaart Zoals reeds werd vermeld, was het de bedoeling een programma te schrijven dat werkte rond een tweede VGA-kaart. Hierbij werden echter meerdere problemen ondervonden. Zoals zal worden beschreven in puntje 2.1, is de problematiek te wijten aan de ontoereikendheid van de VESA1 en VGA standaarden.
2.1
VESA/VGA-conformiteit
De nVidia grafische kaarten worden geadverteerd als VESA/VGA-compatibele kaarten. Het probleem ligt niet bij de maker van de kaart, maar wel bij de standaarden zelf. Die zijn namelijk enkel gedefinieerd voor ´e´en enkele grafische kaart. Om dit probleem uit te leggen moet eerst een stukje computergeschiedenis worden herhaald. 2.1.1
Primitieve visualisatie
Toen de computer werd uitgevonden, was er al nood aan invoer en uitvoer. In de allereerste modellen werd dit gerealiseerd door het zetten van schakelaars en het herleggen van elektrische kabels. Dit bleek al vlug een zeer arbeidsintensieve bezigheid te zijn. Latere systemen gebruikten eerst een papieren band2 waarin gaatjes werden geponst, dan werd overgeschakeld naar magnetische opslag van data. 1 2
VESA is de Video Electronic Standards Association. Dit is een versie van de gekende ponskaarten.
6
Hoofdstuk 2. Secondaire VGA-kaart
7
In een n´og later stadium werd de uitgang verzorgd door een matrix van lampen. De volgende stap in het proces was het aansluiten van een TV op de computer. Om de analoge signalen te genereren die de CRT 3 aanvaardt, was een aparte, toegewijde, rekeneenheid van belang. Deze grafische ‘processor’ vormde de basis voor de eerste VGA-kaarten. 2.1.2
De personal computer
De eerste PC die door IBM werd voorgesteld had reeds een monitor aan boord. Door de grote diversiteit aan grafische implementaties, ontwikkelde IBM zes jaar later, in 1987, de succesvolle VGA-standaard. Deze standaard schrijft voor dat het lineaire adressenbereik van 0x3B0-0x3BB wordt voorbehouden aan monochrome schermadapters en het bereik 0x3D0-0x3DF wordt toegewezen aan kleuren schermadapters. Het gebied 0x3C0-0x3CF was bestemd voor beiden. Dit hield in dat door het uitvoeren van een in of out instructie naar bovenstaande adressen, de VGA-adapter kon worden geprogrammeerd en dat er beelden en/of tekst op het scherm kon worden getoond. Vooraleer dit echter kon gebeuren moest een routine worden opgeroepen die de waarden in de registers omzette naar waarden die de adapter intern kon gebruiken4 . Deze oproepen werden ge¨ımplementeerd aan de hand van interrupt routines. De VGA-kaart kreeg het nummer 0x10 toegewezen in de CPU interrupt vectortabel. De code voor de routines was te vinden in een ROM chip op de kaart zelf, genaamd de VGA-BIOS. Door een int 10h instructie kon bijgevolg de code in die BIOS worden uitgevoerd. Er waren routines om de kaart te initialiseren, pixels naar het scherm te schrijven, etc. De VGA-kaart heeft twee soorten geheugens. Een deel geheugen waarin de registers zich bevinden en een deel dat gebruikt wordt om de getoonde data bij te houden. Toegang tot de registers werd verkregen door het gebruik van de hierboven vermelde 3 4
CRT is de afkorting van Cathode Ray Tube. Elke fabrikant kan namelijk een andere architectuur hanteren om hun grafische kaart te maken.
Hoofdstuk 2. Secondaire VGA-kaart
8
adressen. Toegang tot het grafische geheugen van de kaart kon worden verkregen door te lezen en schrijven van en naar adressen 0xA0000-0xBFFFF. Dit zijn twee gebieden van 64kiB, het eerste wordt gebruikt in grafische modus, het tweede in textmodus. 2.1.3
VGA ontoereikend
Door de stijgende vraag naar grafische toepassingen werd de VGA-standaard al snel ontoereikend. Verschillende fabrikanten hadden reeds voorziening voor hogere resoluties, maar er was nog geen standaard. Om dit probleem op te lossen bundelden de fabrikanten hun krachten en richtten ze het consortium VESA op. Het was dan ook de VESA die verantwoordelijk was voor de nieuwe standaard, genaamd SVGA. Het was een Super versie van de VGA-standaard en bestond uit uitbreidingen op de standaard VGA-BIOS routines. SVGA werd daardoor ook wel VBE1.0 5 genoemd. Tot nu toe werd nog niet gesproken over bijkomende grafische kaarten. Aangezien er slechts ´e´en stel gebieden werd opzij gehouden voor de VGA-kaart, is het niet mogelijk op deze manier een andere VGA-kaart aan te sturen. Hoewel het volgende puntje een techniek introduceert die daar een oplossing voor kan bieden, is er nog steeds geen standaard voor. 2.1.4
Memory mappen
De VGA-standaard voorzag slechts 64kiB geheugen op de grafische kaart. Hogere resoluties, echter, vergen een veel grotere geheugencapaciteit6 . Om dit probleem op te lossen werden geheugens groter dan 64kiB opgesplitst in pages. Door het nummer van de pagina in te vullen in het juiste register, kon toegang verkregen worden tot het volledige geheugen. Deze techniek is traag en allesbehalve optimaal. Dynamische afbeelding van het 5 6
VGA BIOS Extension 1.0 Het aantal bytes nodig is het product van de horizontale en verticale resolutie, vermenigvuldigd met het
gewenst aantal bytes per pixel.
Hoofdstuk 2. Secondaire VGA-kaart
9
geheugen bracht de oplossing. Een gebied in het hoge geheugen ter grootte van het grafische geheugen kon worden toegewezen aan de grafische kaart. Al snel werden de registers ook op deze manier in het geheugen gemapt en kwam een einde aan de nood aan int 10h oproepen. Vele fabrikanten ondersteunen ze nog, maar ze worden nog zelden gebruikt in besturingssystemen zoals Linux en Windows. Zoals eerder vermeld, kan deze techniek ook een oplossing bieden voor meerdere VGA-kaarten. Elke kaart kan een gebied toegewezen krijgen in het geheugen waar haar registers zullen thuishoren. Het aantal van die registers en de relatieve locatie ervan is echter allesbehalve gegarandeerd aangezien ze niet worden beschreven door een standaard. Hierdoor komen we in dezelfde situatie terecht als in 1987, toen werd besloten om de VGA-standaard te ontwikkelen. 2.1.5
De toekomst
De meest recente versie van de VESA standaard is de VBE3.0. Het is een poging om de verouderde int 10h oproepen te vervangen door oproepen die in protected mode kunnen worden uitgevoerd. In plaats van een interrupt op te roepen, wordt een far call uitgevoerd naar een protected-mode routine in de VGA-BIOS. Deze techniek is echter nog weinig, en meestal niet foutloos, ge¨ımplementeerd. Ze werkt eveneens met 16bit protected-mode adressen, waardoor het gebruik op een 32bit PC platform niet eenvoudig is. Kortom, een nieuwe, aangepaste standaard is onontbeerlijk.
2.2
Het ‘nVidia’ mysterie
Zoals werd vermeld in puntje 2.1.4, kan memory-mapping gebruikt worden om de hedendaagse VGA-kaarten te programmeren. Er werd ook verteld dat de locatie van de registers in de gemapte gebieden afhankelijk kunnen zijn van fabrikant tot fabrikant. In het geval van een kaart van het merk nVidia, zijn de specificaties van de locaties niet zomaar te downloaden van het Internet7 . nVidia hanteert namelijk een closedarchitecture beleid. Indien de kern van de nVidia GPU zou worden vrijgegeven, kan 7
Ze zijn echter wel (gedeeltelijk) bijgesloten in bijlage B.
Hoofdstuk 2. Secondaire VGA-kaart
10
de concurrentie snel bijbenen. Dit is vanuit een bedrijf-economisch standpunt niet wenselijk. Doordat de allereerste Linux drivers van het merk wel opensource waren en nVidia een zogenaamde UDA8 gebruikt, heeft de Linux gemeenschap een basisdriver kunnen schrijven voor het XFree86 project. Het is dan ook door het lezen van die drivercode, dat deze thesis vorm heeft kunnen krijgen. Ook werd veel code ge¨ımplementeerd uit het svgalib-project [8]. Het betreft vooral de code die wordt gebruikt om de kaart te initialiseren. Doordat de int 10h oproep niet beschikbaar is, moeten de parameters van de kaart namelijk berekend worden door de applicatie zelf. Dit houdt, onder andere, in dat de waarden van de frequentie van de pixelklok, verticale en horizontale retrace pulsfrequentie (en hun lengte) en de RAMDAC moeten worden berekend uit een gewenste grafische modus.
2.3
Op te lossen problemen
Hieronder wordt in volgorde weergegeven welke stappen moeten worden doorlopen om een beeld op de tweede videokaart te kunnen tonen. Er wordt verondersteld dat het probleem van de tweede VGA-kaart, zoals werd beschreven in puntje 2.1, gekend is. 2.3.1
Het probleem van de koude start
E´en van de allereerste problemen die werden tegengekomen, was het koude start probleem. Zoals eerder vermeld, bevat de VGA-kaart een PCI-expansion ROM. Deze ROM bevat de VGA-BIOS, die op zich dan weer code bevat om de VGA-kaart te initialiseren bij het opstarten van de PC. De grafische kaart moet, net zoals een gewoon PC-platform, worden opgestart. Dit is niet verwonderlijk, aangezien de grafische kaart een zeer krachtige processor, met zijn eigen architectuur, aan boord heeft. Net zoals bij de CPU, moeten bepaalde 8
UDA staat voor Unified Driver Architecture. Hierdoor kan ´e´en enkele driver worden gebruikt om alle
kaarten aan te sturen.
Hoofdstuk 2. Secondaire VGA-kaart
11
registers en geheugenlocaties worden ingevuld met startwaarden. Deze initialisatiecode is afhankelijk van fabrikant en zelfs van product. Hij wordt derhalve meegeleverd in de VGA-BIOS. Hier volgt een kort overzicht van de initialisatie van de grafische kaart. Bij het opstarten van de computer wordt de allereerste uitvoerbare code uit de PC-BIOS gehaald en uitgevoerd. E´en van de taken die de BIOS op zich neemt, is het afzoeken van de PCI- en AGP9 -bussen naar een grafische kaart. Hierbij wordt de configuratiehoofding van het PCI-toestel10 van elke kaart gepolst naar het klassecode veld. Een grafische kaart wordt gevonden indien dit veld de waarde heeft van een VGA-compatibele controller (zie bijlagen A en C). Als de BIOS de kaart heeft gevonden, zal die de VGA-BIOS in het fysieke geheugen kopi¨eren11 waarna ze wordt uitgevoerd. De GPU wordt nu ge¨ınitialiseerd en klaargemaakt voor gebruik. Zolang deze code niet wordt uitgevoerd, kan de kaart niet werken. Deze opstartcyclus wordt de koude start 12 van de kaart genoemd. Aangezien de BIOS dit slechts doet voor de eerste grafische kaart die ze tegenkomt, moet de opstartprocedure voor een volgende kaart door de programmeur zelf worden uitgevoerd. De koude start procedure wordt door software uitgevoerd en wordt nu een soft-boot genoemd. Hiervoor zijn er twee mogelijkheden. real-mode, 16-bit
“Real mode is an operating mode of 80286 and later x86-compatible CPUs. Real mode is characterized by a 16 bit segmented memory address space (meaning that only 1 MB of memory can be addressed), direct software access to BIOS routines and peripheral hardware, and no concept of memory protection or multitasking at the hardware level. All x86 CPUs in the 80286 series and later start up in real mode at power-on; 80186 CPUs and earlier had only one operational mode, which is equivalent to real mode in 9
AGP staat voor Accelerated Graphics Port. Dit zijn de eerste 64 bytes van de data aanwezig in een chip die op elk PCI-toestel terug te vinden is. 11 Dit staat bekend onder de term “VGA BIOS shadowing”. Dit wordt gedaan voor snellere uitvoering van 10
de code. 12 In het Engels cold-start.
Hoofdstuk 2. Secondaire VGA-kaart
12
later chips.”[7] De code die zich in de VGA-BIOS bevindt, moet worden uitgevoerd in real-mode. Hiertoe dient de CPU in real-mode te worden gezet. Dit is niet evident aangezien een besturingssysteem zoals Linux in protected mode werkt. Er is een Linux systeemoproep die de CPU in real-mode kan brengen, maar dit is niet het enige probleem. De grafische kaart verwacht namelijk dat zij de primaire grafische kaart is en zal bijgevolg belangrijke geheugenplaatsen overschrijven. Om dit probleem op te lossen moeten we de secondaire grafische kaart doen geloven dat ze de primaire is. Dit kan door de real-mode te emuleren. De kaart krijgt zo toegang tot virtuele interrupttabellen en geheugenlocaties en mag dan alle waarden overschrijven die ze wil. Om dit te bereiken moet een x86 -emulator worden geschreven. Hoewel zo een emulator reeds bestaat13 , is het gebruik ervan niet evident en dient de interne werking van de CPU grondig gekend te zijn. protected-mode, 32-bit
De code die zich in de VGA-BIOS bevindt kan ook gewoon worden gelezen en uitgevoerd als een script. De coldstart procedure van de BeOS nVidia driver [3] hanteert deze methode. Het is die code die werd aangepast en ge¨ıntegreerd in de geschreven programma’s. De code heeft een wijzer naar de VGA-BIOS locatie nodig. Ze werd aangepast om te kunnen werken met een binair bestand, dat de VGA-BIOS bevat. Het uitvoeren van de originele code blijkt, om ongekende redenen, niet voldoende te zijn om de kaart te initialiseren14 . Daarom worden meerdere malen, verschillende VGA-BIOS codes15 uitgevoerd. Op het moment van schrijven was het noodzakelijk tweemaal de opeenvolging van de originele en een gedownloade versie uit te voeren. 13
Het x86emu-project is deel van X.org. Er verschijnen witte, verticale strepen op het beeld. 15 VGA-BIOS codes kunnen worden gedownload van het internet [6]. 14
Hoofdstuk 2. Secondaire VGA-kaart
2.3.2
13
Afbeelding van het geheugen
Een stuk van de 4GiB geheugenruimte van de 32-bit CPU kan worden toegewezen aan randapparaten. Hierdoor wordt het mogelijk met die toestellen te communiceren door simpelweg een waarde naar het ‘geheugen’ weg te schrijven. Het apparaat leest van of schrijft op de databus als dat adres op de adresbus verschijnt. Een PCI-kaart houdt dit adres, dat toegewezen werd door de BIOS, bij in zijn configuratiehoofding. Het is deze techniek die werd gehanteerd om de grafische kaart aan te spreken. In puntje 3.3.1 worden een aantal mogelijkheden beschreven om de toegewezen geheugen afbeelding adressen uit de configuratiehoofding te halen. Een tweede manier, die hier niet werd gebruikt, is het oproepen van een kernel API 16 -functie. Dit vereist echter toegang tot de kernel in de vorm van een module en werd zoveel mogelijk vermeden. 2.3.3
Initialiseren van een modus
Voor het initialiseren van een geschikte modus, moeten specifieke waarden naar het juiste register worden geschreven. Die specifieke waarden, zijn de instellingen voor bijvoorbeeld de pixelklok 17 . Het instellen van een modus is een vrij complexe zaak die de VGA-BIOS op zich kan nemen. Aangezien er geen gebruik kon gemaakt worden van de VGA-standaard, moeten de parameters in software berekend worden. Hiervoor wordt beroep gedaan op aangepaste code van het svgalib-project [8]. De registers die moeten worden ingevuld bevinden zich in een gebied van 16MiB grootte. De start van het gebied in het geheugen wordt bijgehouden in het BAR0 veld van de configuratiehoofding. Voor meer informatie omtrent de configuratiehoofding, zie bijlage A. 16 17
API betekent Application Programming Interface. Dit is een Phase Locked Loop (PLL) pulsgenerator die de snelheid bepaalt waaraan de pixels op de RGB-
lijnen worden geplaatst.
Hoofdstuk 2. Secondaire VGA-kaart
2.3.4
14
Beelden schrijven naar de kaart
Eens de grafische kaart klaar is voor gebruik, kunnen er beelden naar worden geschreven. Dit gebeurt opnieuw aan de hand van de memory map gebieden. De startplaats van het grafische geheugen, de zogenaamde videokaart RAM, is terug te vinden in het BAR1 veld van de configuratiehoofding. De grootte ervan is afhankelijk van het model van de kaart en kan worden opgevraagd uit de hoofding. Dit wordt, onder andere, beschreven in hoofdstuk 4. Er is een mogelijkheid om in bepaalde gebieden te schrijven, terwijl een ander gebied wordt getoond op het scherm. Deze double buffering techniek werd ook ge¨ımplementeerd.
“Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the Universe trying to produce bigger and better idiots. So far, the Universe is winning.” —Rich Cook—
Hoofdstuk 3
Mogelijkheden in Linux Hieronder wordt kort geschetst welke mogelijkheden er zijn om apparaten en het geheugen aan te spreken in Linux.
3.1
Het ‘proc’ bestandssysteem
Tijdens het opstartproces zal het Linux besturingssysteem een folder ‘proc’ aanmaken in de hoofdfolder waarin speciale bestanden komen te staan. Deze bestanden staan niet op de harde schijf, maar zitten in het geheugen. Er zijn kernelparameters en -informatie in terug te vinden. De belangrijkste bestanden in deze folder zijn voor deze thesis te vinden in de folder /proc/bus/pci. Bovenstaande locatie bevat verschillende sub-folders naargelang het aantal PCIbussen die aanwezig zijn op het moederbord van de PC. In die folders staan binaire bestanden van 256 bytes groot. Dit is een exacte kopie van de configuratiehoofding (zie bijlage A) die aanwezig is op elk PCI-toestel. De configuratiehoofdingen zijn van groot belang voor het mappen van het geheugen. Tijdens het opstarten van de PC worden namelijk de toegewezen geheugenplaatsen in deze locatie geschreven. Ze kunnen er in Linux met het grootste gemak worden uitgelezen. Eveneens is het mogelijk om er waarden naar te schrijven zonder toegang te moeten hebben tot de kernel. Dit kan gebeuren door enerzijds het bestand te openen
16
Hoofdstuk 3. Mogelijkheden in Linux
17
in de programmacode en anderzijds door het setpci commando (zie puntje 3.3).
3.2
Het geheugen
Toegang tot het geheugen kan in Linux worden verkregen door het openen van het speciale ‘karakter ’ bestand /dev/mem. Dit is niet het fysieke geheugen, maar het volledige geheugen zoals de processor het ziet. Door naar de geheugenlocaties te schrijven die werden teruggevonden in de configuratiehoofdingen (zie 3.1), kan data op een PCI-toestel worden geplaatst. Zoals in puntjes 3.4.1 en 3.5.1 wordt beschreven, zal eerst ´e´en en ander moeten worden gedaan vooraleer een proces toegang kan krijgen tot die geheugenlocaties.
3.3
BASH-scripting
Een heel groot voordeel van het Linux besturingssysteem is de uitgebreide mogelijkheid aan scripting. Scripting is een vorm van programmeren met code die niet hoeft te worden gecompileerd. Ze wordt in ware tijd ge¨evalueerd en beschikt over vele mogelijkheden. Er werd dan uiteraard ook zoveel mogelijk gebruik van gemaakt. Zo werd een scriptje geschreven dat de gebruiker een keuze laat welke VGA-kaart te gebruiken en dan het C/C++ programma opstart. Het scriptje zal eveneens controleren of de uitvoerder wel de superuser is en zal de nodige bits in de configuratiehoofding van de geselecteerde kaart instellen zodat memory mapping mogelijk wordt. 3.3.1
Gebruikte commando’s
hexdump
Om te weten te komen hoeveel VGA-kaarten het systeem bevat en waar ze zich bevinden, wordt de configuratiehoofding ingelezen uit de bestanden in de /proc/bus/pci sub-folders. De bestanden worden ´e´en na ´e´en overlopen en er wordt gekeken of het een VGA-toestel betreft. Dit kan worden gezien aan het class code register dat begint na de
Hoofdstuk 3. Mogelijkheden in Linux
18
tiende byte in het bestand. Het is drie bytes groot en de meest significante byte bevat de klassecode. De code voor een VGA-kaart is 0x03. Voor meer informatie omtrent de klassecodes, zie bijlage C Het programma hexdump schrijft informatie die aanwezig is in een bestand uit in hexadecimale vorm. In het voorbeeld hieronder worden twee opties meegegeven aan het commando. De optie ‘s’ vertelt hexdump om het bestand te beginnen lezen vanaf de opgegeven byte. De ‘n’ optie geeft mee hoeveel bytes er moeten worden gelezen. In het onderstaand voorbeeld is het toestel 0x0d op bus 00 met functie 0 een VGAtoestel. Aangezien de klassecode wordt bijgehouden in de meest significante byte van het class code register moet de twaalfde byte (index 11) gelezen worden om de klassecode te ontdekken. 1 2 3
[ root@c3p0 ~]# hexdump -s 11 -n 1 / proc / bus / pci /00/0 d .0 0000000 b 0003 0000000 c
lspci
Een tweede manier om de configuratiehoofding uit te lezen is het gebruik van het lspci commando. Dit schrijft de informatie uit in een formaat dat begrijpbaar is voor mensen. De optie ‘v’ wordt gebruikt om meer informatie uit te schrijven, een maximum van twee v’s kan worden meegegeven om n´og meer informatie te tonen. Hieronder wordt een stuk van de uitvoer getoond. Het betreft hetzelfde PCI-toestel als in het vorige voorbeeld. 1 2 3 4 5 6 7 8 9 10 11 12
[ root@c3p0 ~]# lspci - vv ... 0000:00:0 d .0 VGA compatible controller : nVidia Corporation NV34 [ GeForce FX 5200] ( rev a1 ) ( prog - if 00 [ VGA ]) Control : I /O - Mem - BusMaster - SpecCycle - MemWINV - VGASnoop ParErr - Stepping - SERR - FastB2B Status : Cap + 66 Mhz + UDF - FastB2B + ParErr - DEVSEL = medium > TAbort - < TAbort - < MAbort - > SERR - < PERR Latency : 32 (1250 ns min , 250 ns max ) Interrupt : pin A routed to IRQ 169 Region 0: Memory at f5000000 (32 - bit , non - prefetchable ) Region 1: Memory at e8000000 (32 - bit , prefetchable )
Hoofdstuk 3. Mogelijkheden in Linux [ size =128 M ] Capabilities : [60] Power Management version 2 Flags : PMEClk - DSI - D1 - D2 - AuxCurrent =0 mA PME ( D0 - , D1 - , D2 - , D3hot - , D3cold -) Status : D0 PME - Enable - DSel =0 DScale =0 PME -
13 14 15 16 17 18
19
...
setpci
Zoals reeds vermeld, kan gebruik worden gemaakt van een standaard Linuxcommando om bepaalde registers te modificeren in de configuratiehoofding van het PCI-toestel. In het onderstaande voorbeeld wordt de optie ‘d’ meegegeven. Deze optie geeft de vendorID en deviceID mee, gescheiden door een dubbele punt. In dit geval is de vendorID 0x10de (nVidia) en de deviceID 0x0322 (de GeForce FX5200). De byte op locatie 0x04, de vijfde byte dus, wordt op 0x06 gezet. Zoals in bijlage A te zien is, zijn dit de BM en MA bits die op 1 worden gezet. 1 2 3 4
[ root@c3p0 ~]# hexdump -n 16 / proc / bus / pci /00/0 d .0 0000000 10 de 0322 0000 02 b0 00 a1 0300 2000 0000 0000010 [ root@c3p0 ~]# setpci -d 10 de :0322 0 x04 =0 x06
5 6 7 8
[ root@c3p0 ~]# hexdump -n 16 / proc / bus / pci /00/0 d .0 0000000 10 de 0322 0006 02 b0 00 a1 0300 2000 0000 0000010
3.4
User-space
3.4.1
Beschrijving
Om veiligheidsredenen zal de Linux kernel een niet-kernelmodule opstarten in de zogenaamde user-space. Op deze manier kan het programma geen toegang krijgen tot de data en code van de kernel en kan het programma het systeem niet (opzettelijk of toevallig) doen uitvallen of andere, kwaadaardige dingen doen uitvoeren. Aangezien het user-space geheugen een beperkt bereik heeft, zullen de MMIO 1 1
MMIO staat voor Memory Mapped Input/Output, dit is de manier van PCI-toestellen aanspreken via
de adressen in de Base Address Registers.
Hoofdstuk 3. Mogelijkheden in Linux
20
adressen van de PCI-toestellen niet zomaar kunnen worden aangesproken. Hiervoor dient eerst een C-functie te worden uitgevoerd die het adres zal afbeelden op een adres dat wel binnen het bereik van de normale gebruiker ligt. De C-functie waarvan sprake is, is mmap() en is terug te vinden in sys/mman.h. 3.4.2
Voor- en nadelen
Werken in user-space heeft ´e´en groot voordeel, namelijk, het systeem kan niet lijden onder verkeerdelijk gebruik van het geheugen. Als de applicatie blokkeert, zal het systeem blijven werken. Een nadeel van deze methode is dat er geen gebruik kan gemaakt worden van meer geavanceerde functies zoals bijvoorbeeld interrupts en DMA. De applicatie kan hierdoor een serieuze daling in prestatie ondervinden.
3.5 3.5.1
Kernel-space Beschrijving
Om toegang te krijgen tot de kernel-space zal een programmeur een Linux kernelmodule moeten ontwikkelen. Dit is een soort plug-in voor de kernel. Ze vereist een specifieke syntax en moet opnieuw gecompileerd worden voor elke versie van de kernel. Hoewel kernelmodules toegang hebben tot het volledige geheugen, moet ook nog een C-functie opgeroepen worden om aan de I/O 2 -adressen te kunnen. De C-functie is ioremap() en kan worden teruggevonden in asm/io.h. 3.5.2
Voor- en nadelen
Door het gebruik van een module kan een ontwikkelaar vele systeemfuncties oproepen die de prestatie van een applicatie aanzienlijk kunnen verhogen. Er kunnen meer geavanceerde onderwerpen worden aangekaart bij het gebruik van deze modules. 2
I/O staat voor Input Output.
Hoofdstuk 3. Mogelijkheden in Linux
21
Het schrijven van een module vereist echter wel kennis van een lagere-orde programmeertaal zoals C/C++. Het kan het systeem ook onstabiel maken door belangrijke data te overschrijven.
“UNIX is basically a simple operating system, but you have to be a genius to understand the simplicity.” —Dennis Ritchie—
Hoofdstuk 4
Realisatie - Gedeelde bibliotheken 4.1
libsoftboot.so
De softboot-bibliotheek bestaat grotendeels uit de nVidia drivercode van het BeOS besturingssysteem. De code werd aangepast om gecompileerd te kunnen worden onder Linux. Ze werd ingekort om enkel te functioneren als softboot-module. Eveneens werden bepaalde functies hernoemd. Het is ook vermeldenswaard dat de module nu niet meer zelf naar de VGA-BIOS zal gaan zoeken, maar dat een wijzer naar het begin van de BIOS-data moet worden meegegeven. De BIOS-code was t´e BeOS specifiek. Langs de andere kant heeft dit als voordeel dat er kan gewerkt worden met data die eender waar is opgeslagen. 4.1.1
Exports
De softboot-bibliotheek exporteert de functies die te zien zijn in Tabel 4.11 . Naast de softboot-functionaliteit, voorziet deze bibliotheek ook een aantal functies om bewerkingen uit te voeren op de configuratiehoofding van het PCI-toestel. 1
Het sterretje kan worden vervangen door b, w of l.
23
Hoofdstuk 4. Realisatie - Gedeelde bibliotheken
24
Naam
Beschrijving
Return type
init softboot
Voer de softboot uit
int
write config*
Schrijf naar de configuratiehoofding
void
read config*
Lees uit de configuratiehoofding
uint8 t tot uint32 t
getPCIInfo
Vraag de volledige configuratiehoofding op
void
getBaseAddressSize
Geeft de grootte van de gevraagde BAR
int
getROM
Kan een BIOS inlezen uit een bestand
unsigned char *
Tabel 4.1: De ge¨exporteerde functies van de softboot-bibliotheek.
4.1.2
Functiereferentie
init softboot
Deze functie voert de softboot uit en zal de kaart dus ‘opstarten’. Haar prototype is gedefinieerd als volgt: 1
int init_softboot ( int bus , int dev , int fnc , unsigned char * bios );
return-waarde Deze functie levert een integer op. De waarde ervan is 0 voor een geslaagde softboot, zoniet is de waarde 1. parameters Naam
Beschrijving
type
bus
PCI-Bus waarop het apparaat zit
int
dev
Nummer van het toestel op de bus
int
fnc
Functie op de PCI-kaart
int
bios
Wijzer naar de startlocatie van de VGA-BIOS
unsigned char*
Hoofdstuk 4. Realisatie - Gedeelde bibliotheken
25
write config*
Deze procedure kan gebruikt worden om velden in de configuratiehoofding te wijzigen. Er bestaan drie versies van. Ze schrijven respectievelijk 8, 16 en 32-bit2 waarden naar de opgegeven locatie. Hun prototypes werden gedefinieerd als volgt: 1 2 3 4 5 6
void write_configb ( uint32_t int dev , void write_configw ( uint32_t int dev , void write_configl ( uint32_t int dev ,
location , uint8_t value , int bus , int fnc ); location , uint16_t value , int bus , int fnc ); location , uint32_t value , int bus , int fnc );
return-waarde Deze functies leveren geen waarde op. parameters Naam
Beschrijving
type
location
Startadres in de hoofding waar de
uint32 t
data moeten worden geschreven value
De waarde die moet worden geschreven
b:
uint8 t
w:
uint16 t
l:
uint32 t
bus
PCI-Bus waarop het apparaat zit
int
dev
Nummer van het toestel op de bus
int
fnc
Functie op de PCI-kaart
int
read config*
Deze procedure kan gebruikt worden om velden in de configuratiehoofding op te vragen. Er bestaan drie versies van. Ze lezen respectievelijk 8, 16 en 32-bit waarden uit de opgegeven locatie. Hun prototypes werden gedefinieerd als volgt: 1 2
uint8_t
read_configb ( uint32_t location , int bus , int device ,
Respectievelijk uint8 t, uint16 t en uint32 t. Dit zijn unsigned integers van 8,16,32 bits breed. Deze
types zijn platform onafhankelijk en zijn gedefinieerd in inttypes.h.
Hoofdstuk 4. Realisatie - Gedeelde bibliotheken
2 3 4 5 6
26
int fn ); uint16_t read_configw ( uint32_t location , int bus , int device , int fn ); uint32_t read_configl ( uint32_t location , int bus , int device , int fn );
return-waarde Deze functies leveren een waarde op die respectievelijk 8, 16 en 32-bit breed zullen zijn. De waarde is de inhoud van de configuratiehoofding op de meegegeven locatie. parameters Naam
Beschrijving
type
location
Startadres in de hoofding waar de
uint32 t
data moeten worden gelezen bus
PCI-Bus waarop het apparaat zit
int
dev
Nummer van het toestel op de bus
int
fnc
Functie op de PCI-kaart
int
getPCIInfo
Deze functie kan gebruikt worden om de volledige configuratiehoofding op te vragen3 . Het prototype werd gedefinieerd als volgt: 1
void getPCIInfo ( int bus , int device , int fn , unsigned long * buf );
return-waarde Deze functie levert geen waarde op.
3
Zie bijlage A voor de opbouw van deze hoofding.
Hoofdstuk 4. Realisatie - Gedeelde bibliotheken
27
parameters Naam
Beschrijving
type
bus
PCI-Bus waarop het apparaat zit
int
device
Nummer van het toestel op de bus
int
fn
Functie op de PCI-kaart
int
buf
Pointer naar een array waarin de data moet
unsigned long*
komen, deze moet reeds toegewezen zijn. getBaseAddressSize
Deze functie kan gebruikt worden om de lengte van een Base Address regio op te vragen. Ze wordt bijvoorbeeld gebruikt om de grootte van het RAM-geheugen op de VGA-kaart te bepalen. Het prototype werd gedefinieerd als volgt: 1
int ge tB as eA dd re ss Si ze ( int ban , int bus , int device , int fn );
return-waarde Deze functie levert een integer op. De waarde ervan is de grootte van de regio. Indien het Base Address Register niet werd ge¨ımplementeerd, is de waarde 0. parameters Naam
Beschrijving
type
ban
Nummer van het Base Address Register
int
bus
PCI-Bus waarop het apparaat zit
int
device
Nummer van het toestel op de bus
int
fn
Functie op de PCI-kaart
int
getROM
Deze functie leest een binair bestand met grootte 64kiB van de harde schijf en levert een wijzer naar de data terug. Ze wordt vooral gebruikt om een VGA-BIOS beeld van de harde schijf te laden. Het prototype werd gedefinieerd als volgt: 1
unsigned char * getROM ( const char * filename );
Hoofdstuk 4. Realisatie - Gedeelde bibliotheken
28
return-waarde Deze functie levert een wijzer op naar het begin van de data. De grootte van de array is 65536 bytes. parameters Naam
Beschrijving
type
filename
Pad en bestandsnaam van het te lezen bestand
const char *
4.2
libnvugent.so
De nvugent-bibliotheek bevat de functies en procedures om de beeldkaart, eens ze opgestart is, te initialiseren op een gewenste resolutie en er beelden naar te schrijven. Een groot stuk van de code werd geleend van het svgalib-project[8]. 4.2.1
Exports
Deze bibliotheek exporteert de functies in Tabel 4.2. Naast deze functies wordt ook een variabele genaamd ‘infotable’, van het type struct vgainfo, ge¨exporteerd. Naam
Beschrijving
Return type
init nvugent
Voer de nvugent initialisatie uit
int
vga screenon
Toon video uitvoer
void
vga screenoff
Stop met video uitvoer te tonen
void
vga setmode
Stel een modus in
int
vga setrgbcolor
Stel de huidige tekenkleur in
int
vga drawpixel
Teken een pixel op een bepaalde locatie
int
vga bitblt
Blok transfer een aantal pixels
void
vga waitretrace
Blokkeer tot een verticale retrace
void
vga setstartaddress
Wijzig het beginadres van de te tonen data
void
Tabel 4.2: De ge¨exporteerde functies van de nvugent-bibliotheek.
Naast deze functies zijn ook meer algemene functies beschikbaar om toegang te krijgen
Hoofdstuk 4. Realisatie - Gedeelde bibliotheken
29
tot de standaard VGA-registers en eender welk ander register. Hierbij wordt wel verondersteld dat de kaart opgestart en ge¨ınitialiseerd is. De prototypes voor de standaard VGA-registers zijn als volgt4 : 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
// zorg voor vertraging void vga_delay ( void ); // lees / schrijf miscellaneous register int vga_inmisc ( void ); void vga_outmisc ( int val ); // lees / schrijf CRT Controller registers int vga_incrtc ( int index ); void vga_outcrtc ( int index , int val ); // lees / schrijf CRT Controller registers // voor 2 e video - uitgang int vga_incrtc2 ( int index ); void vga_outcrtc2 ( int index , int val ); // lees / schrijf Sequencer registers int vga_inseq ( int index ); void vga_outseq ( int index , int val ); // lees / schrijf Graphics registers int vga_ingra ( int index ); void vga_outgra ( int index , int val ); // lees Input Status #1 register int vga_inis1 ( void ); // lees / schrijf Attribute registers int vga_inatt ( int index ); void vga_outatt ( int index , int val ); // lees / schrijf Attribute registers // voor 2 e video - uitgang int vga_inatt2 ( int index ); void vga_outatt2 ( int index , int val ); // lees / schrijf Palette registers void vga_inpal ( int index , int *r , int *g , int * b ); void vga_outpal ( int index , int r , int g , int b );
De algemenere functies kunnen gebruikt worden om eender welk register te beschrijven en uit te lezen. Dit zijn de prototypes: 1 2 3 4 5 6 7 8 4
// lees byte / word / long int vga_inb ( int index ); int vga_inw ( int index ); int vga_inl ( int index ); // schrijf byte / word / long void vga_outb ( int index , int val ); void vga_outw ( int index , int val ); void vga_outl ( int index , int val );
De parameters index en val zijn respectievelijk de locatie en de te schrijven waarde.
Hoofdstuk 4. Realisatie - Gedeelde bibliotheken
30
De variabele infotable waarvan sprake is, is een tabel die de parameters voor de verschillende modi bevat5 . Haar type, de struct vgainfo, is gedefinieerd als volgt: 1 2 3 4 5 6 7 8 9 10 11
4.2.2
struct vgainfo { // x en y resolutie int xdim , ydim ; // aantal kleuren int colors ; // aantal bytes per lijn int xbytes ; // aantal bytes per pixel int bytesperpixel ; };
Functiereferentie
init nvugent
Deze functie initialiseert de nvugent-bibliotheek. De geheugenafbeeldingen worden gemaakt en alles wordt klaargezet voor gebruik. Het is de eerste functie die moet worden opgeroepen en ze is als volgt gedefinieerd: 1
int init_nvugent ( int bus , int dev , int fnc )
return-waarde Deze functie levert een integer op. De waarde ervan is 0 bij een succesvolle initialisatie, anders is ze niet 0. parameters
5
Naam
Beschrijving
type
bus
PCI-Bus waarop het apparaat zit
int
dev
Nummer van het toestel op de bus
int
fnc
Functie op de PCI-kaart
int
Zie bijlage D voor een complete lijst.
Hoofdstuk 4. Realisatie - Gedeelde bibliotheken
31
vga setmode
Deze functie stelt de grafische kaart in op de gevraagde resolutie en beeldfrequentie. Er bestaan twee versies van deze functie. De eerste neemt een modus-nummer als argument. De tweede neemt een MonitorModeTiming struct en een vgainfo struct als argumenten, zodat in principe eender welke resolutie kan worden ingesteld. De prototypes van de functies zien er als volgt uit: 1 2
int int
vga_setmode ( int mode ); vga_setmode ( Moni torModeTiming mmt , vgainfo vi );
De MonitorModeTiming struct moet ingevuld worden met specifieke data. Deze data kunnen online berekend worden[2]. De struct werd gedefinieerd als volgt: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
typedef struct _MMT_S MonitorModeTiming ; struct _MMT_S { int pixelClock ; /* Pixel clock in kHz . */ int HDisplay ; /* Horizontal Timing . */ int HSyncStart ; int HSyncEnd ; int HTotal ; int VDisplay ; /* Vertical Timing . */ int VSyncStart ; int VSyncEnd ; int VTotal ; int flags ; Mon itorM odeTim ing * next ; };
Het veld flags is de logische of van ´e´en of meerdere waarden uit Tabel 4.3. De waarde van het veld next mag eender wat zijn, ze wordt intern gebruikt en aangepast.
Hoofdstuk 4. Realisatie - Gedeelde bibliotheken
32
Waarde
Betekenis
PHSYNC
Positief HSYNC -signaal
NHSYNC
Negatief HSYNC -signaal
PVSYNC
Positief VSYNC -signaal
NVSYNC
Negatief VSYNC -signaal
INTERLACED
Mode met interlacing
DOUBLESCAN
Doublescan mode
HADJUSTED
Horizontaal aangepaste CRTC-timing
VADJUSTED
Verticaal aangepaste CRTC-timing
USEPROGRCLOCK
Er wordt een programmeerbare klok gebruikt
TVMODE
Modus is een TV-mode
TVPAL
TV-modus PAL
TVNTSC
TV-modus NTSC Tabel 4.3: De mogelijke waarden van het veld flags.
return-waarde Deze functie levert een integer op. De waarde ervan is 0 bij een succesvolle initialisatie, anders is ze niet 0. parameters Naam
Beschrijving
type
mode
Het modus nummer, zie bijlage D
int
mmt
Struct met timing info
MonitorModeTiming
vi
Struct met mode info
struct vgainfo
vga screenon
Met deze functie wordt de videouitgang aangezet. Het prototype is als volgt: 1
void vga_screenon ( void );
Hoofdstuk 4. Realisatie - Gedeelde bibliotheken
33
return-waarde Deze functie levert geen waarde op. parameters Deze functie heeft geen parameters. vga screenoff
Met deze functie wordt de videouitgang afgezet. Het prototype is als volgt: 1
void vga_screenoff ( void );
return-waarde Deze functie levert geen waarde op. parameters Deze functie heeft geen parameters. vga setrgbcolor
Deze functie stelt de kleur in van de pixel die door de functie vga drawpixel getekend wordt. Het prototype is als volgt: 1
int vga_setrgbcolor ( int r , int g , int b );
return-waarde Deze functie levert een integer op. De waarde ervan is de interne representatie van de kleur. Ze is afhankelijk van de huidige kleurendiepte. De interne representatie is als volgt. De kleur wordt opgeslagen in een integer (32-bit). Neem een kleurendiepte van drie bytes per pixel als voorbeeld. De minst significante acht bits zijn de blauwe component
Hoofdstuk 4. Realisatie - Gedeelde bibliotheken
34
(bits [0:7]). De volgende byte is de groene kleur (bits [8:15]). Ten slotte volgen de rode bits (bits [16:23]). Bij een kleurendiepte met minder dan ´e´en byte per pixel wordt uiteraard geen volledige byte gebruikt om de kleur op te slaan, maar wel het aantal bits per pixel. Bij een kleurendiepte met vier bytes per pixel, wordt de vierde byte genegeerd. parameters Naam
Beschrijving
type
r
De rode component van de kleur
int
g
De groene component van de kleur
int
b
De blauwe component van de kleur
int
vga drawpixel
Met deze functie kan een pixel naar het scherm geschreven worden. Het nulpunt is de linkerbovenhoek van het scherm. Het prototype is als volgt: 1
int vga_drawpixel ( int x , int y );
return-waarde Deze functie levert een integer op. De waarde ervan is steeds 0. parameters Naam
Beschrijving
type
x
De horizontale locatie van de pixel
int
y
De verticale locatie van de pixel
int
vga bitblt
Met deze functie kan een hele blok pixels naar het scherm geschreven worden. De pixels worden meegegeven in tabelvorm. Ze worden opgeslagen zoals beschreven in puntje 4.2.2 (interne representatie). Het prototype is als volgt:
Hoofdstuk 4. Realisatie - Gedeelde bibliotheken
1
35
void vga_bitblt ( unsigned char * image , int size , int offset );
return-waarde Deze functie levert geen waarde op. parameters Naam
Beschrijving
type
image
De bytes die moeten worden getransfereerd
unsigned char*
size
Het aantal te transfereren bytes
int
offset
Het startadres vanwaar wordt geschreven
int
vga waitretrace
Deze procedure blokkeert het proces totdat de grafische kaart een vertical retrace genereert. De verticale retrace is het moment waarop de monitor gedaan heeft met het beeld te schrijven. De cathodestraal gaat dan terug naar de linkerbovenhoek van het scherm. Het prototype is als volgt: 1
void vga_waitretrace ( void );
return-waarde Deze functie levert geen waarde op. parameters Deze functie heeft geen parameters. vga setstartaddress
Deze procedure wordt gebruikt om het beginadres van de beelddata in het videogeheugen aan te geven. Het prototype is als volgt: 1
void v ga _ s et s t a rt a d dr e s s ( int address );
Hoofdstuk 4. Realisatie - Gedeelde bibliotheken
36
return-waarde Deze functie levert geen waarde op. parameters
4.3
Naam
Beschrijving
type
address
Het startadres van de data in het video-geheugen
int
Het gebruik van de bibliotheken
4.3.1
Compilatie en installatie
Het volstaat voor beide bibliotheken om het commando ‘make’ uit te voeren in hun hoofdfolder om hulp te krijgen. Er zijn in totaal zes mogelijkheden. Naast de mogelijkheden in onderstaand voorbeeld, kunnen ook nog de targets ‘debug’ en ‘clean’ worden gemaakt. De eerste target geeft de mogelijkheid om op de voet te volgen wat de bibliotheek doet. De nvugent-bibliotheek zal een bestand genaamd log.txt aanmaken in de folder waar het programma werd uitgevoerd. Eveneens wordt informatie op het scherm getoond. De softboot-bibliotheek zal enkel informatie op het scherm tonen. 1 2
[ root@c3p0 ~/ libsoftboot ]# make Use the following targets to compile :
3 4 5 6 7 8
lib install uninstall demo all
-
make the ’ softboot ’ shared library install the ’ softboot ’ shared library uninstall the ’ softboot ’ shared library make the demos do all of this
De bibliotheken worden ge¨ınstalleerd in de folder /lib. Pas na installatie kunnen de programma’s die er gebruik van maken, worden gecompileerd. 4.3.2
Gebruik
Om de bibliotheek te kunnen gebruiken, moet het header bestand6 in de ‘include’ folder worden ingevoegd. De gemakkelijkste manier om dit te doen, is gewoon het bestand te kopi¨eren naar de folder met Uw bronbestanden. Daarnaast moeten volgende 6
Voor de nvugent-bibliotheek noemt het bestand nvugent.h en voor de softboot-bibliotheek softboot.h.
Hoofdstuk 4. Realisatie - Gedeelde bibliotheken
37
opties worden meegegeven tijdens het compileren: -lnvugent en/of -lsoftboot. Zie Hoofdstuk 6 voor een voorbeeld.
“The most likely way for the world to be destroyed, most experts agree, is by accident. That’s where we come in; we’re computer professionals. We cause accidents.” —Nathaniel Borenstein—
Hoofdstuk 5
Realisatie - Kernelmodule Naast de gedeelde bibliotheken werd ook een kernelmodule geschreven. Deze module stelt de gebruiker in staat toegang te krijgen tot de Expansion ROM op een PCI-kaart. Die toegang wordt verkregen via een ‘karakter’-bestand genaamd vgabios in de /dev folder. Omdat het major -nummer1 dynamisch wordt toegekend door de Linuxkernel, werd een script geschreven dat de aanmaak van het bestand automatiseert. De module werkt slechts als de PCI-kaart reeds werd ge¨ınitialiseerd. In het geval van een additionele grafische kaart vormt dit echter een probleem. Het is namelijk de VGA-BIOS code in de ROM die de kaart moet initialiseren. Deze kernelmodule werd in het begin van het maken van de thesis geschreven om een kopie te maken van die VGA-BIOS. Hierbij werd het XWindows-systeem gebruikt om de kaart op te starten. Het is belangrijk op te merken dat de kernelmodule enkel kan gebruikt worden als het PCI-toestel niet in gebruik is. Om toegang te krijgen tot de BIOS-code moet namelijk een adres worden toegewezen. Dit adres wordt in de kernelmodule geleend van het Base Address Register 0. Zolang de module ingeladen is, kan geen gebruik worden gemaakt van de andere code. 1
Dit nummer is een referentienummer dat intern door de kernel wordt gebruikt om de datastroom van en
naar het bestand naar de juiste module om te leiden.
39
Hoofdstuk 5. Realisatie - Kernelmodule
5.1
40
Compilatie en gebruik
Zoals bij alle geschreven code werd een Makefile gemaakt om de code op een eenvoudige manier te compileren. Hieronder wordt gedemonstreerd hoe ze moet worden gecompileerd en gebruikt. Het dd commando dat wordt gebruikt, kopieert een blok binaire data van if naar of. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
[ root@c3p0 ~/ module ]# make clean / bin / rm - rf .*. cmd *~ *. ko *. o . tmp * *. mod . c [ root@c3p0 ~/ module ]# make Making vgabios module make -C / usr / src / linux / SUBDIRS =/ root / module modules make [1]: Entering directory / usr / src / linux -2.6.8 -24.14 CC [ M ] / root / module / vgabios . o Building modules , stage 2. MODPOST CC / root / module / vgabios . mod . o LD [ M ] / root / module / vgabios . ko make [1]: Leaving directory / usr / src / linux -2.6.8 -24.14 [ root@c3p0 ~/ module ]# ./ insmod . sh VENDORID =4318 DEVICEID =802 mknod / dev / vgabios c 253 0 [ root@c3p0 ~/ module ]# dd if =/ dev / vgabios of = rom . bin bs =65536 count =1 [ root@c3p0 ~/ module ]# rmmod vgabios
Zoals in bovenstaand voorbeeld kan gezien worden, moet men een aantal argumenten met de module meegeven. Deze argumenten zijn de VENDORID en de DEVICEID getallen uit puntje 3.3.1. Ze moeten echter wel meegegeven worden als decimaal getal.
“If the automobile had followed the same development cycle as the computer, a Rolls-Royce would today cost $100, get a million miles per gallon, and explode once a year, killing everyone inside.” —Robert X. Cringely—
Hoofdstuk 6
Realisatie - Voorbeeldprogramma In dit hoofdstuk wordt een kleine demonstratie-applicatie gemaakt om het gebruik van beide besproken bibliotheken te verduidelijken.
6.1
Softboot voorbeeld
Dit programma zal de kaart op locatie 00:0d.0 opstarten en het scherm opvullen met witte pixels. Gemakkelijkheidshalve wordt er niet aan foutcontrole gedaan. De code zit in het bestand /root/vb.cpp en ziet er zo uit: 1 2
# include " softboot . h " # include " nvugent . h "
3 4 5 6 7 8 9 10
int main ( int argc , char ** argv ) { // softboot card init_softboot (0 ,13 ,0 , getROM ( " ROM1 . BIN " )); init_softboot (0 ,13 ,0 , getROM ( " ROM2 . BIN " )); init_softboot (0 ,13 ,0 , getROM ( " ROM1 . BIN " )); init_softboot (0 ,13 ,0 , getROM ( " ROM2 . BIN " ));
11 12 13
// initialize VGA card init_nvugent (0 ,13 ,0);
14 15 16
// set mode 1024 x768x4 vga_setmode (36);
17 18 19
// set color to white vga_setrgbcolor (255 ,255 ,255);
20
42
Hoofdstuk 6. Realisatie - Voorbeeldprogramma
43
// write pixels for ( int i =0; i <1024; i ++) for ( int j =0; j <768; j ++) vga_drawpixel (i , j );
21 22 23 24 25
return 0;
26 27
}
De lezer wordt eraan herinnerd dat het wegens onbekende redenen nodig is de softboot viermaal te herhalen (zie puntje 2.3.1). De compilatie van deze code is als volgt1 : 1
[ root@c3p0 ~]# gcc - lstdc ++ - lsoftboot - lnvugent vb . cpp -o vb . exe
Vooraleer we echter kunnen compileren, moeten de bibliotheken worden gecompileerd en ge¨ınstalleerd. Stel dat beide bibliotheek bronfolders in de root folder staan, dan doen we achtereenvolgens dit: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
[ root@c3p0 [ root@c3p0 ... [ root@c3p0 ... [ root@c3p0 [ root@c3p0 [ root@c3p0 [ root@c3p0 ... [ root@c3p0 ... [ root@c3p0 [ root@c3p0 [ root@c3p0
~]# cd libsoftboot ~/ libsoftboot ]# make lib ~/ libsoftboot ]# make install ~/ libsoftboot ]# cp include / softboot . h / root ~/ libsoftboot ]# cd .. ~]# cd libnvugent ~/ libnvugent ]# make lib ~/ libnvugent ]# make install ~/ libnvugent ]# cp include / nvugent . h / root ~/ libnvugent ]# cd .. ~]# gcc - lstdc ++ - lsoftboot - lnvugent vb . cpp -o vb . exe
Het programma kan nu worden uitgevoerd: 1
6.2
[ root@c3p0 ~]# ./ vb . exe
Dubbele buffering
Dit programma veronderstelt dat de grafische kaart reeds werd opgestart. Het zal het scherm instellen op de resolutie 640×480 en drie buffers beschrijven. De eerste 1
We veronderstellen dat de nodige header bestanden naar de /root folder werden gekopieerd.
Hoofdstuk 6. Realisatie - Voorbeeldprogramma
44
buffer is opgevuld met de kleur rood, de tweede met groen en de laatste met blauw. Elke seconde wordt van buffer gewisseld. Dit gebeurt in totaal tien maal. 1 2
# include " nvugent . h " # include " unistd . h "
3 4 5 6 7
int main ( int argc , char ** argv ) { // initialize VGA card init_nvugent (0 ,13 ,0);
8 9 10
// turn off video vga_screenoff ();
11 12 13 14
// set mode 640 x480x4 int x =640 , y =480 , b =4; vga_setmode (34);
15 16 17
// set color to red vga_setrgbcolor (255 ,0 ,0);
18 19 20 21 22
// write pixels to buffer 0 for ( int i =0; i < x ; i ++) for ( int j =0; j < y ; j ++) vga_drawpixel (i , j );
23 24 25
// set color to green vga_setrgbcolor (0 ,255 ,0);
26 27 28 29 30
// write pixels to buffer 1 for ( int i =0; i < x ; i ++) for ( int j =0; j < y ; j ++) vga_drawpixel (i , j + y );
31 32 33
// set color to blue vga_setrgbcolor (0 ,0 ,255);
34 35 36 37 38
// write pixels to buffer 2 for ( int i =0; i < x ; i ++) for ( int j =0; j < y ; j ++) vga_drawpixel (i , j +2* y );
39 40 41
// turn on video vga_screenon ();
42 43 44 45
// offset is number of bytes per buffer int offset = x * y * b ; for ( int i =0; i <10; i ++)
Hoofdstuk 6. Realisatie - Voorbeeldprogramma
45
{
46
// first buffer v g a_ s e tstartaddress (0); sleep (1); // second buffer v g a_ s e tstartaddress ( offset ); sleep (1); // third buffer v g a_ s e tstartaddress ( offset *2); sleep (1);
47 48 49 50 51 52 53 54 55
}
56 57
return 0;
58 59
6.3
}
Aangepaste resolutie
De bedoeling van dit programma is aan te tonen hoe de MonitorModeTiming struct en de vgainfo struct moeten worden ingevuld. Vooreerst worden de data berekend op de site [2] bij “Basic Configuration”. De resolutie is 352×288 (CIF). De beeldfrequentie is 60Hz. Verder wordt nog Doublescan aangevinkt. De modus lijn kan nu worden berekend. Dit is het resultaat: 1
" 352 x288@60d " 16.25 352 384 408 440 288 294 297 303 doublescan
Het getal 16.25 is de pixelklok en staat in kHz. De code aanvaardt enkel Hz, daardoor moet het getal worden vermenigvuldigd met 1000. Hier volgt de volledige code: 1
# include " nvugent . h "
2 3 4 5 6 7 8
int main ( int argc , char ** argv ) { Mon itorM odeTim ing mmt ={16250 , 352 , 384 , 408 , 440 , 288 , 294 , 297 , 303 , DOUBLESCAN , 0};
9 10
struct vgainfo vi ={352 , 288 , 1 < <24 , 352*4 , 4};
11 12 13
// initialize VGA card init_nvugent (0 ,13 ,0);
14 15 16
// set mode vga_setmode ( mmt , vi );
Hoofdstuk 6. Realisatie - Voorbeeldprogramma
46
17
// set color to white vga_setrgbcolor (255 ,255 ,255);
18 19 20
// clear screen for ( int i =0; i <352; i ++) for ( int j =0; j <288; j ++) vga_drawpixel (i , j );
21 22 23 24 25
return 0;
26 27
}
Er werden verschillende demo-programma’s geschreven voor de bibliotheken. Ze zijn te vinden in de folder demos in de hoofdfolders. Er is eveneens een overkoepelend voorbeeldprogramma, dat zich bevindt in de folder example. Dit programma wordt best uitgevoerd met het run.sh script dat zich in de folder bevindt. Het geeft de gebruiker de keuze tussen de verschillende grafische kaarten die aanwezig zijn in het systeem.
Problems cannot be solved at the same level of awareness that created them. —Albert Einstein—
Hoofdstuk 7
Besluit Er mag zeker gezegd worden dat het vooropgestelde doel bereikt werd. Er werd code geschreven die de gebruiker toelaat om in user-space een secondaire grafische kaart op te starten en ze te initialiseren. De applicatie kan een resolutie instellen en beelden naar de kaart schrijven, al dan niet met gebruik van meerdere buffers. Bijkomstig werd voldaan aan de eisen wat betreft de doelresolutie. Het RESUMEproject levert namelijk beelden op in de CIF -resolutie. Dit is een resolutie van 352×288. Op de machine waar de code op werd geschreven, werd op die resolutie eveneens een prachtige prestatie van 140.35fps neergezet. Hoewel alles blijkt te werken, is het programma zeker vatbaar voor verbeteringen. Een belangrijk punt is dat DMA zou kunnen worden ge¨ımplementeerd, waardoor de processorbelasting aanzienlijk zal verlaagd worden. Hiervoor is echter wel kernel-toegang vereist. De reden waarom dit echter niet werd ge¨ımplementeerd, is dat er gewoonweg te weinig informatie over de hardware ter beschikking was. Het closed-architecture beleid van nVidia ligt hier aan de basis.
48
Bijlage A
De configuratiehoofding De informatie in deze bijlage werd overgenomen uit [5]. 31
16
15
0
Index
Device ID
Vendor ID
0x00
Status
Command
0x04
Class Code Built In Selftest
Header
Latency
0x08
Cache Line Size
0x0C
Base Address Register 0
0x10
Base Address Register 1
0x14
Base Address Register 2
0x18
Base Address Register 3
0x1C
Base Address Register 4
0x20
Base Address Register 5
0x24
Cardbus CIS Pointer
0x28
System ID
Max Latency
Revision
Subsystem Vendor ID
0x2C
Expansion ROM Address
0x30
Reserved
0x34
Reserved
0x38
Min Grant
Interrupt Pin
IRQ Line
0x0C
Tabel A.1: De standaard eerste 64 bytes van de configuratiehoofding van een PCI-kaart.
49
Bijlage A. De configuratiehoofding
50
Uitleg bij de tabel: Vendor ID - 0x00 This is an assigned number unique to each PCI vendor. For a somewhat complete list of these have a look at Linux’s pci.h. Device ID - 0x02 This is a vendor assigned number specifying which device it is. For a somewhat complete list of these have a look at Linux’s pci.h. Command - 0x04 This is used to enable various types of PCI operations 15..10
9
8
7
6
5
4
3
2
1
0
Reserved
BBE
SEE
WC
PER
VPS
MWI
SC
BM
MA
IO
BBE: Fast Back-to-back enable. Enables fast back-to-back transfers during bus mastering. Only enable this if all devices on the bus can do BBE SEE: System Error Enable. When set to one the device can drive the SERR# line. WC: Wait Cycle Enable. Controls whether the device does address/data stepping. PER: Parity Error Response. When set to one the device can report parity errors. VPS: VGA Palette Snoop Enable. Tells the device to enable VGA pallet snooping MWI: Memory Write and Invalidate. Enables the device to generate memory write and invalidate commands. The cache line size must be set before this bit is set. SC: Special Cycle Recognition. Enables the device to monitor for special cycles on the bus. BM: Bus Master Enable. Enables the device to become the bus master. MA: Memory Access Enable. When enabled the device responds to memory mapped I/O requests. IO: I/O Access Enable. When enabled the device responds to I/O-port requests. Status - 0x06 15
14
13
12
11
10
9
8
7
6
5..0
DPE
SSE
RMA
RTA
STA
DT
DPR
FBBC
UDF
66
Reserved
DPE: Detect Parity Error. Set by device when it has detected a parity error
Bijlage A. De configuratiehoofding
51
SSE: Signaled System Error. Set by device when it has driven the SERR# line RMA: Received Master-Abort. Set by master when its transaction is terminated due to a master-abort. RTA: Received Target-Abort. Set by master when its transaction is terminated due to a target-abort. STA: Signaled Target-Abort. Set by target when it terminates a transaction by target-abort. DT: DEVSEL Timing. Read only bits which define the slowest DEVSEL# timing for the device. 00b: = fast 01b: = medium 10b: = slow 11b: = reserved DPR: Data Parity Reported. Set by the bus master when the reporting bus master was the initiator and set the PERR# itself or detected it asserted by the target. FBBC: Fast Back-to-Back Capable. Indicates whether the device can perform fast back-to-back transfers UDF: UDF Supported. Set if the device supports user definable features 66: 66MHz Capable. Set if device can run at 66MHz. Revision - 0x08 8 bit value indicating the revision of the device. Class Code Register - 0x09 Specifies which type of device it is. The class code register is divided up into 3 8-bit parts: Class Code, Sub-Class Code, and Prog. I/F. 23..16 Class Code 15..8 Sub-Class Code 7..0 Prog. I/F Look at the Class Code Table for a list of what these mean. Cache Line Size - 0x0c This is the cache line size of the CPU. This is CPU dependent. It is important that
Bijlage A. De configuratiehoofding
52
devices which do DMA have this value. Latency - 0x0d Specifies the maximum number of PCI cycles the bus master can retain control for the bus. Header Type - 0x0e The header type is divided into two sections. Bits 6..0 comprise the header type. Bit 7 is the single/multi function device flag (0=single 1=multi). The header type specifies the format of bytes 0x10 to 0x3f. The two defined types are 0x00, the standard header type (pictured above), and 0x01, PCI-PCI bridge. Built In Self Test (BIST) - 0x0f 7
6
5..4
3..0
C
S
Reserved
Ret
C: BIST Capable S: Start BIST Ret: BIST Return Code If the device is BIST Capable it must set the return code to 0 within 2 seconds of the Start BIST bit being set, otherwise an error has occurred. Base Address Registers 0-5 - 0x10-0x24 These are base addresses for memory mapped/io mapped communications with the device. The actual function of these registers are device specific CardBus CIS Pointer - 0x28 If this device sits on both PCI and CardBus this is used to point to Card Information Structure (CIS). Subsystem Vendor ID - 0x2c Optional extra vendor info. Subsystem ID - 0x2e Optional extra subsystem info. Expansion Rom Address - 0x30 Address that the expansion ROM of the device (e.g. vga bios rom) is mapped in. IRQ Line - 0x3c
Bijlage A. De configuratiehoofding
53
The IRQ this device is routed through. In other words what IRQ will be triggered when this device generates an interrupt. This value does not actually affect the operation of the device, rather it is a place for the BIOS/Firmware to inform the OS what has been configured. Interrupt Pin - 0x3d Which of the 4 lines (INTA#, INTB#, INTC#, or INTD#) this device raises interrupts on. A value of 0 means no interrupt. A value between 1 and 4 corresponds to INTA# through INTD#. A single function device is required to use INTA#. Min Grant - 0x3e A read only register informing the reader of how long the device would like to maintain control of the bus as a bus master. The value is in increments of 250ns. Max Latency - 0x3f “How often” the device needs to access the PCI bus. The value is in increments of 250ns.
Bijlage B
De nVidia registerlocaties nVidia hanteert dezelfde indices wat betreft de locatie van de registers Er moet echter een offset bij worden opgeteld om ze te kunnen bereiken. In onderstaande tabel wordt de offset weergegeven.
Naam register
standaard VGA-adres
nVidia offset
(Read/Write) in hex
in hex
Attribute controller index
0x3C0/0x3C0∗
0x00601000
Attribute controller data
0x3C1/0x3C0∗
0x00601000
Sequencer index
0x3C4/0x3C4
0x000C0000
Sequencer data
0x3C5/0x3C5
0x000C0000
Palette mask
0x3C6/0x3C6
0x00681000
Palette index
0x3C7/0x3C8
0x00681000
Palette data
0x3C9/0x3C9
0x00681000
Miscellaneous output register
0x3CC/0x3C2
0x000C0000
Graphics controller index
0x3CE/0x3CE
0x000C0000
Graphics controller data
0x3CF/0x3CF
0x000C0000
0x3DA/×
0x00601000
CRT controller index
0x3D4/0x3D4
0x00601000
CRT controller data
0x3D5/0x3D5
0x00601000
Input status #1
54
Bijlage B. De nVidia registerlocaties ∗
55
Dit register werkt met een Set/Reset flipflop. Om de index te schrijven moet eerst een
leesoperatie worden uitgevoerd op het Input status #1 register, waardoor de flipflop gereset wordt. Daarna kan in het Attribute controller index register de index worden geschreven. Dit zet de flipflop op 1, zodat een schrijfoperatie op hetzelfde adres nu een schrijfoperatie is naar het Attribute controller data register. Het valt op te merken dat de offset en de index moeten worden opgeteld bij het memory mapped BAR0 1 -adres en dat alles geldt voor een adapter in color mode. Voor het Miscellaneous output register wordt dit in het geval van BAR0 MMAP=mmap(BAR0) : read :
BAR0 MMAP+0x000C0000+0x000003CC
write:
BAR0 MMAP+0x000C0000+0x000003C2
1
Zie bijlage A voor meer informatie.
Bijlage C
Klassecodes voor PCI De informatie in deze bijlage werd overgenomen uit [4]. Enkel de codes van de beeldschermkaarten werden ingevoegd.
C.1
Klassecode tabel Class
Description
0x00
Devices built before class codes (i.e. pre PCI 2.0)
0x01
Mass storage controller
0x02
Network controller
0x03
Display controller
0x04
Multimedia device
0x05
Memory Controller
0x06
Bridge Device
0x07
Simple communication controllers
0x08
Base system peripherals
0x09
Input devices
0x0A
Docking Stations
0x0B
Processors
0x0C
Serial bus controllers
0x0D
Wireless controllers 56
Bijlage C. Klassecodes voor PCI
0x0E
Intelligent IO controllers
0x0F
Satellite communication controllers
0x10
Encryption/decryption controllers
0x11
Data acquisition and signal processing controllers
0x12-0xFE
Reserved
0xFF
C.2
57
Misc
Klassecodes
Class code 3: display controllers
Sub-Class
Prog. I/F
0x00
0x00
Description VGA compatible controller. Has mapping for 0xA0000..0xBFFFF and io addresses 0x3B0..0x3BB.
0x00
0x01
8514 compatible controller responding to IO address 0x02E8 and 0x02EF
0x01
0x00
XGA controller
0x02
0x00
3D controller
0x80
0x80
Other display controller
Bijlage D
nvugent modi Opmerking: enkel de modi met ´e´en of meer bytes per pixel werken effectief. De tabel werd compleet overgenomen van svgalib[8]. Modus nr.
X Resolutie
Y Resolutie
Bytes per pixel
0
80
25
0
1
320
200
0
2
640
200
0
3
640
350
0
4
640
480
0
5
320
200
1
6
320
240
0
7
320
400
0
8
360
480
0
9
640
480
0
10
640
480
1
11
800
600
1
12
1024
768
1
13
1280
1024
1
14
320
200
2
58
Bijlage D. nvugent modi
59
15
320
200
2
16
320
200
3
17
640
480
2
18
640
480
2
19
640
480
3
20
800
600
2
21
800
600
2
22
800
600
3
23
1024
768
2
24
1024
768
2
25
1024
768
3
26
1280
1024
2
27
1280
1024
2
28
1280
1024
3
29
800
600
0
30
1024
768
0
31
1280
1024
0
32
720
348
0
33
320
200
4
34
640
480
4
35
800
600
4
36
1024
768
4
37
1280
1024
4
38
1152
864
0
39
1152
864
1
40
1152
864
2
41
1152
864
2
42
1152
864
3
43
1152
864
4
Bijlage D. nvugent modi
60
44
1600
1200
0
45
1600
1200
1
46
1600
1200
2
47
1600
1200
2
48
1600
1200
3
49
1600
1200
4
50
320
240
1
51
320
240
2
52
320
240
2
53
320
240
3
54
320
240
4
55
400
300
1
56
400
300
2
57
400
300
2
58
400
300
3
59
400
300
4
60
512
384
1
61
512
384
2
62
512
384
2
63
512
384
3
64
512
384
4
65
960
720
1
66
960
720
2
67
960
720
2
68
960
720
3
69
960
720
4
70
1920
1440
1
71
1920
1440
2
72
1920
1440
2
Bijlage D. nvugent modi
61
73
1920
1440
3
74
1920
1440
4
75
320
400
1
76
320
400
2
77
320
400
2
78
320
400
3
79
320
400
4
80
640
400
1
81
640
400
2
82
640
400
2
83
640
400
3
84
640
400
4
85
320
480
1
86
320
480
2
87
320
480
2
88
320
480
3
89
320
480
4
90
720
540
1
91
720
540
2
92
720
540
2
93
720
540
3
94
720
540
4
95
848
480
1
96
848
480
2
97
848
480
2
98
848
480
3
99
848
480
4
100
1072
600
1
101
1072
600
2
Bijlage D. nvugent modi
62
102
1072
600
2
103
1072
600
3
104
1072
600
4
105
1280
720
1
106
1280
720
2
107
1280
720
2
108
1280
720
3
109
1280
720
4
110
1360
768
1
111
1360
768
2
112
1360
768
2
113
1360
768
3
114
1360
768
4
115
1800
1012
1
116
1800
1012
2
117
1800
1012
2
118
1800
1012
3
119
1800
1012
4
120
1920
1080
1
121
1920
1080
2
122
1920
1080
2
123
1920
1080
3
124
1920
1080
4
125
2048
1152
1
126
2048
1152
2
127
2048
1152
2
128
2048
1152
3
129
2048
1152
4
130
2048
1536
1
Bijlage D. nvugent modi
63
131
2048
1536
2
132
2048
1536
2
133
2048
1536
3
134
2048
1536
4
135
512
480
1
136
512
480
2
137
512
480
2
138
512
480
3
139
512
480
4
140
400
600
1
141
400
600
2
142
400
600
2
143
400
600
3
144
400
600
4
145
400
300
0
146
320
200
1
147
352
288
4
Bibliografie [1] H. Eeckhaut, H. Devos, B. Schrauwen, M. Christiaens, and D. Stroobandt, ‘A hardware-friendly wavelet entropy codec for scalable video’, in DATE 2005 Designers’ Forum Proceedings (March 2005), 14–19. [2] E.
Fischer,
The
XFree86
modeline
generator
(May
2005).
http://xtiming.sourceforge.net/cgi-bin/xtiming.pl. [3] Haiku,
BeBits
-
haiku
NVIDIA
TNT/GF
driver
(Feb.
2005).
http://www.bebits.com/app/3636. [4] T. Shanley and D. Anderson, PCI system architecture, 4th edition (Addison Wesley, 2004). [5] SIGOPS,
PCI
configuration
header
(Oct.
2002).
http://www.acm.uiuc.edu/sigops/roll_your_own/7.c.0.html. [6] whitebunny,
NVIDIA
drivers,
BIOS
and
utilities
(Mar.
2005).
http://whitebunny.demon.nl/hardware/chipset_nvidia.html. [7] Wikipedia,
Real
mode,
wikipedia,
the
free
encyclopedia
(Apr.
2005).
http://en.wikipedia.org/wiki/Real_mode. [8] M. Ziv-Av, B. Vibber, and I. McDonagh, Linux Super-VGA graphics library (Apr. 2005). http://www.svgalib.org/.
64