Permalänk
Medlem

VGA problem

Jag har en bootloader som precis som dem flesta andra kända laddare består av två steg.
Steg 1 är bootsektorn och den är och måste vara på 512 bytes som laddar steg 2.
Steg 2 är ej begränsad i storlek och innehåller anrop till main funktionen i c kerneln
C kerneln är i protected mode och jag vill att den ska ha funktioner som har
med VGA att göra. Specifikt sätt så vill jag att den ska initiera VGA mode 13 så att
jag kan plotta pixlar vilket jag ej kan göra i textmode.
Pixlarna ska sedan sammarbeta med varandra och målsättningen är att få ett lite simpelt GUI.
I realmode är detta lättare att göra då man får hjälp av Bios.
Man använder sig av avbrottsfunktionen int 0x10 för att switcha till det nya video-läget,
vilket verkar vara ganska enkelt.
Men i pmode blir det svårare då man ej har tillgång till Bios funktioner.
Därför måste man göra sitt eget bibliotek.
Jag har läst att man kan implementera v8086 monitor vilket innebär att man
kan köra både pmode och realmode samtidigt, men tyvärr sägs det vara en komplicerad procedur.
Men jag tror ändå denna metod är lättare än att hålla koll på de mer än 300 olika VGA registrena.
Registrena har olika portadresser och därför behöver man en generell funktion som sköter kommunikationen till dessa.
Till exempel för att uppdatera markören så kan man skicka data till någon av dessa portar(0x3D4 och 0x3D5).
På samma sätt pratar man med portar med övrig hårdvara på moderkortet och perifiera enheter etc.
VGA är som man märker en komplex hårdvara och är den minsta gemensamma nämnaren hos alla grafikkort.
När en dator startas så kör den i VGA tills en enhets specifik drivrutin laddas in.
Så antingen får jag helt enkelt hålla mig till realmode (med sina dåliga specifikationer, 16 bitars cpu mode, dålig
addressering och mer eller mindre 630 kb tillgängligt RAM) eller så får man göra en VGA drivrutin från scratch.
Så frågan är alltså, har ni nån erfarenhet av VGA programmering?

Permalänk
Medlem

Att skriva en VGA drivrutin är egentligen inte så svårt då det finns väldigt mycket information om ämnet. Har själv skrivit en PC emulator som emulerar bland annat VGA på registernivå och det gick ganska snabbt och enkelt att göra. Majoriteten av de runt 300 registerna används för att välja färger ur paletten, bara runt 40-50 är kontrollregister.

Det finns väldigt mycket information på denna sida:
http://www.osdever.net/FreeVGA/vga/vga.htm

Visa signatur

Intel Core i7-3770K | NVIDIA Geforce GTX 980 | 16 GB DDR3 | DELL P2415Q | DELL U2711 | DELL U2410

Permalänk

Är det inte så att du måste göra BIOS anrop tidigt för att plocka ut information från BIOS som du behöver sen i alla fall? I så fall kan du kanske passa på att byta videoläge då?

Det verkar som att det är så Linux löser det, se de sista raderna i main.c filen:

http://git.kernel.org/?p=linux/kernel/git/stable/linux-2.6.36...

Permalänk
Medlem

Du har nog rätt! Tack så mycket !
Jag hittade ochså den här länken:
http://wiki.osdev.org/Drawing_In_Protected_Mode
Där står det precis som du säger att man kan switcha om i bootloadern.

Permalänk
Medlem

Jag gjorde detta precis innan farjump till pmode:

... ;---------------------------; ;set video mode 13h; ;---------------------------; mov ah, 0 mov al, 0x13 int 0x10 ; bios funktion ;---------------------------; ; get video mode ; ;---------------------------; mov ah, 0xf int 0x10 ...

Sedan anrop till main i pmode:

... call _main ...

Jag vill att Bios inställningarna ska sparas så att jag kan plotta grafik exempelvis:

... static void fillrect(unsigned char *vram, unsigned char r, unsigned char g, unsigned char b, unsigned char w, unsigned char h) { unsigned char *where = vram; int i, j; for (i = 0; i < w; i++) { for (j = 0; j < h; j++) { where[j*4] = r; where[j*4 + 1] = g; where[j*4 + 2] = b; } where+=3200; } } int main() { fillrect((unsigned char*)0xA0000, 255,255,0,20,20); return 0; } ...

Jag har testat men det leder bara till triplefault av cpun, dvs rebootar.

Permalänk
Medlem

Jag antar att du har satt upp rätt descriptorer (NULL, Code och Data) och har slagit av interrupts innan du går in i protected mode?
DS måste även laddas med rätt selector för att du ska kunna komma åt minnet.

Jag tror att du har missuppfattat mode 13h, det är 320*200 med 256 färger. Varje pixel är en byte som är en index i paletten.

Följande kod fyller t.ex. hela skärmen med en färg, där 0x10 är en index i paletten.

for(i = 0; i < 64000; i++) {vram[i] = 0x10;}

VGA använder egentligen 4 st plan, men mode 13h "kedjar" ihop planen så att de lägsta två bitarna av addressen helt enkelt väljer plan och resten av addressen blir en index i planet.

Visa signatur

Intel Core i7-3770K | NVIDIA Geforce GTX 980 | 16 GB DDR3 | DELL P2415Q | DELL U2711 | DELL U2410

Permalänk

Förutom de saker som Magnus skrev, vad tänker du ska hända när du gör return i main funktionen? Var kommer koden ta vägen?

Har det inte kraschat innan dess så lär det göra det där. Enklast att göra medan du testar är att gå in i en evighetsloop,

while (true) { }

men det är självklart inte en bra lösning på sikt, utan då sätter du upp avbrottshanterare (interrupts) och använder assemblerinstruktionen HLT eller liknande för att få processorn att temporärt sluta exekvera.

Permalänk
Medlem

Ja ni har rätt, jag har nog missuppfattat mode 13h, därför beslutade jag mig för att lära mig VGA från djupet istället.
Alltså att skriva direkt till dess register. Det finns sex typer av VGA register: Generella, Sequencer, Grafik, CRT kontroller, Attribut och färg register.
Alla har en specifik port adress och ett antal index, där varje index består av 8 bitar.
Till exempel genom att ett ställa bit 6 i grafik registret på adress 03CF som ligger på
index (hex)05 så får man 256 färgs läge.
Eller för att precis som du säger få minnet uppträda linjärt istället för "planar" så ettställer man "chain 4" biten.

Det gäller alltså att hitta alla viktiga bitar som berör mode 13h.