12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602 |
- MODULE Machine; (** AUTHOR "Timothée Martiel"; PURPOSE "Machine abstraction module for ARM"; *)
- (**
- * Machine abstraction:
- * - processor management: caches, FPU
- * - interrupts and exceptions
- * - virtual memory management
- *)
- IMPORT SYSTEM, Initializer, Trace, Platform, TraceDevice, BootConfig, PrivateWatchdog;
- CONST
- Version = "A2 on ARM, revision 4677 (15.10.2017)";
- DefaultObjectFileExtension* = ".Gof";
- (* Interrupts Dummy Test *)
- DummyTest = FALSE;
-
- (*
- Used for compatibility with WMPerfMon
- *)
- MMX* = 23; (** bits in features variable *)
- (* Lock levels *)
- TraceOutput* = 0;
- Memory* = 1;
- Heaps* = 2;
- Interrupts* = 3 ;
- Modules* = 4;
- Objects* = 5;
- Processors* = 6;
- KernelLog* = 7;
- MaxLock = 8;
- (* Unit prefixes *)
- k = 1024;
- M = k * k;
- G = M * k;
- LogM = 20; (* log2(M) *)
- (*LogK = 10; (* log2(K) *)*)
- (* CPU number *)
- MaxCPU* = 32(*BootConfig.CpuNb*);
- (* If TRUE, enables some assertions in the code *)
- StrongChecks = TRUE;
- (* Page size, in bytes *)
- PS = 4 * k;
- PSlog2 = 12; (* ASH(1, PSlog2) = PS *)
- PTSize = 400H; (* size of a coarse page table *)
- (*PTEntries = 100H; (* 32bit entries per page table *)*)
- (* Absolute maximal process stack numbers *)
- MaxStackNb = 1024;
- (* Hard limit on cache reference size *)
- MaxCacheRefSize = M;
- (* Interrupt Vector base. Valid only after MMU is enabled *)
- InterruptVector = 0FFFF0000H;
- (* Interrupts *)
- MinIRQ* = 0;
- MaxIRQ* = 255;
- IRQ0* = MinIRQ; (* Alias *)
- (** ID of the global timer IRQ *)
- TimerIRQ* = 27;
- PrivateTimerIRQ* = 29;
- MaxIRQHandlers = 16;
- (* Exceptions codes. DO NOT CHANGE: they represent interrupt vector offsets *)
- Reset * = 20H; (** Reset *)
- Undef * = 24H; (** Undefined Exception *)
- Swi * = 28H; (** Software Interrupt *)
- Prefetch * = 2CH; (** Prefetch Abort *)
- Data * = 30H; (** Data Abort *)
- Irq * = 38H; (** Interrupt Request *)
- Fiq * = 3CH; (** Fast Interrupt *)
- (* Initial Stack size for user stacks *)
- (*InitUserStackSize = PS;*)
- HeapMin = 50; (* "minimum" heap size as percentage of total memory size (used for heap expansion in scope of GC ) *)
- HeapMax = 95; (* "maximum" heap size as percentage of total memory size (used for heap expansion in scope of GC) *)
- ExpandRate = 1; (* always extend heap with at least this percentage of total memory size *)
- Threshold = 10; (* periodic GC initiated when this percentage of total memory size bytes has "passed through" NewBlock *)
- (* Stack parameters *)
- InitStackSize = PS;
- StackGuardSize = PS;
- (* access permissions *)
- SrwUrw = 3;
- FullAccess = (*SrwUrw*400H+SrwUrw*100H+SrwUrw*40H+*)SrwUrw*10H; (* for small pages only *)
- LastStackPage = SrwUrw*400H+SrwUrw*100H+SrwUrw*40H; (* for small pages only *)
- (* first level page table types *)
- flCoarse = 1;
- flSection = 2;
- (* Second Level *)
- slFault = 0;
- slSmall = 2;
- (* cachable/bufferable mapping options *)
- cb = 0;
- C = 8;
- B = 4;
- CB = C + B + 440H;
- (* Inner and Outer Cacheable, Write-Through, no Write Allocate *)
- Cacheable = 100CH; (* here inner cacheable, write-back, write-allocate *)
- (* Shareable *)
- Shareable = 10000H;
- (* NIL *)
- NilAdr* = -1;
- (* Control Register Flags *)
- DCache = 2;
- ICache = 12;
- Second* = 1000; (* frequency of ticks increments in Hz *)
- Preemption* = 31; (** flag for BreakAll() *)
- (* TEMP. Temporary implementation to get Objects to compile *)
- SSESupport* = FALSE;
- SSE2Support* = FALSE;
- KernelLevel * = 1;
- UserLevel* = 1;
- (*CS* = 1;*)
- VMBit* = 2;
- (** Period at which the CPU timer interrupts, in micro seconds *)
- TimerPeriod* = 1000;
- (** Last reboot info *)
- RebootPowerOn * = 0;
- RebootHardReset * = 1;
- RebootSoftReset * = 2;
- RebootSystemWatchdog * = 3;
- RebootWatchdogCPU0 * = 4;
- RebootWatchdogCPU1 * = 5;
- RebootDebug * = 6;
- (** Needed, but not used yet by Reals.Mod *)
- fcr * = {};
- IsCooperative * = FALSE;
- TYPE
- (** processor state *)
- State* = RECORD
- R*: ARRAY 12 OF ADDRESS; (** registers 0-11 *)
- BP*, SP*, LR*, PC*: ADDRESS; (** special registers *)
- PSR*: ADDRESS; (** processor state register *)
- INT*: ADDRESS; (** IRQ number *)
- END;
- (** NEON Coprocessor state *)
- NEONState* = RECORD
- D*: ARRAY 32 OF HUGEINT; (* 32 64-bits registers *)
- FPSCR*: ADDRESS;
- FPEXC*: ADDRESS;
- END;
- (** exception state *)
- ExceptionState* = RECORD
- halt*: LONGINT; (** halt code *)
- instn*: LONGINT; (** undefined instruction *)
- pf*: ADDRESS; (** page fault address *)
- status*: LONGINT; (** page fault status *)
- locks*: SET; (** active locks *)
- END;
- (** Interrupt Hanlder *)
- Handler* = PROCEDURE {DELEGATE} (VAR state: State);
- EventHandler = PROCEDURE (id: LONGINT; CONST state: State);
- (** Spinlock *)
- Lock = RECORD
- locked: BOOLEAN;
- (* Padding to the granularity of exclusive monitor: 8 words on Cortex-A9 *)
- pad: ARRAY 31 OF CHAR;
- END;
- (** Processor status *)
- Proc* = RECORD
- locksHeld*: SET;
- preemptCount*: LONGINT;
- (*nestCount-: LONGINT; (** total locks held by a processor *)*)
- intStatus*, mmu*: BOOLEAN; (* muu: if the MMU is enabled for this processor *)
- END;
- (** Virtual/physical address pair *)
- AddressTuple = RECORD virtual, physical: ADDRESS; END;
- (** Stack descriptor:
- low: lowest possible stack address
- adr: current lowest allocated address
- high: highest address
- *)
- Stack* = RECORD
- low: ADDRESS;
- adr*: ADDRESS;
- high*: ADDRESS;
- END;
- (** Heap memory block *)
- MemoryBlock* = POINTER TO MemoryBlockDesc;
- MemoryBlockDesc* = RECORD
- next- {UNTRACED}: MemoryBlock;
- startAdr-: ADDRESS; (* unused field for I386 *)
- size-: SIZE; (* unused field for I386 *)
- beginBlockAdr-, endBlockAdr-: ADDRESS
- END;
- Address32* = ADDRESS;
- Range* = RECORD
- adr*: ADDRESS; size*: SIZE;
- END;
- CacheRefs = POINTER {UNSAFE,UNTRACED} TO ARRAY MaxCacheRefSize OF SHORTINT;
- VAR
- version -: ARRAY 64 OF CHAR;
-
- features-: SET; (** processor features *)
- sp, fp: ADDRESS;
- (** Interrupt Mask *)
- IRQMask: SET;
- (** IRQ Handlers. IRQ can have multiple handlers. Dispatching to those is done in IRQGlue and IRQCaller. *)
- irqHandler: ARRAY MaxIRQ + 1, MaxIRQHandlers OF Handler;
- (* Exception handlers. Called by *Glue. *)
- undefHandler, swiHandler, prefetchHandler, dataHandler, fiqHandler: Handler;
- stateTag: LONGINT;
- dummyIRQHandler: ARRAY MaxIRQ+1 OF RECORD h: Handler; END;
- (** Low level locks *)
- lock: ARRAY MaxLock OF Lock;
- (** Processors status:
- - locksHeld: set of low-level locks held by the processor
- - preemptCount: preemption counter
- *)
- proc-: ARRAY MaxCPU OF Proc;
- (** IDs of all successfully started processors. *)
- allProcessors-: SET;
- heapHigh, heapLow, stackHigh, stackLow: AddressTuple;
- (* Memory *)
- pageTable: RECORD virtual, memory: ADDRESS END; (* contains the virtual & memory address of the first level page table *)
- memory: RECORD size, free: SIZE; END;
- stackPT: ADDRESS;
- (* Free stack bitmap: each set element is set to indicate free stack *)
- freeStack: ARRAY (MaxStackNb + 31) DIV 32 OF SET;
- freeStackIndex: SIZE;
- (* Address of the highest free page *)
- freePage: ADDRESS;
- (* Memory blocks -- For the heap *)
- memBlockHead-{UNTRACED}, memBlockTail-{UNTRACED}: MemoryBlock;
- initialMemBlock: MemoryBlockDesc;
- dCacheBase: ADDRESS;
- (** GC parameters *)
- expandMin, heapMinKB, heapMaxKB : SIZE;
- gcThreshold: SIZE;
- (** For preemptive scheduling. *)
- Timeslice*: Handler;
- timer: EventHandler;
- (** timer ticks. Written to by GetTicks. Read-only *)
- ticks*: LONGINT;
- eventCount, eventMax: LONGINT;
- event: Handler;
- (** Number of processor used. *)
- numProcessors*: LONGINT;
- numberOfProcessors: LONGINT;
- (** Scheduling start procedure for non-booting processors. *)
- start*: PROCEDURE;
- (** Upcall to get current stack -- used for stack extension *)
- getStack*: PROCEDURE (VAR stack: Stack);
- (* Memory Layout *)
- (* The system area contains:
- * - the interrupt vector, which will be mapped high
- * - interrupt stacks
- * - the page table
- * Except for the first 4kB page, it is mapped 1:1.
- *)
- memSysLowStart,
- memSysLowStop,
- (* The heap area contains:
- * - the static kernel image
- * - the heap
- * The heap is mapped 1:1 with 1MB pages.
- *)
- memHeapStart,
- memHeapStop,
- (* Process Stacks are allocated in this area.
- * Stacks are mapped with 4kB pages. They take at least 2 pages:
- * - 1 for the actual stack
- * - 1 kept unmapped as the stack guard.
- * Stacks are mapped 1:1.
- * The stack size can be tuned to allow the system to run more processes.
- *)
- memStackStart,
- memStackStop,
- (* Boot configuration is placed in memory. It takes 4 kB at most *)
- memConfigStart,
- memConfigStop,
- (* IO registers and peripheral control are located in this region. Mapped 1:1 with 1MB and 4kB
- * pages, as necessary. Mapped as Device memory. *)
- memIOStart,
- memIOStop,
- (* High system memory region. Within the last MB, contains: interrupt vector and reference counts
- * for caching. *)
- memSysHighStart,
- memSysHighStop,
- (* System Parameters *)
- (* Interrupt stacks. 8kB of virtual space (4kB for stack, 4kB for guard) and 4 stacks per processor. *)
- sysIntStackStart,
- sysIntStackStop,
- (* First Level Page Table: size of 16 * k to map 4GB with 1MB pages. *)
- sysFirstLvlPtStart,
- sysFirstLvlPtStop,
- (*
- * Second Level Page Table:
- * - 2 * 256 entries for the system area (first and last MB of VMem)
- * - 256 entries for each MB of virtual stack space
- * 256 entries take 1kB memory space.
- *)
- sysSecondLvlPtStart,
- sysSecondLvlPtStop,
- (*
- * Interrupt Vector. Located at 0FFFFFFF0H
- *)
- sysVectorStart,
- sysVectorStop,
- sysCacheRefStart,
- sysCacheRefStop,
- (*
- * Number of ref counters: 1 per 1st level heap page, 1 per 2nd level stack page.
- * This memory region is organized as follows: the first part [0 .. SysCacheStackOfs) is used for heap pages,
- * the second part, [SysCacheStackOfs .. SysCacheRefSize) is used for stack pages.
- *)
- sysCacheRefSize,
- (* Offset in the ref count table for stack pages. *)
- sysCacheStackOfs: ADDRESS;
- (* Process stack system *)
- maxUserStackSize: SIZE;
- maxUserStacks: LONGINT;
- (* TRUE iff caching should be globally enabled *)
- enableCaching: BOOLEAN;
- (* UART used for kernel output *)
- kernelOutputUart -: LONGINT;
- (** Interrupt tracing option *)
- traceInterrupts: BOOLEAN;
- (** Trace option for CPU state *)
- traceCpus: BOOLEAN;
- (** Use private watchdog to check scheduling timers? *)
- enableWatchdog: BOOLEAN;
- (** Array of reference counts for page caching *)
- cacheRefs -: CacheRefs;
- (** Reason for last reboot *)
- lastReboot -: LONGINT;
- (* ===== Processor Management ===== *)
- (* Current processor's ID, between 0 and MaxProc - 1 *)
- PROCEDURE - ID*(): LONGINT;
- CODE
- MRC p15, 0, R0, C0, C0, 5
- AND R0, R0, #3H; Get the last 2 bits of R0
- END ID;
- (** Enables current processor's L1 caches *)
- PROCEDURE EnableL1Cache;
- CODE
- ; Enable Cache and TLB maintenance broadcast
- mrc p15, 0, r0, c1, c0, 1
- orr r0, r0, #1H
- mcr p15, 0, r0, c1, c0, 1
- isb
- ; Enable Caching in SCTLR
- mrc p15, 0, r0, c1, c0, 0
- orr r0, r0, #4H
- mcr p15, 0, r0, c1, c0, 0
- isb
- END EnableL1Cache;
- (** Enable L2 cache, prefetching and other speculative execution support *)
- PROCEDURE EnableL2Cache;
- CODE
- ldr r0,[pc, #L2CCCrtl-$-8] ; Load L2CC base address base + control register
- mov r1, #0 ; force the disable bit
- str r1, [r0,#0] ; disable the L2 Caches
- ldr r0, [pc, #L2CCAuxCtrl-$-8] ; Load L2CC base address base + Aux control register
- ldr r1,[r0,#0] ; read the register
- ldr r2, [pc, #L2CCAuxControl-$-8] ; set the default bits
- orr r1,r1,r2
- str r1, [r0,#0] ; store the Aux Control Register
- ldr r0,[pc, #L2CCTAGLatReg-$-8] ; Load L2CC base address base + TAG Latency address
- ldr r1, [pc, #L2CCTAGLatency-$-8] ; set the latencies for the TAG
- str r1, [r0,#0] ; store the TAG Latency register Register
- ldr r0, [pc, #L2CCDataLatReg-$-8] ; Load L2CC base address base + Data Latency address
- ldr r1,[pc, #L2CCDataLatency-$-8] ; set the latencies for the Data
- str r1, [r0,#0] ; store the Data Latency register Register
- ldr r0,[pc, #L2CCWay-$-8] ; Load L2CC base address base + way register
- ldr r2, [pc, #H0xffff-$-8]
- str r2, [r0,#0] ; force invalidate
- ldr r0, [pc, #L2CCSync-$-8] ; need to poll 0x730, PSS_L2CC_CACHE_SYNC_OFFSET
- ; Load L2CC base address base + sync register
- ; poll for completion
- Sync:
- ldr r1, [r0,#0]
- cmp r1, #0
- bne Sync
- ldr r0,[pc, #L2CCIntRaw-$-8] ; clear pending interrupts
- ldr r1,[r0,#0]
- ldr r0,[pc, #L2CCIntClear-$-8]
- str r1,[r0,#0]
- ldr r0,[pc,#L2CCCrtl-$-8] ; Load L2CC base address base + control register
- ldr r1,[r0,#0] ; read the register
- mov r2, #1 ; set the enable bit
- orr r1,r1,r2
- str r1, [r0,#0] ; enable the L2 Caches
- mrc p15,0,r0,c1,c0,0 ; flow prediction enable
- orr r0, r0, #0x800 ; #0x800
- mcr p15,0,r0,c1,c0,0
- isb
- mrc p15,0,r0,c1,c0,1 ; read Auxiliary Control Register
- orr r0, r0, #4 ; enable Dside prefetch
- orr r0, r0, #2 ; enable L2 Prefetch hint
- mcr p15,0,r0,c1,c0,1 ; write Auxiliary Control Register
- isb
- b exit
- ; Data
- H0xffff: d32 0FFFFH
- L2CCWay: d32 0F8F02000H + 077CH
- L2CCSync: d32 0F8F02000H + 0730H
- L2CCCrtl: d32 0F8F02000H + 0100H
- L2CCAuxCtrl: d32 0F8F02000H + 0104H
- L2CCTAGLatReg: d32 0F8F02000H + 0108H
- L2CCDataLatReg: d32 0F8F02000H + 010CH
- L2CCIntClear: d32 0F8F02000H + 0220H
- L2CCIntRaw: d32 0F8F02000H + 021CH
- L2CCAuxControl: d32 72360000H
- L2CCTAGLatency: d32 0111H
- L2CCDataLatency: d32 0121H
- exit:
- END EnableL2Cache;
- (** Enables the Snoop Control Unit
- for L1 coherency and LDREX/STREX global monitor
- *)
- PROCEDURE EnableSCU;
- CODE
- ; set scu enable bit in scu
- ldr r7, [pc, #H0xf8f00000-$-8]
- ldr r0, [r7, #0]
- orr r0, r0, #1
- str r0, [r7,#0]
- ; invalidate scu
- ldr r7, [pc, #H0xf8f0000c-$-8]
- ldr r6, [pc, #H0xffff-$-8]
- str r6, [r7, #0]
- b exit
- ; Data
- H0xf8f00000: d32 0F8F00000H
- H0xf8f0000c: d32 0F8F0000CH
- H0xffff: d32 0FFFFH
- exit:
- END EnableSCU;
- (** Init NEON / VFP Engine *)
- PROCEDURE InitFPU;
- CODE
- MRC p15, 0, R0, C1, C0, 2;
- ORR R0, R0, #0x00f00000;
- MCR p15, 0, R0, C1, C0, 2;
- ISB
- MOV R0, #0x40000000;
- VMSR FPEXC, R0;
-
- VMRS R0, FPSCR
- BIC R0, R0, #0x0c00000 ; round to nearest as the default
- ; remark: if we put round to minus infinity as the default, we can spare quite some instructions in emission of ENTIER
- VMSR FPSCR, R0;
- END InitFPU;
- (** Activate the Symmetric Multiprocessing Mode for current CPU.
- This activates L1 cache coherency.
- *)
- PROCEDURE SetSmpMode;
- CODE
- (*
- mrc p15, 0, r0, c1, c0, 1 /* Read ACTLR*/
- orr r0, r0, #(0x01 << 6) /* set SMP bit */
- orr r0, r0, #(0x01 ) /* */
- mcr p15, 0, r0, c1, c0, 1 /* Write ACTLR*/
- *)
- MRC p15, 0, R0, C1, C0, 1
- ORR R0, R0, #047H
- MCR p15, 0, R0, C1, C0, 1
- ISB
- END SetSmpMode;
- (** Activate Assymmetric Multiprocessing Mode for current CPU.
- This desactivates L1 cache coherency
- *)
- PROCEDURE SetAmpMode;
- CODE
- MRC p15, 0, R0, C1, C0, 1
- MOV R1, #040H
- RSB R1, R1, #0
- ORR R0, R0, R1
- MCR p15, 0, R0, C1, C0, 1
- ISB
- END SetAmpMode;
- (** Enable coprocessors CP10 and CP11(= VFP and NEON engine) *)
- PROCEDURE EnableCoprocessors;
- CODE
- mov r0, r0
- mrc p15, 0, r1, c1, c0, 2 ; read cp access control register (CACR) into r1
- orr r1, r1, #0xf00000 ; enable full access for p10 & p11
- mcr p15, 0, r1, c1, c0, 2 ; write back into CACR
- isb
- END EnableCoprocessors;
- (* Initializes a processor. Has to be called once by each processor. *)
- PROCEDURE InitProcessor*;
- BEGIN
- timer := DummyEvent;
- Timeslice := DummyTimeslice;
- SetSmpMode;
- EnableSCU;
- EnableL1Cache;
- InvalidateTLB;
- InvalidateICache;
- Initializer.InvalidateDCache;
- (*InvalidateDCacheRange(0, SYSTEM.VAL(ADDRESS, LastAddress));*)
- (* SCU and L2 caches are enabled in the initialization sequence *)
- EnableL2Cache;
- EnableCoprocessors;
- InitFPU;
- allProcessors := {0}
- END InitProcessor;
- (** Shut system down. If reboot is TRUE, attempts to restart system. *)
- PROCEDURE Shutdown*(reboot: BOOLEAN);
- VAR i: LONGINT; procs: SET;
- BEGIN
- IF enableWatchdog THEN PrivateWatchdog.Stop END;
- StopTicks;
- Trace.String("Shutting down secondary CPUs... ");
- procs := allProcessors;
- FOR i := 0 TO numberOfProcessors - 1 DO
- IF (i # ID()) & (i IN allProcessors) THEN
- EXCL(allProcessors, i)
- END
- END;
- FOR i := 0 TO numberOfProcessors - 1 DO
- IF (i #ID()) & (i IN procs) THEN
- REPEAT UNTIL i IN allProcessors
- END
- END;
- Trace.StringLn("done");
- IF reboot THEN
- Platform.slcr.SLCR_UNLOCK := Platform.SlcrUnlockKey;
- Platform.slcr.PSS_RST_CTRL := 1
- ELSE
- EndInterrupts;
- LOOP
- CODE
- WFE
- END;
- END
- END;
- END Shutdown;
- (** Shut down secondary processors *)
- PROCEDURE ShutdownSecondary;
- BEGIN
- IF enableWatchdog THEN PrivateWatchdog.Stop END;
- INCL(allProcessors, ID());
- LOOP
- CODE
- WFE
- END
- END
- END ShutdownSecondary;
- (** Cleans the whole DCache. Taken from Minos *)
- PROCEDURE CleanDCache *;
- CONST
- L2CCBBase = 0F8F02000H;
- L2COfs = L2CCBBase + 7BCH;
- L2CSync = L2CCBBase + 730H;
- CODE
- ; Clean all sets of all ways of L1 cache
- MOV R0, #0
- WayLoop:
- CMP R0, #4
- BEQ EndWayLoop
- LSL R4, R0, #30
- MOV R1, #0
- SetLoop:
- CMP R1, #256
- BEQ EndSetLoop
- LSL R3, R1, #5
- ORR R3, R4, R3
- MCR P15, 0, R3, C7, C10, 2
- ADD R1, R1, #1
- B SetLoop
- EndSetLoop:
- ADD R0, R0, #1
- B WayLoop
- EndWayLoop:
- DSB
- ; Invalidate all L2 ways
- LDR R0, [PC, #L2COfsAdr - $ - 8] ; R0 := reg7_inv_way address
- MOV R1, #0FH ; R1 := 0FH => invalidate all ways
- STR R1, [R0, #0] ; reg7_inv_way <- R1
- Sync:
- DSB
- LDR R0, [PC, #L2CSyncAdr - $ - 8] ; R0 := L2 cache sync register address
- MOV R1, #1
- STR R1, [R0, #0] ; [R0] := 1
- SyncLoop: ; repeat
- LDR R1, [R0, #0] ; R1 := l2 cache syc state
- CMP R1, #0
- BEQ Exit ; until R1 = 0
- B SyncLoop
- L2COfsAdr: d32 L2COfs
- L2CSyncAdr: d32 L2CSync
- Exit:
- END CleanDCache;
- PROCEDURE FlushDCacheRange*(adr:ADDRESS; len: SIZE);
- CONST
- cacheline = 32;
- L2CCBBase = 0F8F02000H; (*XPS_L2CC_BASEADDR*)
- L2CCCacheSync = L2CCBBase + 00730H; (* Cache Sync *)(*XPS_L2CC_CACHE_SYNC_OFFSET *)
- L2CCCacheInvClnPAOfs= 007F0H; (* Cache Clean by PA *)(*XPS_L2CC_CACHE_INV_CLN_PA_OFFSET*)
- L2CCOffset = L2CCBBase + L2CCCacheInvClnPAOfs;
- BEGIN
- IF ~enableCaching OR (len = 0) THEN RETURN END;
- IF len MOD cacheline # 0 THEN INC(len, cacheline - len MOD cacheline) END;
- IF adr MOD cacheline # 0 THEN DEC(adr, len MOD cacheline) END;
- CODE
- LDR R0, [FP, #adr] ; R0 := adr
- LDR R1, [FP, #len] ; R1 := len
- LDR R2, [PC, #Cacheline - 8 - $] ; R2 := cacheline
- SUB R3, R2, #1 ; R3 := cacheline - 1
- AND R3, R0, R3 ; R3 := adr MOD cacheline
- ADD R1, R1, R0
- SUB R0, R0, R3 ; R0 := adr - adr MOD cacheline
- ;ADD R1, R1, R3 ; R1 := len + adr MOD cacheline
- MOV R3, #0
- MCR P15, 2, R3, C0, C0, 0 ; Select cache level 1
- LDR R4, [PC, #L2COfs - 8 - $] ; R4 := L2 cache flush address register address
- Loop:
- CMP R0, R1 ; while R0 < R1
- BEQ Sync
- BHI Sync
- MCR P15, 0, R0, C7, C14, 1 ; Clean Cache Level 1 By MVA (R0)
- STR R0, [R4, #0] ; Clean Cache Level 2 By PA (R0)
- DSB
- ADD R0, R0, R2 ; R0 := R0 + cacheline
- B Loop ; end
- Sync:
- DSB
- LDR R0, [PC, #L2CSync - 8 - $] ; R0 := L2 cache sync register address
- ;MOV R1, #1
- ;STR R1, [R0, #0] ; [R0] := 1
- SyncLoop: ; repeat
- LDR R1, [R0, #0] ; R1 := l2 cache syc state
- CMP R1, #0
- BEQ Exit ; until R1 = 0
- B SyncLoop
- Cacheline: d32 cacheline
- L2COfs: d32 L2CCOffset
- L2CSync: d32 L2CCCacheSync
- Exit:
- END;
- END FlushDCacheRange;
- PROCEDURE FlushDCachePhysRange * (adr: ADDRESS; len: LONGINT; CONST ranges: ARRAY OF Range; numRanges: LONGINT);
- CONST
- cacheline = 32;
- L2CCBBase = 0F8F02000H; (*XPS_L2CC_BASEADDR*)
- L2CCCacheSync = L2CCBBase + 00730H; (* Cache Sync *)(*XPS_L2CC_CACHE_SYNC_OFFSET *)
- L2CCCacheInvClnPAOfs= 007F0H; (* Cache Clean by PA *)(*XPS_L2CC_CACHE_INV_CLN_PA_OFFSET*)
- L2CCOffset = L2CCBBase + L2CCCacheInvClnPAOfs;
- VAR
- cur, end: ADDRESS;
- r: LONGINT;
- BEGIN
- IF ~enableCaching & (len # 0) THEN
- IF len MOD cacheline # 0 THEN INC(len, cacheline - len MOD cacheline) END;
- (* Select cache L0 Data cache in CSSR *)
- CODE
- mov r0, #0
- mcr p15, 2, r0, c0, c0, 0 (* mtcp(XREG_CP15_CACHE_SIZE_SEL, 0);*)
- END;
- (* Flush all cache lines in the memory region *)
- FOR r := 0 TO numRanges - 1 DO
- cur := ranges[r].adr;
- end := cur + ranges[r].size;
- WHILE (cur < end) DO
- (* Flush L1 Data cache line with virtual address *)
- CODE
- ldr r3, [fp, #adr] (* load*)
- mcr p15, 0, r3, c7, c14, 1; MCR XREG_CP15_CLEAN_INVAL_DC_LINE_MVA_POC :: "r" (adr));
- END;
- (* Flush L2 cache line with physical address *)
- SYSTEM.PUT(L2CCOffset, cur);
- cur := cur + cacheline;
- adr := adr + cacheline
- END
- END
- END;
- (* Wait for L1 and L2 flush to complete *)
- CODE
- DSB
- END;
- SYSTEM.PUT32(L2CCCacheSync, 1);
- REPEAT UNTIL SYSTEM.GET32(L2CCCacheSync) = 0;
- END FlushDCachePhysRange;
- PROCEDURE InvalidateDCacheRange*(adr: ADDRESS; len: SIZE);
- CONST
- cacheline = 32;
- L2CCBBase = 0F8F02000H; (*XPS_L2CC_BASEADDR*)
- L2CCCacheSync = L2CCBBase + 00730H; (* Cache Sync *)(*XPS_L2CC_CACHE_SYNC_OFFSET *)
- L2CCCacheInvPAOfs = 00770H; (* Cache Invalidate by PA *)(*XPS_L2CC_CACHE_INV_CLN_PA_OFFSET*)
- L2CCOffset = L2CCBBase + L2CCCacheInvPAOfs;
- BEGIN
- IF ~enableCaching OR (len = 0) THEN RETURN END;
- IF len MOD cacheline # 0 THEN INC(len, cacheline - len MOD cacheline) END;
- IF adr MOD cacheline # 0 THEN DEC(adr, len MOD cacheline) END;
- CODE
- LDR R0, [FP, #adr] ; R0 := adr
- LDR R1, [FP, #len] ; R1 := len
- LDR R2, [PC, #Cacheline - 8 - $] ; R2 := cacheline
- SUB R3, R2, #1 ; R3 := cacheline - 1
- AND R3, R0, R3 ; R3 := adr MOD cacheline
- SUB R0, R0, R3 ; R0 := adr - adr MOD cacheline
- ADD R1, R1, R3 ; R1 := len + adr MOD cacheline
- MOV R5, #0 ; R5 := 0 (counter value)
- MOV R3, #0
- MCR P15, 2, R3, C0, C0, 0 ; Select cache level 1
- LDR R4, [PC, #L2COfs - 8 - $] ; R4 := L2 cache invalidate address register address
- Loop:
- CMP R5, R1 ; while R5 < R1
- BEQ Sync
- BHI Sync
- STR R0, [R4, #0] ; Invalidate Cache Level 2 By PA (R0)
- DSB
- MCR P15, 0, R0, C7, C6, 1 ; Invalidate Cache Level 1 By MVA (R0)
- ADD R0, R0, R2 ; R0 := R0 + cacheline
- ADD R5, R5, R2
- B Loop ; end
- Sync:
- DSB
- LDR R0, [PC, #L2CSync - 8 - $] ; R0 := L2 cache sync register address
- MOV R1, #1
- STR R1, [R0, #0] ; [R0] := 1
- SyncLoop: ; repeat
- LDR R1, [R0, #0] ; R1 := l2 cache syc state
- CMP R1, #0
- BEQ Exit ; until R1 = 0
- B SyncLoop
- Cacheline: d32 cacheline
- L2COfs: d32 L2CCOffset
- L2CSync: d32 L2CCCacheSync
- Exit:
- END;
- END InvalidateDCacheRange;
- (**
- Disable data cache for the memory range [adr, adr + len). Repeated cache disabling is recorded. A maximum of 127 successive disabling is supported.
- Cache disabling is allowed for heap and stack memory ranges only.
- *)
- PROCEDURE DisableDCacheRange * (adr: ADDRESS; len: LONGINT);
- VAR
- range: ARRAY 1 OF Range;
- end: ADDRESS;
- ofs, entry: LONGINT;
- BEGIN
- (* Changing cache status allowed for heap and stack only. *)
- ASSERT(((memHeapStart <= adr) & (adr + len <= memHeapStop)) OR ((memStackStart <= adr) & (adr + len <= memStackStop)));
- end := adr + len;
- Acquire(Memory);
- WHILE adr < end DO
- entry := GetFirstLevelEntry(adr - adr MOD M);
- CASE entry MOD 4 OF
- 0:
- (* Page is not allocated: generate a data abort trap *)
- Release(Memory);
- ASSERT(entry MOD 4 # 0);
- |flSection:
- (* 1 MB heap page *)
- IF enableCaching THEN
- (* index in cache reference count array *)
- ofs := (adr - memHeapStart) DIV M;
- IF cacheRefs[ofs] = 0 THEN
- (* First disabling: disable cache *)
- range[0].adr := adr - adr MOD M;
- range[0].size := M;
- SetFirstLevelEntry(adr - adr MOD M, adr - adr MOD M(*SHRL(entry, 20)*), SrwUrw, Shareable + B, flSection);
- InvalidateTLBEntry(adr);
- FlushDCachePhysRange(adr - adr MOD M, M, range, 1);
- cacheRefs[ofs] := 1
- ELSE
- (* Increase reference count and avoid overflows. *)
- ASSERT(cacheRefs[ofs] < 127);
- INC(cacheRefs[ofs])
- END
- END;
- INC(adr, M);
- DEC(adr, adr MOD M);
- |flCoarse:
- (* Second level pt *)
- entry := GetSecondLevelEntry(adr - adr MOD PS);
- CASE entry MOD 4 OF
- 0:
- (* Page is not allocated: generate a data abort trap *)
- Release(Memory);
- ASSERT(entry MOD 4 # 0);
- |slSmall:
- (* 4 kB stack page *)
- IF enableCaching THEN
- (* Index in cache reference count array *)
- ofs := (adr - memStackStart) DIV PS + sysCacheStackOfs;
- IF cacheRefs[ofs] = 0 THEN
- (* First disabling: disable cache *)
- range[0].adr := adr - adr MOD PS;
- range[0].size := PS;
- SetSecondLevelEntry(adr - adr MOD PS, SHRL(entry, PSlog2), FullAccess + 400H + B);
- InvalidateTLBEntry(adr);
- FlushDCachePhysRange(adr - adr MOD PS, PS, range, 1);
- cacheRefs[ofs] := 1
- ELSE
- (* Increase reference count and avoid overflows *)
- ASSERT(cacheRefs[ofs] < 127);
- INC(cacheRefs[ofs])
- END
- END;
- INC(adr, PS);
- DEC(adr, adr MOD PS)
- END;
- END;
- END;
- Release(Memory)
- END DisableDCacheRange;
- (**
- Enable data cache for the memory range [adr, adr + len).
- The memory range must have been previously disabled.
- It is the responsibility of client software to re-enable cache for the regions that it disabled.
- *)
- PROCEDURE EnableDCacheRange * (adr: ADDRESS; len: LONGINT);
- VAR
- end: ADDRESS;
- ofs, entry: LONGINT;
- BEGIN
- (* Changing cache status allowed for heap and stack only. *)
- ASSERT(((memHeapStart <= adr) & (adr < memHeapStop)) OR ((memStackStart <= adr) & (adr < memStackStop)));
- (*InvalidateDCacheRange(adr - (adr MOD M), len + M - (adr + len) MOD M + adr MOD M);*)
- Acquire(Memory);
- end := adr + len;
- WHILE adr < end DO
- entry := GetFirstLevelEntry(SHRL(adr, LogM));
- CASE entry MOD 4 OF
- 0:
- (* page not mapped: generate trap *)
- Release(Memory);
- ASSERT(entry MOD 4 # 0);
- |flSection:
- (* 1 MB heap page *)
- IF enableCaching THEN
- ofs := (adr - memHeapStart) DIV M;
- ASSERT(cacheRefs[ofs] > 0);
- IF cacheRefs[ofs] = 1 THEN
- SetFirstLevelEntry(SHRL(adr, LogM), SHRL(entry, LogM), SrwUrw, Cacheable + Shareable, entry MOD 4);
- InvalidateTLBEntry(adr);
- cacheRefs[ofs] := 0
- ELSE
- DEC(cacheRefs[ofs])
- END
- END;
- INC(adr, M);
- DEC(adr, adr MOD M)
- |flCoarse:
- (* Second-level pt entry *)
- entry := GetSecondLevelEntry(SHRL(adr, PSlog2));
- CASE entry MOD 4 OF
- 0:
- (* Page not mapped: generate trap *)
- Release(Memory);
- ASSERT(entry MOD 4 # 0);
- |slSmall:
- (* 4 kB stack page *)
- IF enableCaching THEN
- ofs := (adr - memStackStart) DIV PS + sysCacheStackOfs;
- ASSERT(cacheRefs[ofs] > 0);
- IF cacheRefs[ofs] = 1 THEN
- SetSecondLevelEntry(SHRL(adr, PSlog2), SHRL(entry, PSlog2), FullAccess + CB);
- InvalidateTLBEntry(SHRL(adr, PSlog2));
- cacheRefs[ofs] := 0
- ELSE
- DEC(cacheRefs[ofs])
- END
- END;
- INC(adr, PS);
- DEC(adr, adr MOD PS)
- END;
- END;
- END;
- Release(Memory)
- END EnableDCacheRange;
- (* InvalidateICache - invalidates the ICache. Works only in a priviledged mode. *)
- PROCEDURE InvalidateICache*;
- CODE
- MCR p15, 0, R0, c7, c5, 0 ; invalidate ICache & BTB
- ISB
- ; cpwait
- MRC p15, 0, R0, c2, c0, 0
- MOV R0, R0
- SUB PC, PC, #4
- MOV R0, R0
- MOV R0, R0
- MOV R0, R0
- MOV R0, R0
- END InvalidateICache;
- (* InvalidateTLB: data and instruction TLBs - Works only in a priviledged mode *)
- PROCEDURE - InvalidateTLB *;
- CODE
- MCR p15, 0, R0, c8, c3, 0 ; invalidate I+D TLB
- ISB
- ; cpwait
- MRC p15, 0, R0, c2, c0, 0
- MOV R0, R0
- SUB PC, PC, #4
- MOV R0, R0
- MOV R0, R0
- MOV R0, R0
- MOV R0, R0
- DSB
- END InvalidateTLB;
- (* InvalidateTLBEntry - invalidates the TLB for a given virtual address. Works only in a priviledged mode *)
- PROCEDURE - InvalidateTLBEntry(address: LONGINT);
- CODE
- LDR R0, [SP, #address]
- ADD SP, SP, #4
- ;MCR p15, 0, R0, c8, c6, 1 ; invalidate address
- MCR p15, 0, R0, c8, c3, 1 ; invalidate address
- ISB
- ; cpwait
- MRC p15, 0, R0, c2, c0, 0
- MOV R0, R0
- SUB PC, PC, #4
- MOV R0, R0
- MOV R0, R0
- MOV R0, R0
- MOV R0, R0
- DSB
- END InvalidateTLBEntry;
- (* GetControlRegister - returns the control register of coprocessor 15 *)
- PROCEDURE -GetControlRegister(): SET;
- CODE
- MRC p15, 0, R0, c1, c0, 0
- END GetControlRegister;
- (* SetControlRegister - sets the control register of coprocessor 15. Works only in a priviledged mode *)
- PROCEDURE -SetControlRegister(cr: SET);
- CODE
- LDR R0, [SP, #cr]
- ADD SP, SP, #4 ; remove parameter
- MCR p15, 0, R0, c1, c0, 0
- ISB
- ; cpwait
- MRC p15, 0, R0, c2, c0, 0
- MOV R0, R0
- SUB PC, PC, #4
- MOV R0, R0
- MOV R0, R0
- MOV R0, R0
- MOV R0, R0
- END SetControlRegister;
- (* DrainWriteBuffer - drains the write buffer. Works only in a priviledged mode *)
- PROCEDURE DrainWriteBuffer*;
- CODE
- MCR p15, 0, R0, c7, c10, 4 ; drain WB
- ISB
- ; cpwait
- MRC p15, 0, R0, c2, c0, 0
- MOV R0, R0
- SUB PC, PC, #4
- MOV R0, R0
- MOV R0, R0
- MOV R0, R0
- MOV R0, R0
- END DrainWriteBuffer;
- PROCEDURE -CurrentPC*(): ADDRESS;
- CODE
- MOV R0, PC
- END CurrentPC;
- PROCEDURE GetTimer*(): HUGEINT;
- VAR t: ARRAY 2 OF LONGINT;
- BEGIN
- REPEAT
- t[1] := SYSTEM.GET32(Platform.GlobalTimerCounterRegister1);
- t[0] := SYSTEM.GET32(Platform.GlobalTimerCounterRegister0);
- UNTIL t[1] = SYSTEM.GET32(Platform.GlobalTimerCounterRegister1);
- RETURN SYSTEM.VAL(HUGEINT,t);
- END GetTimer;
- (* ===== Multiprocessor booting ===== *)
- (** Initializes non-booting processors *)
- PROCEDURE InitProcessors*;
- VAR
- i: LONGINT;
- val: ARRAY 8 OF CHAR;
- BEGIN
- GetConfig("TraceCpu", val);
- traceCpus := val = "1";
- InstallHandler(HandleUPTimer, PrivateTimerIRQ);
- InstallHandler(TimerInterruptHandler, PrivateTimerIRQ);
- InitTicks;
- InitWatchdog;
- CleanDCache;
- DrainWriteBuffer;
- FOR i := 1 TO numProcessors - 1 DO
- StartProcessor(i, BootMP);
- END;
- END InitProcessors;
- PROCEDURE StartAll*;
- BEGIN
- END StartAll;
- (* Send event instruction *)
- PROCEDURE -Sev;
- CODE
- SEV
- END Sev;
- (** Start core id on procedure p. *)
- PROCEDURE StartProcessor(id: LONGINT; p: PROCEDURE);
- VAR
- time, ticks0: LONGINT;
- started: BOOLEAN;
- sevCount: SIZE;
- BEGIN
- IF traceCpus THEN
- Acquire(TraceOutput);
- Trace.String("Starting CPU");
- Trace.Int(id, 0);
- Trace.String(" on address ");
- Trace.Address(SYSTEM.VAL(ADDRESS, p));
- Trace.Ln;
- Release(TraceOutput)
- END;
- Initializer.secondaryProcId := id;
- Initializer.secondaryBootProc := SYSTEM.VAL(ADDRESS, p);
- FlushDCacheRange(ADDRESSOF(Initializer.secondaryProcId), 4);
- FlushDCacheRange(ADDRESSOF(Initializer.secondaryBootProc), 4);
- (* wake up the other cores *)
- Sev;
- time := ticks + 1000;
- sevCount := 0;
- ticks0 := ticks;
- REPEAT
- started := id IN allProcessors;
- (*! a workaround for rare but nevertheless occurring case when the other CPU does not wake up *)
- IF ~started & (ticks - ticks0 > 1) THEN
- Sev;
- ticks0 := ticks;
- INC(sevCount);
- END;
- UNTIL started OR (time <= ticks);
- IF traceCpus THEN
- Acquire(TraceOutput);
- Trace.String("SEV call count="); Trace.Int(sevCount,0); Trace.Ln;
- Release(TraceOutput);
- END;
- IF id IN allProcessors THEN
- IF traceCpus THEN
- Acquire(TraceOutput);
- Trace.String("Confirm: CPU");
- Trace.Int(id, 0);
- Trace.StringLn(" started");
- Release(TraceOutput)
- END
- ELSE
- Acquire(TraceOutput);
- Trace.String("WARNING: Could not start CPU");
- Trace.Int(id, 0);
- Trace.Ln;
- Release(TraceOutput)
- END
- END StartProcessor;
- (** Init Memory for non-booting processors.
- This enables MMU and copies the mapping of CPU0
- *)
- PROCEDURE InitMPMemory;
- VAR
- tbFlags: LONGINT;
- BEGIN
- IF enableCaching THEN
- tbFlags := 7BH
- ELSE
- tbFlags := 0
- END;
- EnableMM(sysFirstLvlPtStart, tbFlags, 2000H + 1007H);
- END InitMPMemory;
- (** Init code fo a non-booting processor. No local variable allowed. *)
- PROCEDURE {NOPAF} BootMP;
- BEGIN
- (* Setup stack *)
- SYSTEM.LDPSR( 0, Platform.IRQMode + Platform.FIQDisabled + Platform.IRQDisabled );
- SYSTEM.SETSP(sysIntStackStart + 1000H * 5);
- SYSTEM.LDPSR( 0, Platform.UndefMode + Platform.FIQDisabled + Platform.IRQDisabled );
- SYSTEM.SETSP(sysIntStackStart + 1000H * 6);
- SYSTEM.LDPSR( 0, Platform.AbortMode + Platform.FIQDisabled + Platform.IRQDisabled );
- SYSTEM.SETSP(sysIntStackStart + 1000H * 7);
- SYSTEM.LDPSR( 0, Platform.SVCMode + Platform.FIQDisabled + Platform.IRQDisabled ); (* Disable interrupts, init SP, FP *)
- SYSTEM.SETSP(sysIntStackStart + 1000H * 8);
- SYSTEM.LDPSR( 0, Platform.SystemMode + Platform.FIQDisabled + Platform.IRQDisabled ); (* Disable interrupts, init SP, FP *)
- SYSTEM.SETSP(sysIntStackStart + 1000H * 8);
- Initializer.InvalidateDCache;
- SetSmpMode;
- EnableL1Cache;
- EnableCoprocessors;
- InitFPU;
- InvalidateICache;
- Initializer.InvalidateDCache;
- InitMPMemory;
- (*InvalidateDCacheRange(4096, SYSTEM.VAL(ADDRESS, LastAddress));*)
- (*InvalidateDCacheRange(memSysHighStart, memSysHighStop - memSysHighStart);*)
- (*CODE
- DSB
- END;*)
- InitInterrupts;
- EnableIRQ(PrivateTimerIRQ);
- EnableInterrupts;
- IF traceCpus THEN
- Acquire(TraceOutput);
- Trace.String("CPU "); Trace.Int(ID(), 0); Trace.StringLn(" started.");
- Release(TraceOutput)
- END;
- Acquire(Processors);
- INCL(allProcessors, ID());
- Release(Processors);
- InitTicks;
- InitWatchdog;
- start;
- HALT(400)
- END BootMP;
- PROCEDURE KernelCallHLT*;
- BEGIN
- END KernelCallHLT;
- (* function returning the number of processors that are available to Aos *)
- PROCEDURE NumberOfProcessors*( ): LONGINT;
- BEGIN
- RETURN numberOfProcessors
- END NumberOfProcessors;
- (*! non portable code, for native Aos only *)
- PROCEDURE SetNumberOfProcessors*(num: LONGINT);
- BEGIN
- numberOfProcessors := num;
- END SetNumberOfProcessors;
- (* ===== Context Switching ===== *)
- (** Pushes state of the processor on the stack. Used in task-switching.
- Does not exactly represent the layout of State. Pushed data is always used by JumpState.
- *)
- PROCEDURE -PushState*(CONST state: State);
- CODE
- LDR R0, [SP, #0] ; R0 <- address of state
- ADD SP, SP, #8
- LDR R1, [R0, #60] ; push PC
- STR R1, [SP, #-4]!
- LDR R1, [R0, #56] ; push LR
- STR R1, [SP, #-4]!
- LDR R1, [R0, #48] ; push FP
- STR R1, [SP, #-4]!
- LDR R1, [R0, #44] ; push R11
- STR R1, [SP, #-4]!
- LDR R1, [R0, #40] ; push R10
- STR R1, [SP, #-4]!
- LDR R1, [R0, #36] ; push R9
- STR R1, [SP, #-4]!
- LDR R1, [R0, #32] ; push R8
- STR R1, [SP, #-4]!
- LDR R1, [R0, #28] ; push R7
- STR R1, [SP, #-4]!
- LDR R1, [R0, #24] ; push R6
- STR R1, [SP, #-4]!
- LDR R1, [R0, #20] ; push R5
- STR R1, [SP, #-4]!
- LDR R1, [R0, #16] ; push R4
- STR R1, [SP, #-4]!
- LDR R1, [R0, #12] ; push R3
- STR R1, [SP, #-4]!
- LDR R1, [R0, #8] ; push R2
- STR R1, [SP, #-4]!
- LDR R1, [R0, #4] ; push R1
- STR R1, [SP, #-4]!
- LDR R1, [R0, #0] ; push R0
- STR R1, [SP, #-4]!
- LDR R1, [R0, #64] ; push SPSR
- STR R1, [SP, #-4]!
- END PushState;
- (** Pops a processor state from the stack and restore it. Including jumping to the PC. *)
- PROCEDURE -JumpState*;
- CODE
- ; Load PSR
- LDR R0, [SP], #4
- MSR CPSR_cxsf, R0 ; set CPSR
- ; Load registers, including branch
- LDMIA SP!, {R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, FP, LR}
- LDR PC, [SP], #4
- END JumpState;
- PROCEDURE CopyState*(CONST from: State; VAR to: State);
- BEGIN
- to.R[0] := from.R[0];
- to.R[1] := from.R[1];
- to.R[2] := from.R[2];
- to.R[3] := from.R[3];
- to.R[4] := from.R[4];
- to.R[5] := from.R[5];
- to.R[6] := from.R[6];
- to.R[7] := from.R[7];
- to.R[8] := from.R[8];
- to.R[9] := from.R[9];
- to.R[10] := from.R[10];
- to.R[11] := from.R[11];
- to.BP := from.BP;
- to.SP := from.SP;
- to.LR := from.LR;
- to.PC := from.PC;
- to.PSR := from.PSR;
- END CopyState;
- PROCEDURE -JumpToUserLevel*(userFP: ADDRESS);
- CODE
- ; this is an inlined procedure, so the 'userFP' parameter lies on top of the stack
- LDR FP, [SP, #userFP] ; pop FP (FP is not a banked register)
- ADD SP, SP, #4
- MRS R0, CPSR ; get current PSR
- BIC R0, R0, #1FH ; clear bits 4:0
- ORR R0, R0, #1FH ; CPU mode = System
- MSR CPSR_c, R0 ; switch mode
- MOV SP, FP
- LDMIA SP! , {FP, LR}
- BX LR
- END JumpToUserLevel;
- PROCEDURE UpdateState*;
- BEGIN
- END UpdateState;
- (** Save complete VFP/NEON state *)
- PROCEDURE -FPUSaveFull*(VAR state: NEONState);
- CODE
- LDR R0, [SP, #state]
- ADD SP, SP, #8
- VST1 D0, R0
- ADD R0, R0, #8
- VST1 D1, R0
- ADD R0, R0, #8
- VST1 D2, R0
- ADD R0, R0, #8
- VST1 D3, R0
- ADD R0, R0, #8
- VST1 D4, R0
- ADD R0, R0, #8
- VST1 D5, R0
- ADD R0, R0, #8
- VST1 D6, R0
- ADD R0, R0, #8
- VST1 D7, R0
- ADD R0, R0, #8
- VST1 D8, R0
- ADD R0, R0, #8
- VST1 D9, R0
- ADD R0, R0, #8
- VST1 D10, R0
- ADD R0, R0, #8
- VST1 D11, R0
- ADD R0, R0, #8
- VST1 D12, R0
- ADD R0, R0, #8
- VST1 D13, R0
- ADD R0, R0, #8
- VST1 D14, R0
- ADD R0, R0, #8
- VST1 D15, R0
- ADD R0, R0, #8
-
- VSTR D16, R0, #0
- ADD R0, R0, #8
- VSTR D17, R0, #0
- ADD R0, R0, #8
- VSTR D18, R0, #0
- ADD R0, R0, #8
- VSTR D19, R0, #0
- ADD R0, R0, #8
- VSTR D20, R0, #0
- ADD R0, R0, #8
- VSTR D21, R0, #0
- ADD R0, R0, #8
- VSTR D22, R0, #0
- ADD R0, R0, #8
- VSTR D23, R0, #0
- ADD R0, R0, #8
- VSTR D24, R0, #0
- ADD R0, R0, #8
- VSTR D25, R0, #0
- ADD R0, R0, #8
- VSTR D26, R0, #0
- ADD R0, R0, #8
- VSTR D27, R0, #0
- ADD R0, R0, #8
- VSTR D28, R0, #0
- ADD R0, R0, #8
- VSTR D29, R0, #0
- ADD R0, R0, #8
- VSTR D30, R0, #0
- ADD R0, R0, #8
- VSTR D31, R0, #0
- ADD R0, R0, #8
- VMRS R1, FPSCR
- STR R1, [R0, #0]
- ADD R0, R0, #4
- VMRS R1, FPEXC
- STR R1, [R0, #0]
- END FPUSaveFull;
- (** Save minimal VFP/NEON state *)
- PROCEDURE -FPUSaveMin*(VAR state: NEONState);
- CODE
- ADD SP, SP, #4
- END FPUSaveMin;
- (** Restore full VFP/NEON state *)
- PROCEDURE -FPURestoreFull*(VAR state: NEONState);
- CODE
- LDR R0, [SP, #state];
- ADD SP, SP, #8
- VLD1 D0, R0
- ADD R0, R0, #8
- VLD1 D1, R0
- ADD R0, R0, #8
- VLD1 D2, R0
- ADD R0, R0, #8
- VLD1 D3, R0
- ADD R0, R0, #8
- VLD1 D4, R0
- ADD R0, R0, #8
- VLD1 D5, R0
- ADD R0, R0, #8
- VLD1 D6, R0
- ADD R0, R0, #8
- VLD1 D7, R0
- ADD R0, R0, #8
- VLD1 D8, R0
- ADD R0, R0, #8
- VLD1 D9, R0
- ADD R0, R0, #8
- VLD1 D10, R0
- ADD R0, R0, #8
- VLD1 D11, R0
- ADD R0, R0, #8
- VLD1 D12, R0
- ADD R0, R0, #8
- VLD1 D13, R0
- ADD R0, R0, #8
- VLD1 D14, R0
- ADD R0, R0, #8
- VLD1 D15, R0
- ADD R0, R0, #8
- VLDR D16, R0, #0
- ADD R0, R0, #8
- VLDR D17, R0, #0
- ADD R0, R0, #8
- VLDR D18, R0, #0
- ADD R0, R0, #8
- VLDR D19, R0, #0
- ADD R0, R0, #8
- VLDR D20, R0, #0
- ADD R0, R0, #8
- VLDR D21, R0, #0
- ADD R0, R0, #8
- VLDR D22, R0, #0
- ADD R0, R0, #8
- VLDR D23, R0, #0
- ADD R0, R0, #8
- VLDR D24, R0, #0
- ADD R0, R0, #8
- VLDR D25, R0, #0
- ADD R0, R0, #8
- VLDR D26, R0, #0
- ADD R0, R0, #8
- VLDR D27, R0, #0
- ADD R0, R0, #8
- VLDR D28, R0, #0
- ADD R0, R0, #8
- VLDR D29, R0, #0
- ADD R0, R0, #8
- VLDR D30, R0, #0
- ADD R0, R0, #8
- VLDR D31, R0, #0
- ADD R0, R0, #8
- LDR R1, [R0, #0]
- VMSR FPSCR, R1
- ADD R0, R0, #4
- LDR R1, [R0, #0]
- VMSR FPEXC, R1
- END FPURestoreFull;
- (** Restore minimal VFP/NEON state *)
- PROCEDURE -FPURestoreMin*(VAR state: NEONState);
- CODE
- ADD SP, SP, #4
- END FPURestoreMin;
- (* ===== Interrupts ===== *)
- (* Taken from Minos/Kernel.Mos *)
- PROCEDURE EnableInterrupts*;
- VAR cpsr: LONGINT;
- BEGIN
- SYSTEM.STPSR(0, cpsr);
- cpsr := SYSTEM.VAL(LONGINT, SYSTEM.VAL(SET, cpsr) - {7(*, 8*)});
- SYSTEM.LDPSR(0, cpsr);
- (*SYSTEM.PUT32(Platform.ICDDCR, {EnableSecure, EnableNonSecure});*)
- END EnableInterrupts;
- (* Taken from Minos/Kernel.Mos *)
- PROCEDURE DisableInterrupts*;
- VAR cpsr: LONGINT;
- BEGIN
- SYSTEM.STPSR(0, cpsr);
- cpsr := SYSTEM.VAL(LONGINT, SYSTEM.VAL(SET, cpsr) + {7(*, 8*)});
- SYSTEM.LDPSR( 0, cpsr);
- (*SYSTEM.PUT32(Platform.ICDDCR, {});*)
- END DisableInterrupts;
- (** AreInterruptsEnabled - returns TRUE if interrupts are enabled at the current processor level, FALSE otherwise *)
- PROCEDURE AreInterruptsEnabled*(): BOOLEAN;
- CODE
- MRS R0, CPSR ; move CPSR to R0
- TST R0, #80H ; was IBit set ?
- MOVEQ R0, #1 ; no, interrupts are enabled
- MOVNE R0, #0 ; yep, interrupts are disabled
- END AreInterruptsEnabled;
- (* InstallDefaultInterrupts - installs default interrupt handlers *)
- PROCEDURE InstallDefaultInterrupts;
- VAR p: PROCEDURE; base: ADDRESS;
- i, int: LONGINT;
- BEGIN
- base := 0;
- (* Install all *Glue procedures. *)
- p := undefGlue; SYSTEM.PUT32(base + Undef, SYSTEM.VAL(LONGINT, p));
- p := SWIGlue; SYSTEM.PUT32(base + Swi, SYSTEM.VAL(LONGINT, p));
- p := prefetchGlue; SYSTEM.PUT32(base + Prefetch, SYSTEM.VAL(LONGINT, p));
- p := dataGlue; SYSTEM.PUT32(base + Data, SYSTEM.VAL(LONGINT, p));
- p := DefaultIRQ; SYSTEM.PUT32(base + Irq, SYSTEM.VAL(LONGINT, p));
- p := fiqGlue; SYSTEM.PUT32(base + Fiq, SYSTEM.VAL(LONGINT, p));
- (* Install default exception handlers *)
- InstallExceptionHandler(DefaultUndefined, Undef);
- InstallExceptionHandler(DefaultSWI, Swi);
- InstallExceptionHandler(DefaultPrefetchAbort, Prefetch);
- InstallExceptionHandler(DefaultDataAbort, Data);
- InstallExceptionHandler(DefaultFIQ, Fiq);
- FOR int := 0 TO MaxIRQ DO
- FOR i := 0 TO MaxIRQHandlers -1 DO
- irqHandler[int, i] := NIL
- END
- END;
- END InstallDefaultInterrupts;
- (* DefaultUndef - default handler for undefined instruction exceptions *)
- PROCEDURE DefaultUndefined (VAR state: State);
- VAR
- instn: LONGINT;
- BEGIN
- instn := SYSTEM.GET32(state.PC);
- Acquire(TraceOutput);
- Trace.Ln;
- Trace.StringLn("Undefined Instruction Trap:");
- Trace.String(" pc: "); Trace.Address(state.PC); Trace.Ln;
- Trace.String(" instruction: "); Trace.Hex(instn, -8); Trace.Ln;
- Trace.String(" CPU: "); Trace.Int(ID(), 0); Trace.Ln;
- TraceState(state);
- Trace.String("Kernel Halted");
- Release(TraceOutput);
- LOOP END
- END DefaultUndefined;
- (* DefaultSWI - default handler for software interrupts *)
- PROCEDURE DefaultSWI (VAR state: State);
- BEGIN
- Acquire(TraceOutput);
- Trace.Ln;
- Trace.StringLn("Software Interrupt:");
- Trace.String(" pc: "); Trace.Address(state.PC); Trace.Ln;
- Trace.String(" number: "); Trace.Int(state.INT, -8); Trace.Ln;
- Trace.String(" CPU: "); Trace.Int(ID(), 0); Trace.Ln;
- TraceState(state);
- Trace.Ln;
- Trace.String("Kernel halted.");
- Release(TraceOutput);
- LOOP END
- END DefaultSWI;
- (* Instruction Prefetch abort *)
- PROCEDURE DefaultPrefetchAbort (VAR state: State);
- BEGIN
- Acquire(TraceOutput);
- Trace.String("Prefetch abort at location: "); Trace.Address(state.PC); Trace.Ln;
- Trace.String(" CPU: "); Trace.Int(ID(), 0); Trace.Ln;
- Trace.String(" FP: "); Trace.Address(state.BP); Trace.Ln;
- Trace.String("SPSR: "); Trace.Hex(state.PSR, -8); Trace.Ln;
- TraceState(state);
- Trace.Ln;
- Trace.StringLn("Kernel Halted");
- Release(TraceOutput);
- LOOP END;
- END DefaultPrefetchAbort;
- (* DefaultDataAbort - default handler for data abort exceptions *)
- PROCEDURE DefaultDataAbort (VAR state: State);
- VAR
- faultAdr: ADDRESS;
- faultStatus: LONGINT;
- stack: Stack;
- BEGIN
- GetPageFault(faultAdr, faultStatus);
- (*getStack(stack);
- IF ~ExtendStack(stack, faultAdr) THEN*)
- Acquire(TraceOutput);
- IF faultAdr < 4 * k THEN
- Trace.StringLn("NIL pointer exception");
- Trace.String("pc: "); Trace.Address(state.PC); Trace.Ln
- ELSE
- Trace.StringLn("Data Abort Trap");
- Trace.String("pc: "); Trace.Address(state.PC); Trace.Ln;
- Trace.String("instn: "); Trace.Address(SYSTEM.GET32(state.PC)); Trace.Ln;
- Trace.String("address: "); Trace.Address(faultAdr); Trace.Ln;
- Trace.String("status: "); Trace.Address(faultStatus); Trace.Ln
- END;
- TraceState(state);
- Trace.Ln; Trace.StringLn("Kernel Halted.");
- Release(TraceOutput);
- LOOP END
- (*END*)
- END DefaultDataAbort;
- (* DefaultIRQ - default handler for IRQs *)
- PROCEDURE DefaultIRQ;
- BEGIN
- Acquire(TraceOutput);
- Trace.StringLn("(IRQ)");
- Trace.String(" CPU: "); Trace.Address(ID()); Trace.Ln;
- Trace.Ln; Trace.StringLn("Kernel Halted");
- Release(TraceOutput);
- LOOP END
- END DefaultIRQ;
- (* DefaultFIQ - default handler for fast interrupts *)
- (*PROCEDURE DefaultFIQ;
- BEGIN
- Trace.StringLn("Fast IRQ Trap");
- Trace.String(" CPU: "); Trace.Address(ID()); Trace.Ln;
- Trace.String("Kernel halted.");
- LOOP END
- END DefaultFIQ;*)
- PROCEDURE DefaultFIQ (VAR state: State);
- BEGIN
- Acquire(TraceOutput);
- Trace.StringLn("Fast IRQ Trap");
- Trace.String(" CPU: "); Trace.Address(ID()); Trace.Ln;
- Trace.String("Kernel halted.");
- Release(TraceOutput);
- LOOP END
- END DefaultFIQ;
- PROCEDURE DummyISR(VAR state: State);
- VAR i: LONGINT; icip : SET;
- BEGIN
- icip := SYSTEM.VAL(SET, SYSTEM.GET32((*IC +*) Platform.ICIP));
- FOR i:=MinIRQ TO MaxIRQ DO
- IF i IN icip THEN
- state.INT := i;
- dummyIRQHandler[state.INT].h(state);
- END;
- END;
- END DummyISR;
- (** EnableIRQ - enables a hardware interrupt (also done automatically by InstallHandler) *)
- PROCEDURE InEnableIRQ(num: LONGINT);
- BEGIN
- ASSERT((MinIRQ <= num) & (num<= MaxIRQ));
- (*IF TRUE OR (num = 53) THEN Trace.StringLn("Enable USB IRQ") END;*)
- SYSTEM.PUT32(Platform.ICDISER + 4 * (num DIV 32) , {num MOD 32});
- END InEnableIRQ;
- PROCEDURE EnableIRQ*(int: LONGINT);
- BEGIN
- Acquire(Interrupts);
- InEnableIRQ(int);
- Release(Interrupts)
- END EnableIRQ;
- (** DisableIRQ - disables a hardware interrupt (also done automatically by RemoveHandler) *)
- PROCEDURE InDisableIRQ(num: LONGINT);
- BEGIN
- ASSERT((MinIRQ <= num) & (num <= MaxIRQ));
- (*IF TRUE OR (num = 53) THEN Trace.StringLn("Disable USB IRQ") END;*)
- SYSTEM.PUT32(Platform.ICDICER + 4 * (num DIV 32) , {num MOD 32});
- END InDisableIRQ;
- PROCEDURE DisableIRQ*(int: LONGINT);
- BEGIN
- Acquire(Interrupts);
- InDisableIRQ(int);
- Release(Interrupts)
- END DisableIRQ;
- PROCEDURE IsIRQEnabled(int: LONGINT): BOOLEAN;
- VAR
- enabled: BOOLEAN;
- reg: SET;
- BEGIN
- Acquire(Interrupts);
- SYSTEM.GET(Platform.ICDISER + 4 * (int DIV 32) , reg);
- enabled := (int MOD 32) IN reg;
- Release(Interrupts);
- RETURN enabled
- END IsIRQEnabled;
- (** InstallHandler - installs a interrupt handler & enable IRQ if necessary.
- On entry to h interrupts are disabled and may be enabled with XXXXX. After handling the interrupt
- the state of interrupts are restored. The acknowledgement of a hardware interrupt is done automatically.
- IRQs are mapped from MinIRQ to MaxIRQ. *)
- PROCEDURE InstallHandler*(h: Handler; int: LONGINT);
- VAR
- i: LONGINT;
- BEGIN
- (*NEW(n);*) (* outside locked region, to allow gc *)
- i := 0;
- WHILE irqHandler[int, i] # NIL DO
- INC(i)
- END;
- Acquire(Interrupts);
- (* IRQGlue may traverse list while it is being modified. *)
- irqHandler[int, i] := h;
- IF DummyTest THEN
- irqHandler[int, i] := DummyISR;
- dummyIRQHandler[int].h := h;
- END;
- IF (int >= MinIRQ) & (int <= MaxIRQ) THEN InEnableIRQ(int) END;
- Release(Interrupts);
- IF traceInterrupts THEN
- Acquire(TraceOutput);
- Trace.String("[Machine]InstallHandler: h = 0x"); Trace.Address(SYSTEM.VAL(LONGINT, h));
- Trace.String("; int = "); Trace.Address(int);
- Trace.String("; IRQMask = 0x"); Trace.Address(SYSTEM.VAL(LONGINT, IRQMask));
- Trace.Ln;
- Release(TraceOutput)
- END
- END InstallHandler;
- PROCEDURE RemoveHandler * (h: Handler; int: LONGINT);
- END RemoveHandler;
- PROCEDURE InstallExceptionHandler * (h: Handler; e: LONGINT);
- BEGIN
- CASE e OF
- Undef: undefHandler := h
- |Swi: swiHandler := h
- |Prefetch: prefetchHandler := h
- |Data: dataHandler := h
- |Fiq: fiqHandler := h
- ELSE
- Trace.String("Unknown exception offset: ");
- Trace.Int(e, 0);
- Trace.Ln;
- HALT(99)
- END
- END InstallExceptionHandler;
- (*
- IRQGlue - every IRQ enters through this handler. It reads the IRR (Interrupt Request Register) of the PIC and calls the
- appropriate handlers for each pending IRQ. A problem (which caused a nice debugging session of ~1 day...) is this
- 'VAR state: State' parameter. Theoretically, a interrupt handler can change the values of this field to continue execution in
- a different process, e.g. the scheduler works that way. This means that we can't call the handlers of every pending IRQ in
- one loop - we must exit this procedure after each handled IRQ.
- - routine has been changed so that all handlers of pending interrupts will be called
- - using ICIP (interrupt Pending Register) instead of IRR (Interrupt Request Register)
- - after handler call we don't turn interrupts off explicitly
- *)
- PROCEDURE {NOPAF} IRQGlue;
- CODE
- CLREX
- SUB SP, SP, #72 ; Room for the State record
- STMIA SP, {R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, FP, SP, LR}^
- MOV R0, R0
- ADD SP, SP, #60
- SUB R0, LR, #4 ; return address = LR-4
- STR R0, [SP], #4 ; push ('PC' in 'State'). SP points to offset 64
- MRS R0, SPSR ; get saved PSR
- STR R0, [SP], #4 ; push ('PSR' in 'State'). SP points to offset 68
- SUB SP, SP, #68
- MOV R11, SP
- LDR R5, [pc, #state-$-8] ; load address of stateTag constant
- STR R5, [SP, #-4]! ; push value (type tag)
- STR R11, [SP, #-4]! ; push parameter (address of 'State' parameter)
- BL IRQCaller
- LDR R11, [SP], #4
- ADD SP, SP, #4
- ADD SP, SP, #72 ; adjust SP & remove PAF
- LDR R0, [R11, #64] ; load 'State.PSR'
- MSR SPSR_cxsf, R0 ; and store it into SPSR
- LDR R0, [R11, #60] ; load 'State.PC'...
- MOV LR, R0 ; ...into LR (because we will return to LR, not PC)
- ADD R0, R11, #48 ; R0 points to 'State.SP'
- LDMIA R0, { FP, SP, LR }^ ; load 'State.SP' & 'State.LR' into user mode registers
- MOV R0, R0 ; nop, to not access banked registers after LDM ^
- LDMIA R11, { R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10 } ; restore unbanked regs
- LDR R11, [R11, #44]
- MOVS PC, LR ; SPSR -> CPSR & return
- ; Data section
- state: d32 stateTag ; address of stateTag
- END IRQGlue;
- (** Calls all handlers for all pending IRQs.
- Is called by IRQGlue.
- *)
- PROCEDURE IRQCaller(VAR state: State);
- VAR i, reg, irq, ack, count: LONGINT; handler: Handler; icip: SET;
- BEGIN
- ack := SYSTEM.GET32(Platform.ICCIAR);
- (* service this irq *)
- irq := ack MOD 1024;
- IF irq # 1023 THEN (* not a spurious IRQ *)
- state.INT := irq;
- IF (MinIRQ <= irq) & (irq<= MaxIRQ) THEN
- count := 0;
- handler := irqHandler[irq, count];
- WHILE (handler # NIL) & (count < MaxIRQHandlers - 1) DO
- handler(state);
- DisableInterrupts; (* handler may have reactivated interrupts *)
- INC(count);
- handler := irqHandler[irq, count];
- END;
- SYSTEM.PUT32(Platform.ICCEOIR, ack);
- END;
- END;
- (* service pending IRQs *)
- FOR reg := 0 TO 2 DO
- SYSTEM.GET( Platform.ICDISPR+reg*4, icip );
- i := 0;
- WHILE (i <= 31) & (icip # {}) DO
- IF (i IN icip) THEN
- icip := icip - {i};
- irq := i+reg*32;
- (* Do not service pending interrupts that are disabled: this allows state triggered interrupts to be
- * handled by software in an interrupt process. *)
- IF IsIRQEnabled(irq) & (irq # PrivateTimerIRQ) THEN
- (*Trace.String("Pending IRQ "); Trace.Int(irq, 0); Trace.Ln;*)
- count := 0;
- state.INT := irq;
- handler := irqHandler[irq, count];
- WHILE (handler # NIL) & (count < MaxIRQHandlers - 1) DO
- handler(state);
- DisableInterrupts; (* handler may have reactivated interrupts *)
- INC(count);
- handler := irqHandler[irq, count]
- END;
- SYSTEM.PUT32(Platform.ICCEOIR, irq); (* end of interrupt *)
- SYSTEM.PUT32(Platform.ICDICPR+reg*4, {i}); (* clear pending bit *)
- END
- END;
- INC( i )
- END
- END;
- END IRQCaller;
- (** Undefined Exception Handler. Saves the processor state and calls the registered handler. *)
- PROCEDURE {NOPAF} undefGlue;
- CODE
- CLREX
- SUB SP, SP, #72 ; Room for the State record
- STMIA SP, {R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, FP, SP, LR}^
- MOV R0, R0
- ADD SP, SP, #60
- SUB R0, LR, #4 ; return address = LR-4
- STR R0, [SP], #4 ; push ('PC' in 'State'). SP points to offset 64
- MRS R0, SPSR ; get saved PSR
- STR R0, [SP], #4 ; push ('PSR' in 'State'). SP points to offset 68
- LDR R0, [PC, #undefined-8-$] ; save -Undef in the INT field
- STR R0, [SP], #4
- SUB SP, SP, #72
- MOV R11, SP
- LDR R5, [pc, #state-$-8] ; load address of stateTag constant
- STR R5, [SP, #-4]! ; push value (type tag)
- STR R11, [SP, #-4]! ; push parameter (address of 'State' parameter)
- LDR R0, [PC,#handler-8-$]
- LDR R0, [R0, #0]
- BLX R0
- LDR R11, [SP], #4
- ADD SP, SP, #4
- ADD SP, SP, #72 ; adjust SP & remove PAF
- LDR R0, [R11, #64] ; load 'State.PSR'
- MSR SPSR_cxsf, R0 ; and store it into SPSR
- LDR R0, [R11, #60] ; load 'State.PC'...
- MOV LR, R0 ; ...into LR (because we will return to LR, not PC)
- ADD R0, R11, #48 ; R0 points to 'State.SP'
- LDMIA R0, { FP, SP, LR }^ ; load 'State.SP' & 'State.LR' into user mode registers
- MOV R0, R0 ; nop, to not access banked registers after LDM ^
- LDMIA R11, { R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10 } ; restore unbanked regs
- LDR R11, [R11, #44]
- MOVS PC, LR ; SPSR -> CPSR & return
- ; Data section
- state: d32 stateTag ; address of stateTag
- handler: d32 undefHandler ; handler
- undefined: d32 -Undef ; INT number for undefined instructions
- END undefGlue;
- (**
- * Software Interrupt Handler. Saves the processor state and calls the registered handler.
- * The SWI number is stored into the INT field of the state record.
- *)
- PROCEDURE {NOPAF} SWIGlue;
- CODE
- SUB SP, SP, #72 ; Room for the State record
- STMIA SP, {R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, FP, SP, LR}^
- MOV R0, R0
- ADD SP, SP, #60
- SUB R1, LR, #4 ; return address = LR-4
- STR R1, [SP], #4 ; push ('PC' in 'State'). SP points to offset 64
- MRS R0, SPSR ; get saved PSR
- STR R0, [SP], #4 ; push ('PSR' in 'State'). SP points to offset 68
- LDR R0, [R1, #0] ; Load SWI instruction
- LDR R2, [PC, #HFFFFFF-8-$]
- AND R0, R0, R2 ; R0 MOD 1000000 = SWI number
- STR R0, [SP], #4 ; push SWI number as INT. SP points to offset 72
- SUB SP, SP, #72 ; Update SP to correct location
- MOV R11, SP
- LDR R5, [pc, #state-$-8] ; load address of stateTag constant
- STR R5, [SP, #-4]! ; push value (type tag)
- STR R11, [SP, #-4]! ; push parameter (address of 'State' parameter)
- LDR R0, [PC,#handler-8-$]
- LDR R0, [R0, #0]
- BLX R0
- LDR R11, [SP], #4
- ADD SP, SP, #4
- ADD SP, SP, #72 ; adjust SP & remove PAF
- LDR R0, [R11, #64] ; load 'State.PSR'
- MSR SPSR_cxsf, R0 ; and store it into SPSR
- LDR R0, [R11, #60] ; load 'State.PC'...
- MOV LR, R0 ; ...into LR (because we will return to LR, not PC)
- ADD R0, R11, #48 ; R0 points to 'State.SP'
- LDMIA R0, { FP, SP, LR }^ ; load 'State.SP' & 'State.LR' into user mode registers
- MOV R0, R0 ; nop, to not access banked registers after LDM ^
- LDMIA R11, { R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10 } ; restore unbanked regs
- LDR R11, [R11, #44]
- MOVS PC, LR ; SPSR -> CPSR & return
- ; Data section
- state: d32 stateTag ; address of stateTag
- HFFFFFF: d32 0FFFFFFH ; SWI number mask
- handler: d32 swiHandler ; swiHandler
- END SWIGlue;
- (**
- * Prefetch Abort Handler. Saves the processor state and calls the registered handler.
- * The PC field of the state record holds the address at which the prefetch fault occurred.
- *)
- PROCEDURE {NOPAF} prefetchGlue;
- CODE
- CLREX
- SUB SP, SP, #72 ; Room for the State record
- STMIA SP, {R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, FP, SP, LR}^
- MOV R0, R0
- ADD SP, SP, #60
- SUB R0, LR, #4 ; return address = LR-4
- STR R0, [SP], #4 ; push ('PC' in 'State'). SP points to offset 64
- MRS R0, SPSR ; get saved PSR
- STR R0, [SP], #4 ; push ('PSR' in 'State'). SP points to offset 68
- LDR R0, [PC, #prefetchAbort-8-$] ; save -Data in the INT field
- STR R0, [SP], #4
- SUB SP, SP, #72
- MOV R11, SP
- LDR R5, [pc, #state-$-8] ; load address of stateTag constant
- STR R5, [SP, #-4]! ; push value (type tag)
- STR R11, [SP, #-4]! ; push parameter (address of 'State' parameter)
- LDR R0, [PC,#handler-8-$]
- LDR R0, [R0, #0]
- BLX R0
- LDR R11, [SP], #4
- ADD SP, SP, #4
- ADD SP, SP, #72 ; adjust SP & remove PAF
- LDR R0, [R11, #64] ; load 'State.PSR'
- MSR SPSR_cxsf, R0 ; and store it into SPSR
- LDR R0, [R11, #60] ; load 'State.PC'...
- MOV LR, R0 ; ...into LR (because we will return to LR, not PC)
- ADD R0, R11, #48 ; R0 points to 'State.SP'
- LDMIA R0, { FP, SP, LR }^ ; load 'State.SP' & 'State.LR' into user mode registers
- MOV R0, R0 ; nop, to not access banked registers after LDM ^
- LDMIA R11, { R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10 } ; restore unbanked regs
- LDR R11, [R11, #44]
- MOVS PC, LR ; SPSR -> CPSR & return
- ; Data section
- state: d32 stateTag ; address of stateTag
- handler: d32 prefetchHandler ; handler
- prefetchAbort: d32 -Prefetch ; prefetch INT number
- END prefetchGlue;
- (**
- * Data Abort Handler. Saves the processor state and calls the registered handler.
- * Use procedure GetPageFault to get abort status and address.
- *)
- PROCEDURE {NOPAF} dataGlue;
- CODE
- CLREX
- SUB SP, SP, #72 ; Room for the State record
- STMIA SP, {R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, FP, SP, LR}^
- MOV R0, R0
- ADD SP, SP, #60
- SUB R0, LR, #8 ; return address = LR-8
- STR R0, [SP], #4 ; push ('PC' in 'State'). SP points to offset 64
- MRS R0, SPSR ; get saved PSR
- STR R0, [SP], #4 ; push ('PSR' in 'State'). SP points to offset 68
- LDR R0, [PC, #dataAbort-8-$] ; save -Data in the INT field
- STR R0, [SP], #4
- SUB SP, SP, #72
- MOV R11, SP
- LDR R5, [pc, #state-$-8] ; load address of stateTag constant
- STR R5, [SP, #-4]! ; push value (type tag)
- STR R11, [SP, #-4]! ; push parameter (address of 'State' parameter)
- LDR R0, [PC,#handler-8-$]
- LDR R0, [R0, #0]
- BLX R0
- LDR R11, [SP], #4
- ADD SP, SP, #4
- ADD SP, SP, #72 ; adjust SP & remove PAF
- LDR R0, [R11, #64] ; load 'State.PSR'
- MSR SPSR_cxsf, R0 ; and store it into SPSR
- LDR R0, [R11, #60] ; load 'State.PC'...
- MOV LR, R0 ; ...into LR (because we will return to LR, not PC)
- ADD R0, R11, #48 ; R0 points to 'State.SP'
- LDMIA R0, { FP, SP, LR }^ ; load 'State.SP' & 'State.LR' into user mode registers
- MOV R0, R0 ; nop, to not access banked registers after LDM ^
- LDMIA R11, { R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10 } ; restore unbanked regs
- LDR R11, [R11, #44]
- MOVS PC, LR ; SPSR -> CPSR & return
- ; Data section
- state: d32 stateTag ; address of stateTag
- handler: d32 dataHandler ; address of the handler variable
- dataAbort: d32 -Data
- END dataGlue;
- (** Fast Interrupt Handler. Saves the processor state and calls the registered handler *)
- PROCEDURE {NOPAF} fiqGlue;
- CODE
- CLREX
- SUB SP, SP, #72 ; Room for the State record
- STMIA SP, {R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, FP, SP, LR}^
- MOV R0, R0
- ADD SP, SP, #60
- SUB R0, LR, #4 ; return address = LR-4
- STR R0, [SP], #4 ; push ('PC' in 'State'). SP points to offset 64
- MRS R0, SPSR ; get saved PSR
- STR R0, [SP], #4 ; push ('PSR' in 'State'). SP points to offset 68
- SUB SP, SP, #68
- MOV R11, SP
- LDR R5, [pc, #state-$-8] ; load address of stateTag constant
- STR R5, [SP, #-4]! ; push value (type tag)
- STR R11, [SP, #-4]! ; push parameter (address of 'State' parameter)
- BL fiqHandler
- LDR R11, [SP], #4
- ADD SP, SP, #4
- ADD SP, SP, #72 ; adjust SP & remove PAF
- LDR R0, [R11, #64] ; load 'State.PSR'
- MSR SPSR_cxsf, R0 ; and store it into SPSR
- LDR R0, [R11, #60] ; load 'State.PC'...
- MOV LR, R0 ; ...into LR (because we will return to LR, not PC)
- ADD R0, R11, #48 ; R0 points to 'State.SP'
- LDMIA R0, { FP, SP, LR }^ ; load 'State.SP' & 'State.LR' into user mode registers
- MOV R0, R0 ; nop, to not access banked registers after LDM ^
- LDMIA R11, { R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10 } ; restore unbanked regs
- LDR R11, [R11, #44]
- MOVS PC, LR ; SPSR -> CPSR & return
- ; Data section
- state: d32 stateTag ; address of stateTag
- END fiqGlue;
- (** Initializes IRQ handling. *)
- PROCEDURE InitInterrupts*;
- CONST
- EnableSecure=0;
- EnableNonSecure=1;
- NumberIRQs = 96;
- VAR p: PROCEDURE; i: LONGINT;
- BEGIN
- Acquire(Interrupts);
- IRQMask := {};
- p := IRQGlue;
- SYSTEM.PUT32(InterruptVector + Irq, SYSTEM.VAL(LONGINT, p)); (* install new IRQ handler *)
- SYSTEM.PUT32(Platform.ICDDCR, 0);
- FOR i := 32 DIV 16 TO (NumberIRQs-1) DIV 16 (* 2 bits per IRQ *) DO
- SYSTEM.PUT32(Platform.ICDICFR+i*4, 0);
- END;
- FOR i := 0 TO (NumberIRQs-1) DIV 4 (* 8 bits per IRQ *) DO
- SYSTEM.PUT32(Platform.ICDIPR+i*4, LONGINT(0A0A0A0A0H)); (* set priority of each interrupt to 160 *)
- END;
- FOR i := (32 DIV 4) TO (NumberIRQs-1) DIV 4 (* 8 bits per IRQ *) DO
- SYSTEM.PUT32(Platform.ICDIPTR+i*4, 1010101H); (* reset interrupt targets to processor 0 *)
- END;
- (* disable all interrupt forwardings *)
- FOR i := 0 TO (NumberIRQs-1) DIV 32 (* 1 bit per IRQ *) DO
- SYSTEM.PUT32(Platform.ICDICER+i*4, LONGINT(0FFFFFFFFH));
- END;
- SYSTEM.PUT32(Platform.ICCPMR, 0F0H);
- SYSTEM.PUT32(Platform.ICCICR, {0,1,2});
- SYSTEM.PUT32(Platform.ICCBPR, 0);
- SYSTEM.PUT32(Platform.ICDDCR, {EnableSecure, EnableNonSecure});
- Release(Interrupts);
- (*InvalidateDCache(dCacheBase);*)
- (*EnableIRQ(PrivateTimerIRQ);*)
- END InitInterrupts;
- (** Restore silent, infinitly-looping exception handlers *)
- PROCEDURE EndInterrupts;
- BEGIN
- SYSTEM.PUT32(InterruptVector + Undef, InterruptVector + Undef);
- SYSTEM.PUT32(InterruptVector + Swi, InterruptVector + Swi);
- SYSTEM.PUT32(InterruptVector + Prefetch, InterruptVector + Prefetch);
- SYSTEM.PUT32(InterruptVector + Data, InterruptVector + Data);
- SYSTEM.PUT32(InterruptVector + Irq, InterruptVector + Irq);
- SYSTEM.PUT32(InterruptVector + Fiq, InterruptVector + Fiq);
- END EndInterrupts;
- (* GetExceptionState *)
- PROCEDURE GetExceptionState*(VAR int: State; VAR exc: ExceptionState);
- BEGIN
- (* save all state information while interrupts are still disabled *)
- exc.locks := BreakAll();
- IF int.INT = -Undef THEN
- exc.halt := 17;
- exc.instn := SYSTEM.GET32(int.PC)
- ELSIF int.INT = -Prefetch THEN
- exc.pf := int.PC;
- exc.status := -1;
- exc.halt := 19
- ELSIF int.INT = -Data THEN
- GetPageFault(exc.pf, exc.status);
- IF exc.pf < 4 * k THEN
- (* NIL pointer *)
- exc.halt := 18
- ELSE
- exc.halt := 19
- END
- ELSE
- (* SWI *)
- exc.halt := int.INT
- END
- END GetExceptionState;
- PROCEDURE GetPageFault * (VAR adr: ADDRESS; VAR status: LONGINT);
- CODE
- MRC p15, 0, R0, C5, C0 ; load fault status register (FSR)
- AND R0, R0, #0FFH ; only bits 7:0 are valid
- LDR R1, [FP, #status]
- STR R0, [R1, #0]
- MRC p15, 0, R0, C6, C0 ; load fault address (FAR)
- LDR R1, [FP, #adr]
- STR R0, [R1, #0]
- END GetPageFault;
- (* FAR - returns the Fault Address Register. *)
- PROCEDURE -FAR*(): LONGINT;
- CODE
- MRC p15, 0, R0, C6, C0 ; FAR is co-processor 15 register 6
- END FAR;
- (** Init global timer *)
- PROCEDURE InitGlobalTimer;
- CONST
- TimerEnable=0;
- BEGIN
- (* disable first *)
- SYSTEM.PUT32(Platform.GlobalTimerControlRegister, {});
- (* reset global counter *)
- SYSTEM.PUT32(Platform.GlobalTimerCounterRegister0, 0);
- SYSTEM.PUT32(Platform.GlobalTimerCounterRegister1, 0);
- SYSTEM.PUT32(Platform.GlobalTimerControlRegister, {TimerEnable});
- END InitGlobalTimer;
- (** Init private timer *)
- PROCEDURE InitTicks;
- CONST
- TimerEnable=0;
- AutoReload=1;
- IRQEnable=2;
- VAR
- (* time slot in private timer counts; take into account that private timer clock frequency is equal to half of the CPU clock frequency *)
- delay: LONGINT;
- BEGIN
- delay := ENTIER( ( LONGREAL(TimerPeriod) * 0.5D0 * LONGREAL(BootConfig.GetIntValue("CpuClockHz")) ) / 1.0D6 + 0.5D0 );
- (* disable first *)
- SYSTEM.PUT32(Platform.PrivateTimerControlRegister, {});
- (*SYSTEM.PUT32(Platform.PrivateTimerCounterRegister, Delay);*)
- SYSTEM.PUT32(Platform.PrivateLoadValueRegister, delay);
- SYSTEM.PUT32(Platform.PrivateTimerControlRegister, {TimerEnable, AutoReload, IRQEnable});
- END InitTicks;
- PROCEDURE StopTicks;
- BEGIN
- SYSTEM.PUT32(Platform.PrivateTimerControlRegister, {});
- END StopTicks;
- (** Handle multiprocessor timer interrupt. *)
- PROCEDURE HandleMPTimer*(VAR state: State);
- BEGIN (* {interrupts off} *)
- timer(ID(), state); (* rarely used *)
- (* Clear timer interrupt *)
- SYSTEM.PUT32(Platform.GlobalTimerInterruptStatusRegister, 1);
- EnableInterrupts; (* enable interrupts before acquiring locks below - to avoid deadlock with StopAll. *)
- Timeslice(state); (* fixme: check recursive interrupt *)
- END HandleMPTimer;
- (** Handle uniprocessor timer interrupt. *)
- PROCEDURE HandleUPTimer(VAR state: State);
- BEGIN (* {interrupts off} *)
- timer(ID(), state);
- SYSTEM.PUT32(Platform.PrivateTimerInterruptStatusRegister, 1);
-
- (* Shutdown if requested *)
- IF ~(ID() IN allProcessors) THEN ShutdownSecondary END;
- IF enableWatchdog THEN PrivateWatchdog.Feed(Second) END;
- Timeslice(state)
- END HandleUPTimer;
- (** Install a processor timer event handler. *)
- PROCEDURE InstallEventHandler* (h: EventHandler);
- BEGIN
- IF h # NIL THEN timer := h ELSE timer := DummyEvent END
- END InstallEventHandler;
- PROCEDURE DummyEvent*(id: LONGINT; CONST state: State);
- BEGIN
- END DummyEvent;
- PROCEDURE DummyTimeslice*(VAR state: State);
- BEGIN
- END DummyTimeslice;
- PROCEDURE DummyIRQ*;
- BEGIN
- END DummyIRQ;
- PROCEDURE IRQBeginPrinter;
- BEGIN
- Trace.StringLn("IRQ BEGIN");
- END IRQBeginPrinter;
- PROCEDURE IRQEndPrinter;
- BEGIN
- Trace.StringLn("IRQ END");
- END IRQEndPrinter;
- (* Timer interrupt handler. *)
- PROCEDURE TimerInterruptHandler(VAR state: State);
- BEGIN
- IF ID() = 0 THEN
- INC(ticks);
- DEC(eventCount);
- IF eventCount = 0 THEN
- eventCount := eventMax; event(state)
- END;
- END
- END TimerInterruptHandler;
- (* Set timer upcall. The handler procedure will be called at a rate of Second/divisor Hz. *)
- PROCEDURE InstallTickHandler(handler: Handler; divisor: LONGINT);
- BEGIN
- eventMax := divisor; event := handler;
- eventCount := eventMax
- END InstallTickHandler;
- (* ===== Low-Level Locks ===== *)
- (* Initializes spinlocks. This is not exported in Intel version. *)
- PROCEDURE InitLocks;
- VAR
- i: LONGINT;
- BEGIN
- FOR i := 0 TO MaxLock - 1 DO
- lock[i].locked := FALSE
- END;
- END InitLocks;
- PROCEDURE AcquirePreemption*(): LONGINT;
- VAR
- id: LONGINT;
- BEGIN
- id := ID();
- INC(proc[id].preemptCount);
- RETURN id
- END AcquirePreemption;
- PROCEDURE ReleasePreemption*;
- VAR
- id: LONGINT;
- BEGIN
- id := ID();
- IF StrongChecks THEN
- ASSERT(proc[id].preemptCount > 0);
- END;
- DEC(proc[id].preemptCount);
- END ReleasePreemption;
- PROCEDURE PreemptCount*(id: LONGINT): LONGINT;
- BEGIN
- IF StrongChecks THEN
- ASSERT(id = ID());
- END;
- RETURN proc[id].preemptCount;
- END PreemptCount;
- (* Acquire lock. Disables interrupts. *)
- PROCEDURE Acquire*(level: LONGINT);
- VAR
- id: LONGINT;
- enabled: BOOLEAN;
- BEGIN
- enabled := AreInterruptsEnabled();
- DisableInterrupts();
- id := AcquirePreemption();
- IF proc[id].locksHeld = {} THEN
- proc[id].intStatus := enabled
- END;
- IF StrongChecks THEN
- ASSERT(~AreInterruptsEnabled());
- ASSERT((~enabled) OR (proc[id].locksHeld = {})); (* interrupts enabled => no locks held *)
- ASSERT(~(level IN proc[id].locksHeld)) (* recursive locks not allowed *)
- END;
- AcquireObject(lock[level].locked);
- (* Now, we hold the lock *)
- INCL(proc[id].locksHeld, level);
- IF StrongChecks THEN (* no lower-level locks currently held by this processor *)
- ASSERT((level = 0) OR (proc[id].locksHeld * {0..level-1} = {}));
- END;
- END Acquire;
- (* Release lock. Enables interrupts if last lock held. *)
- PROCEDURE Release*(level: LONGINT);
- VAR
- id: LONGINT;
- BEGIN
- id := ID();
- IF StrongChecks THEN
- ASSERT(~AreInterruptsEnabled());
- ASSERT(level IN proc[id].locksHeld);
- ASSERT(lock[level].locked # FALSE)
- END;
- EXCL(proc[id].locksHeld, level);
- ReleaseObject(lock[level].locked);
- ReleasePreemption;
- IF (proc[id].locksHeld = {}) & proc[id].intStatus THEN
- EnableInterrupts
- END;
- END Release;
- PROCEDURE AcquireAll*;
- VAR
- i: LONGINT;
- BEGIN
- FOR i := MaxLock - 1 TO 0 BY -1 DO
- Acquire(i)
- END
- END AcquireAll;
- PROCEDURE ReleaseAll*;
- VAR
- i: LONGINT;
- BEGIN
- FOR i := 0 TO MaxLock - 1 DO
- Release(i)
- END
- END ReleaseAll;
- (** Acquire a fine-grained lock on an active object. *)
- (* Based on the code from "Barrier Litmus Tests and Cookbook" by Richard Grisenthwaite, ARM, 26.11.2009 *)
- PROCEDURE AcquireObject*(VAR locked: BOOLEAN);
- CODE
- CLREX ; ensure that the local monitor is in the Open Access state after a context switch
- LDR R1, [FP, #locked]
- MOV R0, #1
- Loop:
- LDREXB R5, R1 ; read lock
- CMP R5, #0 ; check if 0
- WFENE ; sleep if the lock is held
- STREXBEQ R5, R0, R1 ; attempt to store new value
- CMPEQ R5, #0 ; test if store suceeded
- BNE Loop ; retry if not
- DMB ; ensures that all subsequent accesses are observed after the gaining of the lock is observed
- ; loads and stores in the critical region can now be performed
- END AcquireObject;
- (** Release an active object lock. *)
- (* Based on the code from "Barrier Litmus Tests and Cookbook" by Richard Grisenthwaite, ARM, 26.11.2009 *)
- PROCEDURE ReleaseObject*(VAR locked: BOOLEAN);
- CODE
- LDR R1, [FP, #locked]
- MOV R0, #0
- DMB ; ensure all previous accesses are observed before the lock is cleared
- STRB R0, [R1, #0] ; clear the lock.
- DSB ; ensure completion of the store that cleared the lock before sending the event
- SEV
- END ReleaseObject;
- (** Break all locks held by current processor (for exception handling). Returns levels released. *)
- PROCEDURE BreakAll*(): SET;
- VAR id, level: LONGINT; released: SET;
- BEGIN
- id := AcquirePreemption();
- released := {};
- FOR level := 0 TO MaxLock-1 DO
- IF level IN proc[id].locksHeld THEN
- lock[level].locked := FALSE; (* break the lock *)
- EXCL(proc[id].locksHeld, level);
- INCL(released, level)
- END
- END;
- (*IF released = {} THEN
- ASSERT(proc[id].nestCount = 0) (* no locks held *)
- ELSE
- ASSERT(proc[id].nestCount > 0); (* some locks held *)
- proc[id].nestCount := 0 (* interrupt state will be restored later *)
- END;*)
- IF proc[id].preemptCount > 1 THEN INCL(released, Preemption) END;
- proc[id].preemptCount := 0; (* clear preemption flag *)
- RETURN released
- END BreakAll; (* !!! interrupts are still off !!! *)
- (* ===== Atomic Operations ===== *)
- (* Atomic INC(x) *)
- PROCEDURE -AtomicInc*(VAR x: LONGINT);
- CODE
- ;loop:
- ; ADD R0, SP, #x ; R0 := ADR(x)
- ; LDREX R1, R0 ; R1 := x
- ; ADD R1, R1, #1 ; increment x
- ; STREX R2, R1, R0
- ; CMP R2, #0
- ; BEQ loop ; if store failed, try again, else exit
- ; ADD SP, SP, #4
- LDR R0, [SP], #4
- loop:
- LDREX R1, R0
- ADD R1, R1, #1
- STREX R2, R1, R0
- CMP R2, #0
- BNE loop
- END AtomicInc;
-
- (* Atomic INC(x) *)
- PROCEDURE -AtomicDec*(VAR x: LONGINT);
- CODE
- LDR R0, [SP], #4
- loop:
- LDREX R1, R0
- SUB R1, R1, #1
- STREX R2, R1, R0
- CMP R2, #0
- BNE loop
- END AtomicDec;
- PROCEDURE -AtomicAdd * (VAR x: LONGINT; y: LONGINT);
- CODE
- LDR R3, [SP, #y] ; R3 := y
- LDR R0, [SP, #x] ; R0 := ADR(x)
- loop:
- LDREX R1, R0 ; R1 := x
- ADD R1, R1, R3 ; increment x
- STREX R2, R1, R0
- CMP R2, #0
- BNE loop ; if store failed, try again, else exit
- ADD SP, SP, #8
- END AtomicAdd;
- (* Atomic compare-and-swap. Set x = new if x = old and return old value of x *)
- PROCEDURE -AtomicCAS * (VAR x: LONGINT; old, new: LONGINT): LONGINT;
- CODE
- LDR R3, [SP, #x] ; R0 := ADDRESSOF(x)
- LDR R1, [SP, #old] ; R1 := old
- LDR R2, [SP, #new] ; R2 := new
- ADD SP, SP, #12 ; pop variable from stack
- loop:
- LDREX R0, R3 ; load excl x
- CMP R0, R1
- BNE exit ; x # old -> exit
- STREX R4, R2, R3 ; x = old -> store excl new -> x
- CMP R4, #0
- BNE loop ; store exclusive failed: retry
- exit:
- END AtomicCAS;
- (* ===== Virtual Memory Management ===== *)
- PROCEDURE Ensure32BitAddress*(adr: ADDRESS): LONGINT;
- BEGIN
- RETURN adr
- END Ensure32BitAddress;
- PROCEDURE GetSecondLevelEntry(virtualAddress: ADDRESS): ADDRESS;
- VAR
- ptIdx, basePT, entry: ADDRESS;
- BEGIN
- IF (PS <= virtualAddress) & (virtualAddress < M) THEN
- (* First 256 entries *)
- basePT := sysSecondLvlPtStart
- ELSIF (4 * G - M <= virtualAddress) THEN
- (* Entries 256 to 511 *)
- basePT := sysSecondLvlPtStart + 400H
- ELSIF (memStackStart <= virtualAddress) & (virtualAddress < memStackStop) THEN
- basePT := sysSecondLvlPtStart + 800H + virtualAddress DIV M * k - memStackStart DIV k
- ELSIF (memConfigStart <= virtualAddress) & (virtualAddress < memConfigStop) THEN
- basePT := sysSecondLvlPtStop - (memConfigStop DIV k - virtualAddress DIV M * k)
- END;
- ptIdx := SHR(virtualAddress MOD M, PSlog2);
- ASSERT(basePT + 4 * ptIdx >= sysSecondLvlPtStart);
- ASSERT(basePT + 4 * ptIdx < sysSecondLvlPtStop);
- entry := SYSTEM.GET32(basePT + 4 * ptIdx);
- RETURN entry
- END GetSecondLevelEntry;
- PROCEDURE SetSecondLevelEntry(virtualAddress, physicalAddress, flags: ADDRESS);
- VAR ptIdx, basePT, entry: ADDRESS;
- firstLvlEntry: ADDRESS;
- BEGIN
- IF (PS <= virtualAddress) & (virtualAddress < M) THEN
- (* First 256 entries *)
- basePT := sysSecondLvlPtStart
- ELSIF (4 * G - M <= virtualAddress) THEN
- (* Entries 256 to 511 *)
- basePT := sysSecondLvlPtStart + 400H
- ELSIF (memStackStart <= virtualAddress) & (virtualAddress < memStackStop) THEN
- basePT := sysSecondLvlPtStart + 800H + virtualAddress DIV M * k - memStackStart DIV k
- ELSIF (memConfigStart <= virtualAddress) & (virtualAddress < memConfigStop) THEN
- basePT := sysSecondLvlPtStop - (memConfigStop DIV k - virtualAddress DIV M * k)
- END;
- ptIdx := SHR(virtualAddress MOD M, PSlog2);
- IF physicalAddress = NilAdr THEN
- entry := slFault
- ELSE
- ASSERT(physicalAddress MOD PS = 0);
- ASSERT((flags DIV PS = 0) & (flags MOD 4 = 0));
- entry := physicalAddress + flags + slSmall
- END;
- ASSERT(basePT + 4 * ptIdx >= sysSecondLvlPtStart);
- ASSERT(basePT + 4 * ptIdx < sysSecondLvlPtStop);
- SYSTEM.PUT32(basePT + 4 * ptIdx, entry);
- END SetSecondLevelEntry;
- PROCEDURE UnmapPhysical*(viartAdr: ADDRESS; size: SIZE);
- BEGIN
- END UnmapPhysical;
- (* Unmap a virtual page and deallocate the corresponding physical page *)
- PROCEDURE DeallocatePage(virtualAdr: ADDRESS);
- VAR memoryAdr: LONGINT;
- BEGIN
- (* unmap the page *)
- memoryAdr := GetSecondLevelEntry(virtualAdr);
- ASSERT(memoryAdr MOD 4 = slSmall); (* page must be mapped *)
- SYSTEM.PUT32(virtualAdr, freePage); (* link freePage list (must be done as long as the page is still mapped !) *)
- SetSecondLevelEntry(virtualAdr, NilAdr, 0);
- InvalidateTLBEntry(SHRL(virtualAdr, PSlog2));
- (* free the page *)
- memoryAdr := SHRL(memoryAdr, 12);
- freePage := memoryAdr;
- INC(memory.free, PS)
- END DeallocatePage;
- (* AllocatePage - allocates and maps one memory page to [virtualAdr...virtualAdr+PageSize]. Returns TRUE iff successful *)
- PROCEDURE AllocatePage(virtualAdr, accessPermissions, flags: ADDRESS): BOOLEAN;
- VAR memoryAdr, entry: ADDRESS;
- BEGIN
- (* Use 1:1 Mapping for stack *)
- (* map the page *)
- entry := GetSecondLevelEntry(virtualAdr);
- IF entry MOD 4 # slFault THEN
- Acquire(TraceOutput);
- Trace.String("Allocate Page: entry = ");
- Trace.Address(entry);
- Trace.String("; vadr = ");
- Trace.Address(virtualAdr);
- Trace.String("; CPU = ");
- Trace.Int(ID(), 0);
- Trace.Ln;
- Release(TraceOutput)
- END;
- ASSERT(entry MOD 4 = slFault); (* page must not be mapped *)
- SetSecondLevelEntry(virtualAdr, (*memoryAdr*) virtualAdr, accessPermissions + flags);
- InvalidateTLBEntry(SHRL(virtualAdr, PSlog2));
- RETURN TRUE
- END AllocatePage;
- (** PhysicalAdr - returns the (real) physical address of the specified range of memory, or NilAdr if the range is not contiguous.
- It is the caller's responsiblilty to assure the range remains allocated during the time it is in use.
- *)
- PROCEDURE PhysicalAdr*(adr, size: LONGINT): LONGINT;
- VAR physAdr: ARRAY 400H OF Range; num, i, end: LONGINT;
- BEGIN
- TranslateVirtual(adr, size, num, physAdr);
- IF (num > 0) THEN
- FOR i := 1 TO num-1 DO
- IF (physAdr[i].adr # (physAdr[i-1].adr + physAdr[i-1].size)) THEN
- RETURN NilAdr
- END
- END;
- RETURN physAdr[0].adr
- ELSE
- RETURN NilAdr
- END
- END PhysicalAdr;
- (** TranslateVirtual - translates a virtual address range to num ranges of (real) physical addresses. num returns 0 on error.*)
- PROCEDURE TranslateVirtual*(virtAdr: ADDRESS; size: LONGINT; VAR num: LONGINT; VAR physAdr: ARRAY OF Range);
- VAR entry, base, ofs, len: LONGINT; endAdr: ADDRESS; abort: BOOLEAN;
- BEGIN
- Acquire(Memory);
- endAdr := virtAdr + size;
- IF ((memHeapStart <= virtAdr) & (endAdr <= memHeapStop)) OR ((memStackStart <= virtAdr) & (endAdr <= memStackStop)) OR ((memIOStart <= virtAdr) & (endAdr <= memIOStop)) THEN
- (* Optimizations: we know that heap, stacks and I/O regions are mapped 1:1. *)
- (*! This code is very aggressive: it returns only 1 range, and not 1 range per physical page. It assumes that all stack pages of the specified region are mapped *)
- num := 1;
- physAdr[0].adr := virtAdr;
- physAdr[0].size := size;
- ELSE
- abort := FALSE;
- num := 0;
- WHILE (size > 0) & (num < LEN(physAdr)) & ~abort DO
- entry := (*SYSTEM.GET32(pageTable.virtual + 4*SHR(virtAdr, LogM));*)GetFirstLevelEntry(virtAdr - virtAdr MOD M);
- IF (entry MOD 4 = flSection) THEN
- ofs := virtAdr MOD M;
- len := MIN(size, M - ofs);
- physAdr[num].adr := SHRL(entry, LogM) + ofs;
- physAdr[num].size := len;
- INC(num);
- INC(virtAdr, len); DEC(size, len)
- ELSIF (entry MOD 4 = flCoarse) THEN
- base := SHRL(entry, 10);
- WHILE (size > 0) & (num < LEN(physAdr)) & ~abort DO
- entry := GetSecondLevelEntry(virtAdr);
- IF (entry MOD 4 = slSmall) THEN
- ofs := virtAdr MOD PS;
- len := MIN(size, PS - ofs);
- physAdr[num].adr := SHRL(entry, 12) + ofs;
- physAdr[num].size := len;
- INC(num);
- INC(virtAdr, len); DEC(size, len)
- ELSE
- num := 0;
- abort := TRUE
- END
- END
- ELSE
- num := 0; abort := TRUE
- END;
- END;
- IF (size > 0) & (num = LEN(physAdr)) THEN num := 0 END; (* array 'physAdr' was too small *)
- END;
- Release(Memory)
- END TranslateVirtual;
- PROCEDURE SetFirstLevelEntry (virtual, physical: ADDRESS; permissions, flags, type: LONGINT);
- VAR
- index, entry: LONGINT;
- BEGIN
- index := SHR(virtual, LogM) * 4;
- ASSERT(index >= 0);
- ASSERT(sysFirstLvlPtStart + index < sysFirstLvlPtStop);
- entry := physical + permissions * 400H + flags + type;
- (*Trace.Address(virtual); Trace.String(" "); Trace.Address(physical); Trace.String(" "); Trace.Address(SysFirstLvlPtStart(*pageTable.virtual*) + index); Trace.String(" "); Trace.Address(entry); Trace.Ln;*)
- SYSTEM.PUT32(sysFirstLvlPtStart + index, entry)
- END SetFirstLevelEntry;
- PROCEDURE GetFirstLevelEntry (virtual: ADDRESS): LONGINT;
- VAR
- index: LONGINT;
- BEGIN
- index := LSH(virtual, -(LogM)) * 4;
- ASSERT(index >= 0);
- ASSERT(sysFirstLvlPtStart + index < sysFirstLvlPtStop);
- RETURN SYSTEM.GET32(sysFirstLvlPtStart + index)
- END GetFirstLevelEntry;
- (* AllocateHeap - allocates and maps [physicalAddress...physicalAddress+size] to [virtualAddress...virtualAddress+size] *)
- PROCEDURE AllocateHeap(virtualAddress, physicalAddress, size: ADDRESS; accessPermissions, flags: LONGINT);
- VAR i, entry: LONGINT;
- BEGIN
- ASSERT(size MOD M = 0);
- FOR i := 0 TO (size DIV M) - 1 DO
- entry := GetFirstLevelEntry(virtualAddress + i * M);
- ASSERT(entry = 0);
- SetFirstLevelEntry(virtualAddress + i * M, physicalAddress + i * M, accessPermissions, flags, flSection)
- END
- END AllocateHeap;
- (** Enable Memory Management and virtual memory. *)
- PROCEDURE EnableMM(translationBase, tbFlags, mmuFlags: ADDRESS);
- BEGIN
- InvalidateTLB;
- CODE
- ; Disable AFE (special permission mode) and TRE (special memory mode)
- ldr r0, [pc, #pattern-$-8]
- mrc p15, 0, r1, c1, c0, 0
- and r1, r0, r1
- mcr p15, 0, r1, c1, c0, 0
- isb
- ;mrc p15, 0, r0, c2, c0, 2
- ;ldr r1, [pc, #TLBCRPattern-$-8]
- ;and r0, r0, r1
- ;mcr p15, 0, r0, c2, c0, 2
- ldr r0, [FP, #translationBase]
- ldr r1, [fp, #tbFlags]
- orr r0, r0, r1
- mcr p15, 0, r0, c2, c0, 0
- isb
- ;mvn r0, #0 ; mmu domains: 16 x 11 = manager on all domains
- ldr r0, [pc, #domains-$-8]
- mcr p15, 0, r0, c3, c0, 0
- isb
- ldr r0, [FP, #mmuFlags]
- ldr r1, [FP, #sctlr-$-8]
- orr r0, r0, r1 ; 1 bits in SCTLR
- mcr p15, 0, r0, c1, c0, 0
- isb
- ;dsb
- ;isb
- b exit
- domains: d32 55555555H ; Client on each domain
- pattern: d32 0CFFFFFFFH ; NOT(AFE+TRE)
- sctlr: d32 0C50078H
- TLBCRPattern: d32 0FFFFFFF8H
- exit:
- END;
- proc[ID()].mmu := TRUE
- END EnableMM;
- PROCEDURE InitMemory;
- VAR
- cr1: SET;
- i: LONGINT;
- base: ADDRESS;
- coarseFlags, fineFlags, tbFlags: LONGINT;
- trace: BOOLEAN;
- val: ARRAY 8 OF CHAR;
- BEGIN
- BootConfig.GetValue("TraceMemory", val);
- trace := val = '1';
- IF trace THEN
- (* Debug Tracing *)
- Trace.String("Memory Layout");
- IF ~enableCaching THEN Trace.String(" - WARNING: Caching Disabled") END;
- Trace.Ln;
- Trace.String("System Start: "); Trace.Address(memSysLowStart); Trace.Ln;
- Trace.String("System Stop: "); Trace.Address(memSysLowStop); Trace.Ln;
- Trace.String("System Size: "); Trace.Address(memSysLowStop - memSysLowStart); Trace.Ln;
- Trace.String(" Interrupt Stack Start: "); Trace.Address(sysIntStackStart); Trace.Ln;
- Trace.String(" Interrupt Stack Stop: "); Trace.Address(sysIntStackStop); Trace.Ln;
- Trace.String(" Interrupt Stack Size: "); Trace.Address(sysIntStackStop - sysIntStackStart); Trace.Ln;
- Trace.String(" First Page Table Start: "); Trace.Address(sysFirstLvlPtStart); Trace.Ln;
- Trace.String(" First Page Table Stop: "); Trace.Address(sysFirstLvlPtStop); Trace.Ln;
- Trace.String(" First Page Table Size: "); Trace.Address(sysFirstLvlPtStop - sysFirstLvlPtStart); Trace.Ln;
- Trace.String(" Second Page Table Start: "); Trace.Address(sysSecondLvlPtStart); Trace.Ln;
- Trace.String(" Second Page Table Stop: "); Trace.Address(sysSecondLvlPtStop); Trace.Ln;
- Trace.String(" Second Page Table Size: "); Trace.Address(sysSecondLvlPtStop - sysSecondLvlPtStart); Trace.Ln;
- Trace.String("Heap Start: "); Trace.Address(memHeapStart); Trace.Ln;
- Trace.String("Heap Stop: "); Trace.Address(memHeapStop); Trace.Ln;
- Trace.String("Heap Size: "); Trace.Address(memHeapStop - memHeapStart); Trace.Ln;
- Trace.String("Stack Start: "); Trace.Address(memStackStart); Trace.Ln;
- Trace.String("Stack Stop: "); Trace.Address(memStackStop); Trace.Ln;
- Trace.String("Stack Size: "); Trace.Address(memStackStop - memStackStart); Trace.Ln;
- Trace.String("Config Start: "); Trace.Address(memConfigStart); Trace.Ln;
- Trace.String("Config Stop: "); Trace.Address(memConfigStop); Trace.Ln;
- Trace.String("Config Size: "); Trace.Address(memConfigStop - memConfigStart); Trace.Ln;
- Trace.String("I/O Start: "); Trace.Address(memIOStart); Trace.Ln;
- Trace.String("I/O Stop: "); Trace.Address(memIOStop); Trace.Ln;
- Trace.String("I/O Size: "); Trace.Address(memIOStop - memIOStart); Trace.Ln;
- Trace.String("SysHigh Start: "); Trace.Address(memSysHighStart); Trace.Ln;
- Trace.String("SysHigh Stop: "); Trace.Hex(memSysHighStop - 1, -8); Trace.Ln;
- Trace.String(" Interrupt Vector Start: "); Trace.Address(sysVectorStart); Trace.Ln;
- Trace.String(" Interrupt Vector Stop: "); Trace.Address(sysVectorStop); Trace.Ln;
- Trace.String(" Interrupt Vector Size: "); Trace.Address(sysVectorStop - sysVectorStart); Trace.Ln;
- Trace.String(" Cache References Start: "); Trace.Address(sysCacheRefStart); Trace.Ln;
- Trace.String(" Cache References Stop: "); Trace.Address(sysCacheRefStop); Trace.Ln;
- Trace.String(" Cache References Size: "); Trace.Address(sysCacheRefSize); Trace.Ln;
- Trace.String(" Cache References Stack Offset: "); Trace.Address(sysCacheStackOfs); Trace.Ln;
- END;
- (* disable caching & buffering globally *)
- cr1 := GetControlRegister();
- SetControlRegister(cr1 - {DCache, ICache});
- (*InvalidateDCache(dCacheBase);*)
- (*InvalidateDCacheRange(0, MemStackStop);*)
- InvalidateICache;
- DrainWriteBuffer;
- (* initialize memory ranges *)
- heapLow.physical := memHeapStart;
- heapLow.virtual := memHeapStart;
- heapHigh.physical := memHeapStop;
- heapHigh.virtual := memHeapStart;
- stackHigh.physical := memStackStop;
- stackHigh.virtual := memStackStop;
- stackLow.physical := memStackStop;
- stackLow.virtual := memStackStart;
- (* initialize global variables *)
- pageTable.virtual := sysFirstLvlPtStart;
- pageTable.memory := sysFirstLvlPtStart;
- stackPT := sysSecondLvlPtStart + 2 * k;
- freePage := NilAdr;
- (* Determine global caching parameter *)
- IF enableCaching THEN
- coarseFlags := Cacheable + Shareable;
- fineFlags := CB
- ELSE
- coarseFlags:= Shareable;
- fineFlags := 0;
- END;
- (* Clear first level page table *)
- Fill32(sysFirstLvlPtStart, sysFirstLvlPtStop - sysFirstLvlPtStart, 0);
- (* Clear second level page table *)
- Fill32(sysSecondLvlPtStart, sysSecondLvlPtStop - sysSecondLvlPtStart, 0);
- (* Map system area *)
- SetFirstLevelEntry(0, sysSecondLvlPtStart, 0, 0, flCoarse);
- FOR i := 1 TO 0FFH DO
- SetSecondLevelEntry(PS * i, PS * i, FullAccess + fineFlags);
- END;
- (* Map page for high part of OCM *)
- AllocateHeap(memSysHighStart, memSysHighStart, MAX(M, LONGINT(memSysHighStop - memSysHighStart)), SrwUrw, coarseFlags);
- (* Map heap area *)
- AllocateHeap(memHeapStart, memHeapStart, memHeapStop - memHeapStart, SrwUrw, coarseFlags);
- (* Map I/O area, device-type, shared memory *)
- AllocateHeap(memIOStart, memIOStart, memIOStop - memIOStart, SrwUrw, Shareable + B);
- (* initialize stack & config page tables (excluding the last MB that is already initalized) *)
- base := SHR(memStackStart, LogM);
- FOR i := memStackStart TO memConfigStop - 1 BY M DO
- SetFirstLevelEntry(i, sysSecondLvlPtStart + 2 * k + PTSize * (SHR(i, LogM) - base), 0, 0, flCoarse)
- END;
- (* Map config region directly *)
- FOR i := 0 TO SHR(memConfigStop - memConfigStart, PSlog2) - 1 DO
- SetSecondLevelEntry(memConfigStart + PS * i, memConfigStart + PS * i, FullAccess + fineFlags)
- END;
- (* flush all caches & the write buffer and invalidate both TLBs *)
- FlushDCacheRange(0, SYSTEM.VAL(ADDRESS, LastAddress));
- InvalidateICache;
- DrainWriteBuffer;
- InvalidateTLB;
- (* get memory size *)
- memory.size := memHeapStop - memHeapStart;
- memory.free := memory.size;
- (* get heap size (check how many MBs are allocated) *)
- heapLow.physical := 1*M; heapLow.virtual := memHeapStart;
- heapHigh.physical := 1*M;
- i := SHR(memHeapStart, LogM);
- WHILE (SYSTEM.GET32(pageTable.virtual + i*4) MOD 4 = flSection) DO
- INC(heapHigh.physical, M);
- DEC(memory.free, M);
- INC(i)
- END;
- heapHigh.virtual := heapLow.virtual + heapHigh.physical - heapLow.physical;
- (* allocate empty memory block with enough space for at least one free block *)
- memBlockHead := SYSTEM.VAL (MemoryBlock, ADDRESSOF (initialMemBlock));
- memBlockTail := memBlockHead;
- initialMemBlock.beginBlockAdr := SYSTEM.VAL (ADDRESS, LastAddress);
- initialMemBlock.endBlockAdr := heapHigh.virtual;
- initialMemBlock.size := initialMemBlock.endBlockAdr - initialMemBlock.beginBlockAdr;
- initialMemBlock.next := NIL;
- freeStackIndex := 0;
- (* init stack bitmap *)
- FOR i := 0 TO (maxUserStacks) DIV 32 - 1 DO
- freeStack[i] := {0..31};
- END;
- freeStack[(maxUserStacks) DIV 32] := {0 .. (LONGINT(maxUserStacks) MOD 32) - 1};
- freeStackIndex := 0;
- (* Init cache ref counts *)
- cacheRefs := sysCacheRefStart;
- Fill32(sysCacheRefStart, sysCacheRefSize, 0);
- IF enableCaching THEN
- tbFlags := 7BH
- ELSE
- tbFlags := 0
- END;
- (* Copy interrupt vector *)
- SYSTEM.MOVE(0, 0FFFF0000H, 4096);
- EnableMM(sysFirstLvlPtStart, tbFlags, 2000H + 1007H);
- END InitMemory;
- (** GetFreeK - returns information on free memory in Kbytes.*)
- PROCEDURE GetFreeK*(VAR total, lowFree, highFree: SIZE);
- BEGIN
- Acquire(Memory);
- total := SHR(memory.size, 10);
- lowFree := 0;
- highFree := SHR(memory.free, 10);
- Release(Memory)
- END GetFreeK;
- (* ===== Stack Management ===== *)
- (** Extend stack to address. Returns TRUE iff done.
- * If a procedure that holds Memory needs triggers a stack extension, this procedure is called by the interrupt handler:
- * we get a trap because Acquire is not reentrant. To solve this, we do not acquire memory iff:
- * - we are in interrupt mode
- * - the current processor holds Memory already
- *)
- PROCEDURE ExtendStack*(VAR s: Stack; virtAdr: ADDRESS): BOOLEAN;
- VAR
- ok, doLock: BOOLEAN;
- access, psr, flags: LONGINT;
- BEGIN
- IF enableCaching THEN
- flags := CB
- ELSE
- flags := 0
- END;
- SYSTEM.STPSR(0, psr);
- (* Need to acquire Memory: if we are not in interrupt mode or if we do not hold this lock yet. *)
- doLock := ~(Memory IN proc[ID()].locksHeld);
- IF doLock THEN Acquire(Memory) END;
- ok := FALSE;
- IF (virtAdr < s.high) & (virtAdr >= s.low) THEN
- (* Get page boundary *)
- DEC(virtAdr, virtAdr MOD PS);
- (* Check if page is mapped *)
- (*InvalidateDCacheRange(memSysLowStart, memSysLowStop - memSysLowStart);*)
- Initializer.InvalidateDCache;
- IF (GetSecondLevelEntry(virtAdr) MOD 4 = slSmall) THEN
- InvalidateTLBEntry(virtAdr);
- Acquire(TraceOutput);
- Trace.String("Stack address already mapped: ");
- Trace.Address(virtAdr); Trace.Ln;
- Release(TraceOutput)
- ELSE
- (* Allocate page: set different permissions for last stack page. *)
- (*IF (virtAdr <= s.low) THEN HALT(100) ELSE access := FullAccess END;*)
- access := FullAccess;
- ok := AllocatePage(virtAdr, access, flags);
- IF virtAdr < s.adr THEN
- s.adr := virtAdr
- END
- END
- ELSE
- Acquire(TraceOutput);
- Trace.StringLn("Address not in stack");Trace.Address(virtAdr);
- Release(TraceOutput);
- ok := FALSE
- END;
- IF doLock THEN Release(Memory) END;
- RETURN ok
- END ExtendStack;
- (** Create a new stack s, for process with the initial stack pointer initSP. *)
- PROCEDURE NewStack*(VAR s: Stack; process: ANY; VAR initSP: ADDRESS);
- VAR
- old, flags: LONGINT;
- adr: ADDRESS;
- free: SET;
- b: BOOLEAN;
- BEGIN
- Acquire(Memory);
- old := freeStackIndex;
- IF enableCaching THEN
- flags := CB
- ELSE
- flags := 0
- END;
- LOOP
- free := freeStack[freeStackIndex];
- IF free # {} THEN
- (* Find the free stack space in that region and mark it as allocated *)
- adr := 0;
- WHILE ~(adr IN free) DO INC(adr) END;
- EXCL(freeStack[freeStackIndex], SIZE(adr));
- adr := memStackStart + (freeStackIndex * 32 + adr) * maxUserStackSize;
- EXIT
- END;
- INC(freeStackIndex);
- IF freeStackIndex = LEN(freeStack) THEN freeStackIndex := 0 END;
- IF freeStackIndex = old THEN HALT(1503) END
- END;
- s.high := adr + maxUserStackSize; s.low := adr + StackGuardSize;
- s.adr := s.high - InitStackSize; (* at the top of the virtual area *)
- initSP := s.high;
- b := AllocatePage(s.adr, FullAccess, flags); (* allocate one physical page first *)
-
- ASSERT(b);
- FlushDCacheRange(sysSecondLvlPtStart, sysSecondLvlPtStop - sysSecondLvlPtStart);
- Release(Memory)
- END NewStack;
- PROCEDURE DisposeStack*(s: Stack);
- VAR
- adr: ADDRESS;
- BEGIN
- Acquire(Memory);
- adr := s.adr;
- WHILE adr # s.high DO
- DeallocatePage(adr);
- INC(adr, PS)
- END;
- adr := (adr - maxUserStacks - memStackStart) DIV maxUserStackSize;
- INCL(freeStack[adr DIV 32], SIZE(adr MOD 32));
- Release(Memory)
- END DisposeStack;
- (** Check if the specified stack is valid. *)
- PROCEDURE ValidStack*(CONST s: Stack; sp: ADDRESS): BOOLEAN;
- VAR valid: BOOLEAN;
- BEGIN
- Acquire(Memory);
- valid := (sp MOD 4 = 0) & (sp >= s.adr) & (sp <= s.high);
- WHILE valid & (sp < s.high) DO
- valid := GetSecondLevelEntry(sp) MOD 4 = slSmall;
- INC(sp, PS)
- END;
- Release(Memory);
- RETURN valid
- END ValidStack;
- PROCEDURE GetStack(adr: ADDRESS; VAR s: Stack): BOOLEAN;
- BEGIN
- IF (adr < memStackStart) OR (adr > memStackStop) THEN
- RETURN FALSE
- END;
- s.high := adr - PS;
- s.low := adr - 4;
- s.adr := adr;
- RETURN TRUE
- END GetStack;
- (* ===== Heap ===== *)
- PROCEDURE ValidHeapAddress*(p: ADDRESS): BOOLEAN;
- BEGIN
- RETURN (memHeapStart <= p) & (p < memHeapStop) & (p MOD 4 = 0)
- END ValidHeapAddress;
- (* Free unused memory block *)
- PROCEDURE FreeMemBlock*(memBlock: MemoryBlock);
- BEGIN
- HALT(515) (* impossible to free heap *)
- END FreeMemBlock;
- (** Set memory block end address *)
- PROCEDURE SetMemoryBlockEndAddress*(memBlock: MemoryBlock; endBlockAdr: ADDRESS);
- BEGIN
- ASSERT(endBlockAdr >= memBlock.beginBlockAdr);
- memBlock.endBlockAdr := endBlockAdr
- END SetMemoryBlockEndAddress;
- (* Policy decision for heap expansion. NewBlock for the same block has failed try times. *)
- (*PROCEDURE ExpandNow(try: LONGINT): BOOLEAN;
- VAR size: SIZE;
- BEGIN
- size := LSH(memBlockTail.endBlockAdr - memBlockHead.beginBlockAdr, -10); (* heap size in KB *)
- RETURN (~ODD(try) OR (size < heapMinKB)) & (size < heapMaxKB)
- END ExpandNow;*)
- (** Attempt to set the heap end address to the specified address. The returned value is the actual new end address (never smaller than previous value). *)
- (*PROCEDURE SetHeapEndAdr(VAR endAdr: ADDRESS);
- VAR n, m: SIZE;
- BEGIN
- HALT(100);
- Acquire(Memory);
- (*
- n := LSH(endAdr+(PS-1), -PSlog2) - LSH(heapEndAdr, -PSlog2); (* pages requested *)
- m := LSH(pageHeapAdr, -PSlog2) - LSH(heapEndAdr, -PSlog2) - ReservedPages; (* max pages *)
- IF n > m THEN n := m END;
- IF n > 0 THEN INC(heapEndAdr, n*PS); DEC(freeHighPages, n) END;
- endAdr := heapEndAdr;
- *)
- Release(Memory)
- END SetHeapEndAdr;*)
- (* Try to expand the heap by at least "size" bytes *)
- PROCEDURE ExpandHeap*(try: LONGINT; size: SIZE; VAR memBlock: MemoryBlock; VAR beginBlockAdr, endBlockAdr: ADDRESS);
- BEGIN
- (*IF ExpandNow(try) THEN
- IF size < expandMin THEN size := expandMin END;
- beginBlockAdr := memBlockHead.endBlockAdr;
- endBlockAdr := beginBlockAdr;
- INC(endBlockAdr, size);
- SetHeapEndAdr(endBlockAdr); (* in/out parameter *)
- memBlock := memBlockHead;
- (* endBlockAdr of memory block is set by caller after free block has been set in memory block - this process is part of lock-free heap expansion *)
- ELSE*)
- beginBlockAdr := memBlockHead.endBlockAdr;
- endBlockAdr := memBlockHead.endBlockAdr;
- memBlock := NIL
- (*END*)
- END ExpandHeap;
- (** GetStaticHeap - get page range (beginAdr..endAdr-1) and first and last block of static heap.*)
- PROCEDURE GetStaticHeap*(VAR beginBlockAdr, endBlockAdr, freeBlockAdr: ADDRESS);
- BEGIN
- beginBlockAdr := initialMemBlock.beginBlockAdr;
- endBlockAdr := initialMemBlock.endBlockAdr;
- freeBlockAdr := beginBlockAdr;
- END GetStaticHeap;
- (* ===== Caches, TLB & other ===== *)
- (** SHR - logical shift right *)
- PROCEDURE SHR(value, shift: ADDRESS): LONGINT;
- CODE
- LDR R0, [FP, #value]
- LDR R1, [FP, #shift]
- MOV R0, R0, LSR R1
- END SHR;
- (** SHRL - shift right and left. Mask out 'shift' lowest bits *)
- PROCEDURE SHRL(value, shift: LONGINT): LONGINT;
- (*CODE
- LDR R0, [FP, #value]
- LDR R1, [FP, #shift]
- MOV R0, R0, LSR R1
- MOV R0, R0, LSL R1*)
- BEGIN
- value := LSH(value, -shift);
- value := LSH(value, shift);
- RETURN value
- END SHRL;
- (** Fills 'size' bytes with 'filler', from 'destAdr' on. size must be multiple of 4 *)
- PROCEDURE Fill32*(destAdr: ADDRESS; size: SIZE; filler: LONGINT);
- CODE
- LDR R0, [FP, #filler]
- LDR R1, [FP, #size]
- LDR R3, [FP, #destAdr]
- ADD R4, R1, R3 ; R4 = size + destAdr
- AND R5, R3, #3 ; R5 := R3 MOD 4
- CMP R5, #0 ; ASSERT(R5 = 0)
- BEQ CheckSize
- SWI #8
- CheckSize:
- AND R5, R1, #3 ; R5 := R1 MOD 4
- CMP R5, #0 ; ASSERT(R5 = 0)
- BEQ Loop
- SWI #8
- Loop:
- CMP R4, R3
- BLS Exit
- STR R0, [R3, #0] ; put(destAdr + counter, filler)
- ADD R3, R3, #4 ; R3 := R3 + 4
- B Loop
- Exit:
- END Fill32;
- (* GetPageTableBase - returns the memory address of the first level page table *)
- PROCEDURE -GetPageTableBase(): LONGINT;
- CODE
- MRC p15, 0, R0, c2, c0, 0
- MOV R0, R0, LSR #14 ; clear bits 13..0
- MOV R0, R0, LSL #14
- END GetPageTableBase;
- (** GC Initialization -- Set machine-dependent parameters gcThreshold, expandMin, heapMinKB and heapMaxKB *)
- PROCEDURE SetGCParams*;
- VAR size, t: SIZE;
- BEGIN
- GetFreeK(size, t, t); (* size is total memory size in KB *)
- heapMinKB := size * HeapMin DIV 100;
- heapMaxKB := size * HeapMax DIV 100;
- expandMin := size * ExpandRate DIV 100 * 1024;
- IF expandMin < 0 THEN expandMin := MAX(LONGINT) END;
- gcThreshold := size * Threshold DIV 100 * 1024;
- IF gcThreshold < 0 THEN gcThreshold := MAX(LONGINT) END
- END SetGCParams;
- (** Called when spinning, just does a NOP *)
- PROCEDURE -SpinHint*;
- CODE
- MOV R0, R0
- END SpinHint;
- (** Convert a string to an integer. Parameter i specifies where in the string scanning should begin (usually 0 in the first call). Scanning stops at the first non-valid character, and i returns the updated position. Parameter s is the string to be scanned. The value is returned as result, or 0 if not valid. Syntax: number = ["-"] digit {digit} ["H" | "h"] . digit = "0" | ... "9" | "A" .. "F" | "a" .. "f" . If the number contains any hexdecimal letter, or if it ends in "H" or "h", it is interpreted as hexadecimal. *)
- PROCEDURE StrToInt* (VAR i: LONGINT; CONST s: ARRAY OF CHAR): LONGINT;
- VAR vd, vh, sgn, d: LONGINT; hex: BOOLEAN;
- BEGIN
- vd := 0; vh := 0; hex := FALSE;
- IF s[i] = "-" THEN sgn := -1; INC (i) ELSE sgn := 1 END;
- LOOP
- IF (s[i] >= "0") & (s[i] <= "9") THEN d := ORD (s[i])-ORD ("0")
- ELSIF (CAP (s[i]) >= "A") & (CAP (s[i]) <= "F") THEN d := ORD (CAP (s[i]))-ORD ("A") + 10; hex := TRUE
- ELSE EXIT
- END;
- vd := 10*vd + d; vh := 16*vh + d;
- INC (i)
- END;
- IF CAP (s[i]) = "H" THEN hex := TRUE; INC (i) END; (* optional H *)
- IF hex THEN vd := vh END;
- RETURN sgn * vd
- END StrToInt;
- (** Read Non Volatile memory. Not implemented. Required by clock. *)
- PROCEDURE GetNVByte* (ofs: LONGINT): CHAR;
- BEGIN
- RETURN 10X
- END GetNVByte;
- (** Write Non Volatile memory. Not implemented. Required by clock. *)
- PROCEDURE PutNVByte* (ofs: LONGINT; val: CHAR);
- END PutNVByte;
- (* empty section allocated at end of bootfile *)
- PROCEDURE {NOPAF, ALIGNED(32)} LastAddress;
- CODE
- END LastAddress;
- PROCEDURE GetConfig*(CONST name: ARRAY OF CHAR; VAR res: ARRAY OF CHAR);
- BEGIN
- BootConfig.GetValue(name, res)
- END GetConfig;
- PROCEDURE MulH * (x, y: HUGEINT): HUGEINT;
- BEGIN
- RETURN LONGINT(x) * LONGINT(y)
- END MulH;
- PROCEDURE DivH * (x, y: HUGEINT): HUGEINT;
- BEGIN
- RETURN x DIV y
- END DivH;
- (** Not implemented yet *)
- PROCEDURE Portin8*(port: LONGINT; VAR val: CHAR);
- END Portin8;
- PROCEDURE Portout8*(port: LONGINT; val: CHAR);
- END Portout8;
- PROCEDURE TraceState * (CONST state: State);
- BEGIN
- Trace.StringLn("General Purpose Registers");
- Trace.String("R0 "); Trace.Address(state.R[0]); Trace.Ln;
- Trace.String("R1 "); Trace.Address(state.R[1]); Trace.Ln;
- Trace.String("R2 "); Trace.Address(state.R[2]); Trace.Ln;
- Trace.String("R3 "); Trace.Address(state.R[3]); Trace.Ln;
- Trace.String("R4 "); Trace.Address(state.R[4]); Trace.Ln;
- Trace.String("R5 "); Trace.Address(state.R[5]); Trace.Ln;
- Trace.String("R6 "); Trace.Address(state.R[6]); Trace.Ln;
- Trace.String("R7 "); Trace.Address(state.R[7]); Trace.Ln;
- Trace.String("R8 "); Trace.Address(state.R[8]); Trace.Ln;
- Trace.String("R9 "); Trace.Address(state.R[9]); Trace.Ln;
- Trace.String("R10 "); Trace.Address(state.R[10]); Trace.Ln;
- Trace.String("R11 "); Trace.Address(state.R[11]); Trace.Ln;
- Trace.StringLn("Stack");
- Trace.String("SP "); Trace.Address(state.SP); Trace.Ln;
- Trace.String("FP "); Trace.Address(state.BP); Trace.Ln;
- Trace.StringLn("Code");
- Trace.String("LR "); Trace.Address(state.LR); Trace.Ln;
- Trace.String("PC "); Trace.Address(state.PC); Trace.Ln;
- Trace.Ln;
- Trace.String("PSR "); Trace.Address(state.PSR); Trace.Ln;
- Trace.Ln;
- Trace.String("int "); Trace.Address(state.INT); Trace.Ln;
- END TraceState;
- PROCEDURE ReadMemLayout;
- VAR
- value: ARRAY 64 OF CHAR;
- i: LONGINT;
- BEGIN
- memSysLowStart := Platform.OCMStart;
- memSysLowStop := memSysLowStart + Platform.OCMSize;
- GetConfig("KernelLoadAdr", value);
- i := 0;
- memHeapStart := StrToInt(i, value);
- GetConfig("HeapSize", value);
- i := 0;
- memHeapStop := memHeapStart + StrToInt(i, value);
- GetConfig("DDRSize", value);
- i := 0;
- memConfigStop := Platform.DDRStart + StrToInt(i, value);
- GetConfig("ConfigSize", value);
- i := 0;
- memConfigStart := memConfigStop - StrToInt(i, value);
- memStackStart := memHeapStop;
- memStackStop := memConfigStart;
- memIOStart := Platform.IOStart;
- memIOStop := memIOStart + Platform.IOSize;
- memSysHighStart := ADDRESS(4 * G - M);
- memSysHighStop := 4 * G - 1;
- (* System Parameters *)
- sysIntStackStart := memSysLowStart + 1000H;
- sysIntStackStop := memSysLowStart + Platform.MaxCpuNb * 4 * 4 * k;
- (* The first level page table is always 16 k large, to map all 4 G of virtual memory space *)
- sysFirstLvlPtStop := memSysLowStop;
- sysFirstLvlPtStart := sysFirstLvlPtStop - 16 * k;
- (*
- * Second Level Page Table:
- * - 2 * 256 entries for the system area (first and last MB of VMem)
- * - 256 entries for each MB of virtual stack space
- * 256 entries take 1kB memory space.
- *)
- sysSecondLvlPtStop := sysFirstLvlPtStart;
- sysSecondLvlPtStart := sysSecondLvlPtStop - (2 + (memStackStop - memStackStart + memConfigStop - memConfigStart) DIV M) * k;
- (*
- * Interrupt Vector. Located at 0FFFFFFF0H
- *)
- sysVectorStart := 0FFFF0000H;
- sysVectorStop := sysVectorStart + PS;
- sysCacheRefStart := 0FFFF1000H;
- (*
- * Number of ref counters: 1 per 1st level heap page, 1 per 2nd level stack page.
- * This memory region is organized as follows: the first part [0 .. SysCacheStackOfs) is used for heap pages,
- * the second part, [SysCacheStackOfs .. SysCacheRefSize) is used for stack pages.
- *)
- sysCacheRefSize := (memHeapStop - memHeapStart) DIV M + (memStackStop - memStackStart) DIV PS;
- INC(sysCacheRefSize, 4 - sysCacheRefSize MOD 4);
- (* Offset in the ref count table for stack pages. *)
- sysCacheStackOfs := (memHeapStop - memHeapStart) DIV M;
- sysCacheRefStop := sysCacheRefStart + sysCacheRefSize;
- (* Process stack system *)
- GetConfig("StackSize", value);
- i := 0;
- maxUserStackSize := StrToInt(i, value);
- maxUserStacks := (memStackStop - memStackStart) DIV maxUserStackSize;
- GetConfig("EnableCaching", value);
- enableCaching := value[0] # '0';
- traceInterrupts := BootConfig.GetBoolValue("TraceInterrupts")
- END ReadMemLayout;
- PROCEDURE GetProcessorNumber;
- VAR
- value: ARRAY 64 OF CHAR;
- i: LONGINT;
- BEGIN
- FOR i := 0 TO 63 DO value[i] := 0X END;
- GetConfig("CpuNb", value);
- i := 0;
- numProcessors := StrToInt(i, value)
- END GetProcessorNumber;
- (** Analyse reasons for reset, print and record them. *)
- PROCEDURE ResetAnalysis;
- CONST
- (* We need these constants as Platform.slcr is not initialized yet *)
- SLCR_REBOOT_STATUS = ADDRESS(0F8000258H);
- SLCR_LOCK = ADDRESS(0F8000004H);
- SLCR_UNLOCK = ADDRESS(0F8000008H);
- Lock = LONGINT(767BH);
- Unlock = LONGINT(0DF0DH);
- VAR
- val: SET;
- error: LONGINT;
- BEGIN
- SYSTEM.GET(SLCR_REBOOT_STATUS, val);
- IF 16 IN val THEN
- lastReboot := RebootSystemWatchdog;
- Trace.StringLn("Starting after system watchdog reset")
- END;
- IF 17 IN val THEN
- lastReboot := RebootWatchdogCPU0;
- Trace.StringLn("Starting after private watchdog reset on CPU0")
- END;
- IF 18 IN val THEN
- lastReboot := RebootWatchdogCPU1;
- Trace.StringLn("Starting after private watchdog reset on CPU1")
- END;
- IF 19 IN val THEN
- lastReboot := RebootSoftReset;
- Trace.StringLn("Starting after software reboot")
- END;
- IF 20 IN val THEN
- lastReboot := RebootDebug;
- Trace.StringLn("Starting after debug reset")
- END;
- IF 21 IN val THEN
- lastReboot := RebootHardReset;
- Trace.StringLn("Starting after hard reset")
- END;
- IF 22 IN val THEN
- lastReboot := RebootPowerOn;
- Trace.StringLn("Starting after power on")
- END;
- error := SYSTEM.VAL(INTEGER, val);
- IF error # 0 THEN
- Trace.String("BootROM error code: "); Trace.Int(error, 0); Trace.Ln
- END;
- SYSTEM.PUT(SLCR_UNLOCK, Unlock);
- SYSTEM.PUT(SLCR_REBOOT_STATUS, LONGINT(0));
- SYSTEM.PUT(SLCR_LOCK, Lock)
- END ResetAnalysis;
- PROCEDURE InitWatchdog;
- VAR val: ARRAY 32 OF CHAR;
- BEGIN
- GetConfig("EnableKernelWatchdog", val);
- enableWatchdog := val = '1';
- IF enableWatchdog THEN
- PrivateWatchdog.Init(BootConfig.GetIntValue("CpuClockHz") DIV 2);
- PrivateWatchdog.Start(PrivateWatchdog.Reset, Second)
- END
- END InitWatchdog;
- PROCEDURE Init;
- BEGIN
- BootConfig.Init;
- ReadMemLayout;
- sp := SYSTEM.GetStackPointer();
- fp := SYSTEM.GetFramePointer();
- SYSTEM.LDPSR( 0, Platform.IRQMode + Platform.FIQDisabled + Platform.IRQDisabled );
- SYSTEM.SETSP(sysIntStackStart + 1000H);
- SYSTEM.LDPSR( 0, Platform.UndefMode + Platform.FIQDisabled + Platform.IRQDisabled );
- SYSTEM.SETSP(sysIntStackStart + 1000H * 2);
- SYSTEM.LDPSR( 0, Platform.AbortMode + Platform.FIQDisabled + Platform.IRQDisabled );
- SYSTEM.SETSP(sysIntStackStart + 1000H * 3);
- SYSTEM.LDPSR( 0, Platform.SVCMode + Platform.FIQDisabled + Platform.IRQDisabled );
- SYSTEM.SETSP(sysIntStackStart + 1000H * 4);
- SYSTEM.LDPSR( 0, Platform.SystemMode + Platform.FIQDisabled + Platform.IRQDisabled ); (* Disable interrupts, init SP, FP *)
- SYSTEM.SETSP(sp);
- SYSTEM.SETFP(fp);
- TraceDevice.Install;
- Trace.String("Machine: "); Trace.StringLn (Version);
- version := Version;
- InitProcessor;
- InstallDefaultInterrupts;
- DisableInterrupts;
- ResetAnalysis;
- (* Ensure memory layout consistency *)
- ASSERT(sysIntStackStart >= 4 * k);
- ASSERT(sysIntStackStop <= sysSecondLvlPtStart);
- ASSERT(sysFirstLvlPtStart MOD (16 * k) = 0);
- ASSERT(memStackStop <= memIOStart);
- ASSERT(memIOStop <= memSysHighStart);
- ASSERT(sysVectorStop <= sysCacheRefStart);
- ASSERT(sysCacheRefStop <= memSysHighStop);
- InitMemory;
- GetProcessorNumber;
- InitLocks;
- InitGlobalTimer
- END Init;
-
- PROCEDURE {INITIAL} Initial;
- BEGIN
- Init;
- END Initial;
-
- END Machine.
|