123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606 |
- 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;
-
- (* 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() *)
- (** 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;
-
- 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 test-and-set. Set x = TRUE and return old value of x. *)
- PROCEDURE -AtomicTestSet * (VAR x: BOOLEAN): BOOLEAN;
- CODE
- LDR R3, [SP, #x] ; R3 := ADDRESSOF(x)
- MOV R1, #0 ; R1 := FALSE
- MOV R2, #1 ; R2 := TRUE
- ADD SP, SP, #4 ; pop variable from stack
- loop:
- LDREXB R0, R3 ; load excl x
- CMP R0, R1
- BNE exit ; x # old -> exit
- STREXB R4, R2, R3 ; x = old -> store excl new -> x
- CMP R4, #0
- BNE loop ; store exclusive failed: retry
- exit:
- END AtomicTestSet;
- (* 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] ; R3 := 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.
|