Minne och minneshantering i en PC

A20, HIMEM.SYS, WINA20.386, EMM386, Real/Protected Mode m.m.

RAM-minnet i en PC kan tyckas vara en enda röra med förkortningar som UMB, HMA, XMS, Extended, Expanded, 640k, EMS mfl. Den här texten försöker förklara anledningarna till att det har blivit som det är. Du som läser bör vara någon som pysslat en del med att göra inställningar i CONFIG.SYS och AUTOEXEC.BAT, men (som de allra flesta) inte riktigt vet vad du ska svara när någon frågar dig varför alla dessa inställningar egentligen behövs.

Mycket av det som står i texten hör hemma ganska djupt inne i datorn men är ändå viktigt (eller åtminstone intressant) att känna till eftersom det bestämmer gränserna för PC-datorn som helhet.

PC-historia.

Den första PC'n från IBM kallades just PC. Den använde CPU'n (processorn) 8088 med 4.7 MHz klockfrekvens och hade normalt 256kB minne. Ganska snart kom uppföljaren XT, också den med 8088- processor på 4.7 MHz. Själva datorlådorna till PC och XT är väldigt lika, sånär som på PC'ns färre kortplatser och uttag för kassettbandspelare.

Efter XT kom AT byggd kring 286-processorn, först 6MHz och sedan 8MHz. Kontakterna för utbyggnadskort förlängdes till 16 bitar. Det var först med AT som det blev riktigt vanligt att ha hårddisk. Några år senare kom IBM med sin PS/2-serie. PS/2 fanns med antingen 8088, 286 eller 386-processor och hade bla en mindre låda, 3.5"-diskettstation samt att de dyrare modellerna fick en helt ny typ av anslutning för utbyggnadskort, sk MicroChannel-bus.

Real Mode, arvet från 8088-processorn.

8088-processorn, som alltså satt i PC och XT, har 20 adresslinjer numrerade A0-A19, och kan därför enbart adressera 2**20 = 1024kB minne. Det innebär att om man ställer instruktionsräknaren på den högsta adressen (som är 1024kB-1 eftersom man börjar räkna på adress 0) och lägger till 1 så slår räkaren över till adress 0 precis som kilometer- räknaren på en bil. Alla program som har skrivits till 8088-processorn räknar med att processorn ska uppföra sig på det här sättet. Till dessa program hör MS-DOS självt och alla de program som kan köras under MS-DOS och som inte är specialskrivna för någon annan processor (dvs 2/3/486).

Efterföljaren till 8088, Intels 286-processor, har hela 24 adresslinjer och kan därmed adressera 16MB. På 286 slår därför inte adressräkaren om till 0 när den passerar 1024kB, utan fortsätter vidare upp till 16MB. Program skrivna till 8088, inklusive DOS självt, skulle därför behöva skrivas om för att passa 286. Men Intel gjorde så att 286 kan köras i två olika lägen; Protected Mode där hela minnet är åtkomligt och Real Mode där 286 uppför sig nästan som en 8088.

Men bara nästan. Istället för att börja om på adress 0 när man passerar 1024kB så fortsätter adressräknaren hos 286 (och även 3/486) i Real Mode ända upp till 1088kB innan den slår om. Detta utrymme mellan 1024kB och 1088kB har kommit att kallas High Memory Area, HMA.

Utrymmet 1024kB-1088kB, HMA.

Att HMA blev till beror inte på någon felkonstruktion hos 286'an utan istället på att när man adresserar minne hos en 8088-processor så delas adressen upp i segment och offset. Segmentet är ett 16-bitars ord och likaså offsetet. När processorn ska göra om segment:offset adressen till en riktig minnesadress tar den segmentet*16 och lägger sedan till offsetet. Den högsta adress som då kan adresseras med segment:offset är FFFF:FFFF, vilket blir 10FFEFh (hexadecimalt), som är detsamma som 1024kB+64kB. För att komma till adressen 10FFEFh går det åt 21 adresslinjer. En 8088 hade bara 20 adresslinjer och slog därför runt och började på adress 0 igen. Alltså: 20 ettor = FFFFFh = F000:FFFF = 1024kB.

Pga detta fick IBM problem när de skulle kontstruera sin AT kring 286- processorn. AT måste ju tvunget kunna köra program skrivna till PC och XT. Därför la IBM till den sk A20-gaten, en elektronisk switch som vid uppstart av datorn öppnar sig och hindrar adresslinje nr 20 från att komma fram till minnet. Det gör att när processorn adresserar HMA- delen av minnet så når inte A20 fram utan det blir istället precis som på 8088.

A20-gaten kontrolleras via keyboard-controllern 8042. Vill man komma åt HMA-minnet så måste därför först keyboard-controllern anropas för att öppna A20-gaten.

(8042 är en liten dator i sig självt, med CPU, RAM och ROM, allt inbyggt i en 40-pinnars DIP-kapsel. 8042 kan programmeras under körning, t.ex för att bortse från Ctrl+Alt+Del.)

I och med att A20-gaten går att styra så kan HMA-minnet utnyttjas för datalagring, detta medan processorn fortfarande arbetar i Real Mode.

I DOS 5 är det drivrutinen HIMEM.SYS som används för att kontrollera åtkomsten till HMA-minnet. Anger man DOS=HIGH i CONFIG.SYS så är det DOS (och enbart DOS) som kommer att använda HMA-minnet för att där lägga vissa delar av sina systemfiler.

Men varje gång något i HMA-minnet ska användas så måste keyboard- controllern anropas för att öppna A20-gaten, och det kan bli väldigt ofta. Om man hela tiden bombarderar keyboardcontrollern med A20-växlingar så får den inte tid över att sköta sin egentliga uppgift, dvs tangentbordet. Det vanligaste symptomen är problem med Shift-tangenten eller att det verkar som man håller nere en tangent fastän man inte gör det.

Utrymmet 640kB-1024kB.

Om nu 8088-processorn kan adressera 1024kB, hur kommer det sig då att man bara kan ha 640kB minne?

De flesta tror att det går en skarp gräns vid 640kB, men detta är inte riktigt sant. DOS har ingen inbyggd gräns vid 640kB utan kan faktiskt använda så mycket oavbrutet minne som finns tillgängligt. Vid just minnesadressen 640kB (segmentadress A000h) så startar dock det minnesområde som är reserverat för bildskärmskort och andra tillbehör, och därför placeras normalt inget vanligt RAM-minne där.

Men alla bildskärmskort startar inte vid A000h. MDA-kortet (enbart monokrom text) startar inte förrän vid B000h och CGA-kortet (färg och begränsad grafik) börjar ända uppe vid B800h. Har man något av dessa kort och installerar minneskretsar från A000h och upp till dessa adresser så kommer DOS att kunna använda detta minne och man kan plötsligt ha kanske 700kB ledigt minne när man kollar detta med tex MEM. Normala DOS-program kommer att fungera utan problem. Kunde man dessutom flytta upp bildskärmskortet ännu en bit i minnet så skulle ännu mera utrymme bli ledigt osv. Det kan man nu inte göra eftersom väldigt många program snabbar upp sina skärmutskrifter genom att skriva direkt in i bildskärmskortets RAM-minne, som därför måste finnas på en bestämd plats.

Ett annat problem är att man på något sätt måste installera RAM- minneskapslar på dessa adresser. Det finns nästan inga extraminneskort som klarar av detta.

Man kan alltså inte direkt öka ut sina 640kB men där finns ju trots allt lediga luckor mellan 640kB och 1024kB som borde kunna användas.

Därför uppfann Lotus/Intel/Microsoft det så kallade LIM-EMS-minnet (Extended Memory Specification). Här låter man ett speciellt minneskontrollkort använda ett visst ledigt utrymme i området 640kB-1024kB (som ju processorn kan adressera i Real Mode) och låta detta område vara ett 'fönster' mot ett helt separat minne som ligger på EMS-kortet. EMS-minneskort var vanliga innan 386- datorerna hade slagit igenom och många program från den tiden kan använda EMS-minne, tex WordPerfect 5.1. Till varje fabrikat och modell av EMS-kort följer en drivrutin, kallad EMM.SYS, EMS.SYS eller liknande. Utan den drivrutinen kan kortet inte användas.

Protected Mode.

Men om vad händer med resten av minnet, dvs det som finns över 1MB+HMA. Det är i och för sig bara program som växlar processorn till Protected Mode som kommer åt detta minne, men även dessa program behöver en minneshanterare så att de inte krockar med varann. HIMEM.SYS sköter detta.

Minnet som ligger på adresser över 1MB och som kontrolleras av HIMEM.SYS kallas XMS-minne, efter regelverket för hur det ska anropas; eXtended Memory Specification. Det är alltså bara program som själva växlar till Protected Mode som kan använda sig av ev minne ovanför 1024kB+64kB. Till exempel Windows.

I en 286-processor så finns det ett kommando för att växla från Real till Protected Mode men inget kommando för att växla från Protected tillbaka till Real. Vitsen med Protected Mode är att processorn ska skydda mot felaktiga adresseringar och skulle man kunna växla till det oskyddade Real Mode så vore inte Protected Mode så skyddat längre. Så tyckte i alla fall Intel när man designade 286-processorn.

Men hur gör då program som ändå utnyttjar Protected Mode på en 286'a ? Jo, IBM har lagt in en nödlösning i självtesten som körs när datorn startas om. Om en viss databit är satt i det batteribackupade CMOS-minnet så körs inte självtesten, utan datorn kör igång direkt. Det man gör för att växla från Protected Mode till Real Mode på en 286'a är alltså att sätta den här databiten i SETUP-CMOS-minnet och sedan reset'ar hela processorn. Det är varken snyggt eller särskilt snabbt. I en 3- och 486-processor däremot så finns en instruktion för att växla från Protected till Real Mode.

Minnesutbyggnad på 386/486

En 3/486'a har dock ett läge på processorn som 286'an saknar, det sk Virtual 8086 Mode, VM8086. Detta läge är ett slags utökat Real Mode. Skillnaden mot det vanliga Real Mode är att ett program även kan adressera minne som ligger utanför 1MB-gränsen. Inte hela minnet dock, utan enbart de delar som bestämdes vara tillåtna innan VM8086-läget startades. Dessutom kan flera VM8086 finnas samtidigt i minnet.

VM8086-läget används främst av programmet EMM386.EXE som utnyttjar det på två sätt. Dels kan 'luckorna' i området 640kB-1024kB användas för att emulera EMS-minne utan att ett utomstående extraminneskort behövs. Dels kan 'luckorna' fyllas på med RAM-minne, då kommer dessa luckor att kallas UMB, Upper Memory Blocks. Om man anger DOS=UMB i CONFIG.SYS så använder DOS dessa UMB för att ladda drivrutiner genom 'DeviceHigh=' i CONFIG.SYS och 'LoadHigh' i AUTOEXEC.BAT.

Observera att när EMM386.EXE används så ställs alltid processorn i VM8086-Mode. Avancerade program som är skrivna innan 386'an var uppfunnen kommer att tro att de befinner sig i Real Mode. Försöker dessa program växla mellan (det de tror är) Real och Protected Mode så kommer datorn att hänga sig, ibland med ett felmeddelande från EMM386.EXE. Ett exempel är MatLab (DOS-versionen).

Om ett UMB läggs direkt efter 640k så kommer det minnet att höra till det vanliga 'Base'-memory, dvs effekten blir att man flyttar upp 640kB- gränsen en bit, man behöver alltså inte använda DOS=umb. Ex: EMM386.EXE med tillägget I=A000-AFFF. En annan lösning är QEMM386's VIDRAM som kan ta oanvänt minne på grafikkortet (EGA/VGA) och lägga ut det som vanligt RAM-minne.

I DOS 5 är användningen av UMB-blocken lite si och så, det går bara att använda för vissa drivrutiner. Dessutom utnyttjas alltid blocken i ordningsföljden: största blocket först och minsta sist, därför bör man ladda drivrutinerna i den ordningen, då är chansen störst att minnet kommer att utnyttjas optimalt. I DOS 6 kan programmet MEMMAKER hjälpa till med placeringen av drivrutiner. Andra tillverkare har gjort liknande och bättre lösningar som skapar och optimerar UMB-minne. Till exempel QEMM från Quarterdeck och 386MAX från Qualitas.

Sammanfattning

I en normal PC med 286 processor så är det bara de första 640kB samt det knappt 64kB stora HMA som kan utnyttjas (så länge processorn står i Real Mode) eftersom det är den enda plats där det finns vanliga RAM-minneskretsar installerade och som processorn kan adressera. Utrymmet mellan 640kB och 1024kB kan visserligen användas, men isåfall måste man skaffa ett EMS-minneskort.

En 286'a kan på ett omständigt sätt växla mellan Real och Protected Mode för att på så sätt tillåta att DOS-program använder minne ovanför 1MB+64kB. 3/486 har däremot en instruktion för att växla från Protected till Real Mode och kan dessutom tack vare VM8086-läget köra Real Mode- program utan besvär.

HIMEM.SYS administrerar allt minne över 1MB och kallar det XMS-minne. EMM386.EXE kan tillhandahålla UMB och EMS i utrymmet 640-1024kB.

Om en ny DOS-version ska kunna utnyttja processorkraften bättre genom att köras i Protected Mode, och dessutom kunna köra alla de miljoner DOS-program som redan finns skrivna för Real Mode så är man helt enkelt tvungen att överge 8088, 8086 och 80286-processorerna. Microsoft kallar detta för Windows NT/95, IBM kallar det för OS/2.


Mindre viktigt om minneshantering.

HIMEM.SYS och Windows 3.0

Windows 3.0 kom före DOS 5.0 och därför vet Windows 3.0 inget om att DOS med hjälp av HIMEM.SYS växlar fram och tillbaka med A20- gaten för att använda HMA-minnet. Det går bra så länge Windows körs som ett vanligt program, dvs i Windows-Real- eller Windows-Standard- Mode. I Windows-Enhanced-Mode däremot, när Windows skapar virutella 8086-maskiner för att kunna köra flera DOS-program samtidigt, så får man problem. Virtuella maskiner skapas av WIN386.EXE och är helt enkelt en kopia av den 1:a megabyten minne som det såg ut innan Windows startades, med alla program och drivrutiner (tex mus) som fanns där. I dessa 1MB ligger alltså också HIMEM som genom att spärra och öppna A20-gaten kommer att förstöra minneadresseringen för resten av systemet. Än värre blir det om man skapar flera sådana virtuella 8086- maskiner (det går faktiskt) med var sin HIMEM.SYS som samtidigt försöker göra sitt jobb. För att lösa problemet kom samtidigt med DOS 5.0 drivern WINA20.386 som laddas i CONFIG.SYS och rättar till detta. I Windows 3.1 behövs inte WINA20.386 längre. Tyvärr tar installlationsprogrammet till Windows 3.1 inte bort WINA20.386 från CONFIG.SYS filen. WINA20.386 behövs alltså enbart då man har använt HIMEM.SYS för att ladda DOS i HMA och sedan startar Windows 3.0 i Enhanced Mode.

DOS Extenders, VCPI, DPMI.

Om man vill skriva ett eget DOS-program att köras i Protected mode så använder man lämpligen en sk DOS Extender när programmet skrivs. En sådan innehåller alla nödvändiga rutiner för att växla mellan Real/VM8086 och Protected mode så att DOS- och BIOS-anrop hanteras på effektivaste sätt. Tidiga DOS Extenders fungerade inte ihop med 386- minneshanterare eftersom bägge två försökte ta kontrollen över hela minnet. PharLap Software och Quarterdeck kom därför överens om standarden VCPI (Virtual Control Program Interface) som är ett sätt för 386-minneshanterare och DOS Extenders att kommunicera och samarbeta. Nya versioner av EMM386.EXE, QEMM386 och 386MAX stödjer VCPI fullt ut.

Efterföljaren till VCPI heter DPMI (DOS Protected Mode Interface). DPMI definierar en uppsättning DOS- och BIOS-anrop som kan göras i Protected Mode varav vissa (Protected Mode minnesalokering) inte finns i Real Mode. Dessutom definieras metoder att anropa Real Mode device drivers. Windows stödjer DPMI.

Segment:offset-adressering. COM/EXE-program.

Idén med segment:offset adressering är att programmet ska kunna ligga var som helst i minnet när det körs. Programmet gör enbart offset- adresseringar och processorn lägger till segment-adressen. Då programmet inte innehåller några absoluta adresseringar så kan det ligga var som helst (dvs i vilket segment som helst) i minnet och köras där det ligger. Nackdelen är att ett program inte utan svårighet kan göras större än att det ryms i ett segment och eftersom ett segment i Real Mode bara är FFFFh, dvs 64kB, så blir det inte särskilt stora program. I DOS har ett sådant här program ändelsen .COM och är en exakt minnesdump av ett segment. Inte hela segmentet naturligtvis, utan bara så stor del som används. Ett .COM-program kan därför aldrig vara större än 64kB eftersom det då inte ryms att laddas in i ett segment, men när programmet väl är igång kan det mycket väl använda minne (=allokera) som ligger utanför segmentet.

Om ett program är så stort att det inte ryms i ett segment så måste en startrutin läggas till som delar upp programmet i delar om max 64kB och placerar dessa i olika segment samt ser till att de olika delarna anropar varandra på ett riktigt sätt. Ett program med en sådan startrutin har ändelsen .EXE och kan vara i princip hur stort som helst. Pga just startrutinen och den något omständigare minneshanteringen så är ett .EXE-program större och startar inte lika snabbt som ett .COM-program. Skilladen är visserligen marginell, men ändå.

Minnesadressering i Real och Protected Mode.

Skillnaden mellan adresseringen i Real och Protected Mode är lite mera komplicerad än att bara säga att Protected Mode har flera adresser. I Protected Mode används 13 av segmentadressens bitar som ett index till en tabell med sk descriptors. Varje descriptor definierar en basadress och en längd. På en 286 är basadressen 24 bitar och längden 16 bitar, alltså kan segmentet ligga var som helst i minnet (16MB) men vara max 64kB stort. På 386 och 486 anges bägge värdena med 32 bitar. Adressen kan då ligga var som helst inom 4GB och vara max 4GB stor. Normalt finns flera descriptor-tabeller, en som används för själva operativsystemet (GDT, Global Descriptor Table) och flera lite mindre tabeller (LDT, Local Descriptor Tables). Segment kan dessutom skyddas mot skrivning och ges olika skyddsnivåer, dvs ett program i en lägre nivå kan inte skriva i ett segment med en högre skyddsnivå. Lämpligen ges operativsystemet den högsta nivån. Om ett program försöker adressera minne utanför den tillåtna längden eller skyddsnivån fås ett sk 'Protection Fault'.

Den icke-dokumenterade LOADALL och en ännu hemligare metod.

Det finns dock en icke dokumenterad CPU-instruktion kallad LOADALL som tillåter ett Real Mode program att accessa hela minnet och inte enbart den del som normalt tillåts i Real Mode.

I Protected mode finns basadress och längd i en indextabell någonstans i minnet. För att slippa att hela tiden läsa från den tabellen så sparas aktuella värden i sk 'descriptor caches'. Det finns en sådan cache för varje segmentregister i processorn. LOADALL laddar alla CPU-register och descriptor caches från en speciell tabell på absoluta RealMode- adressen 800h. Tabellformatet och anropet skiljer sig lite mellan 286 och 386. På 286 är op-coden 0Fh 05h, på 3/486 0Fh 07h. LOADALL finns inte med i Intel's manualer och stöds inte av MASM (assembler). LOADALL saknas på 486. Pga att 286 LOADALL används av så många program så emuleras den dock av alla 386 och 486 BIOS.

Den ännu hemligare metoden går ut på att det går att ändra begränsningen för hur stort ett segment får vara i Real Mode. Det ska vara 64kB men detta kan ändras, lämpligen till 4GB. Genom att sedan använda 32 bitars register för offset-adressen så har man access till hela minnet.

Tips vid A20-problem:

A20-problem visar sig vanligen genom att tangentbordet beter sig egendomligt. Den första åtgärden är då att byta EMM386.EXE och KEYB.COM/KEYBOARD.SYS till den nyaste version man kan komma över. Hjälper inte det kan man testa följande:

- DOS-versionen av WordPerfect är mer känslig än andra program, eftersom den själv programmerar om keyboard-controllern. Om man startar WordPerfect med parametern /nk så undviker man detta.

- Om man har AMI BIOS så kan det i SETUP-programmet finnas ett "FAST A20"-val. Det ska man i så fall aktivera. I botten av AMI's SETUP- skärm så står dessutom något som ser ut som ett serienummer följt av "-Kx", där x:et är keyboardcontrollerns versionsnummer. Det finns många olika t.ex -K8, 9, A, D och F. Vill man undvika problem ska man se till att ha minst version KF. Det är tyvärr inte säkert att en nyinköpt maskin alltid har en ny keyboardcontroller. Man kan naturligtvis även skruva isär datorn för att direkt på IC-kretsen kontrollera versionsnumret.

- Inte alla PC-datorer använder just keyboardcontrollern för att hantera A20-gaten. IBM PS/2 använder en helt annan teknik, liksom AT&T 6300+, Philips datorer, Acer 1100 och några fler. Därför har HIMEM.SYS en parameter för att ange maskintyp: HIMEM.SYS /m:n , där n är ett nummer från 1 till 15. Om du får problem med HIMEM, prova då igenom alla olika maskintyper (1-15), men se till att ha en boot-diskett inom räckhåll.

Användning av EMM386:

Använd inte EMM386 om du inte måste. EMM386 ställer processorn i VM8086 Mode och det gör att en del program fungerar sämre och vissa inte alls. Om datorn 'hänger sig' mer än normalt så beror det väldigt ofta på EMM386. EMM386 använder minnesadresser den inte säkert vet är lediga, interrupt som den inte heller vet är lediga och dessutom ställer den processorn i det lite udda läget VM8086. Startar du sedan Windows, som ju växlar till Protected Mode, så är röran total. Tillfällen då EMM386 i praktiken ändå måste användas är tex för drivrutiner till nätverk, CD-ROM mm. Windows går dock inte ett dugg fortare om man har 610kB ledigt istället för 560kB när Windows startas.

Några förkortningar:

RAM Read And write Memory. Kallas ibland Random Access Memory, men det gäller ju faktiskt även ROM. Den dynamiska varianten används för vanligt minne, det statiska (dyrare och snabbare) används på tex bildskärmskort.
ROM ReadOnly Memory.
LIM Lotus/Intel/Microsoft. Kom överens om EMS. Tillsammans med AST så småningom även om XMS.
EMS Expanded Memory specification. Två vanliga versioner är 3.2 och 4.0. Bägge är ok. Kräver sin egen drivrutin.
EEMS Enhanced EMS. Slog aldrig igenom, men EEMS-kort kan iallafall alltid användas som enbart EMS.
EMM Expanded Memory Manager. Drivrutinen till EMS/EEMS-kortet. Unik till varje enskild tillverkare och kortmodell.
XMS eXtended memory specification. Konsten att anropa HIMEM.SYS.
UMB Upper Memory Block(s). Lediga plater i området 640kB - 1024kB.
HMA High Memory Area. 64kB som finns ovanför 1024kB.
CPU Central Processing Unit. Själva processorn, men ibland även som benämning för hela datorlådan.

EMS = Expanded = Utbyggt
XMS = Extended = Utökat


Informationen är bla hämtad från tidningarna Byte (årgång 1989 rekommenderas), PC Magazine, Personal Computer World, Svenska PC World, Mikrodatorn, Microsofts manualer till DOS 5, Windows 3.0 och Windows 3.1 samt HELP-kommandot i DOS 6. Det kan finnas sakfel i texten men eftersom jag inte resonerat ihop någonting själv så måste felet ha funnits redan i tidningsartikeln/boken.
Tillbaka
Tomas Andersson, d94-tan@nada.kth.se
Kungliga Tekniska Högskolan, Stockholm
1993-04-16, senast ändrat 1996-02-24

Copyright Tomas Andersson 1996.