EFI.AMD64.Machine.Mod 121 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996
  1. MODULE Machine; (** AUTHOR "pjm"; PURPOSE "Bootstrapping, configuration and machine interface"; *)
  2. (* The code of this module body must be the first in the statically linked boot file. *)
  3. IMPORT SYSTEM, Trace;
  4. CONST
  5. Version = "A2 Revision 2958 (26.02.2010)";
  6. MaxCPU* = 8; (** maximum number of processors (up to 16) *)
  7. DefaultObjectFileExtension* = ".Abx";
  8. (** bits in features variable *)
  9. MTTR* = 12; MMX* = 23; HTT* = 28;
  10. MaxDisks = 2; (* maximum number of disks with BIOS parameters *)
  11. HeapAdr = 100000H;
  12. MaxMemTop = 4000000H * 4000000H; (* maximal 52bit wide physical address (architectural limit) *)
  13. DefaultDMASize = 20; (* default size of ISA DMA area in KB *)
  14. CONST
  15. StrongChecks = FALSE; (* perform strong checks *)
  16. Stats* = FALSE; (* acquire statistics *)
  17. TimeCount = 0 (* 100000 *); (* number of lock tries before checking timeout - 0 to disable *)
  18. (** standard lock levels (in order) *) (* also refer to Traps.Show *)
  19. TraceOutput* = 0; (* Trace output *)
  20. Memory* = 1; (* Virtual memory management, stack and page allocation *)
  21. Heaps* = 2; (* Storage allocation and Garbage collection *)
  22. Interrupts* = 3 ; (* Interrupt handling. *)
  23. Modules* = 4; (* Module list *)
  24. Objects* = 5; (* Ready queue *)
  25. Processors* = 6; (* Interprocessor interrupts *)
  26. KernelLog* = 7; (* Atomic output *)
  27. (** highest level is all object locks *)
  28. Preemption* = 31; (** flag for BreakAll *)
  29. MaxLocks = 8; (* { <= 32 } *)
  30. LowestLock = 0; HighestLock = MaxLocks-1;
  31. CONST
  32. TraceVerbose = FALSE; (* write out verbose trace info *)
  33. AddressSize = SIZEOF(ADDRESS);
  34. SetSize = MAX (SET) + 1;
  35. (** error codes *)
  36. Ok* = 0;
  37. (* standard multipliers *)
  38. K = 1024; M = 100000H; (* 1K, 1M *)
  39. (* paging sizes *)
  40. PS = 4096; (* page size in bytes *)
  41. PSlog2 = 12; (* ASH(1, PSlog2) = PS *)
  42. TPS = 4096; (* translation page size *)
  43. PTEs = TPS DIV AddressSize; (* number of entries per translation page table *)
  44. RS = PTEs * PS; (* region covered by a page table in bytes *)
  45. ReservedPages = 8; (* pages reserved on page heap (not for normal heap use) *)
  46. NilAdr* = -1; (** nil value for addresses (not same as pointer NIL value) *)
  47. (* free page stack page node layout *)
  48. NodeSP = 0;
  49. NodeNext = AddressSize;
  50. NodePrev = AddressSize*2;
  51. MinSP = AddressSize*3; MaxSP = PS;
  52. (*
  53. 0 sp
  54. AddressSize nextAdr
  55. AddressSize*2 prevAdr
  56. AddressSize*3 first entry
  57. 4092 last entry
  58. *)
  59. (* virtual memory layout. no area will cross the 2G boundary, to avoid LONGINT sign problems. *)
  60. MapAreaAdr = SHORT(80000000H); (* dynamic mappings: bottom part of 2G..4G *)
  61. MapAreaSize = 64*M;
  62. IntelAreaAdr = SHORT(0FEE00000H); (* reserved by Intel for APIC: 4G-18M..4G-18M+4K *)
  63. IntelAreaSize = 00001000H;
  64. StackAreaAdr = MapAreaAdr+MapAreaSize; (* stacks: middle part of 2G..4G *)
  65. StackAreaSize = IntelAreaAdr-StackAreaAdr;
  66. (* stack sizes *)
  67. KernelStackSize = 2*PS; (* multiple of PS *)
  68. MaxUserStackSize = 128*K; (* multiple of PS *)
  69. InitUserStackSize = PS; (* must be PS (or change NewStack) *)
  70. UserStackGuardSize = PS; (* multiple of PS left unallocated at bottom of stack virtual area *)
  71. MaxUserStacks = StackAreaSize DIV MaxUserStackSize;
  72. (* physical memory layout *)
  73. LowAdr = PS; (* lowest physical address used *)
  74. LinkAdr = M; (* address where kernel is linked, also address where heap begins *)
  75. StaticBlockSize = 32; (* static heap block size *)
  76. BlockHeaderSize = 2 * AddressSize;
  77. RecordDescSize = 3 * AddressSize; (* needs to be adapted in case Heaps.RecordDesc is changed *)
  78. (* gdt indices *)
  79. TSSOfs = 8; (* offset in GDT of TSSs *)
  80. StackOfs = TSSOfs + MaxCPU; (* offset in GDT of stacks *)
  81. GDTSize = TSSOfs + MaxCPU * 2; (* TSS descriptors need 16 bytes each *)
  82. (* gdt selectors *)
  83. Kernel32CodeSel = 1*8; (* selector 1 in gdt, RPL 0 *)
  84. Kernel64CodeSel = 2*8; (* selector 2 in gdt, RPL 0 *)
  85. User32CodeSel = 3*8 + 3; (* selector 3 in gdt, RPL 3 *)
  86. User64CodeSel = 4*8 + 3; (* selector 4 in gdt, RPL 3 *)
  87. KernelStackSel = 5*8; (* selector 5 in gdt, RPL 0 *)
  88. UserStackSel = 6*8 + 3; (* selector 6 in gdt, RPL 3 *)
  89. DataSel = 7*8; (* selector 7 in gdt, RPL 0 *)
  90. KernelTR = TSSOfs*8; (* selector in gdt, RPL 0 *)
  91. (* paging flags *)
  92. PageNotPresent = 0; (* not present page *)
  93. KernelPage = 3; (* supervisor, present, r/w *)
  94. UserPage = 7; (* user, present, r/w *)
  95. HeapMin = 50; (* "minimum" heap size as percentage of total memory size (used for heap expansion in scope of GC ) *)
  96. HeapMax = 95; (* "maximum" heap size as percentage of total memory size (used for heap expansion in scope of GC) *)
  97. ExpandRate = 1; (* always extend heap with at least this percentage of total memory size *)
  98. Threshold = 10; (* periodic GC initiated when this percentage of total memory size bytes has "passed through" NewBlock *)
  99. InitialHeapIncrement = 4096;
  100. HeaderSize = 40H; (* cf. Linker0 *)
  101. EndBlockOfs = 38H; (* cf. Linker0 *)
  102. MemoryBlockOfs = BlockHeaderSize + RecordDescSize + BlockHeaderSize; (* memory block (including header) starts at offset HeaderSize *)
  103. CONST
  104. (** pre-defined interrupts 0-31, used with InstallHandler *)
  105. DE* = 0; DB* = 1; NMI* = 2; BP* = 3; OVF* = 4; BR* = 5; UD* = 6; NM* = 7;
  106. DF* = 8; TS* = 10; NP* = 11; SSF* = 12; GP* = 13; PF* = 14; MF*= 16; AC*= 17; MC* = 18;
  107. IRQ0* = 32; (* {IRQ0 MOD 8 = 0} *)
  108. IRQ2 = IRQ0 + 2;
  109. IRQ7 = IRQ0 + 7;
  110. IRQ8 = IRQ0 + 8;
  111. IRQ15 = 47;
  112. MaxIRQ* = IRQ15; (** hardware interrupt numbers *)
  113. MPKC* = 49; (** SMP: kernel call *)
  114. SoftInt* = 58; (** temporary software interrupt *)
  115. MPIPCLocal* = 59; (** SMP: local interprocessor interrupt *)
  116. MPTMR* = 60; (** SMP: timer interrupt *)
  117. MPIPC* = 61; (** SMP: interprocessor interrupt *)
  118. MPERR* = 62; (** SMP: error interrupt *)
  119. MPSPU* = 63; (** SMP: spurious interrupt {MOD 16 = 15} *)
  120. IDTSize = 64;
  121. MaxNumHandlers = 16;
  122. TraceSpurious = FALSE; (* no message on spurious hardware interrupts *)
  123. HandleSpurious = TRUE OR TraceSpurious; (* do not trap on spurious interrupts *)
  124. IntA0 = 020H; IntA1 = 021H; (* Interrupt Controller 1 *)
  125. IntB0 = 0A0H; IntB1 = 0A1H; (* Interrupt Controller 2 *)
  126. (** RFLAGS bits *)
  127. IFBit* = 9; VMBit* = 17;
  128. KernelLevel* = 0; UserLevel* = 3; (** CS MOD 4 *)
  129. Second* = 1000; (* frequency of ticks increments in Hz *)
  130. CONST
  131. Self* = 0; FrontBarrier* = 1; BackBarrier* = 2; (** Broadcast flags. *)
  132. TraceApic = FALSE;
  133. TraceProcessor = FALSE; (* remove this hack! *)
  134. ClockRateDelay = 50; (* ms - delay when timing bus clock rate *)
  135. TimerClock = 1193180; (* timer clock is 1.19318 MHz *)
  136. CONST
  137. (* low level tracing *)
  138. TraceV24 = 2; TraceScreen = 0;
  139. TraceWidth = 80; TraceHeight = 25;
  140. TraceLen = TraceWidth * SIZEOF (INTEGER);
  141. TraceSize = TraceLen * TraceHeight;
  142. TYPE
  143. Vendor* = ARRAY 13 OF CHAR;
  144. IDMap* = ARRAY 16 OF SHORTINT;
  145. TYPE
  146. Stack* = RECORD (** values are read-only *)
  147. low: ADDRESS; (* lowest virtual address that may be allocated for stack *)
  148. adr*: ADDRESS; (* lowest address on allocated stack *) (* exported for Objects only *)
  149. high*: ADDRESS; (* next virtual address after stack *) (* exported for Objects only *)
  150. END;
  151. (* task state segment *)
  152. TSSDesc = RECORD (* 1, p. 485 and p. 612 for required fields *)
  153. Reserved1: LONGINT;
  154. RSP0 {ALIGNED(4)}, RSP1{ALIGNED(4)}, RSP2{ALIGNED(4)}: HUGEINT;
  155. Reserved2, Reserved3: LONGINT;
  156. IST1 {ALIGNED(4)}, IST2 {ALIGNED(4)}, IST3 {ALIGNED(4)}, IST4{ALIGNED(4)}, IST5{ALIGNED(4)}, IST6{ALIGNED(4)}, IST7{ALIGNED(4)}: HUGEINT;
  157. Reserved4, Reserved5: LONGINT;
  158. Reserved6, IOMapBaseAddress: INTEGER;
  159. (* Implicit: IOBitmap: ARRAY 8192 DIV 4 OF SET *)
  160. END;
  161. Startup* = PROCEDURE; (** can not be a method *)
  162. (* global descriptor table *)
  163. SegDesc = RECORD
  164. low, high: LONGINT
  165. END;
  166. GDT = ARRAY GDTSize OF SegDesc;
  167. Range* = RECORD
  168. adr*: ADDRESS; size*: SIZE;
  169. END;
  170. TYPE
  171. (** processor state, ordering of record fields is predefined! *)
  172. State* = RECORD (* offsets used in FieldInterrupt, FieldIRQ and Objects.RestoreState *)
  173. R15*, R14*, R13*, R12*, R11*, R10*, R9*, R8*: HUGEINT;
  174. RDI*, RSI*, ERR*, RSP0*, RBX*, RDX*, RCX*, RAX*: HUGEINT; (** RSP0 = ADR(s.INT) *)
  175. INT*, BP*, PC*, CS*: HUGEINT; (* RBP and ERR are exchanged by glue code, for procedure link *)
  176. FLAGS*: SET;
  177. SP*, SS*: HUGEINT;
  178. END;
  179. (** exception state, ordering of record fields is predefined! *)
  180. ExceptionState* = RECORD
  181. halt*: ADDRESS; (** halt code *)
  182. pf*: ADDRESS; (** page fault address *)
  183. locks*: SET; (** active locks *)
  184. SP*: ADDRESS; (** actual RSP value at time of interrupt *)
  185. CR*: ARRAY 16 OF HUGEINT; (** control registers *)
  186. DR*: ARRAY 16 OF HUGEINT; (** debug registers *)
  187. FPU*: ARRAY 7 OF SET (** floating-point state *)
  188. END;
  189. Handler* = PROCEDURE {DELEGATE} (VAR state: State);
  190. HandlerRec = RECORD
  191. valid: BOOLEAN; (* offset 0 *)
  192. handler {ALIGNED(4)}: Handler (* offset 4 *)
  193. END;
  194. GateDescriptor = RECORD
  195. offsetBits0to15: INTEGER;
  196. selector: INTEGER;
  197. gateType: INTEGER;
  198. offsetBits16to31: INTEGER;
  199. offsetBits32to63: LONGINT;
  200. reserved: LONGINT;
  201. END;
  202. IDT = ARRAY IDTSize OF GateDescriptor;
  203. SSEState* = ARRAY (512+16) OF CHAR;
  204. TYPE
  205. MemoryBlock* = POINTER TO MemoryBlockDesc;
  206. MemoryBlockDesc* = RECORD
  207. next- {UNTRACED}: MemoryBlock;
  208. startAdr-: ADDRESS; (* unused field for I386 *)
  209. size-: SIZE; (* unused field for I386 *)
  210. beginBlockAdr-, endBlockAdr-: ADDRESS
  211. END;
  212. TYPE
  213. EventHandler = PROCEDURE (id: LONGINT; CONST state: State);
  214. Message* = POINTER TO RECORD END; (** Broadcast message. *)
  215. BroadcastHandler = PROCEDURE (id: LONGINT; CONST state: State; msg: Message);
  216. TimeArray = ARRAY MaxCPU OF HUGEINT;
  217. Address32* = LONGINT;
  218. VAR
  219. lowTop*: ADDRESS; (** top of low memory *)
  220. memTop*: ADDRESS; (** top of memory *)
  221. dmaSize*: SIZE; (** size of ISA dma area, above lowTop (for use in Aos.Diskettes) *)
  222. configMP: ADDRESS; (** MP spec config table physical address (outside reported RAM) *)
  223. revMP: CHAR; (** MP spec revision *)
  224. featureMP: ARRAY 5 OF CHAR; (** MP spec feature bytes 1-5 *)
  225. version-: ARRAY 64 OF CHAR; (** Aos version *)
  226. SSESupport-: BOOLEAN;
  227. SSE2Support-: BOOLEAN;
  228. features-, features2-: SET; (** processor features *)
  229. fcr*: SET; (** default floating-point control register value (default rounding mode is towards -infinity, for ENTIER) *)
  230. mhz*: HUGEINT; (** clock rate of GetTimer in MHz, or 0 if not known *)
  231. chs: ARRAY MaxDisks OF RECORD cyls, hds, spt: LONGINT END;
  232. initRegs0, initRegs1: HUGEINT;
  233. fbadr*, fbInfoPtr*: ADDRESS;
  234. initRegs: ARRAY 2 OF HUGEINT; (* kernel parameters *)
  235. config: ARRAY 2048 OF CHAR; (* config strings *)
  236. bootFlag: ADDRESS;
  237. idAdr: ADDRESS; (* address of processor ID register *)
  238. map: IDMap;
  239. bootID: LONGINT; (* ID of boot processor (0) *)
  240. numberOfProcessors: LONGINT; (* number of processors installed during start up *)
  241. coresPerProcessor : LONGINT; (* number of cores per physical package *)
  242. threadsPerCore : LONGINT; (* number of threads per core *)
  243. CONST
  244. CacheLineSize = 128;
  245. TYPE
  246. (* Synchronization variables should reside in own cache line. This data structure should be aligned to CacheLineSize. *)
  247. Lock = RECORD
  248. locked : BOOLEAN;
  249. filler : ARRAY CacheLineSize - 1 OF CHAR;
  250. END;
  251. VAR
  252. lock: ARRAY MaxLocks OF Lock; (** all locks *)
  253. (*
  254. Every element in the proc array belongs to one processor. It is therefore sufficient to disable interrupts to protect the consistency of these elements. Race conditions with interrupts handled on the same processor are avoided by disabling interrupts for the entire time that a lock is held (using locksHeld & state). The data structures are padded to CacheLineSize to separate the locks out on cache lines of their own, to avoid false sharing.
  255. *)
  256. proc-, trapState-: ARRAY MaxCPU OF RECORD
  257. locksHeld-: SET; (** locks held by a processor *)
  258. state-: SET; (** processor flags (interrupt state) at entry to its first lock *)
  259. preemptCount-: LONGINT; (** if 0, preemption is allowed *)
  260. padding : ARRAY CacheLineSize - 20 OF CHAR;
  261. END;
  262. (* the data structures above should be aligned to CacheLineSize *)
  263. padding : ARRAY 92 OF CHAR;
  264. trapLocksBusy-: SET;
  265. maxTime: HUGEINT;
  266. VAR
  267. gdt: GDT; (* global descriptor table *)
  268. procm: ARRAY MaxCPU OF RECORD (* indexed by ID () *)
  269. tss: TSSDesc;
  270. sp: ADDRESS; (* snapshot for GC *)
  271. stack: Stack
  272. END;
  273. kernelPML4: ADDRESS; (* physical address of page directory *)
  274. freeLowPage: ADDRESS; (* free low page stack pointer (link at offset 0 in page). All addresses physical. NIL = -1 *)
  275. freeLowPages, freeHighPages, totalPages: HUGEINT; (* number of free pages and total number of pages *)
  276. mapTop: ADDRESS; (* virtual address of end of memory mapping area *)
  277. heapEndAdr: ADDRESS; (* virtual address of end of heap (page aligned) *)
  278. topPageNum: HUGEINT; (* page containing byte memTop-1 *)
  279. pageHeapAdr: ADDRESS; (* address (physical and virtual) of bottom of page heap area *)
  280. pageStackAdr: ADDRESS; (* virtual address of top page of free page stack *)
  281. freeStack: ARRAY (MaxUserStacks+SetSize-1) DIV SetSize OF SET; (* free stack bitmap *)
  282. freeStackIndex: HUGEINT; (* current position in bitmap (rotates) *)
  283. Nbigskips-: LONGINT; (* number of times a stack was extended leaving a hole *)
  284. Nfilled-: LONGINT; (* number of times a "hole" in a stack was filled *)
  285. NnewStacks-, NnewStackLoops-, NnewStackInnerLoops-, NdisposeStacks-,
  286. NlostPages-, NreservePagesUsed-, NmaxUserStacks-: HUGEINT;
  287. VAR
  288. idt: IDT; (* interrupt descriptor table *)
  289. glue: ARRAY IDTSize OF ARRAY 15 OF CHAR; (* code *)
  290. intHandler: ARRAY IDTSize, MaxNumHandlers OF HandlerRec; (* array of handlers for interrupts, the table is only filled up to MaxNumHandlers - 1, the last element in each row acts as a sentinel *)
  291. stateTag: ADDRESS;
  292. default: HandlerRec;
  293. i, j, ticks*: LONGINT; (** timer ticks. Use Kernel.GetTicks() to read, don't write *)
  294. VAR
  295. ipcBusy, ipcFlags, ipcFrontBarrier, ipcBackBarrier: SET;
  296. ipcHandler: BroadcastHandler;
  297. ipcMessage: Message;
  298. numProcessors-: LONGINT; (* number of processors we attempted to boot (some may have failed) *)
  299. maxProcessors: LONGINT; (* max number of processors we are allowed to boot (-1 for uni) *)
  300. allProcessors-: SET; (* IDs of all successfully booted processors *)
  301. localAPIC: ADDRESS; (* address of local APIC, 0 if not present *)
  302. apicVer: ARRAY MaxCPU OF LONGINT; (* APIC version *)
  303. started: ARRAY MaxCPU OF BOOLEAN; (* CPU started successfully / CPU halted *)
  304. busHz0, busHz1: ARRAY MaxCPU OF LONGINT; (* unrounded and rounded bus speed in Hz *)
  305. timer: EventHandler;
  306. timerRate: LONGINT; (* Hz - rate at which CPU timers run - for timeslicing and profiling *)
  307. stopped: BOOLEAN; (* StopAll was called *)
  308. idMap: IDMap;
  309. revIDmap: ARRAY MaxCPU OF SHORTINT;
  310. time: TimeArray;
  311. eventCount, eventMax: LONGINT;
  312. event: Handler;
  313. expandMin, heapMinKB, heapMaxKB : SIZE;
  314. gcThreshold-: SIZE;
  315. memBlockHead-{UNTRACED}, memBlockTail-{UNTRACED}: MemoryBlock; (* refer to the same memory block for I386, not traced by GC *)
  316. initialMemBlock: MemoryBlockDesc;
  317. traceProcessorProc*: EventHandler; (** temp tracing *)
  318. traceProcessor: BOOLEAN;
  319. Timeslice*: Handler;
  320. start*: PROCEDURE;
  321. VAR
  322. traceMode: SET; (* tracing mode: Screen or V24 *)
  323. traceBase: ADDRESS; (* screen buffer base address *)
  324. tracePos: SIZE; (* current screen cursor *)
  325. tracePort: LONGINT; (* serial base port *)
  326. traceColor: SHORTINT; (* current screen tracing color *)
  327. (** -- Processor identification -- *)
  328. (** Return current processor ID (0 to MaxNum-1). *)
  329. PROCEDURE ID* (): LONGINT;
  330. CODE {SYSTEM.AMD64}
  331. ; todo: use MOV instead of LEA as soon as assembler returns address for global variables
  332. LEA RAX, idAdr ; get address of idAdr
  333. MOV RAX, [RAX] ; get value of idAdr
  334. MOV EAX, [RAX] ; dereference idAdr
  335. LEA RBX, map ; address of map
  336. SHR EAX, 24
  337. AND EAX, 15
  338. MOV AL, [RBX + RAX]
  339. END ID;
  340. (** -- Miscellaneous -- *)
  341. (** This procedure should be called in all spin loops as a hint to the processor (e.g. Pentium 4). *)
  342. PROCEDURE -SpinHint*;
  343. CODE {SYSTEM.AMD64}
  344. PAUSE
  345. END SpinHint;
  346. (** Fill "size" bytes at "destAdr" with "filler". "size" must be multiple of 4. *)
  347. PROCEDURE Fill32* (destAdr: ADDRESS; size: SIZE; filler: LONGINT);
  348. CODE {SYSTEM.AMD64}
  349. MOV RDI, [RBP + destAdr]
  350. MOV RCX, [RBP + size]
  351. MOV EAX, [RBP + filler]
  352. TEST RCX, 3
  353. JZ ok
  354. PUSH 8 ; ASSERT failure
  355. INT 3
  356. ok:
  357. SHR RCX, 2
  358. CLD
  359. REP STOSD
  360. END Fill32;
  361. (** Return timer value of the current processor, or 0 if not available. *)
  362. (* e.g. ARM does not have a fine-grained timer *)
  363. PROCEDURE -GetTimer* (): HUGEINT;
  364. CODE {SYSTEM.AMD64}
  365. XOR RAX, RAX
  366. RDTSC ; set EDX:EAX
  367. SHL RDX, 32
  368. OR RAX, RDX
  369. END GetTimer;
  370. (** Disable interrupts and return old interrupt state. *)
  371. PROCEDURE -DisableInterrupts* (): SET;
  372. CODE {SYSTEM.AMD64}
  373. PUSHFQ
  374. CLI
  375. POP RAX
  376. END DisableInterrupts;
  377. (** Restore interrupt state. Parameter s must be return value of earlier DisableInterrupts call on same processor. *)
  378. PROCEDURE -RestoreInterrupts* (s: SET);
  379. CODE {SYSTEM.AMD64}
  380. POPFQ
  381. END RestoreInterrupts;
  382. (** Return TRUE iff interrupts are enabled on the current processor. *)
  383. PROCEDURE -InterruptsEnabled* (): BOOLEAN;
  384. CODE {SYSTEM.AMD64}
  385. PUSHFQ
  386. POP RAX
  387. SHR RAX, 9
  388. AND AL, 1
  389. END InterruptsEnabled;
  390. (** -- HUGEINT operations -- *)
  391. (** Return h*g. *)
  392. PROCEDURE MulH* (h, g: HUGEINT): HUGEINT;
  393. BEGIN RETURN h * g;
  394. END MulH;
  395. (** Return h DIV g. Rounding and division by zero behaviour is currently undefined. *)
  396. PROCEDURE DivH* (x, y: HUGEINT): HUGEINT;
  397. BEGIN RETURN x DIV y
  398. END DivH;
  399. (** Return ASH(h, n). *)
  400. PROCEDURE ASHH* (h: HUGEINT; n: LONGINT): HUGEINT;
  401. BEGIN RETURN ASH (h, n);
  402. END ASHH;
  403. (** Return a HUGEINT composed of high and low. *)
  404. PROCEDURE -LInt2ToHInt* (high, low: LONGINT): HUGEINT;
  405. CODE {SYSTEM.AMD64}
  406. POP RAX
  407. END LInt2ToHInt;
  408. (** Return h as a LONGREAL, with possible loss of precision. *)
  409. PROCEDURE -HIntToLReal* (h: HUGEINT): LONGREAL;
  410. CODE {SYSTEM.AMD64, SYSTEM.FPU}
  411. FILD QWORD [ESP]
  412. PAUSE
  413. ADD RSP, 8
  414. END HIntToLReal;
  415. (** -- Processor initialization -- *)
  416. PROCEDURE -SetFCR (s: SET);
  417. CODE {SYSTEM.AMD64, SYSTEM.FPU}
  418. FLDCW WORD [RSP] ; parameter s
  419. POP RAX
  420. END SetFCR;
  421. PROCEDURE -FCR (): SET;
  422. CODE {SYSTEM.AMD64, SYSTEM.FPU}
  423. PUSH 0
  424. FNSTCW WORD [RSP]
  425. FWAIT
  426. POP RAX
  427. END FCR;
  428. PROCEDURE -InitFPU;
  429. CODE {SYSTEM.AMD64, SYSTEM.FPU}
  430. FNINIT
  431. END InitFPU;
  432. (** Setup FPU control word of current processor. *)
  433. PROCEDURE SetupFPU*;
  434. BEGIN
  435. InitFPU; SetFCR(fcr)
  436. END SetupFPU;
  437. (* Set up flags (3, p. 20)
  438. Bit
  439. 1,3,5,15,19..31 - no change
  440. 0,2,4,6..7,11 - CF,PF,AF,ZF,SF,OF off
  441. 8 - TF off
  442. 9 - IF off (no interrupts)
  443. 10 - DF off
  444. 12..13 - IOPL = 3
  445. 14 - NT off (no Windows)
  446. 16 - RF off (no Interference)
  447. 17- VM off (no virtual 8086 mode)
  448. 18 - AC off (no 486 alignment checks) *)
  449. PROCEDURE -SetupFlags;
  450. CODE {SYSTEM.AMD64}
  451. PUSHFD
  452. AND DWORD [RSP], 0FFF8802AH
  453. OR DWORD [RSP], 3000H
  454. POPFD
  455. END SetupFlags;
  456. (* Set up various 486-specific flags (3, p. 23)
  457. 1. Enable exception 16 on math errors.
  458. 2. Disable supervisor mode faults on write to read-only pages
  459. (386-compatible for stack checking).
  460. 3. Enable the Alignment Check field in RFLAGS *)
  461. PROCEDURE -Setup486Flags;
  462. CODE {SYSTEM.486, SYSTEM.Privileged}
  463. MOV EAX, CR0
  464. OR EAX, 00040020H
  465. AND EAX, 0FFFEFFFFH
  466. MOV CR0, EAX
  467. END Setup486Flags;
  468. (* Set up 586-specific things *)
  469. PROCEDURE -Setup586Flags;
  470. CODE {SYSTEM.586, SYSTEM.Privileged}
  471. MOV EAX, CR4
  472. BTR EAX, 2 ; clear TSD
  473. MOV CR4, EAX
  474. END Setup586Flags;
  475. (* Disable exceptions caused by math in new task. (1, p. 479) *)
  476. PROCEDURE -DisableMathTaskEx;
  477. CODE {SYSTEM.386, SYSTEM.Privileged}
  478. MOV EAX,CR0
  479. AND AL, 0F5H
  480. MOV CR0, EAX
  481. END DisableMathTaskEx;
  482. (* Disable math emulation (1, p. 479) , bit 2 of CR0 *)
  483. PROCEDURE -DisableEmulation;
  484. CODE {SYSTEM.386, SYSTEM.Privileged}
  485. MOV EAX, CR0
  486. AND AL, 0FBH
  487. MOV CR0, EAX
  488. END DisableEmulation;
  489. (** CPU identification *)
  490. PROCEDURE CPUID*(function : LONGINT; VAR eax, ebx, ecx, edx : SET);
  491. CODE {SYSTEM.AMD64}
  492. MOV EAX, [RBP+function] ; CPUID function parameter
  493. MOV RSI, [RBP+ecx] ; copy ecx into ECX (sometimes used as input parameter)
  494. MOV ECX, [RSI]
  495. CPUID ; execute CPUID
  496. MOV RSI, [RBP+eax] ; copy EAX into eax;
  497. MOV [RSI], EAX
  498. MOV RSI, [RBP+ebx] ; copy EBX into ebx
  499. MOV [RSI], EBX
  500. MOV RSI, [RBP+ecx] ; copy ECX into ecx
  501. MOV [RSI], ECX
  502. MOV RSI, [RBP+edx] ; copy EDX into edx
  503. MOV [RSI], EDX
  504. END CPUID;
  505. (* If the CPUID instruction is supported, the ID flag (bit 21) of the EFLAGS register is r/w *)
  506. PROCEDURE CpuIdSupported*() : BOOLEAN;
  507. CODE {SYSTEM.AMD64}
  508. PUSHFQ ; save RFLAGS
  509. POP RAX ; store RFLAGS in RAX
  510. MOV EBX, EAX ; save EBX for later testing
  511. XOR EAX, 00200000H ; toggle bit 21
  512. PUSH RAX ; push to stack
  513. POPFQ ; save changed RAX to RFLAGS
  514. PUSHFQ ; push RFLAGS to TOS
  515. POP RAX ; store RFLAGS in RAX
  516. CMP EAX, EBX ; see if bit 21 has changed
  517. SETNE AL; ; return TRUE if bit 21 has changed, FALSE otherwise
  518. END CpuIdSupported;
  519. (** Initialise current processor. Must be called by every processor. *)
  520. PROCEDURE InitProcessor*;
  521. BEGIN
  522. SetupFlags;
  523. Setup486Flags;
  524. Setup586Flags;
  525. DisableMathTaskEx;
  526. DisableEmulation;
  527. SetupFPU;
  528. END InitProcessor;
  529. (** Initialize APIC ID address. *)
  530. PROCEDURE InitAPICIDAdr* (adr: ADDRESS; CONST m: IDMap);
  531. VAR s: SET;
  532. BEGIN
  533. s := DisableInterrupts ();
  534. idAdr := adr; map := m;
  535. RestoreInterrupts (s)
  536. END InitAPICIDAdr;
  537. PROCEDURE InitBoot;
  538. VAR
  539. largestFunction, i: LONGINT;
  540. eax, ebx, ecx, edx : SET;
  541. logicalProcessorCount : LONGINT;
  542. u: ARRAY 8 OF CHAR; vendor : Vendor;
  543. PROCEDURE GetString(VAR string : ARRAY OF CHAR; offset : LONGINT; register : SET);
  544. BEGIN
  545. string[offset] :=CHR(SYSTEM.VAL(LONGINT, register * {0..7}));
  546. string[offset+1] := CHR(SYSTEM.VAL(LONGINT, LSH(register * {8..15}, -8)));
  547. string[offset+2] := CHR(SYSTEM.VAL(LONGINT, LSH(register * {16..23}, -16)));
  548. string[offset+3] := CHR(SYSTEM.VAL(LONGINT, LSH(register * {24..31}, -24)));
  549. END GetString;
  550. BEGIN
  551. vendor := "Unknown"; features := {}; features2 := {};
  552. coresPerProcessor := 1; threadsPerCore := 1;
  553. IF CpuIdSupported() THEN
  554. (* Assume that all processors are the same *)
  555. (* CPUID standard function 0 returns: eax: largest CPUID standard function supported, ebx, edx, ecx: vendor string *)
  556. CPUID(0, eax, ebx, ecx, edx);
  557. largestFunction := SYSTEM.VAL(LONGINT, eax);
  558. ASSERT(LEN(vendor) >= 13);
  559. GetString(vendor, 0, ebx); GetString(vendor, 4, edx); GetString(vendor, 8, ecx); vendor[12] := 0X;
  560. IF (largestFunction >= 1) THEN
  561. (* CPUID standard function 1 returns: CPU features in ecx & edx *)
  562. CPUID(1, eax, ebx, ecx, edx);
  563. features := SYSTEM.VAL(SET, edx);
  564. features2 := SYSTEM.VAL(SET, ecx);
  565. (* The code below is used to determine the number of threads per processor core (hyperthreading). This is required
  566. since processors supporting hyperthreading are listed only once in the MP tables, so we need to know the
  567. exact number of threads per processor to start the processor correctly *)
  568. IF (HTT IN features) THEN (* multithreading supported by CPU *)
  569. (* logical processor count = number of cores * number of threads per core = total number of threads supported *)
  570. logicalProcessorCount := SYSTEM.VAL(LONGINT, LSH(ebx * {16..23}, -16));
  571. IF (vendor = "GenuineIntel") THEN
  572. IF (largestFunction >= 4) THEN
  573. (* CPUID standard function 4 returns: number of processor cores -1 on this die eax[26.31] *)
  574. ecx := SYSTEM.VAL(SET, 0); (* input parameter - must be set to 0 *)
  575. CPUID(4, eax, ebx, ecx, edx);
  576. coresPerProcessor := SYSTEM.VAL(LONGINT, LSH(eax * {26..31}, -26)) + 1;
  577. threadsPerCore := logicalProcessorCount DIV coresPerProcessor;
  578. ELSE
  579. threadsPerCore := logicalProcessorCount;
  580. END;
  581. ELSIF (vendor = "AuthenticAMD") THEN
  582. (* CPUID extended function 1 returns: largest extended function *)
  583. CPUID(SHORT(80000000H), eax, ebx, ecx, edx);
  584. largestFunction := SYSTEM.VAL(LONGINT, eax - {31}); (* remove sign *)
  585. IF (largestFunction >= 8) THEN
  586. (* CPUID extended function 8 returns: *)
  587. CPUID(SHORT(80000008H), eax, ebx, ecx, edx);
  588. coresPerProcessor := SYSTEM.VAL(LONGINT, ecx * {0..7}) + 1;
  589. threadsPerCore := logicalProcessorCount DIV coresPerProcessor;
  590. ELSIF (largestFunction >= 1) THEN
  591. (* CPUID extended function 1 returns CmpLegacy bit in ecx *)
  592. CPUID(SHORT(80000001H), eax, ebx, ecx, edx);
  593. IF 1 IN ecx THEN (* CmpLegacy bit set -> no hyperthreading *)
  594. coresPerProcessor := logicalProcessorCount;
  595. threadsPerCore := 1;
  596. END;
  597. ELSE
  598. (* single-core, single-thread *)
  599. END;
  600. ELSE
  601. Trace.String("Machine: "); Trace.Yellow; Trace.String("Warning: Cannot detect hyperthreading, unknown CPU vendor ");
  602. Trace.String(vendor); Trace.Ln; Trace.Default;
  603. END;
  604. END;
  605. END;
  606. END;
  607. Trace.String("Machine: "); Trace.Int(coresPerProcessor, 0); Trace.String(" cores per physical package, ");
  608. Trace.Int(threadsPerCore, 0); Trace.String(" threads per core.");
  609. Trace.Ln;
  610. InitFPU;
  611. fcr := (FCR () - {0, 2, 3, 10, 11}) + {0 .. 5, 8, 9}; (* default FCR RC=00B *)
  612. bootID := 0; map[0] := 0;
  613. idAdr := ADDRESSOF (bootID);
  614. (* allow user to specify GetTimer rate, for tracing purposes *)
  615. GetConfig ("MHz", u);
  616. i := 0; mhz := StrToInt (i, u);
  617. END InitBoot;
  618. (** -- Configuration and bootstrapping -- *)
  619. (** Return the value of the configuration string specified by parameter name in parameter val. Returns val = "" if the string was not found, or has an empty value. *)
  620. PROCEDURE GetConfig* (CONST name: ARRAY OF CHAR; VAR val: ARRAY OF CHAR);
  621. VAR i, src: LONGINT; ch: CHAR;
  622. BEGIN
  623. ASSERT (name[0] # "="); (* no longer supported, use GetInit instead *)
  624. src := 0;
  625. LOOP
  626. ch := config[src];
  627. IF ch = 0X THEN EXIT END;
  628. i := 0;
  629. LOOP
  630. ch := config[src];
  631. IF (ch # name[i]) OR (name[i] = 0X) THEN EXIT END;
  632. INC (i); INC (src)
  633. END;
  634. IF (ch = 0X) & (name[i] = 0X) THEN (* found: (src^ = 0X) & (name[i] = 0X) *)
  635. i := 0;
  636. REPEAT
  637. INC (src); ch := config[src]; val[i] := ch; INC (i);
  638. IF i = LEN(val) THEN val[i - 1] := 0X; RETURN END (* val too short *)
  639. UNTIL ch = 0X;
  640. val[i] := 0X; RETURN
  641. ELSE
  642. WHILE ch # 0X DO (* skip to end of name *)
  643. INC (src); ch := config[src]
  644. END;
  645. INC (src);
  646. REPEAT (* skip to end of value *)
  647. ch := config[src]; INC (src)
  648. UNTIL ch = 0X
  649. END
  650. END;
  651. val[0] := 0X
  652. END GetConfig;
  653. (** Get CHS parameters of first two BIOS-supported hard disks. *)
  654. PROCEDURE GetDiskCHS* (d: LONGINT; VAR cyls, hds, spt: LONGINT);
  655. BEGIN
  656. cyls := chs[d].cyls; hds := chs[d].hds; spt := chs[d].spt
  657. END GetDiskCHS;
  658. (** Get parameter values from Init string. If n = 0, return val = ASH(bx, 16) + ax, and if n = 1, return val = ASH(dx, 16) + cx, where ax, bx, cx, dx are the register values after the OBL boot loader or noboot.exe have executed the 16-bit x86 code in the Init string. *)
  659. PROCEDURE GetInit* (n: LONGINT; VAR val: HUGEINT);
  660. BEGIN
  661. val := initRegs[n]
  662. END GetInit;
  663. (** 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. *)
  664. PROCEDURE StrToInt* (VAR i: LONGINT; CONST s: ARRAY OF CHAR): LONGINT;
  665. VAR vd, vh, sgn, d: LONGINT; hex: BOOLEAN;
  666. BEGIN
  667. vd := 0; vh := 0; hex := FALSE;
  668. IF s[i] = "-" THEN sgn := -1; INC (i) ELSE sgn := 1 END;
  669. LOOP
  670. IF (s[i] >= "0") & (s[i] <= "9") THEN d := ORD (s[i])-ORD ("0")
  671. ELSIF (CAP (s[i]) >= "A") & (CAP (s[i]) <= "F") THEN d := ORD (CAP (s[i]))-ORD ("A") + 10; hex := TRUE
  672. ELSE EXIT
  673. END;
  674. vd := 10*vd + d; vh := 16*vh + d;
  675. INC (i)
  676. END;
  677. IF CAP (s[i]) = "H" THEN hex := TRUE; INC (i) END; (* optional H *)
  678. IF hex THEN vd := vh END;
  679. RETURN sgn * vd
  680. END StrToInt;
  681. (* Delay for IO *)
  682. PROCEDURE -Wait*;
  683. CODE {SYSTEM.AMD64}
  684. JMP N1
  685. N1: JMP N2
  686. N2: JMP N3
  687. N3:
  688. END Wait;
  689. (* Reset processor by causing a double fault. *)
  690. PROCEDURE Reboot;
  691. CODE {SYSTEM.AMD64, SYSTEM.Privileged}
  692. PUSH DWORD 0
  693. PUSH DWORD 0
  694. LIDT [RSP]
  695. INT 3
  696. END Reboot;
  697. (** Shut down the system. If parameter reboot is set, attempt to reboot the system. *)
  698. PROCEDURE Shutdown* (reboot: BOOLEAN);
  699. VAR i: LONGINT;
  700. BEGIN
  701. Cli;
  702. IF reboot THEN (* attempt reboot *)
  703. Portout8 (70H, 8FX); (* Reset type: p. 5-37 AT Tech. Ref. *)
  704. Wait; Portout8 (71H, 0X); (* Note: soft boot flag was set in InitMemory *)
  705. Wait; Portout8 (70H, 0DX);
  706. Wait; Portout8 (64H, 0FEX); (* reset CPU *)
  707. FOR i := 1 TO 10000 DO END;
  708. Reboot
  709. END;
  710. LOOP END
  711. END Shutdown;
  712. (* Get hard disk parameters. *)
  713. PROCEDURE GetPar (p: ADDRESS; ofs: LONGINT): LONGINT;
  714. VAR ch: CHAR;
  715. BEGIN
  716. SYSTEM.GET (p + 12 + ofs, ch);
  717. RETURN ORD (ch)
  718. END GetPar;
  719. (* Read boot table. *)
  720. PROCEDURE ReadBootTable (bt: ADDRESS);
  721. VAR i, p: ADDRESS; j, d, type, addr, size, heapSize: LONGINT; ch: CHAR;
  722. BEGIN
  723. heapSize := 0; lowTop := 0;
  724. p := bt; d := 0;
  725. LOOP
  726. SYSTEM.GET (p, type);
  727. IF type = -1 THEN
  728. EXIT (* end *)
  729. ELSIF type = 3 THEN (* boot memory/top of low memory *)
  730. SYSTEM.GET (p + 8, addr); SYSTEM.GET (p + 12, size);
  731. lowTop := addr + size
  732. ELSIF type = 4 THEN (* free memory/extended memory size *)
  733. SYSTEM.GET (p + 8, addr); SYSTEM.GET (p + 12, size);
  734. IF addr = HeapAdr THEN heapSize := size END
  735. ELSIF type = 5 THEN (* HD config *)
  736. IF d < MaxDisks THEN
  737. chs[d].cyls := GetPar (p, 0) + 100H * GetPar (p, 1);
  738. chs[d].hds := GetPar (p, 2); chs[d].spt := GetPar (p, 14);
  739. INC (d)
  740. END
  741. ELSIF type = 8 THEN (* config strings *)
  742. i := p + 8; j := 0; (* copy the config strings over *)
  743. LOOP
  744. SYSTEM.GET (i, ch); config[j] := ch; INC (i); INC (j);
  745. IF ch = 0X THEN EXIT END;
  746. REPEAT SYSTEM.GET (i, ch); config[j] := ch; INC (i); INC (j) UNTIL ch = 0X; (* end of name *)
  747. REPEAT SYSTEM.GET (i, ch); config[j] := ch; INC (i); INC (j) UNTIL ch = 0X (* end of value *)
  748. END
  749. END;
  750. SYSTEM.GET (p + 4, size); INC (p, size)
  751. END;
  752. ASSERT((heapSize # 0) & (lowTop # 0));
  753. memTop := HeapAdr + heapSize
  754. END ReadBootTable;
  755. (** Read a byte from the non-volatile setup memory. *)
  756. PROCEDURE GetNVByte* (ofs: LONGINT): CHAR;
  757. VAR c: CHAR;
  758. BEGIN
  759. Portout8 (70H, CHR(ofs)); Wait; Portin8(71H, c);
  760. RETURN c
  761. END GetNVByte;
  762. (** Write a byte to the non-volatile setup memory. *)
  763. PROCEDURE PutNVByte* (ofs: LONGINT; val: CHAR);
  764. BEGIN
  765. Portout8 (70H, CHR(ofs)); Wait; Portout8 (71H, val)
  766. END PutNVByte;
  767. (** Compute a checksum for the Intel SMP spec floating pointer structure. *)
  768. PROCEDURE ChecksumMP* (adr: ADDRESS; size: SIZE): LONGINT;
  769. VAR sum: LONGINT; x: ADDRESS; ch: CHAR;
  770. BEGIN
  771. sum := 0;
  772. FOR x := adr TO adr + size-1 DO
  773. SYSTEM.GET (x, ch);
  774. sum := (sum + ORD(ch)) MOD 256
  775. END;
  776. RETURN sum
  777. END ChecksumMP;
  778. (* Search for MP floating pointer structure. *)
  779. PROCEDURE SearchMem (adr: ADDRESS; size: SIZE): ADDRESS;
  780. VAR x, len: LONGINT; ch: CHAR;
  781. BEGIN
  782. WHILE size > 0 DO
  783. SYSTEM.GET (adr, x);
  784. IF x = 05F504D5FH THEN (* "_MP_" found *)
  785. SYSTEM.GET (adr + 8, ch); len := ORD(ch)*16;
  786. IF len > 0 THEN
  787. SYSTEM.GET (adr + 9, ch);
  788. IF (ch = 1X) OR (ch >= 4X) THEN (* version 1.1 or 1.4 or higher *)
  789. IF ChecksumMP(adr, len) = 0 THEN
  790. RETURN adr (* found *)
  791. END
  792. END
  793. END
  794. END;
  795. INC (adr, 16); DEC (size, 16)
  796. END;
  797. RETURN NilAdr (* not found *)
  798. END SearchMem;
  799. (* Search for MP spec info. *)
  800. PROCEDURE SearchMP;
  801. VAR adr: ADDRESS;
  802. BEGIN
  803. adr := 0;
  804. SYSTEM.GET (040EH, SYSTEM.VAL (INTEGER, adr)); (* EBDA address *)
  805. adr := adr*16;
  806. IF adr < 100000H THEN adr := SearchMem(adr, 1024) (* 1. look in EBDA *)
  807. ELSE adr := NilAdr
  808. END;
  809. IF adr = NilAdr THEN (* 2. look in last kb of base memory *)
  810. adr := SearchMem(lowTop + (-lowTop) MOD 10000H - 1024, 1024);
  811. IF adr = NilAdr THEN (* 3. look at top of physical memory *)
  812. adr := SearchMem(memTop - 1024, 1024);
  813. IF adr = NilAdr THEN (* 4. look in BIOS ROM space *)
  814. adr := SearchMem(0E0000H, 20000H)
  815. END
  816. END
  817. END;
  818. IF adr = NilAdr THEN
  819. revMP := 0X; configMP := NilAdr
  820. ELSE
  821. SYSTEM.GET (adr + 9, revMP);
  822. SYSTEM.MOVE(adr + 11, ADDRESSOF(featureMP[0]), 5); (* feature bytes *)
  823. configMP := SYSTEM.GET32 (adr + 4); (* physical address outside reported RAM (spec 1.4 p. 4-2) *)
  824. IF configMP = 0 THEN configMP := NilAdr END
  825. END
  826. END SearchMP;
  827. (* Allocate area for ISA DMA. *)
  828. PROCEDURE AllocateDMA;
  829. VAR old: ADDRESS;
  830. BEGIN
  831. old := lowTop;
  832. dmaSize := DefaultDMASize*1024;
  833. ASSERT((dmaSize >= 0) & (dmaSize <= 65536));
  834. IF (lowTop-dmaSize) DIV 65536 # (lowTop-1) DIV 65536 THEN (* crosses 64KB boundary *)
  835. DEC (lowTop, lowTop MOD 65536) (* round down to 64KB boundary *)
  836. END;
  837. DEC (lowTop, dmaSize); (* allocate memory *)
  838. dmaSize := old - lowTop (* how much was allocated (including rounding) *)
  839. END AllocateDMA;
  840. (* Check if the specified address is RAM. *)
  841. PROCEDURE IsRAM(adr: ADDRESS): BOOLEAN;
  842. CONST Pattern1 = SHORT(0BEEFC0DEH); Pattern2 = SHORT(0AA55FF00H);
  843. VAR save, x: LONGINT; ok: BOOLEAN;
  844. BEGIN
  845. ok := FALSE;
  846. SYSTEM.GET (adr, save);
  847. SYSTEM.PUT (adr, Pattern1); (* attempt 1st write *)
  848. x := Pattern2; (* write something else *)
  849. SYSTEM.GET (adr, x); (* attempt 1st read *)
  850. IF x = Pattern1 THEN (* first test passed *)
  851. SYSTEM.PUT (adr, Pattern2); (* attempt 2nd write *)
  852. x := Pattern1; (* write something else *)
  853. SYSTEM.GET (adr, x); (* attempt 2nd read *)
  854. ok := (x = Pattern2)
  855. END;
  856. SYSTEM.PUT (adr, save);
  857. RETURN ok
  858. END IsRAM;
  859. (* Map the physical address in the second virtual page *)
  860. PROCEDURE -InvalidateTLB (address: ADDRESS);
  861. CODE {SYSTEM.AMD64, SYSTEM.Privileged}
  862. POP RAX
  863. INVLPG [RAX]
  864. END InvalidateTLB;
  865. PROCEDURE -GetPML4Base (): ADDRESS;
  866. CODE {SYSTEM.AMD64}
  867. MOV RAX, CR3
  868. END GetPML4Base;
  869. PROCEDURE -INVLPG (adr: ADDRESS);
  870. CODE {SYSTEM.AMD64, SYSTEM.Privileged}
  871. POP RAX
  872. INVLPG [RAX]
  873. END INVLPG;
  874. (* Check amount of memory available and update memTop. *)
  875. PROCEDURE CheckMemory;
  876. CONST K = 1024; M = K * K; PS = 2 * M; ExtMemAdr = M;
  877. TPS = 4 * K; UserPage = 7; PageNotPresent = 0;
  878. VAR s: ARRAY 16 OF CHAR; i: LONGINT;
  879. physicalAddress, pml4Base, pdpBase, pdBase: ADDRESS;
  880. pml4e, pdpe, pde, lastTable: ADDRESS;
  881. PROCEDURE AllocateTranslationTable (VAR baseAddress, firstEntry: ADDRESS);
  882. BEGIN
  883. baseAddress := lastTable;
  884. firstEntry := baseAddress;
  885. INC (lastTable, TPS);
  886. Fill32 (baseAddress, TPS, PageNotPresent)
  887. END AllocateTranslationTable;
  888. BEGIN
  889. GetConfig("ExtMemSize", s); (* in MB *)
  890. IF s[0] # 0X THEN (* override detection *)
  891. i := 0;
  892. memTop := ExtMemAdr + LONG (StrToInt(i, s)) * M
  893. END;
  894. pml4Base := GetPML4Base ();
  895. DEC (pml4Base, pml4Base MOD TPS);
  896. SYSTEM.GET (pml4Base, pdpBase);
  897. DEC (pdpBase, pdpBase MOD TPS);
  898. SYSTEM.GET (pdpBase, pdBase);
  899. DEC (pdBase, pdBase MOD TPS);
  900. physicalAddress := PS;
  901. lastTable := pdBase + TPS;
  902. pml4e := pml4Base;
  903. pdpe := pdpBase;
  904. pde := pdBase;
  905. WHILE (pml4e < pml4Base + TPS) DO
  906. WHILE (pdpe < pdpBase + TPS) DO
  907. WHILE (pde < pdBase + TPS) DO
  908. INC (pde, 8);
  909. SYSTEM.PUT (pde, physicalAddress + UserPage + 80H);
  910. INVLPG (physicalAddress);
  911. INC (physicalAddress, PS);
  912. IF physicalAddress >= memTop THEN RETURN END;
  913. END;
  914. INC (pdpe, 8);
  915. AllocateTranslationTable (pdBase, pde);
  916. SYSTEM.PUT (pdpe, pde + UserPage);
  917. END;
  918. INC (pml4e, 8);
  919. AllocateTranslationTable (pdpBase, pdpe);
  920. SYSTEM.PUT (pml4e, pdpe + UserPage);
  921. END;
  922. HALT (99);
  923. END CheckMemory;
  924. (* Initialize locks. *)
  925. PROCEDURE InitLocks;
  926. VAR i: LONGINT; s: ARRAY 12 OF CHAR;
  927. BEGIN
  928. IF TimeCount # 0 THEN
  929. GetConfig("LockTimeout", s);
  930. i := 0; maxTime := StrToInt(i, s);
  931. IF maxTime > MAX(LONGINT) DIV 1000000 THEN
  932. maxTime := MAX(LONGINT)
  933. ELSE
  934. maxTime := maxTime * 1000000
  935. END
  936. END;
  937. FOR i := 0 TO MaxCPU-1 DO
  938. proc[i].locksHeld := {}; proc[i].preemptCount := 0
  939. END;
  940. FOR i := 0 TO MaxLocks-1 DO
  941. lock[i].locked := FALSE
  942. END
  943. END InitLocks;
  944. (* Return flags state. *)
  945. PROCEDURE -GetFlags (): SET;
  946. CODE {SYSTEM.AMD64}
  947. PUSHFQ
  948. POP RAX
  949. END GetFlags;
  950. (* Set flags state. *)
  951. PROCEDURE -SetFlags (s: SET);
  952. CODE {SYSTEM.AMD64}
  953. POPFQ
  954. END SetFlags;
  955. PROCEDURE -PushFlags*;
  956. CODE {SYSTEM.AMD64}
  957. PUSHFQ
  958. END PushFlags;
  959. PROCEDURE -PopFlags*;
  960. CODE {SYSTEM.AMD64}
  961. POPFQ
  962. END PopFlags;
  963. (** Disable preemption on the current processor (increment the preemption counter). Returns the current processor ID as side effect. *)
  964. PROCEDURE AcquirePreemption* (): LONGINT;
  965. VAR id: LONGINT;
  966. BEGIN
  967. PushFlags; Cli;
  968. id := ID ();
  969. INC (proc[id].preemptCount);
  970. PopFlags;
  971. RETURN id
  972. END AcquirePreemption;
  973. (** Enable preemption on the current processor (decrement the preemption counter). *)
  974. PROCEDURE ReleasePreemption*;
  975. VAR id: LONGINT;
  976. BEGIN
  977. PushFlags; Cli;
  978. id := ID ();
  979. IF StrongChecks THEN
  980. ASSERT(proc[id].preemptCount > 0)
  981. END;
  982. DEC (proc[id].preemptCount);
  983. PopFlags
  984. END ReleasePreemption;
  985. (** Return the preemption counter of the current processor (specified in parameter). *)
  986. PROCEDURE PreemptCount* (id: LONGINT): LONGINT;
  987. BEGIN
  988. IF StrongChecks THEN
  989. (*ASSERT(~(9 IN GetFlags ()));*) (* interrupts off *) (* commented out because check is too strong *)
  990. ASSERT(id = ID ()) (* caller must specify current processor *)
  991. END;
  992. RETURN proc[id].preemptCount
  993. END PreemptCount;
  994. (* Spin waiting for a lock. Return AL = 1X iff timed out. *)
  995. PROCEDURE AcquireSpinTimeout(VAR locked: BOOLEAN; count: LONGINT; flags: SET): CHAR;
  996. CODE {SYSTEM.AMD64}
  997. MOV RSI, [RBP + flags] ; RSI := flags
  998. MOV EDI, [RBP + count] ; RDI := count
  999. MOV RBX, [RBP + locked] ; RBX := ADR(locked)
  1000. MOV AL, 1 ; AL := 1
  1001. CLI ; switch interrupts off before acquiring lock
  1002. test:
  1003. CMP [RBX], AL ; locked? { AL = 1 }
  1004. JE wait ; yes, go wait
  1005. XCHG [RBX], AL ; set and read the lock atomically. LOCK prefix implicit.
  1006. CMP AL, 1 ; was locked?
  1007. JNE exit ; no, we have it now, interrupts are off, and AL # 1
  1008. wait:
  1009. ; ASSERT(AL = 1)
  1010. XOR RCX, RCX ; just in case some processor interprets REP this way
  1011. REP NOP ; PAUSE instruction (* see SpinHint *)
  1012. TEST RSI, 200H ; bit 9 - IF
  1013. JZ intoff
  1014. STI ; restore interrupt state quickly to allow pending interrupts (e.g. AosProcessors.StopAll/Broadcast)
  1015. NOP ; NOP required, otherwise STI; CLI not interruptable
  1016. CLI ; disable interrupts
  1017. intoff:
  1018. DEC EDI ; counter
  1019. JNZ test ; not timed out yet
  1020. OR EDI, [RBP + count] ; re-fetch original value & set flags
  1021. JZ test ; if count = 0, retry forever
  1022. ; timed out (AL = 1)
  1023. exit:
  1024. END AcquireSpinTimeout;
  1025. (** Acquire a spin-lock and disable interrupts. *)
  1026. PROCEDURE Acquire* (level: LONGINT);
  1027. VAR id, i: LONGINT; flags: SET; start: HUGEINT;
  1028. BEGIN
  1029. id := AcquirePreemption ();
  1030. flags := GetFlags (); (* store state of interrupt flag *)
  1031. IF StrongChecks THEN
  1032. ASSERT(~(9 IN flags) OR (proc[id].locksHeld = {})); (* interrupts enabled => no locks held *)
  1033. ASSERT(~(level IN proc[id].locksHeld)) (* recursive locks not allowed *)
  1034. END;
  1035. IF (TimeCount = 0) OR (maxTime = 0) THEN
  1036. IF AcquireSpinTimeout(lock[level].locked, 0, flags) = 0X THEN END; (* {interrupts off} *)
  1037. ELSE
  1038. start := GetTimer ();
  1039. WHILE AcquireSpinTimeout(lock[level].locked, TimeCount, flags) = 1X DO
  1040. IF GetTimer () - start > maxTime THEN
  1041. trapState := proc;
  1042. trapLocksBusy := {};
  1043. FOR i := 0 TO MaxLocks-1 DO
  1044. IF lock[i].locked THEN INCL(trapLocksBusy, i) END
  1045. END;
  1046. HALT(1301) (* Lock timeout - see Traps *)
  1047. END
  1048. END
  1049. END;
  1050. IF proc[id].locksHeld = {} THEN
  1051. proc[id].state := flags
  1052. END;
  1053. INCL(proc[id].locksHeld, level); (* we now hold the lock *)
  1054. IF StrongChecks THEN (* no lower-level locks currently held by this processor *)
  1055. ASSERT((level = 0) OR (proc[id].locksHeld * {0..level-1} = {}))
  1056. END
  1057. END Acquire;
  1058. (** Release a spin-lock. Switch on interrupts when last lock released. *)
  1059. PROCEDURE Release* (level: LONGINT);
  1060. VAR id: LONGINT; flags: SET;
  1061. BEGIN (* {interrupts off} *)
  1062. id := ID ();
  1063. IF StrongChecks THEN
  1064. ASSERT(~(9 IN GetFlags ())); (* {interrupts off} *)
  1065. ASSERT(lock[level].locked);
  1066. ASSERT(level IN proc[id].locksHeld)
  1067. END;
  1068. EXCL(proc[id].locksHeld, level);
  1069. IF proc[id].locksHeld = {} THEN
  1070. flags := proc[id].state ELSE flags := GetFlags ()
  1071. END;
  1072. lock[level].locked := FALSE;
  1073. SetFlags(flags);
  1074. ReleasePreemption
  1075. END Release;
  1076. (** Acquire all locks. Only for exceptional cases. *)
  1077. PROCEDURE AcquireAll*;
  1078. VAR lock: LONGINT;
  1079. BEGIN
  1080. FOR lock := HighestLock TO LowestLock BY -1 DO Acquire(lock) END
  1081. END AcquireAll;
  1082. (** Release all locks. Reverse of AcquireAll. *)
  1083. PROCEDURE ReleaseAll*;
  1084. VAR lock: LONGINT;
  1085. BEGIN
  1086. FOR lock := LowestLock TO HighestLock DO Release(lock) END
  1087. END ReleaseAll;
  1088. (** Break all locks held by current processor (for exception handling). Returns levels released. *)
  1089. PROCEDURE BreakAll* (): SET;
  1090. VAR id, level: LONGINT; released: SET;
  1091. BEGIN
  1092. id := AcquirePreemption ();
  1093. PushFlags; Cli;
  1094. released := {};
  1095. FOR level := 0 TO MaxLocks-1 DO
  1096. IF level IN proc[id].locksHeld THEN
  1097. lock[level].locked := FALSE; (* break the lock *)
  1098. EXCL(proc[id].locksHeld, level);
  1099. INCL(released, level)
  1100. END
  1101. END;
  1102. IF proc[id].preemptCount > 1 THEN INCL(released, Preemption) END;
  1103. proc[id].preemptCount := 0; (* clear preemption flag *)
  1104. PopFlags;
  1105. RETURN released
  1106. END BreakAll;
  1107. (** Acquire a fine-grained lock on an active object. *)
  1108. PROCEDURE AcquireObject* (VAR locked: BOOLEAN);
  1109. CODE {SYSTEM.AMD64}
  1110. PUSHFQ
  1111. MOV RBX, [RBP + locked] ; RBX := ADR(locked)
  1112. MOV AL, 1
  1113. test:
  1114. CMP [RBX], AL ; locked? { AL = 1 }
  1115. JNE try
  1116. STI
  1117. PAUSE ; PAUSE instruction (* see SpinHint *)
  1118. CLI
  1119. JMP test
  1120. try:
  1121. XCHG [RBX], AL ; set and read the lock atomically. LOCK prefix implicit.
  1122. CMP AL, 1 ; was locked?
  1123. JE test ; yes, try again
  1124. POPFQ
  1125. END AcquireObject;
  1126. (** Release an active object lock. *)
  1127. PROCEDURE ReleaseObject* (VAR locked: BOOLEAN);
  1128. CODE {SYSTEM.AMD64}
  1129. MOV RBX, [RBP + locked] ; RBX := ADR(locked)
  1130. MOV BYTE [RBX], 0
  1131. END ReleaseObject;
  1132. (* Load global descriptor table *)
  1133. PROCEDURE LoadGDT(base: ADDRESS; size: SIZE);
  1134. CODE {SYSTEM.AMD64, SYSTEM.Privileged}
  1135. ; LGDT needs 10 bytes: 2 for the 16-bit limit and 8 for the 64-bit base address in this order
  1136. ; Assumption: size argument in front of base -> promote size value to upper 48 bits of size
  1137. SHL QWORD [RBP + size], 64-16
  1138. LGDT [RBP + size + (64-16) / 8]
  1139. END LoadGDT;
  1140. (* Load segment registers *)
  1141. PROCEDURE LoadSegRegs(data: INTEGER);
  1142. CODE {SYSTEM.AMD64}
  1143. MOV AX, [RBP + data]
  1144. MOV DS, AX
  1145. XOR AX, AX
  1146. MOV ES, AX
  1147. MOV FS, AX
  1148. MOV GS, AX
  1149. END LoadSegRegs;
  1150. (* Return CS. *)
  1151. PROCEDURE -CS* (): INTEGER;
  1152. CODE {SYSTEM.AMD64}
  1153. MOV AX, CS
  1154. END CS;
  1155. (** -- Memory management -- *)
  1156. (* Allocate a physical page below 1M. Parameter adr returns physical and virtual address (or NilAdr).*)
  1157. PROCEDURE NewLowPage(VAR adr: ADDRESS);
  1158. BEGIN
  1159. adr := freeLowPage;
  1160. IF freeLowPage # NilAdr THEN
  1161. SYSTEM.GET (freeLowPage, freeLowPage); (* freeLowPage := freeLowPage.next *)
  1162. DEC(freeLowPages)
  1163. END
  1164. END NewLowPage;
  1165. (* Allocate a directly-mapped page. Parameter adr returns physical and virtual address (or NilAdr). *)
  1166. PROCEDURE NewDirectPage(VAR adr: ADDRESS);
  1167. BEGIN
  1168. IF pageHeapAdr # heapEndAdr THEN
  1169. DEC(pageHeapAdr, PS); adr := pageHeapAdr;
  1170. DEC(freeHighPages)
  1171. ELSE
  1172. adr := NilAdr
  1173. END
  1174. END NewDirectPage;
  1175. (* Allocate a physical page. *)
  1176. PROCEDURE NewPage(VAR physAdr: ADDRESS);
  1177. VAR sp, prev: ADDRESS;
  1178. BEGIN
  1179. SYSTEM.GET(pageStackAdr + NodeSP, sp);
  1180. ASSERT((sp >= MinSP) & (sp <= MaxSP) & (sp MOD AddressSize = 0)); (* index check *)
  1181. IF sp > MinSP THEN (* stack not empty, pop entry *)
  1182. DEC(sp, AddressSize);
  1183. SYSTEM.GET (pageStackAdr+sp, physAdr);
  1184. SYSTEM.PUT (pageStackAdr+NodeSP, sp);
  1185. SYSTEM.GET (pageStackAdr+NodePrev, prev);
  1186. IF (sp = MinSP) & (prev # NilAdr) THEN
  1187. pageStackAdr := prev
  1188. END;
  1189. DEC(freeHighPages)
  1190. ELSE
  1191. NewDirectPage(physAdr)
  1192. END
  1193. END NewPage;
  1194. (* Deallocate a physical page. *)
  1195. PROCEDURE DisposePage(physAdr: ADDRESS);
  1196. VAR sp, next, newAdr: ADDRESS;
  1197. BEGIN
  1198. SYSTEM.GET (pageStackAdr + NodeSP, sp);
  1199. ASSERT((sp >= MinSP) & (sp <= MaxSP) & (sp MOD AddressSize = 0)); (* index check *)
  1200. IF sp = MaxSP THEN (* current stack full *)
  1201. SYSTEM.GET (pageStackAdr + NodeNext, next);
  1202. IF next # NilAdr THEN (* next stack exists, make it current *)
  1203. pageStackAdr := next;
  1204. SYSTEM.GET (pageStackAdr+NodeSP, sp);
  1205. ASSERT(sp = MinSP) (* must be empty *)
  1206. ELSE (* allocate next stack *)
  1207. NewDirectPage(newAdr);
  1208. IF newAdr = NilAdr THEN
  1209. NewLowPage(newAdr); (* try again from reserve *)
  1210. IF newAdr = NilAdr THEN
  1211. IF Stats THEN INC(NlostPages) END;
  1212. RETURN (* give up (the disposed page is lost) *)
  1213. ELSE
  1214. IF Stats THEN INC(NreservePagesUsed) END
  1215. END
  1216. END;
  1217. sp := MinSP; (* will be written to NodeSP below *)
  1218. SYSTEM.PUT (newAdr + NodeNext, next);
  1219. SYSTEM.PUT (newAdr + NodePrev, pageStackAdr);
  1220. pageStackAdr := newAdr
  1221. END
  1222. END;
  1223. (* push entry on current stack *)
  1224. SYSTEM.PUT (pageStackAdr + sp, physAdr);
  1225. SYSTEM.PUT (pageStackAdr + NodeSP, sp + AddressSize);
  1226. INC(freeHighPages)
  1227. END DisposePage;
  1228. (* Allocate virtual address space for mapping. Parameter size must be multiple of page size. Parameter virtAdr returns virtual address or NilAdr on failure. *)
  1229. PROCEDURE NewVirtual(VAR virtAdr: ADDRESS; size: SIZE);
  1230. BEGIN
  1231. ASSERT(size MOD PS = 0);
  1232. (*
  1233. IF mapTop+size > MapAreaAdr+MapAreaSize THEN
  1234. virtAdr := NilAdr (* out of virtual space *)
  1235. ELSE
  1236. virtAdr := mapTop;
  1237. INC(mapTop, size)
  1238. END
  1239. *)
  1240. (* this code is commented because PACO produces weird behaviour when used with
  1241. 64-bit ADDRESS*)
  1242. virtAdr := mapTop;
  1243. INC(mapTop, size)
  1244. END NewVirtual;
  1245. PROCEDURE DisposeVirtual(virtAdr: ADDRESS; size: SIZE);
  1246. (* to do *)
  1247. END DisposeVirtual;
  1248. (* Map a physical page into the virtual address space. Parameter virtAdr is mapped address and phys is mapping value. Returns TRUE iff mapping successful. *)
  1249. PROCEDURE MapTable (base, index: ADDRESS): ADDRESS;
  1250. VAR pt: ADDRESS;
  1251. BEGIN
  1252. SYSTEM.GET (base + index * AddressSize, pt);
  1253. IF ODD (pt) THEN (* pt present *)
  1254. DEC (pt, pt MOD TPS)
  1255. ELSE
  1256. NewPage(pt);
  1257. IF pt = NilAdr THEN RETURN NilAdr END;
  1258. SYSTEM.PUT (base + index * AddressSize, pt + UserPage);
  1259. Fill32 (pt, TPS, PageNotPresent)
  1260. END;
  1261. RETURN pt;
  1262. END MapTable;
  1263. PROCEDURE MapPage(virtAdr, phys: ADDRESS): BOOLEAN;
  1264. VAR i, pt: ADDRESS;
  1265. pml4e, pdpe, pde, pte: ADDRESS;
  1266. BEGIN
  1267. virtAdr := virtAdr DIV PS;
  1268. pte := virtAdr MOD PTEs; virtAdr := virtAdr DIV PTEs;
  1269. pde := virtAdr MOD PTEs; virtAdr := virtAdr DIV PTEs;
  1270. pdpe := virtAdr MOD PTEs; virtAdr := virtAdr DIV PTEs;
  1271. pml4e := virtAdr MOD PTEs;
  1272. pt := MapTable (kernelPML4, pml4e);
  1273. IF pt = NilAdr THEN RETURN FALSE END;
  1274. pt := MapTable (pt, pdpe);
  1275. IF pt = NilAdr THEN RETURN FALSE END;
  1276. pt := MapTable (pt, pde);
  1277. IF pt = NilAdr THEN RETURN FALSE END;
  1278. SYSTEM.PUT(pt + pte * AddressSize, phys);
  1279. RETURN TRUE;
  1280. END MapPage;
  1281. (* Return mapped page address for a given virtual address (ODD if mapped) *)
  1282. PROCEDURE MappedPage(virtAdr: ADDRESS): ADDRESS;
  1283. VAR pt: ADDRESS;
  1284. pml4e, pdpe, pde, pte: ADDRESS;
  1285. BEGIN
  1286. virtAdr := virtAdr DIV PS;
  1287. pte := virtAdr MOD PTEs; virtAdr := virtAdr DIV PTEs;
  1288. pde := virtAdr MOD PTEs; virtAdr := virtAdr DIV PTEs;
  1289. pdpe := virtAdr MOD PTEs; virtAdr := virtAdr DIV PTEs;
  1290. pml4e := virtAdr MOD PTEs;
  1291. SYSTEM.GET(kernelPML4 + pml4e * AddressSize, pt);
  1292. IF ~ODD(pt) THEN RETURN 0 END;
  1293. DEC (pt, pt MOD 1000H);
  1294. SYSTEM.GET(pt + pdpe * AddressSize, pt);
  1295. IF ~ODD(pt) THEN RETURN 0 END;
  1296. DEC (pt, pt MOD 1000H);
  1297. SYSTEM.GET(pt + pde * AddressSize, pt);
  1298. IF ~ODD(pt) THEN RETURN 0 END;
  1299. DEC (pt, pt MOD 1000H);
  1300. SYSTEM.GET (pt + pte * AddressSize, pt);
  1301. RETURN pt;
  1302. END MappedPage;
  1303. (* Unmap a page and return the previous mapping, like MappedPage (). Caller must flush TLB. *)
  1304. PROCEDURE UnmapPage(virtAdr: ADDRESS): ADDRESS;
  1305. VAR t, pt: ADDRESS;
  1306. pml4e, pdpe, pde, pte: ADDRESS;
  1307. BEGIN
  1308. virtAdr := virtAdr DIV PS;
  1309. pte := virtAdr MOD PTEs; virtAdr := virtAdr DIV PTEs;
  1310. pde := virtAdr MOD PTEs; virtAdr := virtAdr DIV PTEs;
  1311. pdpe := virtAdr MOD PTEs; virtAdr := virtAdr DIV PTEs;
  1312. pml4e := virtAdr MOD PTEs;
  1313. SYSTEM.GET(kernelPML4 + pml4e * AddressSize, pt);
  1314. IF ~ODD(pt) THEN RETURN 0 END;
  1315. DEC (pt, pt MOD 1000H);
  1316. SYSTEM.GET(pt + pdpe * AddressSize, pt);
  1317. IF ~ODD(pt) THEN RETURN 0 END;
  1318. DEC (pt, pt MOD 1000H);
  1319. SYSTEM.GET(pt + pde * AddressSize, pt);
  1320. IF ~ODD(pt) THEN RETURN 0 END;
  1321. DEC (pt, pt MOD 1000H);
  1322. SYSTEM.GET(pt + pte * AddressSize, t);
  1323. SYSTEM.PUT(pt + pte * AddressSize, NIL);
  1324. INVLPG (t);
  1325. RETURN t;
  1326. END UnmapPage;
  1327. (* Map area [virtAdr..virtAdr+size) directly to area [Adr(phys)..Adr(phys)+size). Returns TRUE iff successful. *)
  1328. PROCEDURE MapDirect(virtAdr: ADDRESS; size: SIZE; phys: ADDRESS): BOOLEAN;
  1329. BEGIN
  1330. (*
  1331. Trace.String("MapDirect "); Trace.Address (virtAdr); Trace.Char(' '); Trace.Address (phys); Trace.Char (' '); Trace.Int (size, 0);
  1332. Trace.Int(size DIV PS, 8); Trace.Ln;
  1333. *)
  1334. ASSERT((virtAdr MOD PS = 0) & (size MOD PS = 0));
  1335. WHILE size # 0 DO
  1336. IF ~ODD(MappedPage(virtAdr)) THEN
  1337. IF ~MapPage(virtAdr, phys) THEN RETURN FALSE END
  1338. END;
  1339. INC(virtAdr, PS); INC(phys, PS); DEC(size, PS)
  1340. END;
  1341. RETURN TRUE
  1342. END MapDirect;
  1343. (* Policy decision for heap expansion. NewBlock for the same block has failed try times. *)
  1344. PROCEDURE ExpandNow(try: LONGINT): BOOLEAN;
  1345. VAR size: SIZE;
  1346. BEGIN
  1347. size := LSH(memBlockTail.endBlockAdr - memBlockHead.beginBlockAdr, -10); (* heap size in KB *)
  1348. RETURN (~ODD(try) OR (size < heapMinKB)) & (size < heapMaxKB)
  1349. END ExpandNow;
  1350. (* Try to expand the heap by at least "size" bytes *)
  1351. PROCEDURE ExpandHeap*(try: LONGINT; size: SIZE; VAR memBlock: MemoryBlock; VAR beginBlockAdr, endBlockAdr: ADDRESS);
  1352. BEGIN
  1353. IF ExpandNow(try) THEN
  1354. IF size < expandMin THEN size := expandMin END;
  1355. beginBlockAdr := memBlockHead.endBlockAdr;
  1356. endBlockAdr := beginBlockAdr;
  1357. INC(endBlockAdr, size);
  1358. SetHeapEndAdr(endBlockAdr); (* in/out parameter *)
  1359. memBlock := memBlockHead;
  1360. (* 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 *)
  1361. ELSE
  1362. beginBlockAdr := memBlockHead.endBlockAdr;
  1363. endBlockAdr := memBlockHead.endBlockAdr;
  1364. memBlock := NIL
  1365. END
  1366. END ExpandHeap;
  1367. (* Set memory block end address *)
  1368. PROCEDURE SetMemoryBlockEndAddress*(memBlock: MemoryBlock; endBlockAdr: ADDRESS);
  1369. BEGIN
  1370. ASSERT(endBlockAdr >= memBlock.beginBlockAdr);
  1371. memBlock.endBlockAdr := endBlockAdr
  1372. END SetMemoryBlockEndAddress;
  1373. (* Free unused memory block *)
  1374. PROCEDURE FreeMemBlock*(memBlock: MemoryBlock);
  1375. BEGIN
  1376. HALT(515) (* impossible to free heap in I386 native A2 version *)
  1377. END FreeMemBlock;
  1378. (** 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). *)
  1379. PROCEDURE SetHeapEndAdr(VAR endAdr: ADDRESS);
  1380. VAR n, m: SIZE;
  1381. BEGIN
  1382. Acquire(Memory);
  1383. n := LSH(endAdr+(PS-1), -PSlog2) - LSH(heapEndAdr, -PSlog2); (* pages requested *)
  1384. m := LSH(pageHeapAdr, -PSlog2) - LSH(heapEndAdr, -PSlog2) - ReservedPages; (* max pages *)
  1385. IF n > m THEN n := m END;
  1386. IF n > 0 THEN INC(heapEndAdr, n*PS); DEC(freeHighPages, n) END;
  1387. endAdr := heapEndAdr;
  1388. Release(Memory)
  1389. END SetHeapEndAdr;
  1390. (** Map a physical memory area (physAdr..physAdr+size-1) into the virtual address space. Parameter virtAdr returns the virtual address of mapped region, or NilAdr on failure. *)
  1391. PROCEDURE MapPhysical*(physAdr: ADDRESS; size: SIZE; VAR virtAdr: ADDRESS);
  1392. VAR ofs: ADDRESS;
  1393. BEGIN
  1394. IF (LSH(physAdr, -PSlog2) <= topPageNum) &
  1395. (LSH(physAdr+size-1, -PSlog2) <= topPageNum) &
  1396. (LSH(physAdr, -PSlog2) >= LSH(LowAdr, -PSlog2)) THEN
  1397. virtAdr := physAdr (* directly mapped *)
  1398. ELSE
  1399. ofs := physAdr MOD PS;
  1400. DEC(physAdr, ofs); INC(size, ofs); (* align start to page boundary *)
  1401. INC(size, (-size) MOD PS); (* align end to page boundary *)
  1402. Acquire(Memory);
  1403. NewVirtual(virtAdr, size);
  1404. IF virtAdr # NilAdr THEN
  1405. IF ~MapDirect(virtAdr, size, physAdr + UserPage) THEN
  1406. DisposeVirtual(virtAdr, size);
  1407. virtAdr := NilAdr
  1408. END
  1409. END;
  1410. Release(Memory);
  1411. IF TraceVerbose THEN
  1412. Acquire (TraceOutput);
  1413. Trace.String("Mapping ");
  1414. Trace.IntSuffix(SHORT(size), 1, "B"); Trace.String(" at ");
  1415. Trace.Address (physAdr); Trace.String (" - "); Trace.Address (physAdr+size-1);
  1416. IF virtAdr = NilAdr THEN
  1417. Trace.String(" failed")
  1418. ELSE
  1419. Trace.String (" to "); Trace.Address (virtAdr);
  1420. IF ofs # 0 THEN Trace.String (", offset "); Trace.Int(SHORT(ofs), 0) END
  1421. END;
  1422. Trace.Ln;
  1423. Release (TraceOutput);
  1424. END;
  1425. IF virtAdr # NilAdr THEN INC(virtAdr, ofs) END (* adapt virtual address to correct offset *)
  1426. END
  1427. END MapPhysical;
  1428. (** Unmap an area previously mapped with MapPhysical. *)
  1429. PROCEDURE UnmapPhysical*(virtAdr: ADDRESS; size: SIZE);
  1430. (* to do *)
  1431. END UnmapPhysical;
  1432. (** Return the physical address of the specified range of memory, or NilAdr if the range is not contiguous. It is the caller's responsibility to assure the range remains allocated during the time it is in use. *)
  1433. PROCEDURE PhysicalAdr*(adr: ADDRESS; size: SIZE): ADDRESS;
  1434. VAR physAdr, mapped, expected: ADDRESS;
  1435. BEGIN
  1436. IF (LSH(adr, -PSlog2) <= topPageNum) & (LSH(adr+size-1, -PSlog2) <= topPageNum) THEN
  1437. RETURN adr (* directly mapped *)
  1438. ELSE
  1439. Acquire(Memory);
  1440. mapped := MappedPage(adr);
  1441. Release(Memory);
  1442. IF ODD(mapped) & (size > 0) THEN (* mapped, and range not empty or too big *)
  1443. physAdr := mapped - mapped MOD PS + adr MOD PS; (* strip paging bits and add page offset *)
  1444. (* now check if whole range is physically contiguous *)
  1445. DEC(size, PS - adr MOD PS); (* subtract distance to current page end *)
  1446. IF size > 0 THEN (* range crosses current page end *)
  1447. expected := LSH(mapped, -PSlog2)+1; (* expected physical page *)
  1448. LOOP
  1449. INC(adr, PS); (* step to next page *)
  1450. Acquire(Memory);
  1451. mapped := MappedPage(adr);
  1452. Release(Memory);
  1453. IF ~ODD(mapped) OR (LSH(mapped, -PSlog2) # expected) THEN
  1454. physAdr := NilAdr; EXIT
  1455. END;
  1456. DEC(size, PS);
  1457. IF size <= 0 THEN EXIT END; (* ok *)
  1458. INC(expected)
  1459. END
  1460. ELSE
  1461. (* ok, skip *)
  1462. END
  1463. ELSE
  1464. physAdr := NilAdr
  1465. END;
  1466. RETURN physAdr
  1467. END
  1468. END PhysicalAdr;
  1469. (** Translate a virtual address range to num ranges of physical address. num returns 0 on error. *)
  1470. PROCEDURE TranslateVirtual*(virtAdr: ADDRESS; size: SIZE; VAR num: LONGINT; VAR physAdr: ARRAY OF Range);
  1471. VAR ofs, phys1: ADDRESS; size1: SIZE;
  1472. BEGIN
  1473. Acquire(Memory);
  1474. num := 0;
  1475. LOOP
  1476. IF size = 0 THEN EXIT END;
  1477. IF num = LEN(physAdr) THEN num := 0; EXIT END; (* index check *)
  1478. ofs := virtAdr MOD PS; (* offset in page *)
  1479. size1 := PS - ofs; (* distance to next page boundary *)
  1480. IF size1 > size THEN size1 := size END;
  1481. phys1 := MappedPage(virtAdr);
  1482. IF ~ODD(phys1) THEN num := 0; EXIT END; (* page not present *)
  1483. physAdr[num].adr := phys1 - phys1 MOD PS + ofs;
  1484. physAdr[num].size := size1; INC(num);
  1485. INC(virtAdr, size1); DEC(size, size1)
  1486. END;
  1487. IF num = 0 THEN physAdr[0].adr := NilAdr; physAdr[0].size := 0 END;
  1488. Release(Memory)
  1489. END TranslateVirtual;
  1490. (** Return information on free memory in Kbytes. *)
  1491. PROCEDURE GetFreeK*(VAR total, lowFree, highFree: SIZE);
  1492. CONST KperPage = PS DIV 1024;
  1493. BEGIN
  1494. Acquire(Memory);
  1495. total := totalPages * KperPage;
  1496. lowFree := freeLowPages * KperPage;
  1497. highFree := freeHighPages * KperPage;
  1498. Release(Memory)
  1499. END GetFreeK;
  1500. (** -- Stack -- *)
  1501. (** Extend the stack to include the specified address, if possible. Returns TRUE iff ok. *)
  1502. PROCEDURE ExtendStack*(VAR s: Stack; virtAdr: ADDRESS): BOOLEAN;
  1503. VAR phys: ADDRESS; ok: BOOLEAN;
  1504. BEGIN
  1505. Acquire(Memory);
  1506. ok := FALSE;
  1507. IF (virtAdr < s.high) & (virtAdr >= s.low) THEN
  1508. DEC(virtAdr, virtAdr MOD PS); (* round down to page boundary *)
  1509. IF Stats & (virtAdr < s.adr-PS) THEN INC(Nbigskips) END;
  1510. IF ODD(MappedPage(virtAdr)) THEN (* already mapped *)
  1511. ok := TRUE
  1512. ELSE
  1513. NewPage(phys);
  1514. IF phys # NilAdr THEN
  1515. IF MapPage(virtAdr, phys + UserPage) THEN
  1516. IF virtAdr < s.adr THEN
  1517. s.adr := virtAdr
  1518. ELSE
  1519. IF Stats THEN INC(Nfilled) END
  1520. END;
  1521. ok := TRUE
  1522. ELSE
  1523. DisposePage(phys)
  1524. END
  1525. END
  1526. END
  1527. END;
  1528. Release(Memory);
  1529. RETURN ok
  1530. END ExtendStack;
  1531. (** Allocate a stack. Parameter initSP returns initial stack pointer value. *)
  1532. PROCEDURE NewStack*(VAR s: Stack; process: ANY; VAR initSP: ADDRESS);
  1533. VAR adr, phys: ADDRESS; old: HUGEINT; free: SET;
  1534. BEGIN
  1535. ASSERT(InitUserStackSize = PS); (* for now *)
  1536. Acquire(Memory);
  1537. IF Stats THEN INC(NnewStacks) END;
  1538. old := freeStackIndex;
  1539. LOOP
  1540. IF Stats THEN INC(NnewStackLoops) END;
  1541. free := freeStack[freeStackIndex];
  1542. IF free # {} THEN
  1543. adr := 0; WHILE ~(adr IN free) DO INC(adr) END; (* BTW: BSF instruction is not faster *)
  1544. IF Stats THEN INC(NnewStackInnerLoops, adr+1) END;
  1545. EXCL(freeStack[freeStackIndex], adr);
  1546. adr := 10000000H + (freeStackIndex*SetSize + adr)*MaxUserStackSize; (*StackAreaAdr *)
  1547. EXIT
  1548. END;
  1549. INC(freeStackIndex);
  1550. IF freeStackIndex = LEN(freeStack) THEN freeStackIndex := 0 END;
  1551. IF freeStackIndex = old THEN HALT(1503) END (* out of stack space *)
  1552. END;
  1553. NewPage(phys); ASSERT(phys # NilAdr); (* allocate one physical page at first *)
  1554. s.high := adr + MaxUserStackSize; s.low := adr + UserStackGuardSize;
  1555. s.adr := s.high - InitUserStackSize; (* at the top of the virtual area *)
  1556. initSP := s.high-AddressSize;
  1557. IF ~MapPage(s.adr, phys + UserPage) THEN HALT(99) END;
  1558. SYSTEM.PUT (initSP, process);
  1559. Release(Memory)
  1560. END NewStack;
  1561. (** Return the process pointer set when the current user stack was created (must be running on user stack). *)
  1562. PROCEDURE -GetProcessPtr* (): ANY;
  1563. CODE {SYSTEM.AMD64}
  1564. MOV RAX, -MaxUserStackSize
  1565. AND RAX, RSP
  1566. MOV RAX, [RAX + MaxUserStackSize - 8]
  1567. POP RBX; pointer return passed via stack
  1568. MOV [RBX], RAX
  1569. END GetProcessPtr;
  1570. (** True iff current process works on a kernel stack *)
  1571. PROCEDURE WorkingOnKernelStack* (): BOOLEAN;
  1572. VAR id: LONGINT; sp: ADDRESS;
  1573. BEGIN
  1574. ASSERT(KernelStackSize # MaxUserStackSize - UserStackGuardSize); (* detection does only work with this assumption *)
  1575. sp := CurrentSP ();
  1576. id := ID ();
  1577. RETURN (sp >= procm[id].stack.low) & (sp <= procm[id].stack.high)
  1578. END WorkingOnKernelStack;
  1579. (** Deallocate a stack. Current thread should not dispose its own stack. Uses privileged instructions. *)
  1580. PROCEDURE DisposeStack*(CONST s: Stack);
  1581. VAR adr, phys: ADDRESS;
  1582. BEGIN
  1583. (* First make sure there are no references to virtual addresses of the old stack in the TLBs. This is required because we are freeing the pages, and they could be remapped later at different virtual addresses. DisposeStack will only be called from the thread finalizer, which ensures that the user will no longer be referencing this memory. Therefore we can make this upcall from outside the locked region, avoiding potential deadlock. *)
  1584. GlobalFlushTLB; (* finalizers are only called after Processors has initialized this upcall *)
  1585. Acquire(Memory);
  1586. IF Stats THEN INC(NdisposeStacks) END;
  1587. adr := s.adr; (* unmap and deallocate all pages of stack *)
  1588. REPEAT
  1589. phys := UnmapPage(adr); (* TLB was flushed and no intermediate references possible to unreachable stack *)
  1590. IF ODD(phys) THEN DisposePage(phys - phys MOD PS) END;
  1591. INC(adr, PS)
  1592. UNTIL adr = s.high;
  1593. adr := (adr - MaxUserStackSize - StackAreaAdr) DIV MaxUserStackSize;
  1594. INCL(freeStack[adr DIV 32], adr MOD 32);
  1595. Release(Memory)
  1596. END DisposeStack;
  1597. (** Check if the specified stack is valid. *)
  1598. PROCEDURE ValidStack*(CONST s: Stack; sp: ADDRESS): BOOLEAN;
  1599. VAR valid: BOOLEAN;
  1600. BEGIN
  1601. Acquire(Memory);
  1602. valid := (sp MOD 4 = 0) & (sp >= s.adr) & (sp <= s.high);
  1603. WHILE valid & (sp < s.high) DO
  1604. valid := ODD(MappedPage(sp));
  1605. INC(sp, PS)
  1606. END;
  1607. Release(Memory);
  1608. RETURN valid
  1609. END ValidStack;
  1610. (** Update the stack snapshot of the current processor. (for Processors) *)
  1611. PROCEDURE UpdateState*;
  1612. VAR id: LONGINT;
  1613. BEGIN
  1614. ASSERT(CS () MOD 4 = 0); (* to get kernel stack pointer *)
  1615. id := ID ();
  1616. ASSERT(procm[id].stack.high # 0); (* current processor stack has been assigned *)
  1617. procm[id].sp := CurrentBP () (* instead of ESP, just fetch EBP of current procedure (does not contain pointers) *)
  1618. END UpdateState;
  1619. (** Get kernel stack regions for garbage collection. (for Heaps) *)
  1620. PROCEDURE GetKernelStacks*(VAR stack: ARRAY OF Stack);
  1621. VAR i: LONGINT;
  1622. BEGIN (* {UpdateState has been called by each processor} *)
  1623. FOR i := 0 TO MaxCPU-1 DO
  1624. stack[i].adr := procm[i].sp;
  1625. stack[i].high := procm[i].stack.high
  1626. END
  1627. END GetKernelStacks;
  1628. (* Init page tables (paging still disabled until EnableMM is called). *)
  1629. PROCEDURE InitPages;
  1630. VAR i, j: HUGEINT; phys, lTop, mTop: ADDRESS;
  1631. BEGIN
  1632. (* get top of high and low memory *)
  1633. mTop := memTop;
  1634. DEC(mTop, mTop MOD PS); (* mTop MOD PS = 0 *)
  1635. topPageNum := LSH(mTop-1, -PSlog2);
  1636. lTop := lowTop;
  1637. DEC(lTop, lTop MOD PS); (* lTop MOD PS = 0 *)
  1638. (* initialize NewDirectPage and SetHeapEndAdr (get kernel range) *)
  1639. SYSTEM.GET (LinkAdr + EndBlockOfs, heapEndAdr);
  1640. (* ug *) (*
  1641. SYSTEM.PUT (heapEndAdr, NIL); (* set tag to NIL *)
  1642. INC(heapEndAdr, AddressSize); (* space for NIL *)
  1643. *)
  1644. (* ug: not needed, extension of heap done in GetStaticHeap anyway
  1645. INC(heapEndAdr, K); (* space for free heap block descriptor of type Heaps.HeapBlockDesc at heapEndAdr, initialization is done in Heaps *)
  1646. INC(heapEndAdr, (-heapEndAdr) MOD PS); (* round up to page size *)
  1647. *)
  1648. pageHeapAdr := mTop;
  1649. freeHighPages := LSH(pageHeapAdr, -PSlog2) - LSH(heapEndAdr, -PSlog2);
  1650. IF TraceVerbose THEN
  1651. Trace.String("Kernel: "); Trace.Address (LinkAdr); Trace.String(" .. ");
  1652. Trace.Address (heapEndAdr-1); Trace.Ln;
  1653. Trace.String ("High: "); Trace.Address (heapEndAdr); Trace.String(" .. ");
  1654. Trace.Address (pageHeapAdr-1); Trace.String(" = "); Trace.Int (SHORT(freeHighPages),0);
  1655. Trace.StringLn (" free pages")
  1656. END;
  1657. (* initialize empty free page stack *)
  1658. NewDirectPage(pageStackAdr); ASSERT(pageStackAdr # NilAdr);
  1659. SYSTEM.PUT (pageStackAdr+NodeSP, SYSTEM.VAL (ADDRESS, MinSP));
  1660. SYSTEM.PUT (pageStackAdr+NodeNext, SYSTEM.VAL (ADDRESS, NilAdr));
  1661. SYSTEM.PUT (pageStackAdr+NodePrev, SYSTEM.VAL (ADDRESS, NilAdr));
  1662. (* free low pages *)
  1663. freeLowPage := NilAdr; freeLowPages := 0;
  1664. i := lTop DIV PS; j := LowAdr DIV PS;
  1665. IF TraceVerbose THEN
  1666. Trace.String("Low: "); Trace.Address (j*PS); Trace.String (".."); Trace.Address (i*PS-1)
  1667. END;
  1668. REPEAT
  1669. DEC(i); phys := i*PS;
  1670. SYSTEM.PUT (phys, freeLowPage); (* phys.next := freeLowPage *)
  1671. freeLowPage := phys; INC(freeLowPages)
  1672. UNTIL i = j;
  1673. IF TraceVerbose THEN
  1674. Trace.String(" = "); Trace.Int(SHORT(freeLowPages), 1); Trace.StringLn (" free pages")
  1675. END;
  1676. totalPages := LSH(memTop - M + lowTop + dmaSize + PS, -PSlog2); (* what BIOS gave us *)
  1677. (* stacks *)
  1678. ASSERT((StackAreaAdr MOD MaxUserStackSize = 0) & (StackAreaSize MOD MaxUserStackSize = 0));
  1679. FOR i := 0 TO LEN(freeStack)-1 DO freeStack[i] := {0..SetSize-1} END;
  1680. FOR i := MaxUserStacks TO LEN(freeStack)*SetSize-1 DO EXCL(freeStack[i DIV SetSize], i MOD SetSize) END;
  1681. freeStackIndex := 0;
  1682. (* mappings *)
  1683. mapTop := MapAreaAdr;
  1684. (* create the address space *)
  1685. NewPage(kernelPML4); ASSERT(kernelPML4 # NilAdr);
  1686. Fill32(kernelPML4, TPS, PageNotPresent);
  1687. IF ~MapDirect(LowAdr, memTop-LowAdr, LowAdr + UserPage) THEN HALT(99) END (* map heap direct *)
  1688. END InitPages;
  1689. (* Generate a memory segment descriptor. type IN {0..7} & dpl IN {0..3}.
  1690. type
  1691. 0 data, expand-up, read-only
  1692. 1 data, expand-up, read-write
  1693. 2 data, expand-down, read-only
  1694. 3 data, expand-down, read-write
  1695. 4 code, non-conforming, execute-only
  1696. 5 code, non-conforming, execute-read
  1697. 6 code, conforming, execute-only
  1698. 7 code, conforming, execute-read
  1699. *)
  1700. PROCEDURE GenCodeSegDesc (dpl, base, limit: LONGINT; conforming, longmode: BOOLEAN; VAR sd: SegDesc);
  1701. VAR s: SET;
  1702. BEGIN
  1703. sd.low := ASH(base MOD 10000H, 16) + limit MOD 10000H;
  1704. s := SYSTEM.VAL(SET, ASH(ASH(base, -24), 24) + ASH(ASH(limit, -16), 16) +
  1705. ASH(dpl, 13) + ASH(base, -16) MOD 100H);
  1706. s := s + {9, 11, 12, 15, 23}; (* present=1, D = 0*)
  1707. IF conforming THEN INCL(s, 10) END;
  1708. IF longmode THEN INCL(s, 21) ELSE INCL (s, 22) END; (* long mode flag or default 32-bit operand *)
  1709. sd.high := SYSTEM.VAL(LONGINT, s)
  1710. END GenCodeSegDesc;
  1711. PROCEDURE GenDataSegDesc (dpl, base, limit: LONGINT; VAR sd: SegDesc);
  1712. VAR s: SET;
  1713. BEGIN
  1714. sd.low := ASH(base MOD 10000H, 16) + limit MOD 10000H;
  1715. s := SYSTEM.VAL(SET, ASH(ASH(base, -24), 24) + ASH(ASH(limit, -16), 16) +
  1716. ASH(dpl, 13) + ASH(base, -16) MOD 100H);
  1717. s := s + {9, 12, 15, 22, 23}; (* present=1 *)
  1718. sd.high := SYSTEM.VAL(LONGINT, s)
  1719. END GenDataSegDesc;
  1720. (* Generate a 64-bit TSS descriptor (16bytes). *)
  1721. PROCEDURE GenTSSDesc(base: ADDRESS; limit, dpl: LONGINT; VAR sdl, sdh: SegDesc);
  1722. VAR s: SET;
  1723. BEGIN
  1724. sdl.low := SYSTEM.VAL(LONGINT, ASH(base MOD 10000H, 16) + limit MOD 10000H);
  1725. s := SYSTEM.VAL(SET, ASH(ASH(base, -24), 24) + ASH(ASH(limit, -16), 16) +
  1726. ASH(dpl, 13) + ASH(base, -16) MOD 100H);
  1727. s := s + {8, 11, 15}; (* type=non-busy TSS, present=1, AVL=0, 32-bit=0 *)
  1728. sdl.high := SYSTEM.VAL(LONGINT, s);
  1729. sdh.low := SYSTEM.VAL(LONGINT, base DIV 10000000H);
  1730. sdh.high := 0;
  1731. END GenTSSDesc;
  1732. (* Initialize segmentation. *)
  1733. PROCEDURE InitSegments;
  1734. VAR i: LONGINT;
  1735. BEGIN
  1736. (* limits and bases are ignored in 64-bit mode *)
  1737. (* GDT 0: Null segment *)
  1738. gdt[0].low := 0; gdt[0].high := 0;
  1739. (* GDT 1: 32-bit Kernel code: non-conforming, execute-read, base 0, limit 4G, PL 0 *)
  1740. GenCodeSegDesc(0, 0, M-1, FALSE, FALSE, gdt[1]);
  1741. (* GDT 2: 64-bit Kernel code: non-conforming, execute-read, base 0, limit 4G, PL 0 *)
  1742. GenCodeSegDesc(0, 0, M-1, FALSE, TRUE, gdt[2]);
  1743. (* GDT 3: 32-bit User code: non-conforming, execute-read, base 0, limit 4G, PL 0 *)
  1744. GenCodeSegDesc(0, 0, M-1, TRUE, FALSE, gdt[3]);
  1745. (* GDT 4: 64-bit User code: conforming, execute-read, base 0, limit 4G, PL 0 *)
  1746. GenCodeSegDesc(0, 0, M-1, TRUE, TRUE, gdt[4]);
  1747. (* GDT 5: Kernel stack: read-write, base 0, limit 4G, PL 0 *)
  1748. GenDataSegDesc(0, 0, M-1, gdt[5]);
  1749. (* GDT 6: User stack: read-write, base 0, limit 4G, PL 3 *)
  1750. GenDataSegDesc(3, 0, M-1, gdt[6]);
  1751. (* GDT 7: User/Kernel data: expand-up, read-write, base 0, limit 4G, PL 3 *)
  1752. GenDataSegDesc(3, 0, M-1, gdt[7]);
  1753. FOR i := 0 TO MaxCPU-1 DO
  1754. GenTSSDesc(ADDRESSOF(procm[i].tss), SIZEOF(TSSDesc)-1, 0, gdt[TSSOfs+i*2], gdt[TSSOfs+i*2 + 1]);
  1755. procm[i].sp := 0; procm[i].stack.high := 0
  1756. END
  1757. END InitSegments;
  1758. (* Enable segmentation on the current processor. *)
  1759. PROCEDURE EnableSegments;
  1760. BEGIN
  1761. LoadGDT(ADDRESSOF(gdt[0]), SIZEOF(GDT)-1);
  1762. LoadSegRegs(DataSel)
  1763. END EnableSegments;
  1764. (* Allocate a kernel stack. *)
  1765. PROCEDURE NewKernelStack(VAR stack: Stack);
  1766. VAR phys, virt: ADDRESS; size: SIZE;
  1767. BEGIN
  1768. size := KernelStackSize;
  1769. NewVirtual(virt, size + PS); (* add one page for overflow protection *)
  1770. ASSERT(virt # NilAdr, 1502);
  1771. INC(virt, PS); (* leave page open at bottom *)
  1772. stack.low := virt;
  1773. stack.adr := virt; (* return stack *)
  1774. REPEAT
  1775. NewPage(phys); ASSERT(phys # NilAdr);
  1776. IF ~MapPage(virt, phys + KernelPage) THEN HALT(99) END;
  1777. DEC(size, PS); INC(virt, PS)
  1778. UNTIL size = 0;
  1779. stack.high := virt
  1780. END NewKernelStack;
  1781. (* Set task register *)
  1782. PROCEDURE -SetTR(tr: ADDRESS);
  1783. CODE {SYSTEM.AMD64, SYSTEM.Privileged}
  1784. POP RAX
  1785. LTR AX
  1786. END SetTR;
  1787. (* Enable memory management and switch to new stack in virtual space.
  1788. Stack layout:
  1789. caller1 return
  1790. caller1 RBP <-- caller0 RBP
  1791. [caller0 locals]
  1792. 04 caller0 return
  1793. 00 caller0 RBP <-- RBP
  1794. locals <-- RSP
  1795. *)
  1796. PROCEDURE -EnableMM(pml4Base, rsp: ADDRESS);
  1797. CODE {SYSTEM.AMD64, SYSTEM.Privileged}
  1798. POP RBX
  1799. POP RAX
  1800. MOV RCX, [RBP + 8] ; caller0 return
  1801. MOV RDX, [RBP] ; caller0 RBP
  1802. MOV RDX, [RDX + 8] ; caller 1 return
  1803. MOV CR3, RAX ; pml4 page translation base address
  1804. XOR RAX, RAX
  1805. MOV [RBX - 8], RAX ; not UserStackSel (cf. GetUserStack)
  1806. MOV [RBX - 16], RDX ; caller1 return on new stack
  1807. MOV [RBX - 24], RAX ; caller1 RBP on new stack
  1808. LEA RBP, [RBX - 24] ; new stack top
  1809. MOV RSP, RBP
  1810. JMP RCX
  1811. END EnableMM;
  1812. (** -- Initialization -- *)
  1813. (** Initialize memory management.
  1814. o every processor calls this once during initialization
  1815. o mutual exclusion with other processors must be guaranteed by the caller
  1816. o interrupts must be off
  1817. o segmentation and paging is enabled
  1818. o return is on the new stack => caller must have no local variables
  1819. *)
  1820. PROCEDURE InitMemory*;
  1821. VAR id: LONGINT;
  1822. BEGIN
  1823. EnableSegments;
  1824. (* allocate stack *)
  1825. id := ID ();
  1826. NewKernelStack(procm[id].stack);
  1827. procm[id].sp := 0;
  1828. (* initialize TSS *)
  1829. Fill32(ADDRESSOF(procm[id].tss), SIZEOF(TSSDesc), 0);
  1830. procm[id].tss.RSP0 := procm[id].stack.high; (* kernel stack org *)
  1831. procm[id].tss.IOMapBaseAddress := -1; (* no bitmap *)
  1832. (* enable paging and switch stack *)
  1833. SetTR(KernelTR + id*16);
  1834. EnableMM(kernelPML4, procm[id].tss.RSP0)
  1835. END InitMemory;
  1836. (** Initialize a boot page for MP booting. Parameter physAdr returns the physical address of a low page. *)
  1837. PROCEDURE InitBootPage*(start: Startup; VAR physAdr: ADDRESS);
  1838. CONST BootOfs = 800H;
  1839. VAR adr, a: ADDRESS;
  1840. BEGIN
  1841. Acquire(Memory);
  1842. NewLowPage(physAdr);
  1843. Release(Memory);
  1844. ASSERT((physAdr # NilAdr) & (physAdr >= 0) & (physAdr < M) & (physAdr MOD PS = 0));
  1845. adr := physAdr + BootOfs;
  1846. a := adr;
  1847. (* put binary code copy of SMP.Bin to address a (cf. BinToCode.Mod ) *)
  1848. SYSTEM.PUT32(a, 0002F10EBH); INC (a, 4);
  1849. SYSTEM.PUT32(a, 000000000H); INC (a, 4);
  1850. SYSTEM.PUT32(a, 000000000H); INC (a, 4);
  1851. SYSTEM.PUT32(a, 000000000H); INC (a, 4);
  1852. SYSTEM.PUT32(a, 031660000H); INC (a, 4);
  1853. SYSTEM.PUT32(a, 066C88CC0H); INC (a, 4);
  1854. SYSTEM.PUT32(a, 02E04E0C1H); INC (a, 4);
  1855. SYSTEM.PUT32(a, 04A060966H); INC (a, 4);
  1856. SYSTEM.PUT32(a, 0010F2E08H); INC (a, 4);
  1857. SYSTEM.PUT32(a, 02E08081EH); INC (a, 4);
  1858. SYSTEM.PUT32(a, 00216010FH); INC (a, 4);
  1859. SYSTEM.PUT32(a, 0C4896608H); INC (a, 4);
  1860. SYSTEM.PUT32(a, 000C48166H); INC (a, 4);
  1861. SYSTEM.PUT32(a, 00F000008H); INC (a, 4);
  1862. SYSTEM.PUT32(a, 00F66C020H); INC (a, 4);
  1863. SYSTEM.PUT32(a, 00F00E8BAH); INC (a, 4);
  1864. SYSTEM.PUT32(a, 0662EC022H); INC (a, 4);
  1865. SYSTEM.PUT32(a, 0080E1E8BH); INC (a, 4);
  1866. SYSTEM.PUT32(a, 00850EA66H); INC (a, 4);
  1867. SYSTEM.PUT32(a, 000080000H); INC (a, 4);
  1868. SYSTEM.PUT32(a, 00FE0200FH); INC (a, 4);
  1869. SYSTEM.PUT32(a, 00F05E8BAH); INC (a, 4);
  1870. SYSTEM.PUT32(a, 0220FE022H); INC (a, 4);
  1871. SYSTEM.PUT32(a, 00080B9DBH); INC (a, 4);
  1872. SYSTEM.PUT32(a, 0320FC000H); INC (a, 4);
  1873. SYSTEM.PUT32(a, 008E8BA0FH); INC (a, 4);
  1874. SYSTEM.PUT32(a, 0200F300FH); INC (a, 4);
  1875. SYSTEM.PUT32(a, 0E8BA0FC0H); INC (a, 4);
  1876. SYSTEM.PUT32(a, 0C0220F1FH); INC (a, 4);
  1877. SYSTEM.PUT32(a, 0000000EAH); INC (a, 4);
  1878. SYSTEM.PUT16(a, 01000H); INC (a, 2);
  1879. SYSTEM.PUT8(a, 000H); INC (a);
  1880. (* the following offsets must be patched and can be reported
  1881. by the assembler when assembling SMP.S with: PCAAMD64.Assemble SMP.S l~ *)
  1882. SYSTEM.PUT32 (adr+14, SYSTEM.VAL (LONGINT, kernelPML4)); (* cf. label PML4BASE *)
  1883. SYSTEM.PUT32 (adr+117, SYSTEM.VAL (LONGINT, start)); (* not a method *) (* cf. label KENTRY *)
  1884. SYSTEM.PUT32 (adr+4, SYSTEM.VAL (LONGINT, ADDRESSOF(gdt[0]))); (* cf. label GDT *)
  1885. (* jump at start *)
  1886. SYSTEM.PUT8(physAdr, 0EAX); (* jmp far *)
  1887. SYSTEM.PUT32(physAdr + 1, ASH(physAdr, 16-4) + BootOfs) (* seg:ofs *)
  1888. END InitBootPage;
  1889. (** The BP in a MP system calls this to map the APIC physical address directly. *)
  1890. PROCEDURE InitAPICArea*(adr: ADDRESS; size: SIZE);
  1891. BEGIN
  1892. (* ASSERT((size = PS) & (adr >= IntelAreaAdr) & (adr+size-1 < IntelAreaAdr+IntelAreaSize)); *)
  1893. IF ~MapDirect(adr, size, adr + UserPage) THEN HALT(99) END
  1894. END InitAPICArea;
  1895. (* Set machine-dependent parameters gcThreshold, expandMin, heapMinKB and heapMaxKB *)
  1896. PROCEDURE SetGCParams*;
  1897. VAR size, t: SIZE;
  1898. BEGIN
  1899. GetFreeK(size, t, t); (* size is total memory size in KB *)
  1900. heapMinKB := size * HeapMin DIV 100;
  1901. heapMaxKB := size * HeapMax DIV 100;
  1902. expandMin := size * ExpandRate DIV 100 * 1024;
  1903. IF expandMin < 0 THEN expandMin := MAX(LONGINT) END;
  1904. gcThreshold := size * Threshold DIV 100 * 1024;
  1905. IF gcThreshold < 0 THEN gcThreshold := MAX(LONGINT) END
  1906. END SetGCParams;
  1907. (** Get first memory block and first free address, heap area in first memory block is automatically expanded to account for the first
  1908. few calls to NEW *)
  1909. PROCEDURE GetStaticHeap*(VAR beginBlockAdr, endBlockAdr, freeBlockAdr: ADDRESS);
  1910. BEGIN
  1911. beginBlockAdr := initialMemBlock.beginBlockAdr;
  1912. endBlockAdr := initialMemBlock.endBlockAdr;
  1913. freeBlockAdr := beginBlockAdr;
  1914. END GetStaticHeap;
  1915. (* returns if an address is a currently allocated heap address *)
  1916. PROCEDURE ValidHeapAddress*(p: ADDRESS): BOOLEAN;
  1917. BEGIN
  1918. RETURN (p >= memBlockHead.beginBlockAdr) & (p <= memBlockTail.endBlockAdr)
  1919. OR (p>=401000H) & (p<=500000H) (*! guess until kernel size known *)
  1920. END ValidHeapAddress;
  1921. (** Jump from kernel to user mode. Every processor calls this during initialization. *)
  1922. PROCEDURE JumpToUserLevel*(userRBP: ADDRESS);
  1923. CODE {SYSTEM.AMD64, SYSTEM.Privileged}
  1924. PUSH UserStackSel ; SS3
  1925. PUSH QWORD [RBP + userRBP] ; RSP3
  1926. PUSHFQ ; RFLAGS3
  1927. PUSH User64CodeSel ; CS3
  1928. CALL DWORD L1 ; PUSH L1 (RIP3)
  1929. L1:
  1930. ADD QWORD [RSP], BYTE 7 ; adjust RIP3 to L2 (L2-L1 should be 7)
  1931. IRETQ ; switch to level 3 and continue at following instruction
  1932. L2:
  1933. POP RBP ; from level 3 stack (refer to AosActive.NewProcess)
  1934. RET ; jump to body of first active object; cf. Objects.NewProcess
  1935. END JumpToUserLevel;
  1936. (* should ensure that a given address can be represented in the legacy 4GB address space
  1937. replacement for unsafe: x := SYSTEM.VAL (LONGINT, y) with y of type ADDRESS
  1938. -> better rewrite client code! this procedure should be redundant and removable in the end! *)
  1939. PROCEDURE Ensure32BitAddress*(adr: ADDRESS): Address32;
  1940. BEGIN
  1941. (* TODO *)
  1942. ASSERT (Is32BitAddress (adr), 9876);
  1943. RETURN SYSTEM.VAL (Address32, adr)
  1944. END Ensure32BitAddress;
  1945. PROCEDURE Is32BitAddress*(adr: ADDRESS): BOOLEAN;
  1946. BEGIN RETURN SYSTEM.VAL (Address32, adr) = adr;
  1947. END Is32BitAddress;
  1948. (**
  1949. * Flush Data Cache for the specified virtual address range. If len is negative, flushes the whole cache.
  1950. * This is used on some architecture to interact with DMA hardware (e.g. Ethernet and USB. It can be
  1951. * left empty on Intel architecture.
  1952. *)
  1953. PROCEDURE FlushDCacheRange * (adr: ADDRESS; len: LONGINT);
  1954. END FlushDCacheRange;
  1955. (**
  1956. * Invalidate Data Cache for the specified virtual address range. If len is negative, flushes the whole cache.
  1957. * This is used on some architecture to interact with DMA hardware (e.g. Ethernet and USB. It can be
  1958. * left empty on Intel architecture.
  1959. *)
  1960. PROCEDURE InvalidateDCacheRange * (adr: ADDRESS; len: LONGINT);
  1961. END InvalidateDCacheRange;
  1962. (**
  1963. * Invalidate Instruction Cache for the specified virtual address range. If len is negative, flushes the whole cache.
  1964. * This is used on some architecture to interact with DMA hardware (e.g. Ethernet and USB. It can be
  1965. * left empty on Intel architecture.
  1966. *)
  1967. PROCEDURE InvalidateICacheRange * (adr: ADDRESS; len: LONGINT);
  1968. END InvalidateICacheRange;
  1969. (* Unexpected - Default interrupt handler *)
  1970. PROCEDURE Unexpected(VAR state: State);
  1971. VAR int: HUGEINT; isr, irr: CHAR;
  1972. BEGIN
  1973. int := state.INT;
  1974. IF HandleSpurious & ((int >= IRQ0) & (int <= MaxIRQ) OR (int = MPSPU)) THEN (* unexpected IRQ, get more info *)
  1975. IF (int >= IRQ8) & (int <= IRQ15) THEN
  1976. Portout8 (IntB0, 0BX); Portin8(IntB0, isr);
  1977. Portout8 (IntB0, 0AX); Portin8(IntB0, irr)
  1978. ELSIF (int >= IRQ0) & (int <= IRQ7) THEN
  1979. Portout8 (IntA0, 0BX); Portin8(IntA0, isr);
  1980. Portout8 (IntA0, 0AX); Portin8(IntA0, irr)
  1981. ELSE
  1982. isr := 0X; irr := 0X
  1983. END;
  1984. IF TraceSpurious THEN
  1985. Acquire (TraceOutput);
  1986. Trace.String("INT"); Trace.Int(SHORT(int), 1);
  1987. Trace.Hex(ORD(isr), -3); Trace.Hex(ORD(irr), -2); Trace.Ln;
  1988. Release (TraceOutput);
  1989. END
  1990. ELSE
  1991. Acquire (TraceOutput);
  1992. Trace.StringLn ("Unexpected interrupt");
  1993. Trace.Memory(ADDRESSOF(state), SIZEOF(State)-4*8); (* exclude last 4 fields *)
  1994. IF int = 3 THEN (* was a HALT or ASSERT *)
  1995. (* It seems that no trap handler is installed (Traps not linked), so wait endlessly, while holding trace lock. This should quiten down the system, although other processors may possibly still run processes. *)
  1996. LOOP END
  1997. ELSE
  1998. Release (TraceOutput);
  1999. SetRAX(int);
  2000. HALT(1801) (* unexpected interrupt *)
  2001. END
  2002. END
  2003. END Unexpected;
  2004. (* InEnableIRQ - Enable a hardware interrupt (caller must hold module lock). *)
  2005. PROCEDURE -InEnableIRQ (int: HUGEINT);
  2006. CODE {SYSTEM.AMD64}
  2007. POP RBX
  2008. CMP RBX, IRQ7
  2009. JG cont2
  2010. IN AL, IntA1
  2011. SUB RBX, IRQ0
  2012. BTR RAX, RBX
  2013. OUT IntA1, AL
  2014. JMP end
  2015. cont2:
  2016. IN AL, IntB1
  2017. SUB RBX, IRQ8
  2018. BTR RAX, RBX
  2019. OUT IntB1, AL
  2020. end:
  2021. END InEnableIRQ;
  2022. (* InDisableIRQ - Disable a hardware interrupt (caller must hold module lock). *)
  2023. PROCEDURE -InDisableIRQ (int: HUGEINT);
  2024. CODE {SYSTEM.AMD64}
  2025. POP RBX
  2026. CMP RBX, IRQ7
  2027. JG cont2
  2028. IN AL, IntA1
  2029. SUB RBX, IRQ0
  2030. BTS RAX, RBX
  2031. OUT IntA1, AL
  2032. JMP end
  2033. cont2:
  2034. IN AL, IntB1
  2035. SUB RBX, IRQ8
  2036. BTS RAX, RBX
  2037. OUT IntB1, AL
  2038. end:
  2039. END InDisableIRQ;
  2040. (** EnableIRQ - Enable a hardware interrupt (also done automatically by InstallHandler). *)
  2041. PROCEDURE EnableIRQ* (int: HUGEINT);
  2042. BEGIN
  2043. (* ASSERT((int >= IRQ0) & (int <= IRQ15) & (int # IRQ2)); *)
  2044. Acquire(Interrupts); (* protect interrupt mask register *)
  2045. InEnableIRQ(int);
  2046. Release(Interrupts)
  2047. END EnableIRQ;
  2048. (** DisableIRQ - Disable a hardware interrupt. *)
  2049. PROCEDURE DisableIRQ* (int: HUGEINT);
  2050. BEGIN
  2051. ASSERT((int >= IRQ0) & (int <= IRQ15) & (int # IRQ2));
  2052. Acquire(Interrupts); (* protect interrupt mask register *)
  2053. InDisableIRQ(int);
  2054. Release(Interrupts)
  2055. END DisableIRQ;
  2056. (** InstallHandler - Install interrupt handler & enable IRQ if necessary.
  2057. On entry to h interrupts are disabled and may be enabled with Sti. After handling the interrupt
  2058. the state of interrupts are restored. The acknowledgement of a hardware interrupt is done automatically.
  2059. IRQs are mapped from IRQ0 to MaxIRQ. *)
  2060. PROCEDURE InstallHandler* (h: Handler; int: LONGINT);
  2061. VAR (* n: HandlerList; *) i: LONGINT; unexpected: Handler;
  2062. BEGIN
  2063. ASSERT(default.valid); (* initialized *)
  2064. ASSERT(int # IRQ2); (* IRQ2 is used for cascading and remapped to IRQ9 *)
  2065. Acquire(Interrupts);
  2066. (* FieldInterrupt may traverse list while it is being modified *)
  2067. i := 0;
  2068. unexpected := Unexpected;
  2069. IF intHandler[int, 0].handler # unexpected THEN
  2070. WHILE (i < MaxNumHandlers - 1) & intHandler[int, i].valid DO
  2071. INC(i)
  2072. END;
  2073. IF i < MaxNumHandlers - 1 THEN
  2074. intHandler[int, i].valid := TRUE;
  2075. intHandler[int, i].handler := h;
  2076. ELSE
  2077. Acquire(TraceOutput);
  2078. Trace.String("Machine.InstallHandler: handler could not be installed for interrupt "); Trace.Int(int, 0);
  2079. Trace.String(" - too many handlers per interrupt number"); Trace.Ln;
  2080. Release(TraceOutput)
  2081. END
  2082. ELSE
  2083. intHandler[int, 0].handler := h;
  2084. IF (int >= IRQ0) & (int <= IRQ15) THEN InEnableIRQ(int) END
  2085. END;
  2086. Release(Interrupts)
  2087. END InstallHandler;
  2088. (** RemoveHandler - Uninstall interrupt handler & disable IRQ if necessary *)
  2089. PROCEDURE RemoveHandler* (h: Handler; int: LONGINT);
  2090. VAR (* p, c: HandlerList; *) i, j, foundIndex: LONGINT;
  2091. BEGIN
  2092. ASSERT(default.valid); (* initialized *)
  2093. Acquire(Interrupts);
  2094. (* find h *)
  2095. i := 0;
  2096. foundIndex := -1;
  2097. WHILE (i < MaxNumHandlers - 1) & intHandler[int, i].valid DO
  2098. IF intHandler[int, i].handler = h THEN foundIndex := i END;
  2099. INC(i)
  2100. END;
  2101. IF foundIndex # -1 THEN
  2102. (* h found -> copy interrupt handlers higher than foundIndex *)
  2103. FOR j := foundIndex TO i - 2 DO
  2104. intHandler[int, j] := intHandler[int, j + 1]
  2105. END
  2106. END;
  2107. IF ~intHandler[int, 0].valid THEN
  2108. (* handler h was the only interrupt handler for interrupt int -> install the default handler *)
  2109. intHandler[int, 0] := default;
  2110. IF (int >= IRQ0) & (int <= IRQ15) THEN DisableIRQ(int) END
  2111. END;
  2112. Release(Interrupts)
  2113. END RemoveHandler;
  2114. (* Get control registers. *)
  2115. PROCEDURE GetCR0to4(VAR cr: ARRAY OF HUGEINT);
  2116. CODE {SYSTEM.AMD64, SYSTEM.Privileged}
  2117. MOV RDI, [RBP + cr]
  2118. MOV RAX, CR0
  2119. XOR RBX, RBX ; CR1 is not documented
  2120. MOV RCX, CR2
  2121. MOV RDX, CR3
  2122. MOV [RDI + 0], RAX
  2123. MOV [RDI + 8], RBX
  2124. MOV [RDI + 16], RCX
  2125. MOV [RDI + 24], RDX
  2126. MOV RAX, CR4 ; Pentium only
  2127. MOV [RDI + 32], RAX
  2128. END GetCR0to4;
  2129. (* GetDR0to7 - Get debug registers. *)
  2130. PROCEDURE GetDR0to7(VAR dr: ARRAY OF HUGEINT);
  2131. CODE {SYSTEM.AMD64, SYSTEM.Privileged}
  2132. MOV RDI, [RBP + dr]
  2133. MOV RAX, DR0
  2134. MOV RBX, DR1
  2135. MOV RCX, DR2
  2136. MOV RDX, DR3
  2137. MOV [RDI + 0], RAX
  2138. MOV [RDI + 8], RBX
  2139. MOV [RDI + 16], RCX
  2140. MOV [RDI + 24], RDX
  2141. XOR RAX, RAX ; DR4 is not documented
  2142. XOR RBX, RBX ; DR5 is not documented
  2143. MOV RCX, DR6
  2144. MOV RDX, DR7
  2145. MOV [RDI + 32], RAX
  2146. MOV [RDI + 40], RBX
  2147. MOV [RDI + 48], RCX
  2148. MOV [RDI + 56], RDX
  2149. END GetDR0to7;
  2150. (* CLTS - Clear task-switched flag. *)
  2151. PROCEDURE -CLTS;
  2152. CODE {SYSTEM.AMD64, SYSTEM.Privileged}
  2153. CLTS
  2154. END CLTS;
  2155. (* GetFPU - Store floating-point environment (28 bytes) and mask all floating-point exceptions. *)
  2156. PROCEDURE -GetFPU(adr: ADDRESS);
  2157. CODE {SYSTEM.AMD64, SYSTEM.FPU}
  2158. POP RBX
  2159. FNSTENV [RBX] ; also masks all exceptions
  2160. FWAIT
  2161. END GetFPU;
  2162. (* CR2 - Get page fault address. *)
  2163. PROCEDURE -CR2* (): ADDRESS;
  2164. CODE {SYSTEM.AMD64, SYSTEM.Privileged}
  2165. MOV RAX, CR2
  2166. END CR2;
  2167. (** GetExceptionState - Get exception state from interrupt state (and switch on interrupts). *)
  2168. PROCEDURE GetExceptionState* (VAR int: State; VAR exc: ExceptionState);
  2169. VAR id: LONGINT; level0: BOOLEAN;
  2170. BEGIN
  2171. (* save all state information while interrupts are still disabled *)
  2172. exc.halt := -int.INT; id := ID ();
  2173. IF int.INT = PF THEN exc.pf := CR2 () ELSE exc.pf := 0 END;
  2174. GetCR0to4(exc.CR);
  2175. GetDR0to7(exc.DR);
  2176. CLTS; (* ignore task switch flag *)
  2177. IF int.INT = MF THEN
  2178. GetFPU(ADDRESSOF(exc.FPU[0]));
  2179. int.PC := SYSTEM.VAL (ADDRESS, exc.FPU[3]); (* modify PC according to FPU info *)
  2180. (* set halt code according to FPU info *)
  2181. IF 2 IN exc.FPU[1] THEN exc.halt := -32 (* division by 0 *)
  2182. ELSIF 3 IN exc.FPU[1] THEN exc.halt := -33 (* overflow *)
  2183. ELSIF 0 IN exc.FPU[1] THEN exc.halt := -34 (* operation invalid *)
  2184. ELSIF 6 IN exc.FPU[1] THEN exc.halt := -35 (* stack fault *)
  2185. ELSIF 1 IN exc.FPU[1] THEN exc.halt := -36 (* denormalized *)
  2186. ELSIF 4 IN exc.FPU[1] THEN exc.halt := -37 (* underflow *)
  2187. ELSIF 5 IN exc.FPU[1] THEN exc.halt := -38 (* precision loss *)
  2188. ELSE (* {exc.halt = -16} *)
  2189. END
  2190. ELSE
  2191. Fill32(ADDRESSOF(exc.FPU[0]), LEN(exc.FPU)*SIZEOF(SET), 0)
  2192. END;
  2193. SetupFPU;
  2194. level0 := (int.CS MOD 4 = KernelLevel);
  2195. IF int.INT = BP THEN (* breakpoint (HALT) *)
  2196. IF level0 THEN
  2197. exc.halt := int.SP (* get halt code *)
  2198. (* if HALT(MAX(INTEGER)), leave halt code on stack when returning, but not serious problem.*)
  2199. ELSE
  2200. SYSTEM.GET (int.SP, exc.halt); (* get halt code from outer stack *)
  2201. IF exc.halt >= MAX(INTEGER) THEN INC (int.SP, AddressSize) END (* pop halt code from outer stack *)
  2202. END;
  2203. IF exc.halt < MAX(INTEGER) THEN DEC (int.PC) END; (* point to the INT 3 instruction (assume 0CCX, not 0CDX 3X) *)
  2204. ELSIF int.INT = OVF THEN (* overflow *)
  2205. DEC (int.PC) (* point to the INTO instruction (assume 0CEX, not 0CDX 4X) *)
  2206. ELSIF int.INT = PF THEN (* page fault *)
  2207. IF int.PC = 0 THEN (* reset PC to return address of indirect CALL to 0 *)
  2208. IF level0 THEN int.PC := int.SP (* ret adr *) ELSE SYSTEM.GET (int.SP, int.PC) END
  2209. END
  2210. END;
  2211. (* get segment registers *)
  2212. IF level0 THEN (* from same level, no ESP, SS etc. on stack *)
  2213. exc.SP := ADDRESSOF(int.SP) (* stack was here when interrupt happened *)
  2214. ELSE (* from outer level *)
  2215. exc.SP := int.SP
  2216. END
  2217. END GetExceptionState;
  2218. (* FieldInterrupt and FieldIRQ *)
  2219. (*
  2220. At entry to a Handler procedure the stack is as follows:
  2221. -- if (VMBit IN .RFLAGS) --
  2222. 176 -- .SS
  2223. 168 -- .RSP ; or haltcode
  2224. -- (VMBit IN .RFLAGS) OR (CS MOD 4 < .CS MOD 4) --
  2225. 160 -- .RFLAGS
  2226. 152 -- .CS
  2227. 144 -- .RIP ; rest popped by IRETD
  2228. 136 -- .ERR/RBP ; pushed by processor or glue code, popped by POP RBP
  2229. 128 -- .INT <-- .RSP0 ; pushed by glue code, popped by POP RBP
  2230. 120 -- .RAX
  2231. 112 -- .RCX
  2232. 104 -- .RDX
  2233. 96 -- .RBX
  2234. 88 -- .RSP0
  2235. 80 -- .RBP/ERR ; exchanged by glue code
  2236. 72 -- .RSI
  2237. 64 -- .RDI
  2238. 56 -- .R8
  2239. 48 -- .R9
  2240. 40 -- .R10
  2241. 32 -- .R11
  2242. 24 -- .R12
  2243. 16 -- .R13
  2244. 08 -- .R14
  2245. 00 48 .R15 <--- state: State
  2246. -- 40 ptr
  2247. -- 32 object pointer for DELEGATE
  2248. -- 24 TAG(state)
  2249. -- 16 ADR(state)
  2250. -- 08 RIP' (RET to FieldInterrupt)
  2251. -- 00 RBP' <-- RBP
  2252. -- -- locals <-- RSP
  2253. *)
  2254. PROCEDURE {NOPAF} FieldInterrupt;
  2255. CONST SizeOfHandlerRec = SIZEOF(HandlerRec);
  2256. CODE {SYSTEM.AMD64, SYSTEM.Privileged}
  2257. entry:
  2258. ; fake PUSHAD (not available in 64-bit mode)
  2259. PUSH RAX
  2260. PUSH RCX
  2261. PUSH RDX
  2262. PUSH RBX ; (error code)
  2263. LEA RAX, [RSP - 4 * 8] ; (RSP minus the four pushed 64-bit registers)
  2264. PUSH RAX ; original value of RSP
  2265. PUSH RBP
  2266. PUSH RSI
  2267. PUSH RDI
  2268. PUSH R8
  2269. PUSH R9
  2270. PUSH R10
  2271. PUSH R11
  2272. PUSH R12
  2273. PUSH R13
  2274. PUSH R14
  2275. PUSH R15
  2276. LEA RBP, [RSP + 136]
  2277. MOV RBX, [RSP + 128] ; RBX = int number
  2278. IMUL RBX, RBX, MaxNumHandlers
  2279. IMUL RBX, RBX, SizeOfHandlerRec
  2280. ; todo: replace LEA by MOV when compiler supports this
  2281. LEA RAX, intHandler
  2282. ADD RAX, RBX ; address of intHandler[int, 0]
  2283. ; todo: replace LEA by MOV when compiler supports this
  2284. LEA RDX, stateTag
  2285. loop: ; call all handlers for the interrupt
  2286. MOV RCX, RSP
  2287. PUSH RAX ; save ptr for table
  2288. PUSH QWORD [RAX + 12] ; delegate
  2289. PUSH RDX ; TAG(state)
  2290. PUSH RCX ; ADR(state)
  2291. CALL QWORD [RAX + 4] ; call handler
  2292. ADD RSP, 24
  2293. CLI ; handler may have re-enabled interrupts
  2294. POP RAX
  2295. ADD RAX, SizeOfHandlerRec
  2296. MOV RBX, [RAX]
  2297. CMP RBX, 0
  2298. JNE loop
  2299. ; fake POPAD (not available in 64-bit mode)
  2300. POP R15
  2301. POP R14
  2302. POP R13
  2303. POP R12
  2304. POP R11
  2305. POP R10
  2306. POP R9
  2307. POP R8
  2308. POP RDI
  2309. POP RSI
  2310. POP RBP
  2311. ADD RSP, 8 ;POP RSP
  2312. POP RBX
  2313. POP RDX
  2314. POP RCX
  2315. POP RAX ; now EBP = error code
  2316. POP RBP ; now EBP = INT
  2317. POP RBP ; now EBP = caller RBP
  2318. IRETQ
  2319. END FieldInterrupt;
  2320. PROCEDURE {NOPAF} FieldIRQ;
  2321. CONST SizeOfHandlerRec = SIZEOF(HandlerRec);
  2322. CODE {SYSTEM.AMD64}
  2323. entry:
  2324. ; fake PUSHAD (not available in 64-bit mode)
  2325. PUSH RAX
  2326. PUSH RCX
  2327. PUSH RDX
  2328. PUSH RBX ; (error code)
  2329. LEA RAX, [RSP - 4 * 8] ; (RSP minus the four pushed 64-bit registers)
  2330. PUSH RAX ; original value of RSP
  2331. PUSH RBP
  2332. PUSH RSI
  2333. PUSH RDI
  2334. PUSH R8
  2335. PUSH R9
  2336. PUSH R10
  2337. PUSH R11
  2338. PUSH R12
  2339. PUSH R13
  2340. PUSH R14
  2341. PUSH R15
  2342. LEA RBP, [RSP + 136]
  2343. ;; PUSH 32[ESP] ; int number
  2344. ;; CALL traceInterruptIn
  2345. MOV RBX, [RSP + 128] ; RBX = int number
  2346. IMUL RBX, RBX, MaxNumHandlers
  2347. IMUL RBX, RBX, SizeOfHandlerRec
  2348. ; todo: replace LEA by MOV when compiler supports this
  2349. LEA RAX, intHandler
  2350. ADD RAX, RBX ; address of intHandler[int, 0]
  2351. ; todo: replace LEA by MOV when compiler supports this
  2352. LEA RDX, stateTag
  2353. loop: ; call all handlers for the interrupt
  2354. MOV RCX, RSP
  2355. PUSH RAX ; save ptr for linked list
  2356. PUSH QWORD [RAX + 12] ; delegate
  2357. PUSH RDX ; TAG(state)
  2358. PUSH RCX ; ADR(state)
  2359. CALL QWORD [RAX + 4] ; call handler
  2360. ADD RSP, 24
  2361. CLI ; handler may have re-enabled interrupts
  2362. POP RAX
  2363. ADD RAX, SizeOfHandlerRec
  2364. MOV RBX, [RAX]
  2365. CMP RBX, 0
  2366. JNE loop
  2367. ;; PUSH 32[ESP] ; int number
  2368. ;; CALL traceInterruptOut
  2369. ; ack interrupt
  2370. MOV AL, 20H ; undoc PC ed. 2 p. 1018
  2371. CMP BYTE [RSP + 128], IRQ8
  2372. JB irq0
  2373. OUT IntB0, AL ; 2nd controller
  2374. irq0:
  2375. OUT IntA0, AL ; 1st controller
  2376. ; fake POPAD (not available in 64-bit mode)
  2377. POP R15
  2378. POP R14
  2379. POP R13
  2380. POP R12
  2381. POP R11
  2382. POP R10
  2383. POP R9
  2384. POP R8
  2385. POP RDI
  2386. POP RSI
  2387. POP RBP
  2388. ADD RSP, 8 ;POP RSP
  2389. POP RBX
  2390. POP RDX
  2391. POP RCX
  2392. POP RAX ; now RBP = error code
  2393. POP RBP ; now RBP = INT
  2394. POP RBP ; now RBP = caller RBP
  2395. IRETQ
  2396. END FieldIRQ;
  2397. (* LoadIDT - Load interrupt descriptor table *)
  2398. PROCEDURE LoadIDT(base: ADDRESS; size: SIZE);
  2399. CODE {SYSTEM.AMD64, SYSTEM.Privileged}
  2400. ; LIDT needs 10 bytes: 2 for the 16-bit limit and 8 for the 64-bit base address
  2401. ; Assumption: size in front of base -> promote size value to upper 48 bits of size
  2402. SHL QWORD [RBP + size], 64-16
  2403. LIDT [RBP + size + (64-16) / 8]
  2404. END LoadIDT;
  2405. (** Init - Initialize interrupt handling. Called once during initialization. Uses NEW. *)
  2406. (*
  2407. The glue code is:
  2408. entry0: ; entry point for interrupts without error code
  2409. PUSH 0 ; fake error code
  2410. entry1: ; entry point for interrupts with error code
  2411. XCHG [ESP], EBP ; exchange error code and caller EBP
  2412. PUSH int ; interrupt number
  2413. JMP FieldInterrupt:entry
  2414. *)
  2415. PROCEDURE InitInterrupts*;
  2416. VAR a: ADDRESS; o, i: LONGINT; p: PROCEDURE; mask: SET;
  2417. BEGIN
  2418. stateTag := SYSTEM.TYPECODE(State);
  2419. (* initialise 8259 interrupt controller chips *)
  2420. Portout8 (IntA0, 11X); Portout8 (IntA1, CHR(IRQ0));
  2421. Portout8 (IntA1, 4X); Portout8 (IntA1, 1X); Portout8 (IntA1, 0FFX);
  2422. Portout8 (IntB0, 11X); Portout8 (IntB1, CHR(IRQ8));
  2423. Portout8 (IntB1, 2X); Portout8 (IntB1, 1X); Portout8 (IntB1, 0FFX);
  2424. (* enable interrupts from second interrupt controller, chained to line 2 of controller 1 *)
  2425. Portin8(IntA1, SYSTEM.VAL (CHAR, mask));
  2426. EXCL(mask, IRQ2-IRQ0);
  2427. Portout8 (IntA1, SYSTEM.VAL (CHAR, mask));
  2428. (*
  2429. NEW(default); default.next := NIL; default.handler := Unexpected;
  2430. *)
  2431. (*
  2432. newrec (SYSTEM.VAL (ANY, default), SYSTEM.TYPECODE (HandlerList));
  2433. *)
  2434. (* default.next := NIL; default.handler := Unexpected; *)
  2435. default.valid := TRUE; default.handler := Unexpected;
  2436. FOR i := 0 TO IDTSize-1 DO (* set up glue code *)
  2437. intHandler[i, 0] := default; o := 0;
  2438. (* PUSH error code, int num & regs *)
  2439. glue[i][o] := 6AX; INC (o); glue[i][o] := 0X; INC (o); (* PUSH 0 ; {o = 2} *)
  2440. glue[i][o] := 48X; INC(o); glue[i][o] := 87X; INC(o); glue[i][o] := 2CX; INC(o); glue[i][o] := 24X; INC(o); (* XCHG [RSP], RBP *)
  2441. glue[i][o] := 6AX; INC (o); glue[i][o] := CHR(i); INC (o); (* PUSH i *)
  2442. IF (i >= IRQ0) & (i <= IRQ15) THEN p := FieldIRQ ELSE p := FieldInterrupt END;
  2443. a := SYSTEM.VAL(ADDRESS, p) - (ADDRESSOF(glue[i][o])+5);
  2444. (* a must be a 32-bit offset to be used with the followingjump instruction, ensured since
  2445. both the glue code array and the interrupt functions are inside this module *)
  2446. glue[i][o] := 0E9X; INC (o); (* JMP FieldInterrupt.entry *)
  2447. SYSTEM.PUT32 (ADDRESSOF(glue[i][o]), a);
  2448. (* set up IDT entry *)
  2449. IF (i > 31) OR ~(i IN {8, 10..14, 17}) THEN a := ADDRESSOF(glue[i][0]) (* include PUSH 0 *)
  2450. ELSE a := ADDRESSOF(glue[i][2]) (* skip PUSH 0, processor supplies error code *)
  2451. END;
  2452. idt[i].offsetBits0to15 := SHORT (SHORT(a MOD 10000H));
  2453. (* IRQ0 must be at level 0 because time slicing in Objects needs to set interrupted process' ESP *)
  2454. (* all irq's are handled at level 0, because of priority experiment in Objects.FieldIRQ *)
  2455. IF TRUE (* (i < IRQ0) OR (i > IRQ15) OR (i = IRQ0) OR (i = IRQ0 + 1)*) THEN
  2456. idt[i].selector := Kernel64CodeSel; (* gdt[1] -> non-conformant segment => level 0 *)
  2457. idt[i].gateType := SYSTEM.VAL(INTEGER, 0EE00H) (* present, DPL 3, system, 64-bit interrupt gate *)
  2458. ELSE (* {IRQ0..IRQ15} - {IRQ0 + 1} *)
  2459. idt[i].selector := User64CodeSel; (* gdt[3] -> conformant segment => level 0 or 3 *)
  2460. idt[i].gateType := SYSTEM.VAL(INTEGER, 08E00H) (* present, DPL 0, system, 64-bit interrupt gate *)
  2461. END;
  2462. idt[i].offsetBits16to31 := SHORT (SHORT(a DIV 10000H));
  2463. idt[i].offsetBits32to63 := SHORT(a DIV 100000000H);
  2464. idt[i].reserved := 0;
  2465. END
  2466. END InitInterrupts;
  2467. (** Start - Start handling interrupts. Every processor calls this once during initialization. *)
  2468. PROCEDURE Start*;
  2469. BEGIN
  2470. ASSERT(default.valid); (* initialized *)
  2471. LoadIDT(ADDRESSOF(idt[0]), SIZEOF(IDT)-1);
  2472. Sti
  2473. END Start;
  2474. (* Return current instruction pointer *)
  2475. PROCEDURE CurrentPC* (): ADDRESS;
  2476. CODE {SYSTEM.AMD64}
  2477. MOV RAX, [RBP + 8]
  2478. END CurrentPC;
  2479. (* Return current frame pointer *)
  2480. PROCEDURE -CurrentBP* (): ADDRESS;
  2481. CODE {SYSTEM.AMD64}
  2482. MOV RAX, RBP
  2483. END CurrentBP;
  2484. (* Set current frame pointer *)
  2485. PROCEDURE -SetBP* (bp: ADDRESS);
  2486. CODE {SYSTEM.AMD64}
  2487. POP RBP
  2488. END SetBP;
  2489. (* Return current stack pointer *)
  2490. PROCEDURE -CurrentSP* (): ADDRESS;
  2491. CODE {SYSTEM.AMD64}
  2492. MOV RAX, RSP
  2493. END CurrentSP;
  2494. (* Set current stack pointer *)
  2495. PROCEDURE -SetSP* (sp: ADDRESS);
  2496. CODE {SYSTEM.AMD64}
  2497. POP RSP
  2498. END SetSP;
  2499. PROCEDURE -GetRAX*(): HUGEINT;
  2500. CODE{SYSTEM.AMD64}
  2501. END GetRAX;
  2502. PROCEDURE -GetRCX*(): HUGEINT;
  2503. CODE{SYSTEM.AMD64}
  2504. MOV RAX,RCX
  2505. END GetRCX;
  2506. PROCEDURE -GetRSI*(): HUGEINT;
  2507. CODE{SYSTEM.AMD64}
  2508. MOV RAX,RSI
  2509. END GetRSI;
  2510. PROCEDURE -GetRDI*(): HUGEINT;
  2511. CODE{SYSTEM.AMD64}
  2512. MOV RAX,RDI
  2513. END GetRDI;
  2514. PROCEDURE -SetRAX*(n: HUGEINT);
  2515. CODE{SYSTEM.AMD64}
  2516. NOP
  2517. POP RAX
  2518. END SetRAX;
  2519. PROCEDURE -SetRBX*(n: HUGEINT);
  2520. CODE{SYSTEM.AMD64}
  2521. NOP
  2522. POP RBX
  2523. END SetRBX;
  2524. PROCEDURE -SetRCX*(n: HUGEINT);
  2525. CODE{SYSTEM.AMD64}
  2526. POP RCX
  2527. END SetRCX;
  2528. PROCEDURE -SetRDX*(n: HUGEINT);
  2529. CODE{SYSTEM.AMD64}
  2530. POP RDX
  2531. END SetRDX;
  2532. PROCEDURE -SetRSI*(n: HUGEINT);
  2533. CODE{SYSTEM.AMD64}
  2534. POP RSI
  2535. END SetRSI;
  2536. PROCEDURE -SetRDI*(n: HUGEINT);
  2537. CODE{SYSTEM.AMD64}
  2538. POP RDI
  2539. END SetRDI;
  2540. PROCEDURE Portin8*(port: LONGINT; VAR val: CHAR);
  2541. CODE{SYSTEM.AMD64}
  2542. MOV EDX,[RBP+port]
  2543. IN AL, DX
  2544. MOV RCX, [RBP+val]
  2545. MOV [RCX], AL
  2546. END Portin8;
  2547. PROCEDURE Portin16*(port: LONGINT; VAR val: INTEGER);
  2548. CODE{SYSTEM.AMD64}
  2549. MOV EDX,[RBP+port]
  2550. IN AX, DX
  2551. MOV RCX, [RBP+val]
  2552. MOV [RCX], AX
  2553. END Portin16;
  2554. PROCEDURE Portin32*(port: LONGINT; VAR val: LONGINT);
  2555. CODE{SYSTEM.AMD64}
  2556. MOV EDX,[RBP+port]
  2557. IN EAX, DX
  2558. MOV RCX, [RBP+val]
  2559. MOV [RCX], EAX
  2560. END Portin32;
  2561. PROCEDURE Portout8*(port: LONGINT; val: CHAR);
  2562. CODE{SYSTEM.AMD64}
  2563. MOV AL,[RBP+val]
  2564. MOV EDX,[RBP+port]
  2565. OUT DX,AL
  2566. END Portout8;
  2567. PROCEDURE Portout16*(port: LONGINT; val: INTEGER);
  2568. CODE{SYSTEM.AMD64}
  2569. MOV AX,[RBP+val]
  2570. MOV EDX,[RBP+port]
  2571. OUT DX,AX
  2572. END Portout16;
  2573. PROCEDURE Portout32*(port: LONGINT; val: LONGINT);
  2574. CODE{SYSTEM.AMD64}
  2575. MOV EAX,[RBP+val]
  2576. MOV EDX,[RBP+port]
  2577. OUT DX,EAX
  2578. END Portout32;
  2579. PROCEDURE -Cli*;
  2580. CODE{SYSTEM.AMD64}
  2581. CLI
  2582. END Cli;
  2583. PROCEDURE -Sti*;
  2584. CODE{SYSTEM.AMD64}
  2585. STI
  2586. END Sti;
  2587. (* Save minimal FPU state (for synchronous process switches). *)
  2588. (* saving FPU state takes 108 bytes memory space, no alignment required *)
  2589. PROCEDURE -FPUSaveMin* (VAR state: SSEState);
  2590. CODE {SYSTEM.AMD64, SYSTEM.FPU}
  2591. POP RAX
  2592. FNSTCW [RAX] ; control word is at state[0]
  2593. FWAIT
  2594. END FPUSaveMin;
  2595. (* Restore minimal FPU state. *)
  2596. PROCEDURE -FPURestoreMin* (VAR state: SSEState);
  2597. CODE {SYSTEM.AMD64, SYSTEM.FPU}
  2598. POP RAX
  2599. FLDCW [RAX] ; control word is at state[0]
  2600. END FPURestoreMin;
  2601. (* Save full FPU state (for asynchronous process switches). *)
  2602. PROCEDURE -FPUSaveFull* (VAR state: SSEState);
  2603. CODE {SYSTEM.AMD64, SYSTEM.FPU}
  2604. POP RAX
  2605. FSAVE [RAX]
  2606. END FPUSaveFull;
  2607. (* Restore full FPU state. *)
  2608. PROCEDURE -FPURestoreFull* (VAR state: SSEState);
  2609. CODE {SYSTEM.AMD64, SYSTEM.FPU}
  2610. POP RAX
  2611. FRSTOR [RAX]
  2612. END FPURestoreFull;
  2613. (* stateAdr must be the address of a 16-byte aligned memory area of at least 512 bytes *)
  2614. PROCEDURE -SSESaveFull* (stateAdr: ADDRESS);
  2615. CODE {SYSTEM.AMD64, SYSTEM.FPU}
  2616. POP RAX
  2617. FXSAVE [RAX]
  2618. FWAIT
  2619. FNINIT
  2620. END SSESaveFull;
  2621. PROCEDURE -SSERestoreFull* (stateAdr: ADDRESS);
  2622. CODE {SYSTEM.AMD64, SYSTEM.FPU}
  2623. POP RAX
  2624. FXRSTOR [RAX]
  2625. END SSERestoreFull;
  2626. PROCEDURE -SSESaveMin* (stateAdr: ADDRESS);
  2627. CODE {SYSTEM.AMD64, SYSTEM.FPU}
  2628. POP RAX
  2629. FNSTCW [RAX]
  2630. FWAIT
  2631. STMXCSR [RAX + 24]
  2632. END SSESaveMin;
  2633. PROCEDURE -SSERestoreMin* (stateAdr: ADDRESS);
  2634. CODE {SYSTEM.AMD64, SYSTEM.FPU}
  2635. POP RAX
  2636. FLDCW [RAX]
  2637. LDMXCSR [RAX + 24]
  2638. END SSERestoreMin;
  2639. (* Helper functions for SwitchTo. *)
  2640. PROCEDURE -PushState* (CONST state: State);
  2641. CODE {SYSTEM.AMD64}
  2642. POP RAX ; ADR (state)
  2643. POP RBX ; TYPECODE (state), ignored
  2644. PUSH QWORD [RAX + 176] ; SS
  2645. PUSH QWORD [RAX + 168] ; SP
  2646. PUSH QWORD [RAX + 160] ; FLAGS
  2647. PUSH QWORD [RAX + 152] ; CS
  2648. PUSH QWORD [RAX + 144] ; PC
  2649. PUSH QWORD [RAX + 120] ; RAX
  2650. PUSH QWORD [RAX + 112] ; RCX
  2651. PUSH QWORD [RAX + 104] ; RDX
  2652. PUSH QWORD [RAX + 96] ; RBX
  2653. PUSH DWORD 0; ignored
  2654. PUSH QWORD [RAX + 136] ; RBP
  2655. PUSH QWORD [RAX + 72] ; RSI
  2656. PUSH QWORD [RAX + 64] ; RDI
  2657. PUSH QWORD [RAX + 56] ; R8
  2658. PUSH QWORD [RAX + 48] ; R9
  2659. PUSH QWORD [RAX + 40] ; R10
  2660. PUSH QWORD [RAX + 32] ; R11
  2661. PUSH QWORD [RAX + 24] ; R12
  2662. PUSH QWORD [RAX + 16] ; R13
  2663. PUSH QWORD [RAX + 8] ; R14
  2664. PUSH QWORD [RAX + 0] ; R15
  2665. END PushState;
  2666. PROCEDURE -JumpState*;
  2667. CODE {SYSTEM.AMD64}
  2668. POP R15
  2669. POP R14
  2670. POP R13
  2671. POP R12
  2672. POP R11
  2673. POP R10
  2674. POP R9
  2675. POP R8
  2676. POP RDI
  2677. POP RSI
  2678. POP RBP
  2679. POP RBX; ignored
  2680. POP RBX
  2681. POP RDX
  2682. POP RCX
  2683. POP RAX
  2684. IRETQ
  2685. END JumpState;
  2686. PROCEDURE -CallLocalIPC*;
  2687. CODE {SYSTEM.AMD64}
  2688. INT MPIPCLocal
  2689. END CallLocalIPC;
  2690. PROCEDURE -HLT*;
  2691. CODE {SYSTEM.AMD64, SYSTEM.Privileged}
  2692. STI ; (* required according to ACPI 2.0 spec section 8.2.2 *)
  2693. HLT
  2694. END HLT;
  2695. (* Kernel mode upcall to perform global processor halt. *)
  2696. PROCEDURE KernelCallHLT*;
  2697. CODE {SYSTEM.AMD64}
  2698. MOV EAX, 2
  2699. INT MPKC
  2700. END KernelCallHLT;
  2701. (* Parse processor entry in MP config table. *)
  2702. PROCEDURE CPUID1*(): LONGINT;
  2703. CODE {SYSTEM.AMD64}
  2704. MOV EAX, 1
  2705. CPUID
  2706. MOV EAX, EBX
  2707. END CPUID1;
  2708. (** -- Atomic operations -- *)
  2709. (** Atomic INC(x). *)
  2710. PROCEDURE -AtomicInc*(VAR x: LONGINT);
  2711. CODE {SYSTEM.AMD64}
  2712. POP RAX
  2713. LOCK
  2714. INC DWORD [RAX]
  2715. END AtomicInc;
  2716. (** Atomic DEC(x). *)
  2717. PROCEDURE -AtomicDec*(VAR x: LONGINT);
  2718. CODE {SYSTEM.AMD64}
  2719. POP RAX
  2720. LOCK
  2721. DEC DWORD [RAX]
  2722. END AtomicDec;
  2723. (** Atomic EXCL. *)
  2724. PROCEDURE AtomicExcl* (VAR s: SET; bit: LONGINT);
  2725. CODE {SYSTEM.AMD64}
  2726. MOV EAX, [RBP + bit]
  2727. MOV RBX, [RBP + s]
  2728. LOCK
  2729. BTR [RBX], EAX
  2730. END AtomicExcl;
  2731. (** Atomic INC(x, y). *)
  2732. PROCEDURE -AtomicAdd*(VAR x: LONGINT; y: LONGINT);
  2733. CODE {SYSTEM.AMD64}
  2734. POP EBX
  2735. POP RAX
  2736. LOCK
  2737. ADD DWORD [RAX], EBX
  2738. END AtomicAdd;
  2739. (** Atomic test-and-set. Set x = TRUE and return old value of x. *)
  2740. PROCEDURE -AtomicTestSet*(VAR x: BOOLEAN): BOOLEAN;
  2741. CODE {SYSTEM.AMD64}
  2742. POP RBX
  2743. MOV AL, 1
  2744. XCHG [RBX], AL
  2745. END AtomicTestSet;
  2746. (* Atomic compare-and-swap. Set x = new if x = old and return old value of x *)
  2747. PROCEDURE -AtomicCAS* (VAR x: LONGINT; old, new: LONGINT): LONGINT;
  2748. CODE {SYSTEM.AMD64}
  2749. POP EBX ; new
  2750. POP EAX ; old
  2751. POP RCX ; address of x
  2752. LOCK CMPXCHG [RCX], EBX ; atomicly compare x with old and set it to new if equal
  2753. END AtomicCAS;
  2754. PROCEDURE CopyState* (CONST from: State; VAR to: State);
  2755. BEGIN
  2756. to.R15 := from.R15;
  2757. to.R14 := from.R14;
  2758. to.R13 := from.R13;
  2759. to.R12 := from.R12;
  2760. to.R11 := from.R11;
  2761. to.R10 := from.R10;
  2762. to.R9 := from.R9;
  2763. to.R8 := from.R8;
  2764. to.RDI := from.RDI;
  2765. to.RSI := from.RSI;
  2766. to.RBX := from.RBX;
  2767. to.RDX := from.RDX;
  2768. to.RCX := from.RCX;
  2769. to.RAX := from.RAX;
  2770. to.BP := from.BP;
  2771. to.PC := from.PC;
  2772. to.CS := from.CS;
  2773. to.SP := from.SP;
  2774. to.SS := from.SS;
  2775. to.FLAGS := from.FLAGS;
  2776. END CopyState;
  2777. (* function returning the number of processors that are available to Aos *)
  2778. PROCEDURE NumberOfProcessors*( ): LONGINT;
  2779. BEGIN
  2780. RETURN numberOfProcessors
  2781. END NumberOfProcessors;
  2782. (*! non portable code, for native Aos only *)
  2783. PROCEDURE SetNumberOfProcessors*(num: LONGINT);
  2784. BEGIN
  2785. numberOfProcessors := num;
  2786. END SetNumberOfProcessors;
  2787. (* function for changing byte order *)
  2788. PROCEDURE ChangeByteOrder* (n: LONGINT): LONGINT;
  2789. CODE {SYSTEM.AMD64}
  2790. MOV EAX, [RBP + n] ; load n in eax
  2791. BSWAP EAX ; swap byte order
  2792. END ChangeByteOrder;
  2793. (* Write a value to the APIC. *)
  2794. PROCEDURE ApicPut(ofs: SIZE; val: SET);
  2795. BEGIN
  2796. IF TraceApic THEN
  2797. Acquire(TraceOutput);
  2798. Trace.Hex(ofs, SIZEOF(SIZE)*2); Trace.String(" := "); Trace.Hex(SYSTEM.VAL (LONGINT, val), 9); Trace.Ln;
  2799. Release(TraceOutput);
  2800. END;
  2801. SYSTEM.PUT(localAPIC+ofs, SYSTEM.VAL (LONGINT, val))
  2802. END ApicPut;
  2803. (* Read a value from the APIC. *)
  2804. PROCEDURE ApicGet(ofs: SIZE): SET;
  2805. VAR val: SET;
  2806. BEGIN
  2807. SYSTEM.GET(localAPIC+ofs, SYSTEM.VAL (LONGINT, val));
  2808. IF TraceApic THEN
  2809. Acquire(TraceOutput);
  2810. Trace.String(" ("); Trace.Hex(ofs, SIZEOF(SIZE)*2); Trace.String(" = ");
  2811. Trace.Hex(SYSTEM.VAL(LONGINT, val), 9); Trace.StringLn (")");
  2812. Release(TraceOutput);
  2813. END;
  2814. RETURN val
  2815. END ApicGet;
  2816. (* Handle interprocessor interrupt. During upcall interrupts are off and processor is at kernel level. *)
  2817. PROCEDURE HandleIPC(VAR state: State);
  2818. VAR id: LONGINT;
  2819. BEGIN
  2820. id := ID();
  2821. IF ~TraceProcessor OR (id IN allProcessors) THEN
  2822. IF FrontBarrier IN ipcFlags THEN
  2823. AtomicExcl(ipcFrontBarrier, id);
  2824. WHILE ipcFrontBarrier # {} DO SpinHint END (* wait for all *)
  2825. END;
  2826. ipcHandler(id, state, ipcMessage); (* interrupts off and at kernel level *)
  2827. IF BackBarrier IN ipcFlags THEN
  2828. AtomicExcl(ipcBackBarrier, id);
  2829. WHILE ipcBackBarrier # {} DO SpinHint END (* wait for all *)
  2830. END;
  2831. AtomicExcl(ipcBusy, id) (* ack - after this point we do not access shared variables for this broadcast *)
  2832. END;
  2833. IF state.INT = MPIPC THEN
  2834. ApicPut(0B0H, {}) (* EOI (not needed for NMI or local call, see 7.4.10.6) *)
  2835. END
  2836. END HandleIPC;
  2837. (* Handle MP error interrupt. *)
  2838. PROCEDURE HandleError(VAR state: State);
  2839. VAR esr: SET; (* int: LONGINT; *)
  2840. BEGIN
  2841. (* int := state.INT; *) esr := ApicGet(280H);
  2842. ApicPut(0B0H, {}); (* EOI *)
  2843. HALT(2302) (* SMP error *)
  2844. END HandleError;
  2845. (* Interprocessor broadcasting. Lock level SMP. *)
  2846. PROCEDURE LocalBroadcast(h: BroadcastHandler; msg: Message; flags: SET);
  2847. BEGIN
  2848. IF Self IN flags THEN ipcBusy := allProcessors
  2849. ELSE ipcBusy := allProcessors - {ID()}
  2850. END;
  2851. ipcFrontBarrier := ipcBusy; ipcBackBarrier := ipcBusy;
  2852. ipcHandler := h; ipcMessage := msg; ipcFlags := flags;
  2853. IF numProcessors > 1 THEN (* ICR: Fixed, Physical, Edge, All Excl. Self, INT IPC *)
  2854. ApicPut(300H, {18..19} + SYSTEM.VAL (SET, MPIPC));
  2855. (*REPEAT UNTIL ~(12 IN ApicGet(300H))*) (* wait for send to finish *)
  2856. END;
  2857. IF Self IN flags THEN CallLocalIPC END; (* "send" to self also *)
  2858. WHILE ipcBusy # {} DO SpinHint END; (* wait for all to ack before we release locks *)
  2859. ipcHandler := NIL; ipcMessage := NIL (* no race, because we have IPC lock *)
  2860. END LocalBroadcast;
  2861. (** Broadcast an operation to all processors. *)
  2862. PROCEDURE Broadcast* (h: BroadcastHandler; msg: Message; flags: SET);
  2863. BEGIN
  2864. Acquire(Processors);
  2865. LocalBroadcast(h, msg, flags);
  2866. Release(Processors)
  2867. END Broadcast;
  2868. (* Start all halted processors. *) (* Lock level Processors. *)
  2869. PROCEDURE StartAll*;
  2870. BEGIN
  2871. Acquire(Processors); (* wait for any pending Stops to finish, and disallow further Stops *)
  2872. ASSERT(stopped & (ipcBusy = {}));
  2873. ipcBusy := allProcessors - {ID()};
  2874. stopped := FALSE;
  2875. WHILE ipcBusy # {} DO SpinHint END; (* wait for all to ack *)
  2876. Release(Processors)
  2877. END StartAll;
  2878. PROCEDURE HandleFlushTLB(id: LONGINT; CONST state: State; msg: Message);
  2879. CODE {SYSTEM.AMD64, SYSTEM.Privileged}
  2880. MOV EAX, CR3
  2881. MOV CR3, EAX
  2882. END HandleFlushTLB;
  2883. (** Flush the TLBs on all processors (multiprocessor-safe). *)
  2884. PROCEDURE GlobalFlushTLB;
  2885. BEGIN
  2886. Acquire(Processors);
  2887. LocalBroadcast(HandleFlushTLB, NIL, {Self, FrontBarrier, BackBarrier});
  2888. Release(Processors)
  2889. END GlobalFlushTLB;
  2890. PROCEDURE HandleFlushCache(id: LONGINT; CONST state: State; msg: Message);
  2891. CODE {SYSTEM.AMD64, SYSTEM.Privileged}
  2892. WBINVD ; write back and invalidate internal cache and initiate write back and invalidation of external caches
  2893. END HandleFlushCache;
  2894. (** Flush the caches on all processors (multiprocessor-safe). *)
  2895. PROCEDURE GlobalFlushCache;
  2896. BEGIN
  2897. Acquire(Processors);
  2898. LocalBroadcast(HandleFlushCache, NIL, {Self, FrontBarrier, BackBarrier});
  2899. Release(Processors)
  2900. END GlobalFlushCache;
  2901. (* Activate the garbage collector in single-processor mode. Lock level ALL. *)
  2902. PROCEDURE HandleKernelCall(VAR state: State);
  2903. BEGIN (* level 0 *)
  2904. IF IFBit IN state.FLAGS THEN
  2905. Sti (* re-enable interrupts *)
  2906. END;
  2907. CASE state.RAX OF (* see KernelCall* *)
  2908. |2: (* HLT *)
  2909. IF IFBit IN state.FLAGS THEN
  2910. HLT
  2911. END
  2912. END
  2913. END HandleKernelCall;
  2914. (*
  2915. (** Activate the garbage collector immediately (multiprocessor-safe). *)
  2916. PROCEDURE GlobalGC*;
  2917. BEGIN
  2918. Acquire(Processors);
  2919. gcBarrier := allProcessors;
  2920. LocalBroadcast(HandleGC, NIL, {Self, BackBarrier});
  2921. Release(Processors);
  2922. END GlobalGC;
  2923. *)
  2924. PROCEDURE HandleGetTimestamp(id: LONGINT; CONST state: State; msg: Message);
  2925. BEGIN
  2926. time[id] := GetTimer()
  2927. END HandleGetTimestamp;
  2928. (** Get timestamp on all processors (for testing). *)
  2929. PROCEDURE GlobalGetTimestamp;
  2930. VAR t: TimeArray; i: LONGINT; mean, var, n: HUGEINT;
  2931. BEGIN
  2932. Acquire(Processors);
  2933. LocalBroadcast(HandleGetTimestamp, NIL, {Self, FrontBarrier});
  2934. LocalBroadcast(HandleGetTimestamp, NIL, {Self, FrontBarrier});
  2935. t := time;
  2936. Release(Processors);
  2937. Acquire (TraceOutput);
  2938. FOR i := 0 TO numProcessors-1 DO Trace.HIntHex(t[i], 17) END;
  2939. IF numProcessors > 1 THEN
  2940. mean := 0;
  2941. n := numProcessors;
  2942. FOR i := 0 TO numProcessors-1 DO
  2943. INC (mean, t[i])
  2944. END;
  2945. mean := DivH(mean, n);
  2946. var := 0;
  2947. FOR i := 0 TO numProcessors-1 DO
  2948. n := t[i] - mean;
  2949. INC (var, MulH(n, n))
  2950. END;
  2951. var := DivH(var, numProcessors - 1);
  2952. Trace.String(" mean="); Trace.HIntHex(mean, 16);
  2953. Trace.String(" var="); Trace.HIntHex(var, 16);
  2954. Trace.String(" var="); Trace.Int(SHORT (var), 1);
  2955. Trace.String(" diff:");
  2956. FOR i := 0 TO numProcessors-1 DO
  2957. Trace.Int(SHORT (t[i] - mean), 1); Trace.Char(" ")
  2958. END
  2959. END;
  2960. Release (TraceOutput);
  2961. END GlobalGetTimestamp;
  2962. PROCEDURE ParseProcessor(adr: ADDRESS);
  2963. VAR id, idx, signature, family, feat, ver, log: LONGINT; flags: SET; string : ARRAY 8 OF CHAR;
  2964. BEGIN
  2965. SYSTEM.GET(adr, SYSTEM.VAL (LONGINT, flags));
  2966. id := ASH(SYSTEM.VAL (LONGINT, flags * {8..15}), -8);
  2967. ver := ASH(SYSTEM.VAL (LONGINT, flags * {16..23}), -16);
  2968. SYSTEM.GET (adr+4, signature);
  2969. family := ASH(signature, -8) MOD 10H;
  2970. SYSTEM.GET (adr+8, feat);
  2971. idx := -1;
  2972. IF (family # 0) & (signature MOD 1000H # 0FFFH) & (24 IN flags) & (id < LEN(idMap)) & (idMap[id] = -1) THEN
  2973. IF 25 IN flags THEN idx := 0 (* boot processor *)
  2974. ELSIF numProcessors < maxProcessors THEN idx := numProcessors; INC(numProcessors)
  2975. ELSE (* skip *)
  2976. END
  2977. END;
  2978. IF idx # -1 THEN apicVer[idx] := ver; idMap[id] := SHORT(SHORT(idx)) END;
  2979. Trace.String(" Processor "); Trace.Int(id, 1);
  2980. Trace.String(", APIC"); Trace.Hex(ver, -3);
  2981. Trace.String(", ver "); Trace.Int(family, 1);
  2982. Trace.Char("."); Trace.Int(ASH(signature, -4) MOD 10H, 1);
  2983. Trace.Char("."); Trace.Int(signature MOD 10H, 1);
  2984. Trace.String(", features "); Trace.Hex(feat, 9);
  2985. Trace.String(", ID "); Trace.Int(idx, 1);
  2986. IF (threadsPerCore > 1) THEN Trace.String(" ("); Trace.Int(threadsPerCore, 0); Trace.String(" threads)"); END;
  2987. Trace.Ln;
  2988. IF (threadsPerCore > 1) THEN
  2989. GetConfig("DisableHyperthreading", string);
  2990. IF (string = "1") THEN
  2991. Trace.String("Machine: Hyperthreading disabled."); Trace.Ln;
  2992. RETURN;
  2993. END;
  2994. log := (LSH(CPUID1(), -16) MOD 256);
  2995. WHILE log > 1 DO
  2996. INC(id); DEC(log);
  2997. IF numProcessors < maxProcessors THEN
  2998. idx := numProcessors; INC(numProcessors);
  2999. apicVer[idx] := ver; idMap[id] := SHORT(SHORT(idx))
  3000. END
  3001. END
  3002. END
  3003. END ParseProcessor;
  3004. (* Parse MP configuration table. *)
  3005. PROCEDURE ParseMPConfig;
  3006. VAR adr, x: ADDRESS; i: LONGINT; entries: INTEGER; ch: CHAR; s: SET; str: ARRAY 8 OF CHAR;
  3007. BEGIN
  3008. localAPIC := 0; numProcessors := 1; allProcessors := {0};
  3009. FOR i := 0 TO LEN(idMap)-1 DO idMap[i] := -1 END; (* all unassigned *)
  3010. FOR i := 0 TO MaxCPU-1 DO started[i] := FALSE END;
  3011. adr := configMP;
  3012. GetConfig("MaxProcs", str);
  3013. i := 0; maxProcessors := StrToInt(i, str);
  3014. IF maxProcessors = 0 THEN maxProcessors := MaxCPU END;
  3015. IF (maxProcessors > 0) & (adr # NilAdr) THEN (* MP config table present, possible multi-processor *)
  3016. Trace.String("Machine: Intel MP Spec "); Trace.Int(ORD(revMP) DIV 10H + 1, 1);
  3017. Trace.Char("."); Trace.Int(ORD(revMP) MOD 10H, 1); Trace.Ln;
  3018. IF TraceVerbose THEN
  3019. IF ODD(ASH(ORD(featureMP[1]), -7)) THEN
  3020. Trace.StringLn (" PIC mode");
  3021. (* to do: enable SymIO *)
  3022. ELSE
  3023. Trace.StringLn (" Virtual wire mode");
  3024. END
  3025. END;
  3026. IF featureMP[0] # 0X THEN (* pre-defined configuration *)
  3027. Trace.String(" Default config "); Trace.Int(ORD(featureMP[0]), 1); Trace.Ln;
  3028. localAPIC := SHORT(0FEE00000H);
  3029. apicVer[0] := 0; apicVer[1] := 0
  3030. ELSE (* configuration defined in table *)
  3031. MapPhysical(adr, 68*1024, adr); (* 64K + 4K header *)
  3032. SYSTEM.GET (adr, i); ASSERT(i = 504D4350H); (* check signature *)
  3033. SYSTEM.GET (adr+4, i); (* length *)
  3034. ASSERT(ChecksumMP(adr, i MOD 10000H) = 0);
  3035. IF TraceVerbose THEN
  3036. Trace.String(" ID: ");
  3037. FOR x := adr+8 TO adr+27 DO
  3038. SYSTEM.GET (x, ch); Trace.Char(ch);
  3039. IF x = adr+15 THEN Trace.Char(" ") END
  3040. END;
  3041. Trace.Ln
  3042. END;
  3043. localAPIC := 0; SYSTEM.GET(adr+36, SYSTEM.VAL (LONGINT, localAPIC));
  3044. IF TraceVerbose THEN Trace.String(" Local APIC:"); Trace.Address (localAPIC); Trace.Ln END;
  3045. SYSTEM.GET (adr+34, entries);
  3046. INC(adr, 44); (* skip header *)
  3047. WHILE entries > 0 DO
  3048. SYSTEM.GET (adr, ch); (* type *)
  3049. CASE ORD(ch) OF
  3050. 0: (* processor *)
  3051. ParseProcessor(adr);
  3052. INC(adr, 20)
  3053. |1: (* bus *)
  3054. IF TraceVerbose THEN
  3055. SYSTEM.GET (adr+1, ch);
  3056. Trace.String(" Bus "); Trace.Int(ORD(ch), 1); Trace.String(": ");
  3057. FOR x := adr+2 TO adr+7 DO SYSTEM.GET (x, ch); Trace.Char(ch) END;
  3058. Trace.Ln
  3059. END;
  3060. INC(adr, 8)
  3061. |2: (* IO APIC *)
  3062. IF TraceVerbose THEN
  3063. SYSTEM.GET (adr+1, ch); Trace.String(" IO APIC ID:"); Trace.Hex(ORD(ch), -3);
  3064. SYSTEM.GET (adr+2, ch); Trace.String(", version "); Trace.Int(ORD(ch), 1);
  3065. SYSTEM.GET(adr, SYSTEM.VAL (LONGINT, s)); IF ~(24 IN s) THEN Trace.String(" (disabled)") END;
  3066. Trace.Ln
  3067. END;
  3068. INC(adr, 8)
  3069. |3: (* IO interrupt assignment *)
  3070. INC(adr, 8)
  3071. |4: (* Local interrupt assignment *)
  3072. INC(adr, 8)
  3073. END; (* CASE *)
  3074. DEC(entries)
  3075. END
  3076. END
  3077. END;
  3078. IF localAPIC = 0 THEN (* single processor *)
  3079. Trace.StringLn ("Machine: Single-processor");
  3080. apicVer[0] := 0
  3081. END;
  3082. started[0] := TRUE;
  3083. FOR i := 0 TO MaxCPU-1 DO revIDmap[i] := -1 END;
  3084. FOR i := 0 TO LEN(idMap)-1 DO
  3085. x := idMap[i];
  3086. IF x # -1 THEN
  3087. ASSERT(revIDmap[x] = -1); (* no duplicate APIC ids *)
  3088. revIDmap[x] := SHORT(SHORT(i))
  3089. END
  3090. END;
  3091. (* timer configuration *)
  3092. GetConfig("TimerRate", str);
  3093. i := 0; timerRate := StrToInt(i, str);
  3094. IF timerRate = 0 THEN timerRate := 1000 END;
  3095. IF TraceProcessor THEN
  3096. GetConfig("TraceProc", str);
  3097. i := 0; traceProcessor := StrToInt(i, str) # 0
  3098. END
  3099. END ParseMPConfig;
  3100. (* Return the current average measured bus clock speed in Hz. *)
  3101. PROCEDURE GetBusClockRate(): LONGINT;
  3102. VAR timer: LONGINT; t: LONGINT;
  3103. BEGIN
  3104. t := ticks;
  3105. REPEAT UNTIL ticks # t; (* wait for edge *)
  3106. timer := ticks + ClockRateDelay;
  3107. ApicPut(380H, SYSTEM.VAL (SET, MAX(LONGINT))); (* initial count *)
  3108. REPEAT UNTIL timer - ticks <= 0;
  3109. t := MAX(LONGINT) - SYSTEM.VAL (LONGINT, ApicGet(390H)); (* current count *)
  3110. IF t <= MAX(LONGINT) DIV 1000 THEN
  3111. RETURN 1000 * t DIV ClockRateDelay
  3112. ELSE
  3113. RETURN t DIV ClockRateDelay * 1000
  3114. END
  3115. END GetBusClockRate;
  3116. (* Initialize APIC timer for timeslicing. *)
  3117. PROCEDURE InitMPTimer;
  3118. VAR rate: LONGINT;
  3119. BEGIN
  3120. IF timerRate > 0 THEN
  3121. ApicPut(3E0H, {0,1,3}); (* divide by 1 *)
  3122. ApicPut(320H, {16} + SYSTEM.VAL (SET, MPTMR)); (* masked, one-shot *)
  3123. rate := GetBusClockRate();
  3124. busHz0[ID()] := rate;
  3125. rate := (rate+500000) DIV 1000000 * 1000000; (* round to nearest MHz *)
  3126. busHz1[ID()] := rate;
  3127. ApicPut(320H, {17} + SYSTEM.VAL (SET, MPTMR)); (* unmasked, periodic *)
  3128. ApicPut(380H, SYSTEM.VAL (SET, rate DIV timerRate)) (* initial count *)
  3129. END
  3130. END InitMPTimer;
  3131. (* Handle multiprocessor timer interrupt. *)
  3132. PROCEDURE HandleMPTimer(VAR state: State);
  3133. BEGIN (* {interrupts off} *)
  3134. timer(ID(), state);
  3135. ApicPut(0B0H, {}); (* EOI *)
  3136. Sti; (* enable interrupts before acquiring locks below - to avoid deadlock with StopAll. *)
  3137. Timeslice(state) (* fixme: check recursive interrupt *)
  3138. END HandleMPTimer;
  3139. (* Handle uniprocessor timer interrupt. *)
  3140. PROCEDURE HandleUPTimer(VAR state: State);
  3141. BEGIN (* {interrupts off} *)
  3142. timer(0, state);
  3143. Sti; (* enable interrupts before acquiring locks below - to avoid deadlock with StopAll. *)
  3144. Timeslice(state)
  3145. END HandleUPTimer;
  3146. PROCEDURE DummyEvent(id: LONGINT; CONST state: State);
  3147. END DummyEvent;
  3148. (** Install a processor timer event handler. *)
  3149. PROCEDURE InstallEventHandler* (h: EventHandler);
  3150. BEGIN
  3151. IF h # NIL THEN timer := h ELSE timer := DummyEvent END
  3152. END InstallEventHandler;
  3153. (* Initialize APIC for current processor. *)
  3154. PROCEDURE InitAPIC;
  3155. BEGIN
  3156. (* enable APIC, set focus checking & set spurious interrupt handler *)
  3157. ASSERT(MPSPU MOD 16 = 15); (* low 4 bits set, p. 7-29 *)
  3158. ApicPut(0F0H, {8} + SYSTEM.VAL (SET, MPSPU));
  3159. (* set error interrupt handler *)
  3160. ApicPut(370H, SYSTEM.VAL (SET, MPERR));
  3161. InitMPTimer
  3162. END InitAPIC;
  3163. (* Start processor activity. *)
  3164. PROCEDURE StartMP;
  3165. VAR id: LONGINT; state: State;
  3166. BEGIN (* running at kernel level with interrupts on *)
  3167. InitAPIC;
  3168. id := ID(); (* timeslicing is disabled, as we are running at kernel level *)
  3169. Acquire (TraceOutput);
  3170. Trace.String (" P"); Trace.Int(id, 1); Trace.StringLn (" running");
  3171. Release (TraceOutput);
  3172. IF TraceProcessor & traceProcessor & (id = numProcessors-1) THEN
  3173. DEC(numProcessors) (* exclude from rest of activity *)
  3174. ELSE
  3175. INCL(allProcessors, id)
  3176. END;
  3177. (* synchronize with boot processor - end of mutual exclusion *)
  3178. started[id] := TRUE;
  3179. IF TraceProcessor & ~(id IN allProcessors) THEN
  3180. Acquire (TraceOutput);
  3181. Trace.String (" P"); Trace.Int(id, 1); Trace.StringLn (" tracing");
  3182. Release (TraceOutput);
  3183. LOOP
  3184. IF traceProcessorProc # NIL THEN traceProcessorProc(id, state) END;
  3185. SpinHint
  3186. END
  3187. END;
  3188. (* wait until woken up *)
  3189. WHILE stopped DO SpinHint END;
  3190. (* now fully functional, including storage allocation *)
  3191. AtomicExcl(ipcBusy, id); (* ack *)
  3192. Acquire (TraceOutput);
  3193. Trace.String (" P"); Trace.Int(id, 1); Trace.StringLn(" scheduling");
  3194. Release (TraceOutput);
  3195. ASSERT(id = ID()); (* still running on same processor *)
  3196. start;
  3197. END StartMP;
  3198. (* Subsequent processors start executing here. *)
  3199. PROCEDURE EnterMP;
  3200. (* no local variables allowed, because stack is switched. *)
  3201. BEGIN (* running at kernel level with interrupts off *)
  3202. InitProcessor;
  3203. InitMemory; (* switch stack *)
  3204. Start;
  3205. StartMP
  3206. END EnterMP;
  3207. (* Start another processor. *)
  3208. PROCEDURE StartProcessor(phys: ADDRESS; apicid: LONGINT; startup: BOOLEAN);
  3209. VAR j, k: LONGINT; s: SET; timer: LONGINT;
  3210. BEGIN
  3211. (* clear APIC errors *)
  3212. ApicPut(280H, {}); s := ApicGet(280H);
  3213. (* assert INIT *)
  3214. ApicPut(310H, SYSTEM.VAL (SET, ASH(apicid, 24))); (* set destination *)
  3215. ApicPut(300H, {8, 10, 14, 15}); (* set Dest, INIT, Phys, Assert, Level *)
  3216. timer := ticks + 5; (* > 200us *)
  3217. REPEAT UNTIL timer - ticks <= 0;
  3218. (* deassert INIT *)
  3219. ApicPut(310H, SYSTEM.VAL (SET, ASH(apicid, 24))); (* set destination *)
  3220. ApicPut(300H, {8, 10, 15}); (* set Dest, INIT, Deassert, Phys, Level *)
  3221. IF startup THEN (* send STARTUP if required *)
  3222. j := 0; k := 2;
  3223. WHILE j # k DO
  3224. ApicPut(280H, {});
  3225. ApicPut(310H, SYSTEM.VAL (SET, ASH(apicid, 24))); (* set destination *)
  3226. (* set Dest, Startup, Deassert, Phys, Edge *)
  3227. ApicPut(300H, {9, 10} + SYSTEM.VAL (SET, phys DIV 4096 MOD 256));
  3228. timer := ticks + 10; (* ~10ms *)
  3229. REPEAT UNTIL timer - ticks <= 0;
  3230. IF ~(12 IN ApicGet(300H)) THEN (* idle *)
  3231. IF ApicGet(280H) * {0..3, 5..7} = {} THEN k := j (* ESR success, exit *)
  3232. ELSE INC(j) (* retry *)
  3233. END
  3234. ELSE INC(j) (* retry *)
  3235. END
  3236. END
  3237. END
  3238. END StartProcessor;
  3239. (* Boot other processors, one at a time. *)
  3240. PROCEDURE BootMP;
  3241. VAR phys, page0Adr: ADDRESS; i: LONGINT; timer: LONGINT;
  3242. BEGIN
  3243. stopped := TRUE; ipcBusy := {}; (* other processors can be woken with StartAll *)
  3244. InitBootPage(EnterMP, phys);
  3245. MapPhysical(0, 4096, page0Adr); (* map in BIOS data area *)
  3246. Acquire(TraceOutput); Trace.String("Machine: Booting processors... "); Trace.Ln; Release(TraceOutput);
  3247. FOR i := 1 TO numProcessors-1 DO
  3248. (* set up booting for old processor types that reset on INIT & don't understand STARTUP *)
  3249. SYSTEM.PUT (page0Adr + 467H, ASH(phys, 16-4));
  3250. PutNVByte(15, 0AX); (* shutdown status byte *)
  3251. (* attempt to start another processor *)
  3252. Acquire(TraceOutput); Trace.String(" P0 starting P"); Trace.Int(i, 1); Trace.Ln; Release(TraceOutput);
  3253. StartProcessor(phys, revIDmap[i], apicVer[i] >= 10H); (* try booting processor i *)
  3254. (* wait for CPU to become active *)
  3255. timer := ticks + 5000; (* ~5s timeout *)
  3256. REPEAT SpinHint UNTIL started[i] OR (timer - ticks <= 0);
  3257. (* end of mutual exclusion *)
  3258. Acquire(TraceOutput);
  3259. IF started[i] THEN
  3260. Trace.String(" P0 recognized P"); Trace.Int(i, 1);
  3261. ELSE
  3262. Trace.String(" P0 timeout on P"); Trace.Int(i, 1);
  3263. END;
  3264. Trace.Ln;
  3265. Release(TraceOutput);
  3266. END;
  3267. SYSTEM.PUT (page0Adr + 467H, SYSTEM.VAL (LONGINT, 0));
  3268. UnmapPhysical(page0Adr, 4096);
  3269. PutNVByte(15, 0X) (* restore shutdown status *)
  3270. END BootMP;
  3271. (* Timer interrupt handler. *)
  3272. PROCEDURE TimerInterruptHandler(VAR state: State);
  3273. BEGIN
  3274. INC(ticks);
  3275. DEC(eventCount);
  3276. IF eventCount = 0 THEN
  3277. eventCount := eventMax; event(state)
  3278. END
  3279. END TimerInterruptHandler;
  3280. PROCEDURE Dummy(VAR state: State);
  3281. END Dummy;
  3282. PROCEDURE InitTicks;
  3283. CONST Div = (2*TimerClock + Second) DIV (2*Second); (* timer clock divisor *)
  3284. BEGIN
  3285. eventCount := 0; eventMax := 0; event := Dummy;
  3286. (* initialize timer hardware *)
  3287. ASSERT(Div <= 65535);
  3288. Portout8(43H, 34X); Wait; (* mode 2, rate generator *)
  3289. Portout8(40H, CHR(Div MOD 100H)); Wait;
  3290. Portout8(40H, CHR(ASH(Div, -8)));
  3291. InstallHandler(TimerInterruptHandler, IRQ0)
  3292. END InitTicks;
  3293. (* Set timer upcall. The handler procedure will be called at a rate of Second/divisor Hz. *)
  3294. PROCEDURE InstallTickHandler(handler: Handler; divisor: LONGINT);
  3295. BEGIN
  3296. eventMax := divisor; event := handler;
  3297. eventCount := eventMax
  3298. END InstallTickHandler;
  3299. (* Initialize processors *)
  3300. PROCEDURE InitProcessors*;
  3301. BEGIN
  3302. traceProcessor := FALSE; traceProcessorProc := NIL;
  3303. ASSERT(Second = 1000); (* use of Machine.ticks *)
  3304. InitTicks;
  3305. timer := DummyEvent;
  3306. ParseMPConfig;
  3307. InstallHandler(HandleIPC, MPIPCLocal);
  3308. IF localAPIC # 0 THEN (* APIC present *)
  3309. InitAPICArea(localAPIC, 4096);
  3310. InitAPICIDAdr(localAPIC+20H, idMap);
  3311. ASSERT(MPSPU MOD 16 = 15); (* use default handler (see 7.4.11.1) *)
  3312. InstallHandler(HandleError, MPERR);
  3313. InstallHandler(HandleMPTimer, MPTMR);
  3314. InstallHandler(HandleIPC, MPIPC);
  3315. InitAPIC;
  3316. IF numProcessors > 1 THEN BootMP END
  3317. ELSE
  3318. IF timerRate > 0 THEN
  3319. InstallTickHandler(HandleUPTimer, Second DIV timerRate)
  3320. END
  3321. END;
  3322. InstallHandler(HandleKernelCall, MPKC);
  3323. END InitProcessors;
  3324. (* Send and print character *)
  3325. PROCEDURE TraceChar (c: CHAR);
  3326. VAR status: SHORTINT;
  3327. (* Scroll the screen by one line. *)
  3328. PROCEDURE Scroll;
  3329. VAR adr: ADDRESS; off: SIZE;
  3330. BEGIN
  3331. adr := traceBase + TraceLen;
  3332. SYSTEM.MOVE (adr, adr - TraceLen, TraceSize - TraceLen);
  3333. adr := traceBase + TraceSize - TraceLen;
  3334. FOR off := 0 TO TraceLen - SIZEOF(INTEGER) BY SIZEOF(INTEGER) DO SYSTEM.PUT16 (adr + off, 100H * 7H + 32) END
  3335. END Scroll;
  3336. BEGIN
  3337. IF TraceV24 IN traceMode THEN
  3338. REPEAT (* wait until port is ready to accept a character *)
  3339. Portin8 (tracePort + 5, SYSTEM.VAL(CHAR,status))
  3340. UNTIL ODD (status DIV 20H); (* THR empty *)
  3341. Portout8 (tracePort, c);
  3342. END;
  3343. IF TraceScreen IN traceMode THEN
  3344. IF c = 9X THEN c := 20X END;
  3345. IF c = 0DX THEN (* CR *)
  3346. DEC (tracePos, tracePos MOD TraceLen)
  3347. ELSIF c = 0AX THEN (* LF *)
  3348. IF tracePos < TraceSize THEN
  3349. INC (tracePos, TraceLen) (* down to next line *)
  3350. ELSE
  3351. Scroll
  3352. END
  3353. ELSE
  3354. IF tracePos >= TraceSize THEN
  3355. Scroll;
  3356. DEC (tracePos, TraceLen)
  3357. END;
  3358. SYSTEM.PUT16 (traceBase + tracePos, 100H * traceColor + ORD (c));
  3359. INC (tracePos, SIZEOF(INTEGER))
  3360. END
  3361. END
  3362. END TraceChar;
  3363. (* Change color *)
  3364. PROCEDURE TraceColor (c: SHORTINT);
  3365. BEGIN traceColor := c;
  3366. END TraceColor;
  3367. (* Initialise tracing. *)
  3368. PROCEDURE InitTrace;
  3369. CONST MaxPorts = 8;
  3370. VAR i, p, bps: LONGINT; off: SIZE; s, name: ARRAY 32 OF CHAR;
  3371. baselist: ARRAY MaxPorts OF LONGINT;
  3372. BEGIN
  3373. GetConfig ("TraceMode", s);
  3374. p := 0; traceMode := SYSTEM.VAL (SET, StrToInt (p, s));
  3375. IF TraceScreen IN traceMode THEN
  3376. GetConfig ("TraceMem", s);
  3377. p := 0; traceBase := SYSTEM.VAL (ADDRESS, StrToInt (p, s));
  3378. IF traceBase = 0 THEN traceBase := 0B8000H END; (* default screen buffer *)
  3379. FOR off := 0 TO TraceSize - SIZEOF(INTEGER) BY SIZEOF(INTEGER) DO SYSTEM.PUT16 (traceBase + off, 100H * 7H + 32) END;
  3380. tracePos := 0;
  3381. Portout8(3D4H, 0EX);
  3382. Portout8(3D5H, CHR((TraceWidth*TraceHeight) DIV 100H));
  3383. Portout8(3D4H, 0FX);
  3384. Portout8(3D5H, CHR((TraceWidth*TraceHeight) MOD 100H))
  3385. END;
  3386. IF TraceV24 IN traceMode THEN
  3387. FOR i := 0 TO MaxPorts - 1 DO
  3388. COPY ("COMx", name); name[3] := CHR (ORD ("1") + i);
  3389. GetConfig (name, s); p := 0; baselist[i] := StrToInt (p, s);
  3390. END;
  3391. IF baselist[0] = 0 THEN baselist[0] := 3F8H END; (* COM1 port default values *)
  3392. IF baselist[1] = 0 THEN baselist[1] := 2F8H END; (* COM2 port default values *)
  3393. GetConfig("TracePort", s); p := 0; p := StrToInt(p, s); DEC(p);
  3394. IF (p >= 0) & (p < MaxPorts) THEN tracePort := baselist[p] ELSE tracePort := baselist[0] END;
  3395. ASSERT(tracePort > 0);
  3396. GetConfig("TraceBPS", s); p := 0; bps := StrToInt(p, s);
  3397. IF bps <= 0 THEN bps := 38400 END;
  3398. Portout8 (tracePort + 3, 80X); (* Set the Divisor Latch Bit - DLAB = 1 *)
  3399. bps := 115200 DIV bps; (* compiler DIV/PORTOUT bug workaround *)
  3400. Portout8 (tracePort + 1, CHR (bps DIV 100H)); (* Set the Divisor Latch MSB *)
  3401. Portout8 (tracePort, CHR (bps MOD 100H)); (* Set the Divisor Latch LSB *)
  3402. Portout8 (tracePort + 3, 3X); (* 8N1 *)
  3403. Portout8 (tracePort + 4, 3X); (* Set DTR, RTS on in the MCR *)
  3404. Portout8 (tracePort + 1, 0X); (* Disable receive interrupts *)
  3405. END;
  3406. traceColor := 7; Trace.Char := TraceChar; Trace.Color := TraceColor;
  3407. END InitTrace;
  3408. (* The following procedure is linked as the first block in the bootfile *)
  3409. PROCEDURE {NOPAF, FIXED(01000000H)} FirstAddress;
  3410. CODE{SYSTEM.AMD64}
  3411. ; save arguments passed by bootloader
  3412. MOV bootFlag, RAX
  3413. MOV initRegs0,RSI
  3414. MOV initRegs1, RDI
  3415. MOV fbadr, RDI
  3416. MOV fbInfoPtr, RCX
  3417. END FirstAddress;
  3418. (*
  3419. (* The following procedure is linked as the first block in the bootfile *)
  3420. PROCEDURE {NOPAF, FIXED(0100000H)} FirstAddress;
  3421. CODE{SYSTEM.AMD64}
  3422. ; relocate the bootfile from 0x1000 to target address 0x100000
  3423. PUSH RAX
  3424. PUSH RSI
  3425. PUSH RDI
  3426. MOV RSI,1000H
  3427. MOV RDI,100000H
  3428. MOV RCX, LastAddress
  3429. SUB RCX, RDI
  3430. ; CLD
  3431. ; REP MOVSB
  3432. ADD RSI, RCX
  3433. ADD RDI, RCX
  3434. STD
  3435. REP MOVSB
  3436. POP RDI
  3437. POP RSI
  3438. POP RAX
  3439. ; continue in relocated bootfile
  3440. JMP DWORD 100000H - 1000H + Skip
  3441. Skip:
  3442. ; save arguments passed by bootloader
  3443. MOV bootFlag, RAX
  3444. MOV initRegs0,RSI
  3445. MOV initRegs1, RDI
  3446. END FirstAddress;
  3447. *)
  3448. (* empty section allocated at end of bootfile *)
  3449. PROCEDURE {NOPAF} LastAddress;
  3450. CODE {SYSTEM.AMD64}
  3451. END LastAddress;
  3452. (* Init code called from OBL. EAX = boot table offset. ESI, EDI=initRegs. 2k stack is available. No trap handling. *)
  3453. BEGIN
  3454. initRegs[0] := initRegs0;
  3455. initRegs[1] := initRegs1;
  3456. (* registers 6 and 7 get converted to 32 bit, cf. PCB.Assigne
  3457. SYSTEM.GETREG(6, initRegs[0]); SYSTEM.GETREG(7, initRegs[1]); (* initRegs0 & initRegs1 *)
  3458. *)
  3459. SYSTEM.PUT16(0472H, 01234H); (* soft boot flag, for when we reboot *)
  3460. ReadBootTable(bootFlag);
  3461. InitTrace;
  3462. Trace.String("Machine: "); Trace.Blue;Trace.StringLn (Version); Trace.Default;
  3463. CheckMemory;
  3464. SearchMP;
  3465. AllocateDMA; (* must be called after SearchMP, as lowTop is modified *)
  3466. version := Version;
  3467. InitBoot;
  3468. InitProcessor;
  3469. InitLocks;
  3470. NmaxUserStacks := MaxUserStacks;
  3471. ASSERT(ASH(1, PSlog2) = PS);
  3472. Trace.String("Machine: Enabling MMU... ");
  3473. InitSegments; (* enable flat segments *)
  3474. InitPages; (* create page tables *)
  3475. InitMemory; (* switch on segmentation, paging and switch stack *)
  3476. Trace.Green; Trace.StringLn("Ok"); Trace.Default;
  3477. (* allocate empty memory block with enough space for at least one free block *)
  3478. memBlockHead := SYSTEM.VAL (MemoryBlock, ADDRESSOF (initialMemBlock));
  3479. memBlockTail := memBlockHead;
  3480. initialMemBlock.beginBlockAdr := SYSTEM.VAL (ADDRESS, LastAddress);
  3481. initialMemBlock.endBlockAdr := initialMemBlock.beginBlockAdr + StaticBlockSize;
  3482. initialMemBlock.size := initialMemBlock.endBlockAdr - initialMemBlock.beginBlockAdr;
  3483. FOR i := 0 TO IDTSize - 1 DO
  3484. FOR j := 0 TO MaxNumHandlers - 1 DO
  3485. intHandler[i, j].valid := FALSE;
  3486. intHandler[i, j].handler := NIL
  3487. END
  3488. END;
  3489. default.valid := FALSE; (* initialized later *)
  3490. END Machine.
  3491. (*
  3492. 03.03.1998 pjm First version
  3493. 30.06.1999 pjm ProcessorID moved to AosProcessor
  3494. *)
  3495. (**
  3496. Notes
  3497. This module defines an interface to the boot environment of the system. The facilities provided here are only intended for the lowest levels of the system, and should never be directly imported by user modules (exceptions are noted below). They are highly specific to the system hardware and firmware architecture.
  3498. Typically a machine has some type of firmware that performs initial testing and setup of the system. The firmware initiates the operating system bootstrap loader, which loads the boot file. This module is the first module in the statically linked boot file that gets control.
  3499. There are two more-or-less general procedures in this module: GetConfig and StrToInt. GetConfig is used to query low-level system settings, e.g., the location of the boot file system. StrToInt is a utility procedure that parses numeric strings.
  3500. Config strings:
  3501. ExtMemSize Specifies size of extended memory (above 1MB) in MB. This value is not checked for validity. Setting it false may cause the system to fail, possible after running for some time. The memory size is usually detected automatically, but if the detection does not work for some reason, or if you want to limit the amount of memory detected, this string can be set. For example, if the machine has 64MB of memory, this value can be set as ExtMemSize="63".
  3502. *)