LOADER.MOD 102 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895
  1. IMPLEMENTATION MODULE Loader;
  2. IMPORT SYSTEM,LoaderA;
  3. FROM LoaderA IMPORT MoveUp,MainName;
  4. (*# data(const_in_code=>off) *)
  5. (*# call(o_a_copy=>off,o_a_size=>off) *)
  6. (*# call(seg_name=>null) *)
  7. (*# data(near_ptr=>off,threshold=>0FFFFH) *)
  8. (*#call(inline_max=>1000)*)
  9. (*# call(near_call=>off,overlay=>on) *)
  10. (* limits *)
  11. CONST
  12. MaxName = 80; (* size of module name *)
  13. MaxSeg = 255; (* number of segments in a module *)
  14. MaxEntry = 1000; (* number of entry points in a module *)
  15. MaxModule = 64; (* number of modules *)
  16. MaxGate = 2000;
  17. HeapSize = 6000H;
  18. FileLimit = 10; (* open file limit (temp file not included) *)
  19. TempLimit = 8*100000H; (* 8 Megabytes *)
  20. TempPageShift = 10;
  21. TempPageSize = 1 << TempPageShift;
  22. (*%T EMS*)
  23. CONST EmsPageSize = 4000H DIV TempPageSize;
  24. (*%E*)
  25. CONST PanicSize = 8000H;
  26. TYPE SegKind = (StaticSeg, SwapSeg, MoveSeg, FixedSeg, SystemSeg);
  27. TYPE SegKindSet = SET OF SegKind;
  28. (* tracing controls *)
  29. CONST
  30. MemoryTrace = FALSE;
  31. LoadTrace = FALSE;
  32. ExitTrace = FALSE;
  33. MemTraceSet = SegKindSet{ StaticSeg, SwapSeg, MoveSeg, FixedSeg};
  34. UsageTrace = FALSE;
  35. OutOfMemTrace = FALSE;
  36. MoveTrace = FALSE;
  37. Debuging = FALSE;
  38. GraphUseTrace = FALSE;
  39. TraceToFile = FALSE;
  40. (* emergency tracing *)
  41. CONST
  42. LockTrace = FALSE;
  43. FileTrace = FALSE;
  44. CallTrace = FALSE;
  45. EntryTableTrace = FALSE;
  46. RelocateTrace = FALSE;
  47. (* error messages *)
  48. ErrBase = 8500;
  49. ErrOutOfMem = 0;
  50. ErrTempFileLimit = 1;
  51. ErrLoad = 2;
  52. ErrPoolLimit = 3;
  53. ErrGateLimit = 4;
  54. ErrTempDiskFull = 5;
  55. ErrDiskFull = 6;
  56. ErrTempCreate = 7;
  57. ErrInternal = 8;
  58. ErrNearHeap = 9;
  59. ErrModuleLimit = 10;
  60. ErrInvalidProcedure = 11;
  61. ErrMemoryCorruption = 12;
  62. ErrTooManyUnlocks = 13;
  63. ErrCallChainInvalid = 14;
  64. ErrOpenFail = 15;
  65. ErrNamedImport = 16;
  66. ErrInvalidVUnfix = 17;
  67. ErrInvalidVFix = 18;
  68. ErrInvalidFree = 19;
  69. (*-----------------------------------------------------------------------*)
  70. (* low level file handling *)
  71. (*-----------------------------------------------------------------------*)
  72. (*# save,call(same_ds=>off) *)
  73. (*# call(near_call=>on) *)
  74. (*# call(reg_param=>(bx, dx, cx), reg_saved=>(ds, di, si, st1, st2)) *)
  75. PROCEDURE FileSeek(h:CARDINAL;pos:LONGCARD); IN LoaderA;
  76. (*# call(reg_param=>(dx, ax, cx, bx), reg_saved=>(ds, di, si, st1, st2)) *)
  77. PROCEDURE FileRead(a:ADDRESS;count:CARDINAL;h:CARDINAL); IN LoaderA;
  78. PROCEDURE FileWrite(a:ADDRESS;count:CARDINAL;h:CARDINAL):CARDINAL; IN LoaderA;
  79. (*# call(reg_param=>(bx), reg_saved=>(ds, di, si, st1, st2)) *)
  80. PROCEDURE FileClose(h:CARDINAL); IN LoaderA;
  81. (*# call(reg_param=>(ax,bx,cx,dx,si)) *)
  82. PROCEDURE Exec(psp,ss,sp,cs,ip:CARDINAL); IN LoaderA;
  83. (*# call(reg_param=>(dx, bx, ax), reg_saved=>(ds, di, si, st1, st2)) *)
  84. PROCEDURE FileOpen(name:ARRAY OF CHAR;mode:BITSET):CARDINAL; IN LoaderA;
  85. PROCEDURE DosExit; IN LoaderA;
  86. PROCEDURE FileDelete(name:ARRAY OF CHAR); IN LoaderA;
  87. PROCEDURE FileCreate(name:ARRAY OF CHAR):CARDINAL; IN LoaderA;
  88. PROCEDURE FileCreateNew(VAR name : ARRAY OF CHAR):CARDINAL; IN LoaderA;
  89. (*# call(reg_param=>(bx), reg_saved=>(ds, di, si, st1, st2)) *)
  90. PROCEDURE FileSize(h:CARDINAL):LONGCARD; IN LoaderA;
  91. (*# restore *)
  92. TYPE
  93. ModNum = [1..MaxModule];
  94. SegNum = CARDINAL;
  95. DoSegOp = (Load,Swap,Discard);
  96. TYPE HeapADDR = SHORTADDR;
  97. CONST HeapAdr ::= Ofs;
  98. (*# data(near_ptr=>on) *)
  99. CONST FreeGate = 0;
  100. CONST DeletedGate = 1;
  101. CONST IndirectGate = 0E8H; (* call near *)
  102. CONST DirectGate = 0EAH; (* jump far *)
  103. TYPE
  104. GatePtr = POINTER TO GateRec;
  105. GateRec = RECORD
  106. state : SHORTCARD;
  107. w1 : CARDINAL;
  108. w2 : CARDINAL;
  109. next_direct: GatePtr;
  110. END; (*GateRec*)
  111. (* bits for Seghdr.flags *)
  112. SegAttr = (IsData,Typ2,Typ3,IsIter,IsMove,IsPure,IsPreLoad,IsExRd,
  113. HasReloc,Iop1,Iop2,Iop3,IsDiscard,Is32,IsHuge,DataActive);
  114. SegSet = SET OF SegAttr;
  115. SegPtr = POINTER TO SegRec;
  116. SegRec = RECORD
  117. no_op : SHORTCARD; (* 090H return gates point here *)
  118. jump_op : SHORTCARD; (* 0E9H call gates point here *)
  119. jump_disp : CARDINAL; (* jumps to GateHandler *)
  120. seg_val : CARDINAL;
  121. direct_list: GatePtr;
  122. fix_count : CARDINAL;
  123. (* last four fields are read straight from file *)
  124. sector : CARDINAL;
  125. filebyte : CARDINAL;
  126. flags : SegSet;
  127. membyte : CARDINAL;
  128. END; (*SegRec*)
  129. ModStage = (initial_stage,internal_stage,sub_module_stage,execute_stage);
  130. EntryRec = RECORD
  131. seg : SHORTCARD;
  132. ofs : CARDINAL;
  133. END; (*EntryRec*)
  134. Module = POINTER TO ModuleRec;
  135. ModuleRec = RECORD
  136. file : CARDINAL;
  137. seg_count : CARDINAL;
  138. log_sector_size : CARDINAL;
  139. stage : ModStage;
  140. is_exe : BOOLEAN;
  141. name : POINTER TO ARRAY[0..MaxName] OF CHAR;
  142. seg_info : POINTER TO ARRAY[1..MaxSeg] OF SegRec;
  143. entry_table: POINTER TO ARRAY[1..MaxEntry] OF EntryRec;
  144. module_table:POINTER TO ARRAY[1..MaxModule] OF SHORTCARD;
  145. END; (*ModuleRec*)
  146. (*# data(near_ptr=>off) *)
  147. LoadState = RECORD
  148. (*%T Debuging*)
  149. trap_seg : SegNum; (* for debugging *)
  150. trap_mod : ModNum; (* for debugging *)
  151. trap_off : CARDINAL; (* for debugging *)
  152. trap_alloc : CARDINAL;
  153. (*%E*)
  154. (*%T MemoryTrace*) (* don't trace internal operations *)
  155. internal : BOOLEAN;
  156. (*%E*)
  157. psp : CARDINAL;
  158. stk : CARDINAL;
  159. module_count:CARDINAL;
  160. abort : ExitHandler;
  161. OutOfMem : MemHandler;
  162. file_count : INTEGER;
  163. near_alloc : CARDINAL;
  164. start : CARDINAL; (* start of memory *)
  165. end : CARDINAL; (* last para of normal (not ems) memory *)
  166. freemem : CARDINAL;
  167. allockind : SegKind;
  168. panic_reserve:CARDINAL;
  169. temp_file : CARDINAL;
  170. temp_reserve:LONGINT;
  171. temp_ems : CARDINAL; (* number of temp pages mapped into ems *)
  172. temp_map : ARRAY [0..TempLimit DIV (8*SIZE(BITSET)*TempPageSize)] OF BITSET;
  173. (*%T ExitTrace *)
  174. temp_max : CARDINAL;
  175. (*%E*)
  176. (*%T MoveTrace *)
  177. move_total : LONGCARD;
  178. (*%E*)
  179. ems_frame : CARDINAL;
  180. (*%T EMS*)
  181. ems_present: BOOLEAN;
  182. ems_count : CARDINAL;
  183. ems_temp_handle:CARDINAL;
  184. ems_data_handle:CARDINAL;
  185. (*%E*)
  186. module_list: ARRAY ModNum OF Module;
  187. delay : ModNum;
  188. gate_count : CARDINAL;
  189. gate_table : ARRAY [1..MaxGate] OF GateRec;
  190. (*%T VidSupport*)
  191. vid_present: BOOLEAN;
  192. vid_delayed: BOOLEAN;
  193. vid_id1,
  194. vid_id2 : CARDINAL;
  195. (*%E*)
  196. heap : ARRAY [1..HeapSize] OF SHORTCARD;
  197. Tick : CARDINAL;
  198. END; (*LoadState*)
  199. TYPE A1 = SHORTCARD;
  200. TYPE A2 = ARRAY [1..2] OF SHORTCARD;
  201. TYPE A4 = ARRAY [1..4] OF SHORTCARD;
  202. TYPE A6 = ARRAY [1..6] OF SHORTCARD;
  203. TYPE A7 = ARRAY [1..7] OF SHORTCARD;
  204. TYPE A8 = ARRAY [1..8] OF SHORTCARD;
  205. TYPE A9 = ARRAY [1..9] OF SHORTCARD;
  206. TYPE A12= ARRAY [1..12] OF SHORTCARD;
  207. TYPE A13= ARRAY [1..13] OF SHORTCARD;
  208. TYPE
  209. HandlerRec = RECORD
  210. b01,b02,b03,b04:SHORTCARD;
  211. OffsetShift:SHORTCARD;
  212. b11,b12,b13,b14,b15,b16,b17:SHORTCARD;
  213. PageDisp:CARDINAL;
  214. b21,b22,b23,b24:SHORTCARD;
  215. MemStart:CARDINAL;
  216. b25,b26,b27,b28:SHORTCARD;
  217. MemEnd:CARDINAL;
  218. b29,b30,b31,b32:SHORTCARD;
  219. EmsStart:CARDINAL;
  220. b33,b34,b35,b36:SHORTCARD;
  221. EmsEnd:CARDINAL;
  222. b37:A8;b38:CARDINAL; b39:A4; b40:CARDINAL; b41:A12;
  223. OffsetMask:BITSET;
  224. b42:SHORTCARD;
  225. BlankShift:SHORTCARD;
  226. b5:A13;
  227. QFix:ADDRESS;
  228. b61,b62,b63:SHORTCARD;
  229. END;
  230. CONST
  231. MaxPage = 1024;
  232. TYPE
  233. WP = POINTER TO CARDINAL;
  234. ParaRec = RECORD
  235. Size : CARDINAL; (* Size in paragraphs of alloc *)
  236. Used : CARDINAL; (* Paragraphs currently in use *)
  237. Prev : CARDINAL; (* Previous ParaRec Segment *)
  238. Active : BOOLEAN;
  239. Kind : SegKind; (* Kind of segment *)
  240. Id1,Id2 : CARDINAL;
  241. Lock : CARDINAL; (* Segment Locked in memory *)
  242. Tick : CARDINAL; (* LRU Tick Count *)
  243. END; (*ParaRec*)
  244. T = POINTER TO ParaRec;
  245. CONST H = (SIZE(ParaRec)+15) DIV 16; (* overhead in paragraphs *)
  246. CONST loader_name = 'LOADER';
  247. TYPE t_loader_hdr = ARRAY [1..1] OF SegRec;
  248. CONST loader_hdr = t_loader_hdr(
  249. SegRec(90H, 0E9H, 0, 0, GatePtr(0), 0, 0, 0, SegSet{IsPreLoad}, 0)
  250. );
  251. Entries = 34;
  252. TYPE t_loader_entry = ARRAY [1..Entries] OF EntryRec;
  253. (* N.B. this has to be consistent with loader.exp *)
  254. CONST loader_entry = t_loader_entry (
  255. EntryRec(1,Ofs(LoadModule)),
  256. EntryRec(1,Ofs(UnLoadModule)),
  257. EntryRec(1,Ofs(GetProcAddr)),
  258. EntryRec(1,Ofs(ShrinkHeap)),
  259. EntryRec(1,Ofs(GrowHeap)),
  260. EntryRec(1,Ofs(UserFlush)),
  261. EntryRec(1,Ofs(InvalidProc)),
  262. EntryRec(1,Ofs(InvalidProc)),
  263. EntryRec(1,Ofs(AllocMem)),
  264. EntryRec(1,Ofs(ClearAllocMem)),
  265. EntryRec(1,Ofs(HugeAllocMem)),
  266. EntryRec(1,Ofs(FreeMem)),
  267. EntryRec(1,Ofs(SetExitHandler)),
  268. EntryRec(1,Ofs(SetMemHandler)),
  269. EntryRec(1,Ofs(InvalidProc)),
  270. EntryRec(1,Ofs(LoadSeg)),
  271. EntryRec(1,Ofs(UnloadSeg)),
  272. EntryRec(1,Ofs(Terminate)),
  273. EntryRec(1,Ofs(InvalidProc)),
  274. EntryRec(1,Ofs(RetGate)),
  275. EntryRec(1,Ofs(Avail)),
  276. EntryRec(1,Ofs(TotalAvail)),
  277. EntryRec(1,Ofs(SetEms)),
  278. EntryRec(1,Ofs(Getseg)),
  279. EntryRec(1,Ofs(ExpandMem)),
  280. EntryRec(1,Ofs(HugeExpandMem)),
  281. EntryRec(1,Ofs(HeapWalk)),
  282. EntryRec(1,Ofs(HeapCheck)),
  283. EntryRec(1,Ofs(GetOrdProcAddr)),
  284. EntryRec(1,Ofs(VAlloc)),
  285. EntryRec(1,Ofs(VUnfix)),
  286. EntryRec(1,Ofs(VFix)),
  287. EntryRec(1,Ofs(VUnfixAll)),
  288. EntryRec(1,Ofs(VFree))
  289. );
  290. VAR g:LoadState;
  291. CONST loader_module = ModuleRec (
  292. MAX(CARDINAL),
  293. 2,
  294. 0,
  295. execute_stage,
  296. FALSE, (* not exe *)
  297. HeapADDR(HeapAdr(loader_name)),
  298. HeapADDR(HeapAdr(loader_hdr)),
  299. HeapADDR(HeapAdr(loader_entry)),
  300. HeapADDR(0)
  301. );
  302. (*-----------------------------------------------------------------------*)
  303. (* inline functions *)
  304. (*-----------------------------------------------------------------------*)
  305. (*# save, call(inline=>on, same_ds=>off) *)
  306. (*# call(reg_saved=>(bx,cx,dx,si,di,ds,es,st1,st2)) *)
  307. INLINE PROCEDURE GetBP():CARDINAL = A2(89H, 0E8H); (* mov ax,bp *)
  308. INLINE PROCEDURE GetSP():CARDINAL = A2(89H, 0E0H); (* mov ax,sp *)
  309. INLINE PROCEDURE Int3() = A1(0CCH);
  310. INLINE PROCEDURE Int66() = A2(0CDH,066H); (* used to enter symdeb *)
  311. (*# call(reg_param=>(si,ax,di,es,cx), reg_saved=>(bx,dx,ds,st1,st2)) *)
  312. INLINE PROCEDURE Move(fr,to : ADDRESS; count : CARDINAL)=
  313. A12(1EH,8EH,0D8H,0D1H,0E9H,0F3H,0A5H,013H,0C9H,0F3H,0A4H,1FH);
  314. (* push ds; mov ds,ax; shr cx,1; rep; movsw; adc cx,cx; rep; movsb; pop ds *)
  315. (*# call(reg_param=>(di,es,cx,ax), reg_saved=>(bx,dx,si,ds,st1,st2)) *)
  316. INLINE PROCEDURE Fill(a:ADDRESS;count:CARDINAL;w:CARDINAL) = A7(0D1H,0E9H,0F3H,0ABH,073H,001H,0AAH);
  317. (*# call(reg_param=>(dx,si,ax)) *)
  318. INLINE PROCEDURE GetCurDir (drive : SHORTCARD;VAR p : ARRAY OF CHAR) =
  319. A8(1EH, 8EH,0D8H, 0B4H,47H, 0CDH,21H, 1FH);
  320. (* push ds; mov ds,ax; mov ah,47H; int 21H; pop ds *)
  321. (*# call(reg_return=>(ax)) *)
  322. INLINE PROCEDURE GetCurDrive():SHORTCARD = A4(0B4H,19H, 0CDH,21H); (* mov ah, 19H; int 21H *)
  323. (*%T EMS*)
  324. (* Ems support *)
  325. (*# call(reg_param=>(ax,bx,dx), reg_saved =>(si,di,ds,st1,st2)) *)
  326. INLINE PROCEDURE EmsTest(ax:CARDINAL):CARDINAL = A2(0CDH,67H);
  327. INLINE PROCEDURE EmsMap(ax:CARDINAL;bx:CARDINAL;dx:CARDINAL) = A2(0CDH,67H);
  328. (*# call(reg_return=>(bx)) *)
  329. INLINE PROCEDURE EmsGet(ax:CARDINAL):CARDINAL = A2(0CDH,67H);
  330. (*# call(reg_return=>(dx)) *)
  331. INLINE PROCEDURE EmsAlloc(ax:CARDINAL;bx:CARDINAL):CARDINAL = A2(0CDH,67H);
  332. (*%E*)
  333. (*# call(reg_param=>(dx,ax)) *)
  334. INLINE PROCEDURE Out (p:CARDINAL;v:SHORTCARD)=SHORTCARD(0EEH);
  335. INLINE PROCEDURE DI()=SHORTCARD(0FAH);
  336. INLINE PROCEDURE EI()=SHORTCARD(0FBH);
  337. (*# restore *)
  338. INLINE PROCEDURE GetTick():CARDINAL;
  339. BEGIN
  340. RETURN g.Tick;
  341. END GetTick;
  342. INLINE PROCEDURE IncTick():CARDINAL;
  343. BEGIN
  344. INC(g.Tick);
  345. RETURN g.Tick;
  346. END IncTick;
  347. (* tracing *)
  348. (*%T TraceToFile*) VAR output_file : CARDINAL; (*%E*)
  349. (*%F TraceToFile*) CONST output_file = 1; (*%E*)
  350. PROCEDURE string(s: ARRAY OF CHAR);
  351. VAR i:CARDINAL;
  352. BEGIN
  353. i := 0;
  354. WHILE s[i]#0C DO
  355. INC(i);
  356. END;
  357. i := FileWrite(ADR(s), i, output_file);
  358. END string;
  359. PROCEDURE eol;
  360. CONST CRLF = CHAR(13) + CHAR(10);
  361. VAR i:CARDINAL;
  362. p:LONGCARD;
  363. BEGIN
  364. i := FileWrite(ADR(CRLF), 2, output_file);
  365. END eol;
  366. PROCEDURE char(c: CHAR);
  367. VAR i:CARDINAL;
  368. BEGIN
  369. i := FileWrite(ADR(c), 1, output_file);
  370. END char;
  371. PROCEDURE hex(n: CARDINAL);
  372. CONST dig = '0123456789ABCDEF';
  373. VAR buf:ARRAY [0..3] OF CHAR;
  374. i:CARDINAL;
  375. BEGIN
  376. FOR i := 0 TO 3 DO
  377. buf[3-i] := dig[n MOD 16];
  378. n := n DIV 16;
  379. END;
  380. i := FileWrite(ADR(buf), 4, output_file);
  381. END hex;
  382. PROCEDURE dec(n: CARDINAL);
  383. VAR div:CARDINAL;
  384. BEGIN
  385. div := n DIV 10;
  386. IF div#0 THEN
  387. dec(div);
  388. END;
  389. char('0' + CHAR(n MOD 10));
  390. END dec;
  391. (*%T GraphUseTrace*)
  392. TYPE graphsegrec = RECORD
  393. seg : CARDINAL;
  394. pos : CARDINAL;
  395. lasttick : CARDINAL;
  396. END;
  397. VAR graphsegs : ARRAY[1..300] OF graphsegrec;
  398. TYPE GTmode = (GTadd,GTdel,GTlru);
  399. PROCEDURE GraphTrace(seg : CARDINAL;
  400. pos : CARDINAL;
  401. mode : GTmode);
  402. VAR i,j,s,segm : CARDINAL;
  403. c : CHAR;
  404. BEGIN
  405. (* IF NOT(4 IN BITSET([40H:17H T]^)) THEN RETURN END; *)
  406. hex([40H:6CH]^);
  407. char(' ');
  408. CASE mode OF
  409. |GTadd: char('¯');
  410. |GTdel: char('®');
  411. |GTlru: char(' ');
  412. END;
  413. IF mode=GTlru THEN string('flush ');hex(pos);
  414. ELSE
  415. char(' ');
  416. hex(seg);
  417. char(' ');hex([pos-1:0 T]^.Used);
  418. END;
  419. char(' ');
  420. j := HIGH(graphsegs);
  421. WHILE (j>0)AND(graphsegs[j].seg=0)DO DEC(j); END;
  422. IF j<HIGH(graphsegs) THEN INC(j); END;
  423. FOR i := 1 TO j DO
  424. s := graphsegs[i].seg;
  425. IF (s=0)OR((s=seg)AND(mode=GTadd)) THEN
  426. IF mode=GTadd THEN
  427. graphsegs[i].seg := seg;
  428. graphsegs[i].pos := pos;
  429. graphsegs[i].lasttick := [pos-1:0 T]^.Tick;
  430. c := '¸';
  431. mode := GTlru;
  432. ELSE
  433. c := ' ';
  434. END;
  435. ELSIF (s=seg)AND(mode=GTdel) THEN
  436. c := '¾';
  437. graphsegs[i].pos := 0;
  438. ELSE
  439. IF graphsegs[i].pos=0 THEN
  440. c := ' ';
  441. ELSE
  442. segm := SegPtr(HeapAdr(g.module_list[s DIV 256]^.seg_info^[s MOD 256]))^.seg_val;
  443. IF graphsegs[i].pos<>segm THEN
  444. graphsegs[i].pos := segm;
  445. c := 'Æ';
  446. ELSIF graphsegs[i].lasttick <> [graphsegs[i].pos-1:0 T]^.Tick THEN
  447. graphsegs[i].lasttick := [graphsegs[i].pos-1:0 T]^.Tick;
  448. c := 'Ã';
  449. ELSE
  450. c := '³';
  451. END;
  452. END;
  453. END;
  454. char(c);
  455. END;
  456. eol;
  457. END GraphTrace;
  458. (*%E*)
  459. PROCEDURE DumpMemory; FORWARD;
  460. PROCEDURE DumpSegName(seg:CARDINAL);FORWARD;
  461. PROCEDURE release_panic; FORWARD;
  462. (*#save,call(reg_param=>())*)
  463. PROCEDURE abort(errno:SHORTCARD);
  464. (*#restore*)
  465. TYPE
  466. fp = POINTER Seg(errno) TO RECORD
  467. bp,ip,cs: CARDINAL;
  468. END; (*fp*)
  469. VAR
  470. bp : fp;
  471. cs,i : CARDINAL;
  472. res : BOOLEAN;
  473. BEGIN
  474. (*%T TraceToFile*)
  475. DumpMemory;
  476. (*%E*)
  477. release_panic;
  478. (*%T CHECK*)
  479. eol;
  480. bp := fp(GetBP());
  481. i := 0;
  482. LOOP
  483. IF (bp = fp(0))OR(i=10) THEN EXIT END;
  484. INC(i);
  485. hex(CARDINAL(bp));string(' ');hex(bp^.ip);string(' ');DumpSegName(bp^.cs);eol;
  486. IF (bp^.bp=0) THEN
  487. EXIT;
  488. ELSIF bp^.bp <= CARDINAL(bp) THEN
  489. EXIT
  490. END; (*IF*)
  491. bp := fp(bp^.bp);
  492. END;
  493. (*%E*)
  494. g.abort(g.module_list[1]^.name^,ErrBase+CARDINAL(errno));
  495. Terminate;
  496. DosExit;
  497. END abort;
  498. PROCEDURE is_mem(seg:CARDINAL):BOOLEAN;
  499. BEGIN
  500. RETURN ((seg >= g.start) & (seg < g.end))
  501. (*%T EMS*)
  502. OR ((seg >= g.ems_frame) & (seg < g.ems_frame + 1000H))
  503. (*%E*)
  504. ;
  505. END is_mem;
  506. PROCEDURE encode_temp(i:CARDINAL):CARDINAL;
  507. BEGIN
  508. IF g.ems_frame < g.start THEN
  509. IF i >= g.ems_frame THEN
  510. INC(i, 1000H);
  511. END;
  512. END;
  513. IF i >= g.start THEN
  514. INC(i, g.end - g.start);
  515. END;
  516. IF g.ems_frame > g.start THEN
  517. IF i >= g.ems_frame THEN
  518. INC(i, 1000H);
  519. END;
  520. END;
  521. (*%T CHECK*) IF (i=0) OR is_mem(i) THEN abort(ErrTempFileLimit) END; (*%E*)
  522. RETURN i;
  523. END encode_temp;
  524. PROCEDURE decode_temp(i:CARDINAL):CARDINAL;
  525. BEGIN
  526. IF g.ems_frame > g.start THEN
  527. IF i >= g.ems_frame THEN
  528. DEC(i,1000H);
  529. END;
  530. END;
  531. IF i >= g.start THEN
  532. DEC(i, g.end - g.start);
  533. END;
  534. IF g.ems_frame < g.start THEN
  535. IF i >= g.ems_frame THEN
  536. DEC(i, 1000H);
  537. END;
  538. END;
  539. RETURN i;
  540. END decode_temp;
  541. (*%T CHECK *)
  542. PROCEDURE CheckAlloc(seg:CARDINAL;err : CARDINAL);
  543. (* checks that block is a valid allocated segment *)
  544. BEGIN
  545. DEC(seg, H);
  546. WITH [seg:0 T]^ DO
  547. IF (seg < g.start) OR
  548. (Kind > MAX(SegKind)) OR
  549. (Used > Size) OR
  550. (Prev + [Prev:0 T]^.Size # seg) OR
  551. ([seg+Size:0 T]^.Prev # seg) THEN
  552. IF err=0 THEN
  553. abort(ErrMemoryCorruption);
  554. ELSE
  555. abort(SHORTCARD(err));
  556. END;
  557. END; (*IF*)
  558. END; (*WITH*)
  559. END CheckAlloc;
  560. PROCEDURE CalcFreeMem():CARDINAL;
  561. VAR
  562. res,p : CARDINAL;
  563. BEGIN
  564. res := 0;
  565. p := g.start;
  566. REPEAT
  567. WITH [p:0 T]^ DO
  568. INC(res,Size - Used);
  569. INC(p,Size);
  570. END; (*WITH*)
  571. UNTIL p = g.start;
  572. RETURN res;
  573. END CalcFreeMem;
  574. PROCEDURE CheckMem;
  575. VAR
  576. p : CARDINAL;
  577. BEGIN
  578. p := g.start;
  579. REPEAT
  580. CheckAlloc(p+H,0);
  581. INC(p,[p:0 T]^.Size);
  582. UNTIL p = g.start;
  583. IF CalcFreeMem() # g.freemem THEN
  584. abort(ErrInternal);
  585. END; (*IF*)
  586. END CheckMem;
  587. (*%E*)
  588. (*%F CHECK*) INLINE (*%E*) PROCEDURE Locked(w:CARDINAL):BOOLEAN;
  589. BEGIN
  590. RETURN ([w-H:0 T]^.Lock # 0);
  591. END Locked;
  592. PROCEDURE SwapMove(VAR seg:CARDINAL);
  593. BEGIN
  594. IF is_mem(seg) THEN
  595. (*%T CHECK*)
  596. CheckAlloc(seg,0);
  597. (*%E*)
  598. WITH [seg-H:0 T]^ DO
  599. (*%T CHECK*)
  600. IF Kind # MoveSeg THEN
  601. abort(ErrInternal);
  602. END;
  603. (*%E*)
  604. Kind := SwapSeg;
  605. Tick := IncTick();
  606. END; (*WITH*)
  607. END; (*IF*)
  608. END SwapMove;
  609. PROCEDURE DumpLockedStatics;
  610. VAR
  611. modnum:ModNum;
  612. segnum:SegNum;
  613. module:Module;
  614. segment:CARDINAL;
  615. BEGIN
  616. string('Locked static segments '); eol;
  617. FOR modnum := 1 TO g.module_count DO
  618. module := g.module_list[modnum];
  619. string(module^.name^);
  620. string(' : ');
  621. FOR segnum := 1 TO module^.seg_count DO
  622. segment := module^.seg_info^[segnum].seg_val;
  623. IF is_mem(segment) THEN
  624. WITH [segment-H:0 T]^ DO
  625. IF Lock<>0 THEN
  626. dec(segnum);
  627. char('(');
  628. dec(Lock);
  629. char(')');
  630. char(' ');
  631. END
  632. END;
  633. END;
  634. END;
  635. eol;
  636. END;
  637. END DumpLockedStatics;
  638. PROCEDURE DumpSegKind(kind:SegKind);
  639. BEGIN
  640. CASE kind OF
  641. | StaticSeg: string('sta');
  642. | SwapSeg: string('swa');
  643. | MoveSeg: string('mov');
  644. | FixedSeg: string('fix');
  645. | SystemSeg: string('sys');
  646. END;
  647. END DumpSegKind;
  648. PROCEDURE DumpSegName(seg:CARDINAL);
  649. BEGIN
  650. WITH [seg-H:0 T]^ DO
  651. CASE Kind OF
  652. | StaticSeg:
  653. string(g.module_list[Id1]^.name^);
  654. char('.');
  655. hex(Id2);
  656. | SwapSeg:
  657. DumpSegName(Id2); char(':'); hex(Id1);
  658. | MoveSeg:
  659. DumpSegName(Id2); char(':'); hex(Id1);
  660. ELSE
  661. hex(seg);
  662. END;
  663. END;
  664. END DumpSegName;
  665. PROCEDURE DumpSeg(s:ARRAY OF CHAR;seg:CARDINAL);
  666. BEGIN
  667. string(s);
  668. WITH [seg-H:0 T]^ DO
  669. hex(seg);
  670. (*string(' Size='); hex(Size);*)
  671. string(' Used='); hex(Used);
  672. (*string(' Prev='); hex(Prev);*)
  673. string(' Free='); hex(Size-Used);
  674. string(' Kind=');
  675. DumpSegKind(Kind);
  676. string(' Lock='); dec(Lock);
  677. string(' Name='); DumpSegName(seg);
  678. CASE Kind OF
  679. | MoveSeg, SwapSeg, StaticSeg: string(' Age='); dec(GetTick()-Tick);
  680. END;
  681. eol;
  682. END;
  683. END DumpSeg;
  684. PROCEDURE TraceSeg(s:ARRAY OF CHAR; seg:CARDINAL);
  685. BEGIN
  686. hex(g.freemem);
  687. char(' ');
  688. hex(seg);
  689. char(' ');
  690. string(s);
  691. WITH [seg-H:0 T]^ DO
  692. string(' Size='); hex(Used);
  693. string(' Kind=');
  694. DumpSegKind(Kind);
  695. CASE Kind OF
  696. | MoveSeg, SwapSeg, StaticSeg: string(' Name='); DumpSegName(seg);
  697. IF GetTick()#Tick THEN
  698. string(' Age='); dec(GetTick()-Tick);
  699. END;
  700. END;
  701. eol;
  702. END;
  703. END TraceSeg;
  704. (* splits free space of block p, returning lower half *)
  705. PROCEDURE SplitLow(size:CARDINAL; p:CARDINAL):CARDINAL;
  706. VAR
  707. res : CARDINAL;
  708. free : CARDINAL;
  709. BEGIN
  710. WITH [p:0 T]^ DO
  711. res := p + Used;
  712. free := Size - Used;
  713. Size := Used;
  714. END; (*WITH*)
  715. WITH [res:0 T]^ DO
  716. IF p # res THEN
  717. Prev := p;
  718. END; (*IF*)
  719. Size := free;
  720. Used := size;
  721. END; (*WITH*)
  722. WITH [res+free:0 T]^ DO
  723. Prev := res;
  724. END; (*WITH*)
  725. DEC(g.freemem,size);
  726. RETURN res;
  727. END SplitLow;
  728. (* Trys to find a block with with free space >= size, begin search at *)
  729. (* s, end at e. *)
  730. PROCEDURE Try(size:CARDINAL; s,e:CARDINAL):CARDINAL;
  731. VAR
  732. p,res : CARDINAL;
  733. BEGIN
  734. IF size = 0 THEN
  735. RETURN 0;
  736. END; (*IF*)
  737. p := s;
  738. LOOP
  739. WITH [p:0 T]^ DO
  740. IF Size - Used >= size THEN
  741. RETURN p;
  742. END; (*IF*)
  743. INC(p,Size);
  744. IF p = e THEN
  745. RETURN 0;
  746. END; (*IF*)
  747. END; (*WITH*)
  748. END; (*LOOP*)
  749. END Try;
  750. (* An area is a sequence of blocks satisfying ~Locked except for the *)
  751. (* first block. *)
  752. (* Returns size of possible free space in area starting at s..e, *)
  753. (* assuming blocks of size < req can be evacuated *)
  754. PROCEDURE Poss(s,e:CARDINAL; req:CARDINAL):CARDINAL;
  755. VAR
  756. res : CARDINAL;
  757. BEGIN
  758. WITH [s:0 T]^ DO
  759. IF Active THEN
  760. RETURN 0;
  761. END; (*IF*)
  762. res := Size - Used;
  763. INC(s,Size);
  764. END; (*WITH*)
  765. WHILE s # e DO
  766. WITH [s:0 T]^ DO
  767. INC(res,Size);
  768. IF Size >= req THEN
  769. DEC(res,Used);
  770. END; (*IF*)
  771. INC(s,Size);
  772. END; (*WITH*)
  773. END; (*WHILE*)
  774. RETURN res;
  775. END Poss;
  776. (* Returns amount of free space in area s..e. *)
  777. PROCEDURE Got(s,e:CARDINAL):CARDINAL;
  778. VAR
  779. res : CARDINAL;
  780. BEGIN
  781. res := 0;
  782. WHILE s # e DO
  783. WITH [s:0 T]^ DO
  784. INC(res,Size);
  785. DEC(res,Used);
  786. INC(s,Size);
  787. END; (*WITH*)
  788. END; (*WHILE*)
  789. RETURN res;
  790. END Got;
  791. PROCEDURE NextArea(r:CARDINAL):CARDINAL;
  792. BEGIN
  793. INC(r,[r:0 T]^.Size);
  794. LOOP
  795. WITH [r:0 T]^ DO
  796. IF Lock<>0 THEN
  797. RETURN r;
  798. END; (*IF*)
  799. INC(r,Size);
  800. END; (*WITH*)
  801. END; (*LOOP*)
  802. END NextArea;
  803. (* Find area containing r *)
  804. PROCEDURE Find(r:CARDINAL):CARDINAL;
  805. BEGIN
  806. WHILE [r:0 T]^.Lock=0 DO
  807. r := [r:0 T]^.Prev;
  808. END; (*WHILE*)
  809. RETURN r;
  810. END Find;
  811. (* Returns largest Poss(s,e,req) less than bound over all areas s..e *)
  812. PROCEDURE MaxPoss(req:CARDINAL; VAR sm,em:CARDINAL):CARDINAL;
  813. VAR
  814. s,e : CARDINAL;
  815. max,try : CARDINAL;
  816. BEGIN
  817. s := g.start;
  818. max := 0;
  819. REPEAT
  820. e := NextArea(s); (*<<<*)
  821. try := Poss(s,e,req); (*<<<*)
  822. IF (try > max) THEN
  823. sm := s;
  824. em := e;
  825. max := try;
  826. END; (*IF*)
  827. s := e;
  828. UNTIL s = g.start;
  829. RETURN max;
  830. END MaxPoss;
  831. CONST
  832. (*%T DEBUG*)
  833. Hide = 10H;
  834. (*%E*)
  835. (*%F DEBUG*)
  836. Hide = 200H;
  837. (*%E*)
  838. (* Returns largest Got(s,e) over all areas s..e *)
  839. PROCEDURE Avail():CARDINAL;
  840. VAR
  841. s,e : CARDINAL;
  842. max,try : CARDINAL;
  843. BEGIN
  844. g.allockind := FixedSeg;
  845. s := g.start;
  846. max := 0;
  847. REPEAT
  848. e := NextArea(s); (*<<<*)
  849. try := Got(s,e); (*<<<*)
  850. IF (try > max) THEN
  851. max := try;
  852. END; (*IF*)
  853. s := e;
  854. UNTIL s = g.start;
  855. IF max<Hide+2 THEN RETURN 0 END;
  856. RETURN max-Hide-2;
  857. END Avail;
  858. PROCEDURE MemPic;
  859. VAR
  860. tmp:CARDINAL;
  861. used:CARDINAL;
  862. lock:BOOLEAN;
  863. BEGIN
  864. string('MemPic=');
  865. tmp := g.start;
  866. used := 0;
  867. lock := FALSE;
  868. REPEAT
  869. WITH [tmp:0 T]^ DO
  870. IF Lock # 0 THEN
  871. lock := TRUE;
  872. END;
  873. INC(used, Used);
  874. IF Size > Used THEN
  875. IF lock THEN
  876. char('+');
  877. ELSE
  878. char('.');
  879. END;
  880. dec(used);
  881. char('_');
  882. dec(Size-Used);
  883. used := 0;
  884. lock := FALSE;
  885. END;
  886. tmp := tmp + Size;
  887. END;
  888. UNTIL tmp = g.start;
  889. eol;
  890. END MemPic;
  891. PROCEDURE MemStat;
  892. VAR
  893. kind : SegKind;
  894. ucount,tcount,
  895. usize,tsize : ARRAY SegKind OF CARDINAL;
  896. dummy : CARDINAL;
  897. tmp : CARDINAL;
  898. TDummy : T;
  899. BEGIN
  900. FOR kind := MIN(SegKind) TO MAX(SegKind) DO
  901. tcount[kind] := 0;
  902. ucount[kind] := 0;
  903. tsize[kind] := 0;
  904. usize[kind] := 0;
  905. END; (*FOR*)
  906. tmp := g.start;
  907. REPEAT
  908. WITH [tmp:0 T]^ DO
  909. TDummy := [tmp:0 T];
  910. INC(tsize[Kind],Used);
  911. INC(tcount[Kind]);
  912. IF Lock=0 THEN
  913. INC(usize[Kind],Used);
  914. INC(ucount[Kind]);
  915. END; (*IF*)
  916. INC(tmp,Size);
  917. END; (*WITH*)
  918. UNTIL tmp = g.start;
  919. dec(g.freemem);
  920. char('/');
  921. dec(MaxPoss(0FFFFH,dummy,dummy));
  922. FOR kind := MIN(SegKind) TO FixedSeg DO
  923. char(' ');
  924. IF (usize[kind] # 0) & (usize[kind] # tsize[kind]) THEN
  925. dec(tcount[kind]-ucount[kind]);
  926. char(':');
  927. dec(tsize[kind]-usize[kind]);
  928. char('/');
  929. dec(ucount[kind]);
  930. char(':');
  931. dec(usize[kind]);
  932. ELSE
  933. dec(tcount[kind]);
  934. char(':');
  935. dec(tsize[kind]);
  936. END; (*IF*)
  937. END; (*FOR*)
  938. (*%T MoveTrace *)
  939. string(' M=');
  940. dec(CARDINAL(g.move_total DIV 400H));
  941. char('k');
  942. (*%E*)
  943. eol;
  944. MemPic;
  945. END MemStat;
  946. PROCEDURE DumpMemory;
  947. VAR tmp:CARDINAL;
  948. BEGIN
  949. string('Memory dump'); eol;
  950. tmp := g.start;
  951. REPEAT
  952. WITH [tmp:0 T]^ DO
  953. DumpSeg('dump ', tmp+H);
  954. tmp := tmp + Size;
  955. END;
  956. UNTIL tmp = g.start;
  957. MemStat;
  958. (*%T TraceToFile*)
  959. FileClose(output_file);
  960. output_file := 1;
  961. (*%E*)
  962. END DumpMemory;
  963. PROCEDURE TotalAvail():CARDINAL;
  964. VAR
  965. res,p : CARDINAL;
  966. BEGIN
  967. (*%T CHECK*)
  968. IF g.freemem # CalcFreeMem() THEN
  969. abort(ErrInternal);
  970. END; (*IF*)
  971. (*%E*)
  972. res := g.freemem;
  973. IF res > Hide THEN
  974. DEC(res,Hide); (* keep 8k free to stop too much shuffling *)
  975. ELSE
  976. res := 0;
  977. END; (*IF*)
  978. RETURN res;
  979. END TotalAvail;
  980. PROCEDURE Free(seg:CARDINAL);
  981. VAR
  982. prev,next : CARDINAL;
  983. TDummy : T;
  984. BEGIN
  985. IF seg=0 THEN RETURN END;
  986. (*%T CHECK*)
  987. CheckAlloc(seg,ErrInvalidFree);
  988. (*%E*)
  989. DEC(seg);
  990. WITH [seg:0 T]^ DO
  991. TDummy := [seg:0 T];
  992. (*%T MemoryTrace*)
  993. IF (Kind IN MemTraceSet) & (~ g.internal) THEN
  994. TraceSeg('Free ',seg+H);
  995. (* MemStat;*)
  996. END; (*IF*)
  997. (*%E*)
  998. INC(g.freemem,Used);
  999. IF seg = g.start THEN
  1000. Used := 1;
  1001. Lock := 1;
  1002. Kind := SystemSeg;
  1003. DEC(g.freemem);
  1004. ELSE
  1005. next := seg + Size;
  1006. prev := Prev;
  1007. [next:0 T]^.Prev := prev;
  1008. [prev:0 T]^.Size := next-prev;
  1009. END; (*IF*)
  1010. END; (*WITH*)
  1011. (*%T CHECK*)
  1012. CheckMem;
  1013. (*%E*)
  1014. END Free;
  1015. PROCEDURE TempAlloc(count:CARDINAL):CARDINAL;
  1016. VAR
  1017. i,j:CARDINAL;
  1018. found:CARDINAL;
  1019. BEGIN
  1020. i := 0;
  1021. LOOP
  1022. IF i > HIGH(g.temp_map) THEN
  1023. abort(ErrTempFileLimit);
  1024. END;
  1025. IF g.temp_map[i] # BITSET{0..15} THEN
  1026. EXIT;
  1027. END;
  1028. INC(i);
  1029. END;
  1030. (* search for count consecutive bits *)
  1031. j := 0;
  1032. found := 0;
  1033. LOOP
  1034. IF j IN g.temp_map[i] THEN
  1035. found := 0;
  1036. ELSE
  1037. INC(found);
  1038. IF found = count THEN
  1039. EXIT;
  1040. END;
  1041. END;
  1042. INC(j);
  1043. IF j = 16 THEN
  1044. j := 0;
  1045. INC(i);
  1046. IF i > HIGH(g.temp_map) THEN
  1047. abort(ErrTempFileLimit);
  1048. END;
  1049. END;
  1050. END;
  1051. (* set the bits *)
  1052. LOOP
  1053. INCL(g.temp_map[i], j);
  1054. DEC(found);
  1055. IF found=0 THEN
  1056. EXIT;
  1057. END;
  1058. IF j=0 THEN
  1059. DEC(i);
  1060. j := 15;
  1061. ELSE
  1062. DEC(j);
  1063. END;
  1064. END;
  1065. i := 1 + j + i*16;
  1066. (*%T ExitTrace *) IF i+CARDINAL(count)-1 > g.temp_max THEN g.temp_max := i+CARDINAL(count)-1; END; (*%E*)
  1067. RETURN i;
  1068. END TempAlloc;
  1069. PROCEDURE TempFree(i:CARDINAL;count:CARDINAL);
  1070. VAR j:CARDINAL;
  1071. BEGIN
  1072. DEC(i);
  1073. j := i MOD 16;
  1074. i := i DIV 16;
  1075. REPEAT
  1076. (*%T CHECK*) IF ~ (j IN g.temp_map[i]) THEN abort(ErrInternal) END; (*%E*)
  1077. EXCL(g.temp_map[i], j);
  1078. INC(j);
  1079. IF j = 16 THEN
  1080. j := 0;
  1081. INC(i);
  1082. END;
  1083. DEC(count);
  1084. UNTIL count = 0;
  1085. END TempFree;
  1086. PROCEDURE reserve_panic;
  1087. BEGIN
  1088. IF g.panic_reserve = 0 THEN
  1089. g.panic_reserve := TempAlloc(PanicSize DIV TempPageSize);
  1090. END;
  1091. END reserve_panic;
  1092. PROCEDURE release_panic;
  1093. BEGIN
  1094. IF g.panic_reserve # 0 THEN
  1095. TempFree(g.panic_reserve, PanicSize DIV TempPageSize);
  1096. g.panic_reserve := 0;
  1097. END;
  1098. END release_panic;
  1099. PROCEDURE TempXfer(action:DoSegOp;VAR tpv:CARDINAL;seg,off:CARDINAL;count:CARDINAL);
  1100. VAR
  1101. (*%T EMS*)
  1102. ems_page,ems_off,
  1103. (*%E*)
  1104. p,amount,tp,
  1105. temp_size : CARDINAL;
  1106. BEGIN
  1107. tp := tpv;
  1108. IF action = Load THEN
  1109. tpv := seg;
  1110. ELSE
  1111. tpv := 0;
  1112. END; (*IF*)
  1113. IF count = 0 THEN
  1114. RETURN;
  1115. END; (*IF*)
  1116. temp_size := 1+((count-1) DIV TempPageSize);
  1117. IF action = Swap THEN
  1118. tp := TempAlloc(temp_size);
  1119. tpv := encode_temp(tp);
  1120. ELSIF (tp # 0) & ~ is_mem(tp) THEN
  1121. tp := decode_temp(tp);
  1122. TempFree(tp, temp_size);
  1123. END; (*IF*)
  1124. IF (action = Load) & (tp = 0) THEN
  1125. Fill([seg:off],count,0);
  1126. ELSIF action # Discard THEN
  1127. (*%T EMS*)
  1128. LOOP
  1129. IF tp <= g.temp_ems THEN
  1130. amount := TempPageSize;
  1131. IF amount > count THEN
  1132. amount := count;
  1133. END; (*IF*)
  1134. ems_page := (tp-1) DIV EmsPageSize;
  1135. ems_off := ((tp-1) MOD EmsPageSize) * TempPageSize;
  1136. IF seg+(off DIV 16) >= g.ems_frame+800H THEN
  1137. p := 0;
  1138. ELSE
  1139. p := 3;
  1140. INC(ems_off, 0C000H);
  1141. END; (*IF*)
  1142. EmsMap(4400H+p,ems_page,g.ems_temp_handle);
  1143. IF action=Swap THEN
  1144. Move([seg:off],[g.ems_frame:ems_off],amount);
  1145. ELSE
  1146. Move([g.ems_frame:ems_off],[seg:off],amount);
  1147. END; (*IF*)
  1148. EmsMap(4400H+p,p,g.ems_data_handle);
  1149. DEC(count,amount);
  1150. IF count = 0 THEN
  1151. EXIT;
  1152. END;
  1153. INC(off,amount);
  1154. INC(tp);
  1155. ELSE
  1156. (*%E*)
  1157. FileSeek(g.temp_file,LONGCARD(tp-g.temp_ems-1) * TempPageSize);
  1158. IF action=Swap THEN
  1159. IF FileWrite([seg:off],count,g.temp_file) # count THEN
  1160. abort(ErrTempDiskFull);
  1161. END; (*IF*)
  1162. ELSE
  1163. FileRead([seg:off],count,g.temp_file);
  1164. END; (*IF*)
  1165. (*%T EMS*)
  1166. EXIT;
  1167. END; (*IF*)
  1168. END; (*LOOP*)
  1169. (*%E*)
  1170. END; (*IF*)
  1171. END TempXfer;
  1172. PROCEDURE Para(size:CARDINAL):CARDINAL;
  1173. BEGIN
  1174. IF size = 0 THEN
  1175. RETURN 0;
  1176. ELSE
  1177. RETURN 1 + ((size-1) DIV 16);
  1178. END;
  1179. END Para;
  1180. PROCEDURE P;
  1181. BEGIN
  1182. string('trap');
  1183. eol;
  1184. END P;
  1185. PROCEDURE GetSeg(module:Module;segnum:SegNum):SegPtr;
  1186. BEGIN
  1187. RETURN SegPtr(HeapAdr(module^.seg_info^[segnum]));
  1188. END GetSeg;
  1189. PROCEDURE SetIndirect(seghdr:SegPtr);
  1190. VAR
  1191. gate : GatePtr;
  1192. BEGIN
  1193. gate := seghdr^.direct_list;
  1194. seghdr^.direct_list := GatePtr(0);
  1195. WHILE gate<>GatePtr(0) DO
  1196. gate^.state := IndirectGate;
  1197. gate^.w2 := gate^.w1;
  1198. gate^.w1 := CARDINAL(seghdr) - CARDINAL(gate) - 2;
  1199. gate := gate^.next_direct;
  1200. END;
  1201. END SetIndirect;
  1202. PROCEDURE Gate(off:CARDINAL;seghdr:SegPtr;iscall:BOOLEAN):CARDINAL;
  1203. VAR
  1204. disp:CARDINAL;
  1205. hash:CARDINAL;
  1206. gp,ff:GatePtr;
  1207. BEGIN
  1208. disp := CARDINAL(seghdr)-3;
  1209. IF iscall THEN
  1210. INC(disp);
  1211. END;
  1212. hash := 1 + (disp + off) MOD MaxGate;
  1213. gp := GatePtr(HeapAdr(g.gate_table[hash]));
  1214. ff := GatePtr(0);
  1215. LOOP
  1216. CASE gp^.state OF
  1217. | FreeGate :
  1218. IF ff # GatePtr(0) THEN
  1219. gp := ff;
  1220. ELSE
  1221. INC(g.gate_count);
  1222. IF g.gate_count = MaxGate THEN
  1223. abort(ErrGateLimit);
  1224. END;
  1225. END;
  1226. gp^.state := IndirectGate;
  1227. gp^.w2 := off;
  1228. gp^.w1 := disp - CARDINAL(gp);
  1229. EXIT;
  1230. | DeletedGate :
  1231. IF ff = GatePtr(0) THEN
  1232. ff := gp;
  1233. END;
  1234. | IndirectGate :
  1235. IF (gp^.w2 = off) & (gp^.w1 + CARDINAL(gp) = disp) THEN
  1236. EXIT;
  1237. END;
  1238. | DirectGate :
  1239. IF (gp^.w1 = off) & (gp^.w2 = seghdr^.seg_val) THEN
  1240. EXIT;
  1241. END;
  1242. END;
  1243. IF gp = GatePtr(HeapAdr(g.gate_table[MaxGate])) THEN
  1244. gp := GatePtr(HeapAdr(g.gate_table[1]));
  1245. ELSE
  1246. INC(CARDINAL(gp),SIZE(gp^));
  1247. END;
  1248. END;
  1249. RETURN CARDINAL(gp);
  1250. END Gate;
  1251. PROCEDURE RetGate(off, seg:CARDINAL):ADDRESS;
  1252. VAR
  1253. modnum:ModNum;
  1254. segnum:SegNum;
  1255. seghdr:SegPtr;
  1256. BEGIN
  1257. (*%T CHECK*) CheckAlloc(seg,0); (*%E*)
  1258. WITH [seg-1:0 T]^ DO
  1259. modnum := Id1;
  1260. segnum := Id2;
  1261. END;
  1262. seghdr := GetSeg(g.module_list[modnum], segnum);
  1263. RETURN [Seg(g) : Gate(off, seghdr, FALSE)];
  1264. END RetGate;
  1265. PROCEDURE Append(VAR s:ARRAY OF CHAR;e:ARRAY OF CHAR); (*String*)
  1266. VAR i,j:CARDINAL;
  1267. BEGIN
  1268. i := 0;
  1269. WHILE s[i]#0C DO
  1270. INC(i);
  1271. END;
  1272. j := 0;
  1273. LOOP
  1274. s[i] := e[j];
  1275. IF s[i] = 0C THEN
  1276. EXIT;
  1277. END;
  1278. INC(i);
  1279. INC(j);
  1280. END;
  1281. END Append;
  1282. PROCEDURE PathOpen(tail:ARRAY OF CHAR):CARDINAL;
  1283. CONST pathname='PATH=';
  1284. VAR
  1285. envptr : POINTER TO ARRAY [0..999] OF CHAR;
  1286. envseg,i,j:CARDINAL;
  1287. c:CHAR;
  1288. file:CARDINAL;
  1289. path:ARRAY [0..255] OF CHAR;
  1290. BEGIN
  1291. file := FileOpen(tail, BITSET(0)); (* Try local *)
  1292. IF file # MAX(CARDINAL) THEN RETURN file; END;
  1293. envseg := [g.psp: 2CH]^;
  1294. envptr := [envseg: 0];
  1295. i := 0;
  1296. j := 0;
  1297. LOOP (* search for 'PATH=' *)
  1298. c := pathname[j];
  1299. IF c=0C THEN
  1300. EXIT;
  1301. END;
  1302. IF c # envptr^[i] THEN
  1303. j := 0;
  1304. WHILE envptr^[i]#0C DO
  1305. INC(i);
  1306. END;
  1307. INC(i);
  1308. IF envptr^[i]=0C THEN
  1309. EXIT;
  1310. END;
  1311. ELSE
  1312. INC(j);
  1313. INC(i);
  1314. END;
  1315. END;
  1316. j := 0;
  1317. LOOP
  1318. c := envptr^[i];
  1319. path[j] := c;
  1320. IF (c = ';') OR (c=0C) THEN
  1321. IF c#'\' THEN
  1322. path[j] := '\';
  1323. INC(j);
  1324. END;
  1325. path[j] := 0C;
  1326. Append(path,tail);
  1327. file := FileOpen(path, BITSET(0));
  1328. IF file # MAX(CARDINAL) THEN
  1329. EXIT;
  1330. END;
  1331. IF c = 0C THEN
  1332. EXIT;
  1333. END;
  1334. j := 0;
  1335. ELSE
  1336. INC(j);
  1337. END;
  1338. INC(i);
  1339. END;
  1340. RETURN file;
  1341. END PathOpen;
  1342. PROCEDURE ModuleRead(module:Module;pos:LONGCARD;a:ADDRESS;count:CARDINAL):BOOLEAN;
  1343. VAR
  1344. modnum:ModNum;
  1345. victim:Module;
  1346. fullname:ARRAY [0..99] OF CHAR;
  1347. file:CARDINAL;
  1348. BEGIN
  1349. IF count=0 THEN
  1350. RETURN FALSE;
  1351. END;
  1352. file := module^.file;
  1353. modnum := 1;
  1354. WHILE ((file = MAX(CARDINAL)) & (g.file_count >= FileLimit)) OR
  1355. (g.file_count > FileLimit)
  1356. DO
  1357. (*%T CHECK*) IF modnum > g.module_count THEN abort(ErrInternal); END; (*%E*)
  1358. victim := g.module_list[modnum];
  1359. IF (victim^.file # MAX(CARDINAL)) & (victim^.file # file) THEN
  1360. FileClose(victim^.file);
  1361. IF FileTrace THEN
  1362. string('Close file ');
  1363. string(victim^.name^);
  1364. eol;
  1365. END;
  1366. victim^.file := MAX(CARDINAL);
  1367. DEC(g.file_count);
  1368. END;
  1369. INC(modnum);
  1370. END;
  1371. IF file = MAX(CARDINAL) THEN
  1372. fullname[0] := 0C;
  1373. Append(fullname, module^.name^);
  1374. IF module^.is_exe THEN
  1375. Append(fullname, '.exe');
  1376. ELSE
  1377. Append(fullname, '.dll');
  1378. END;
  1379. file := PathOpen(fullname);
  1380. module^.file := file;
  1381. IF FileTrace THEN
  1382. string('Open file ');
  1383. string(fullname);
  1384. IF file = MAX(CARDINAL) THEN
  1385. string(' - failed to open !!');
  1386. END;
  1387. eol;
  1388. END;
  1389. IF file = MAX(CARDINAL) THEN
  1390. RETURN TRUE;
  1391. END;
  1392. INC(g.file_count);
  1393. END;
  1394. FileSeek(file, pos);
  1395. FileRead(a, count, file);
  1396. RETURN FALSE;
  1397. END ModuleRead;
  1398. (*%T VidSupport*)
  1399. (*# save, call(reg_param=>(ax,bx,cx,dx,si),
  1400. reg_saved =>(ds,es,di,st1,st2), inline=>on) *)
  1401. PROCEDURE debug_int(data_ptr:ADDRESS;name_ptr:ADDRESS;action:CARDINAL) =
  1402. A2(0CDH,063H);
  1403. (*# restore *)
  1404. TYPE VidAction = (VID_XX, VID_LOAD_MODULE, VID_LOAD_SEG, VID_UNLOAD_SEG);
  1405. PROCEDURE TellVid(modnum:ModNum;segnum:SegNum;action:VidAction);
  1406. TYPE
  1407. StrPtr = POINTER TO ARRAY[0..79] OF CHAR;
  1408. SegListPtr = POINTER TO SegListRec;
  1409. DllLoadPtr = POINTER TO DllLoadRec;
  1410. SegListRec = RECORD
  1411. new_rlc : CARDINAL;
  1412. module : DllLoadPtr;
  1413. ext_deps : SHORTADDR;
  1414. seg_val : CARDINAL;
  1415. seg_size : CARDINAL;
  1416. reloc_num : CARDINAL;
  1417. type : CARDINAL;
  1418. use_count : SHORTCARD;
  1419. lru_count : SHORTCARD;
  1420. status : SHORTCARD;
  1421. seg_no : SHORTCARD;
  1422. (*%T EMS*)
  1423. ems_page : SHORTCARD;
  1424. ems_size : SHORTCARD;
  1425. (*%E*)
  1426. ref_count : CARDINAL;
  1427. swap_pos : CARDINAL;
  1428. END;
  1429. DllLoadRec = RECORD
  1430. total_entries : CARDINAL;
  1431. entries : ADDRESS;
  1432. segs : SegListPtr;
  1433. total_segments : CARDINAL;
  1434. status : SHORTCARD;
  1435. entry_point : PROC;
  1436. module_no : SHORTCARD;
  1437. END;
  1438. VAR
  1439. m:DllLoadRec;
  1440. s:SegListRec;
  1441. dp:ADDRESS;
  1442. name:ARRAY [0..255] OF CHAR;
  1443. module:Module;
  1444. BEGIN
  1445. IF g.vid_present THEN
  1446. module := g.module_list[modnum];
  1447. m.total_segments := module^.seg_count;
  1448. IF action = VID_LOAD_MODULE THEN
  1449. dp := ADR(m);
  1450. ELSE
  1451. dp := ADR(s);
  1452. s.module := ADR(m);
  1453. s.seg_no := SHORTCARD(segnum);
  1454. s.seg_val := module^.seg_info^[segnum].seg_val;
  1455. s.seg_size := module^.seg_info^[segnum].membyte;
  1456. END;
  1457. name[0] := 0C;
  1458. Append(name, module^.name^);
  1459. IF module^.is_exe THEN
  1460. Append(name, '.EXE');
  1461. ELSE
  1462. Append(name, '.DLL');
  1463. (*Int66;*)
  1464. END;
  1465. debug_int(dp, ADR(name), CARDINAL(action));
  1466. END;
  1467. END TellVid;
  1468. PROCEDURE TellVidMove;
  1469. BEGIN
  1470. IF g.vid_delayed THEN
  1471. g.vid_delayed := FALSE;
  1472. TellVid(g.vid_id1,g.vid_id2,VID_LOAD_SEG);
  1473. END;
  1474. END TellVidMove;
  1475. PROCEDURE FindVid;
  1476. VAR
  1477. iv:POINTER TO ADDRESS;
  1478. cp:POINTER TO ARRAY [0..0] OF CHAR;
  1479. BEGIN
  1480. iv := [0:63H*4];
  1481. cp := iv^;
  1482. IF (cp^[-3]='V') & (cp^[-2]='I') & (cp^[-1]='D') THEN
  1483. g.vid_present := TRUE;
  1484. END;
  1485. END FindVid;
  1486. (*%E*)
  1487. PROCEDURE MakeSys(seg:CARDINAL); FORWARD;
  1488. PROCEDURE ReserveDisk(amount:LONGCARD):BOOLEAN;
  1489. VAR dummy:CHAR;
  1490. BEGIN
  1491. INC(g.temp_reserve, amount);
  1492. IF (g.temp_reserve > LONGINT(FileSize(g.temp_file))) THEN
  1493. FileSeek(g.temp_file, g.temp_reserve + 1001H);
  1494. dummy := 'x';
  1495. IF FileWrite(ADR(dummy), 1, g.temp_file) # 1 THEN
  1496. DEC(g.temp_reserve, amount);
  1497. RETURN FALSE;
  1498. END;
  1499. END;
  1500. RETURN TRUE;
  1501. END ReserveDisk;
  1502. PROCEDURE ReleaseDisk(amount:LONGCARD);
  1503. BEGIN
  1504. DEC(g.temp_reserve, amount);
  1505. END ReleaseDisk;
  1506. PROCEDURE TempHandle():CARDINAL;
  1507. BEGIN
  1508. RETURN g.temp_file;
  1509. END TempHandle;
  1510. (*# save,data(const_in_code=>on) *)
  1511. CONST TempFileName = '\tstemp00.$$$';
  1512. CONST FullTempFileName =
  1513. 'A:\ ';
  1514. (*%T EMS*)
  1515. CONST EmsName = 'EMMXXXX0';
  1516. (*%E*)
  1517. (*# restore *)
  1518. PROCEDURE SetEms(on:BOOLEAN):BOOLEAN;
  1519. (*%T EMS*)
  1520. VAR
  1521. ems:CARDINAL;
  1522. i,p:CARDINAL;
  1523. ems_page,ems_off:CARDINAL;
  1524. avail:CARDINAL;
  1525. LABEL restore_data, return;
  1526. (*%E*)
  1527. BEGIN
  1528. (*%T EMS*)
  1529. release_panic;
  1530. IF (g.ems_temp_handle # 0) = on THEN
  1531. GOTO return;
  1532. END;
  1533. IF on THEN
  1534. IF g.ems_data_handle = 0 THEN
  1535. IF ~ g.ems_present THEN
  1536. GOTO return;
  1537. END;
  1538. avail := EmsGet(4200H); (* get number of free pages *)
  1539. IF avail < 4 THEN
  1540. GOTO return;
  1541. END;
  1542. g.ems_count := avail;
  1543. g.ems_data_handle := EmsAlloc(4300H, 4); (* allocate free pages *)
  1544. (* put 64K block in free memory chain*)
  1545. FOR p := 0 TO 3 DO
  1546. EmsMap(4400H+p, p, g.ems_data_handle);
  1547. END;
  1548. MakeSys(g.ems_frame + 1000H - 1);
  1549. MakeSys(g.ems_frame);
  1550. WITH [g.ems_frame:0 T]^ DO
  1551. Used := 0;
  1552. INC(g.freemem, Size);
  1553. END;
  1554. END;
  1555. avail := EmsGet(4200H); (* get number of free pages *)
  1556. IF avail = 0 THEN
  1557. GOTO return;
  1558. END;
  1559. g.ems_temp_handle := EmsAlloc(4300H, avail); (* allocate free pages *)
  1560. g.temp_ems := avail * EmsPageSize;
  1561. ReleaseDisk(LONGINT(g.temp_ems)*TempPageSize);
  1562. END;
  1563. (* transfer pages from temp file to/from ems *)
  1564. FOR i := 0 TO g.temp_ems-1 DO
  1565. IF (i MOD 16) IN g.temp_map[i DIV 16] THEN
  1566. ems_page := i DIV EmsPageSize;
  1567. ems_off := (i MOD EmsPageSize) * TempPageSize;
  1568. EmsMap(4400H, ems_page, g.ems_temp_handle);
  1569. FileSeek(g.temp_file, LONGCARD(i)*TempPageSize);
  1570. IF on THEN
  1571. FileRead([g.ems_frame:ems_off], TempPageSize, g.temp_file);
  1572. ELSE
  1573. IF FileWrite([g.ems_frame:ems_off], TempPageSize, g.temp_file) # TempPageSize THEN
  1574. GOTO restore_data;
  1575. END;
  1576. END;
  1577. END;
  1578. END;
  1579. IF ~ on THEN
  1580. IF ~ ReserveDisk(LONGINT(g.temp_ems)*TempPageSize) THEN
  1581. GOTO restore_data;
  1582. END;
  1583. EmsMap(4500H, 0, g.ems_temp_handle); (* free temp pages *)
  1584. g.ems_temp_handle := 0;
  1585. g.temp_ems := 0;
  1586. END;
  1587. restore_data:
  1588. EmsMap(4400H, 0, g.ems_data_handle); (* restore data page *)
  1589. return:
  1590. reserve_panic;
  1591. RETURN g.ems_temp_handle # 0;
  1592. (*%E*)
  1593. (*%F EMS*)
  1594. RETURN FALSE;
  1595. (*%E*)
  1596. END SetEms;
  1597. PROCEDURE DoSeg(modnum:ModNum;segnum:SegNum;op:DoSegOp):CARDINAL; FORWARD;
  1598. PROCEDURE DoDelay;
  1599. VAR
  1600. module : Module;
  1601. modnum : ModNum;
  1602. segnum : SegNum;
  1603. segment : CARDINAL;
  1604. gate : GatePtr;
  1605. seghdr : SegPtr;
  1606. seginfosize : CARDINAL;
  1607. BEGIN
  1608. IF g.delay # 0 THEN
  1609. modnum := g.delay;
  1610. g.delay := 0;
  1611. module := g.module_list[modnum];
  1612. (* swap out all segments *)
  1613. FOR segnum := 1 TO module^.seg_count DO
  1614. segment := DoSeg(modnum,segnum,Discard);
  1615. END; (*FOR*)
  1616. (* delete gates *)
  1617. seginfosize := module^.seg_count * SIZE(SegRec);
  1618. gate := GatePtr(HeapAdr(g.gate_table));
  1619. LOOP
  1620. IF gate^.state = IndirectGate THEN
  1621. seghdr := SegPtr(gate^.w1 + CARDINAL(gate) + 3);
  1622. IF CARDINAL(seghdr) - CARDINAL(module^.seg_info) < seginfosize THEN
  1623. gate^.state := DeletedGate;
  1624. END; (*IF*)
  1625. END; (*IF*)
  1626. IF gate = GatePtr(HeapAdr(g.gate_table[MaxGate])) THEN
  1627. EXIT;
  1628. END; (*IF*)
  1629. INC(CARDINAL(gate),SIZE(GateRec));
  1630. END; (*LOOP*)
  1631. (* close file *)
  1632. IF (module^.file # MAX(CARDINAL)) THEN
  1633. FileClose(module^.file);
  1634. IF FileTrace THEN
  1635. string('Close file ');
  1636. string(module^.name^);
  1637. eol;
  1638. END; (*IF*)
  1639. module^.file := MAX(CARDINAL);
  1640. DEC(g.file_count);
  1641. END; (*IF*)
  1642. (* free heap if last module *)
  1643. IF modnum = g.module_count THEN
  1644. DEC(g.module_count);
  1645. Fill(ADR(module^),g.near_alloc - CARDINAL(module),0);
  1646. g.near_alloc := CARDINAL(module);
  1647. END; (*IF*)
  1648. END; (*IF*)
  1649. END DoDelay;
  1650. PROCEDURE UnLoadModule(modnum:CARDINAL);
  1651. BEGIN
  1652. IF g.delay # modnum THEN
  1653. DoDelay;
  1654. END;
  1655. g.delay := modnum;
  1656. END UnLoadModule;
  1657. PROCEDURE GetOrdProcAddr (modnum:CARDINAL;entry:CARDINAL):ADDRESS;
  1658. VAR
  1659. offset:CARDINAL;
  1660. module:Module;
  1661. BEGIN
  1662. module := g.module_list[modnum];
  1663. offset := Gate(module^.entry_table^[entry].ofs,
  1664. GetSeg(module, SegNum(module^.entry_table^[entry].seg)), TRUE);
  1665. RETURN [Seg(g) : offset];
  1666. END GetOrdProcAddr;
  1667. PROCEDURE New(size:CARDINAL):HeapADDR;
  1668. (* Allocate bytes from Near Heap *)
  1669. VAR res:HeapADDR;
  1670. BEGIN
  1671. res := SHORTADDR(g.near_alloc);
  1672. INC(g.near_alloc,size);
  1673. IF g.near_alloc > Ofs(g.heap[HeapSize]) THEN
  1674. abort(ErrNearHeap);
  1675. END; (*IF*)
  1676. RETURN res;
  1677. END New;
  1678. PROCEDURE Length(s: ARRAY OF CHAR):CARDINAL; (*String*)
  1679. VAR i:CARDINAL;
  1680. BEGIN
  1681. i := 0;
  1682. WHILE s[i]#0C DO
  1683. INC(i);
  1684. END;
  1685. RETURN i;
  1686. END Length;
  1687. PROCEDURE Compare(s1,s2:ARRAY OF CHAR):BOOLEAN; (*String*)
  1688. VAR
  1689. i : CARDINAL;
  1690. BEGIN
  1691. i := 0;
  1692. LOOP
  1693. IF s1[i] # s2[i] THEN
  1694. RETURN FALSE;
  1695. END;
  1696. IF s1[i] = 0C THEN
  1697. RETURN TRUE;
  1698. END;
  1699. INC(i);
  1700. END;
  1701. END Compare;
  1702. PROCEDURE GetNextFree(seg : CARDINAL;VAR fsize : CARDINAL) : CARDINAL;
  1703. (* Returns next area > seg that is not being used for anything *)
  1704. (* Used for spawn *)
  1705. VAR p:CARDINAL; fseg : CARDINAL;
  1706. BEGIN
  1707. p := g.start;
  1708. LOOP
  1709. WITH [p:0 T]^ DO
  1710. IF p+Used>seg THEN
  1711. fseg := p+Used;
  1712. fsize := Size-Used;
  1713. IF (fsize>0) THEN
  1714. (*%T EMS*)
  1715. IF (g.ems_data_handle = 0) OR
  1716. (fseg<g.ems_frame) OR
  1717. (fseg>g.ems_frame+1000H)
  1718. THEN
  1719. EXIT;
  1720. END;
  1721. (*%E*)
  1722. (*%F EMS*)
  1723. EXIT;
  1724. (*%E*)
  1725. END;
  1726. END;
  1727. p := p+Size;
  1728. END;
  1729. IF p = g.start THEN
  1730. fseg := 0;
  1731. EXIT;
  1732. END;
  1733. END;
  1734. RETURN fseg;
  1735. END GetNextFree;
  1736. (*%F CHECK*) INLINE (*%E*) PROCEDURE Lock(seg:CARDINAL);
  1737. BEGIN
  1738. IF LockTrace THEN
  1739. string('Lock '); hex(seg); eol;
  1740. END;
  1741. (*%T CHECK*)
  1742. CheckAlloc(seg,0);
  1743. (*%E*)
  1744. INC([seg-H:0 T]^.Lock);
  1745. END Lock;
  1746. (*%F CHECK*) INLINE (*%E*) PROCEDURE UnLock(seg:CARDINAL);
  1747. BEGIN
  1748. IF LockTrace THEN
  1749. string('UnLock '); hex(seg); eol;
  1750. END;
  1751. (*%T CHECK*)
  1752. CheckAlloc(seg,0);
  1753. IF [seg-H:0 T]^.Lock = 0 THEN abort(ErrTooManyUnlocks); END;
  1754. (*%E*)
  1755. DEC([seg-H:0 T]^.Lock);
  1756. END UnLock;
  1757. PROCEDURE DoSwap(seg : CARDINAL);
  1758. (* Only called for StaticSeg and SwapSeg *)
  1759. VAR
  1760. dummy : CARDINAL;
  1761. seghdr : SegPtr;
  1762. BEGIN
  1763. WITH [seg:0 T]^ DO
  1764. IF Kind=StaticSeg THEN
  1765. (*%T CHECK*)
  1766. seghdr := SegPtr(HeapAdr(g.module_list[Id1]^.seg_info^[Id2]));
  1767. IF seghdr^.direct_list<>GatePtr(0) THEN
  1768. abort(ErrInternal);
  1769. END;
  1770. (*%E*)
  1771. dummy := DoSeg(Id1,Id2,Swap);
  1772. ELSIF Kind=SwapSeg THEN
  1773. TempXfer(Swap,[Id2:Id1 WP]^,seg+1,0,([seg:0 T]^.Used-1)*16);
  1774. Free(seg+1);
  1775. ELSE
  1776. (*%T CHECK*)
  1777. abort(ErrInternal);
  1778. (*%E*)
  1779. END;
  1780. END;
  1781. END DoSwap;
  1782. PROCEDURE IsActive(seghdr:SegPtr):BOOLEAN;
  1783. TYPE
  1784. fp = POINTER Seg(seghdr) TO RECORD
  1785. bp,ip,cs: CARDINAL;
  1786. END; (*fp*)
  1787. VAR
  1788. bp : fp;
  1789. cs : CARDINAL;
  1790. res : BOOLEAN;
  1791. BEGIN
  1792. res := FALSE;
  1793. cs := seghdr^.seg_val;
  1794. bp := fp(GetBP());
  1795. REPEAT
  1796. (*%T CHECK*)
  1797. IF bp^.bp # 0 THEN
  1798. CheckAlloc(bp^.cs,ErrCallChainInvalid);
  1799. END; (*IF*)
  1800. (*%E*)
  1801. IF bp^.cs = cs THEN
  1802. bp^.ip := Gate(bp^.ip,seghdr,FALSE);
  1803. bp^.cs := Seg(g);
  1804. res := TRUE;
  1805. END; (*IF*)
  1806. (*%T CHECK*)
  1807. IF ((bp^.bp=0)AND(bp^.ip # 1234H)) OR
  1808. ((bp^.bp<>0)AND(bp^.bp <= CARDINAL(bp))) THEN
  1809. abort(ErrCallChainInvalid);
  1810. END; (*IF*)
  1811. (*%E*)
  1812. bp := fp(bp^.bp);
  1813. UNTIL bp = fp(0);
  1814. RETURN res;
  1815. END IsActive;
  1816. PROCEDURE MyCaller():CARDINAL;
  1817. VAR
  1818. res : BOOLEAN;
  1819. TYPE
  1820. fp = POINTER Seg(res) TO RECORD
  1821. bp,ip,cs: CARDINAL;
  1822. END; (*fp*)
  1823. VAR
  1824. bp : fp;
  1825. BEGIN
  1826. res := FALSE;
  1827. bp := fp(GetBP());
  1828. REPEAT
  1829. (*%T CHECK*)
  1830. IF bp^.bp # 0 THEN
  1831. CheckAlloc(bp^.cs,ErrCallChainInvalid);
  1832. END; (*IF*)
  1833. IF ((bp^.bp=0)AND(bp^.ip # 1234H)) OR
  1834. ((bp^.bp<>0)AND(bp^.bp <= CARDINAL(bp))) THEN
  1835. abort(ErrCallChainInvalid);
  1836. END; (*IF*)
  1837. (*%E*)
  1838. IF bp^.cs<>Seg(MyCaller) THEN
  1839. RETURN bp^.cs;
  1840. END;
  1841. bp := fp(bp^.bp);
  1842. UNTIL bp = fp(0);
  1843. RETURN 0;
  1844. END MyCaller;
  1845. PROCEDURE RelocStatic(seghdr:SegPtr;new:CARDINAL);
  1846. TYPE
  1847. fp = POINTER Seg(seghdr) TO RECORD
  1848. bp,ip,cs: CARDINAL;
  1849. END; (*fp*)
  1850. VAR
  1851. bp : fp;
  1852. cs : CARDINAL;
  1853. gate : GatePtr;
  1854. BEGIN
  1855. cs := seghdr^.seg_val;
  1856. seghdr^.seg_val := new;
  1857. gate := seghdr^.direct_list;
  1858. WHILE gate # GatePtr(0) DO
  1859. gate^.w2 := new;
  1860. gate := gate^.next_direct;
  1861. END; (*WHILE*)
  1862. bp := fp(GetBP());
  1863. REPEAT
  1864. IF bp^.cs = cs THEN
  1865. bp^.cs := new;
  1866. (*%T CHECK*)
  1867. ELSIF bp^.bp # 0 THEN
  1868. CheckAlloc(bp^.cs,ErrCallChainInvalid);
  1869. (*%E*)
  1870. END; (*IF*)
  1871. (*%T CHECK*)
  1872. IF ((bp^.bp=0)AND(bp^.ip # 1234H)) OR
  1873. ((bp^.bp<>0)AND(bp^.bp <= CARDINAL(bp))) THEN
  1874. abort(ErrCallChainInvalid);
  1875. END; (*IF*)
  1876. (*%E*)
  1877. bp := fp(bp^.bp);
  1878. UNTIL bp = fp(0);
  1879. END RelocStatic;
  1880. PROCEDURE DoFlushAll;
  1881. VAR
  1882. tmp : CARDINAL;
  1883. change : BOOLEAN;
  1884. BEGIN
  1885. REPEAT
  1886. change := FALSE;
  1887. tmp := g.start;
  1888. REPEAT
  1889. WITH [tmp:0 T]^ DO
  1890. IF (Lock = 0) & (Kind # MoveSeg) THEN
  1891. IF Kind=StaticSeg THEN
  1892. SetIndirect(SegPtr(HeapAdr(g.module_list[Id1]^.seg_info^[Id2])));
  1893. END;
  1894. DoSwap(tmp);
  1895. change := TRUE;
  1896. END; (*IF*)
  1897. INC(tmp,Size);
  1898. END; (*WITH*)
  1899. UNTIL tmp = g.start;
  1900. UNTIL ~change;
  1901. END DoFlushAll;
  1902. PROCEDURE TinyFlush; FORWARD;
  1903. (* Should do long jump to reset point, Also OutOfDisk needs doing *)
  1904. PROCEDURE OutOfMem(request:CARDINAL);
  1905. BEGIN
  1906. IF OutOfMemTrace THEN
  1907. string('Out of memory.');
  1908. eol;
  1909. DumpMemory;
  1910. MemStat;
  1911. END; (*IF*)
  1912. IF ~g.OutOfMem(request) THEN
  1913. abort(ErrOutOfMem);
  1914. END; (*IF*)
  1915. END OutOfMem;
  1916. PROCEDURE FlushLRU(req:CARDINAL);
  1917. VAR
  1918. tmp : CARDINAL;
  1919. lru : CARDINAL;
  1920. age,maxage : CARDINAL;
  1921. res : BOOLEAN;
  1922. i : CARDINAL;
  1923. wants : CARDINAL;
  1924. ssize : CARDINAL;
  1925. seghdr : SegPtr;
  1926. BEGIN
  1927. (*%T GraphUseTrace*)
  1928. GraphTrace(0,req,GTlru);
  1929. (*%E*)
  1930. wants := req+400H;
  1931. (*%T CHECK*)
  1932. CheckMem;
  1933. (*%E*)
  1934. TinyFlush;
  1935. tmp := g.start;
  1936. (* Mark all segments as indirect to help LRU *)
  1937. REPEAT
  1938. WITH [tmp:0 T]^ DO
  1939. IF (Kind =StaticSeg) & (Lock=0) THEN
  1940. seghdr := SegPtr(HeapAdr(g.module_list[Id1]^.seg_info^[Id2]));
  1941. IF seghdr^.direct_list<>GatePtr(0) THEN
  1942. SetIndirect(seghdr);
  1943. END;
  1944. END; (*IF*)
  1945. INC(tmp,Size);
  1946. END; (*WITH*)
  1947. UNTIL tmp = g.start;
  1948. [MyCaller()-H:0 T]^.Tick := IncTick();
  1949. LOOP
  1950. ssize := 0;
  1951. maxage := 0;
  1952. tmp := g.start;
  1953. lru := 0;
  1954. REPEAT
  1955. WITH [tmp:0 T]^ DO
  1956. IF (Kind # MoveSeg) & (Lock=0) THEN
  1957. age := GetTick() - Tick;
  1958. IF (age >= maxage) THEN
  1959. lru := tmp;
  1960. maxage := age;
  1961. END; (*IF*)
  1962. END; (*IF*)
  1963. INC(tmp,Size);
  1964. END; (*WITH*)
  1965. UNTIL tmp = g.start;
  1966. IF lru # 0 THEN
  1967. WITH [lru:0 T]^ DO
  1968. ssize := Used;
  1969. DoSwap(lru);
  1970. (*%T UsageTrace*)
  1971. string('Age=');
  1972. dec(maxage);
  1973. string('Req=');
  1974. dec(req);
  1975. char(' ');
  1976. MemStat;
  1977. (*%E*)
  1978. IF ssize>=wants THEN
  1979. EXIT;
  1980. END;
  1981. DEC(wants,ssize);
  1982. END; (*WITH*)
  1983. ELSE
  1984. IF ssize=0 THEN
  1985. OutOfMem(req);
  1986. END;
  1987. EXIT;
  1988. END; (*IF*)
  1989. END; (*LOOP*)
  1990. END FlushLRU;
  1991. PROCEDURE Relocate(old,new:CARDINAL);
  1992. BEGIN
  1993. IF RelocateTrace THEN
  1994. string('Relocate ');
  1995. hex(old+H);
  1996. string(' to ');
  1997. hex(new+H);
  1998. eol;
  1999. END; (*IF*)
  2000. INC(new, H);
  2001. WITH [old:0 T]^ DO
  2002. CASE Kind OF
  2003. StaticSeg : (*%T VidSupport*)
  2004. TellVid(Id1,Id2,VID_UNLOAD_SEG);
  2005. (*%E*)
  2006. RelocStatic(SegPtr(HeapAdr(g.module_list[Id1]^.seg_info^[Id2])),new);
  2007. (*%T VidSupport*)
  2008. g.vid_delayed := TRUE;
  2009. g.vid_id1 := Id1;
  2010. g.vid_id2 := Id2;
  2011. (*%E*) |
  2012. MoveSeg,SwapSeg : [Id2:Id1 WP]^ := new; |
  2013. ELSE
  2014. abort(ErrInternal);
  2015. END; (*CASE*)
  2016. END; (*WITH*)
  2017. END Relocate;
  2018. (* Used to move relocatable block, No overlap *)
  2019. PROCEDURE SimpleMove(old,new:CARDINAL);
  2020. CONST
  2021. K = VSIZE(ParaRec.Prev);
  2022. VAR
  2023. size : CARDINAL;
  2024. BEGIN
  2025. Relocate(old,new);
  2026. size := [old:0 T]^.Used;
  2027. Move([old:K],[new:K],size*16-K);
  2028. (*%T VidSupport*)
  2029. TellVidMove;
  2030. (*%E*)
  2031. (*%T MemoryTrace*)
  2032. g.internal := TRUE;
  2033. (*%E*)
  2034. Free(old+H);
  2035. (*%T MemoryTrace*)
  2036. g.internal := FALSE;
  2037. (*%E*)
  2038. (*%T CHECK*)
  2039. CheckAlloc(new+H,0);
  2040. (*%E*)
  2041. END SimpleMove;
  2042. (* move segments in area (s..e) down *)
  2043. PROCEDURE Shuffle(s,e:CARDINAL);
  2044. VAR
  2045. old,new,diff,size : CARDINAL;
  2046. BEGIN
  2047. LOOP
  2048. WITH [s:0 T]^ DO
  2049. old := s + Size;
  2050. IF old = e THEN
  2051. EXIT;
  2052. END; (*IF*)
  2053. diff := Size - Used;
  2054. new := old - diff;
  2055. IF diff > 0 THEN
  2056. size := [old:0 T]^.Used;
  2057. Relocate(old,new);
  2058. (*%T MoveTrace *)
  2059. INC(g.move_total,LONGCARD(size*16));
  2060. (*%E*)
  2061. Move([old:0],[new:0],size*16);
  2062. (*%T VidSupport*)
  2063. TellVidMove;
  2064. (*%E*)
  2065. DEC(Size,diff);
  2066. WITH [new:0 T]^ DO
  2067. INC(Size,diff);
  2068. [new+Size:0 T]^.Prev := new;
  2069. END; (*WITH*)
  2070. (*%T CHECK*)
  2071. CheckAlloc(new+H,0);
  2072. (*%E*)
  2073. END; (*IF*)
  2074. s := new;
  2075. END; (*WITH*)
  2076. END; (*LOOP*)
  2077. END Shuffle;
  2078. PROCEDURE Get(req:CARDINAL):CARDINAL; FORWARD;
  2079. (* Choose a block of size < max to evacuate. We choose largest up to *)
  2080. (* aim, then smallest. Thus we search the range (res,max) until *)
  2081. (* size(res) >= aim then we search the range (aim,size(res)). *)
  2082. PROCEDURE Choose(s,e,aim,max:CARDINAL):CARDINAL;
  2083. VAR
  2084. res,min,size,poss : CARDINAL;
  2085. BEGIN
  2086. INC(s,[s:0 T]^.Size);
  2087. min := 0;
  2088. res := 0;
  2089. poss := 0;
  2090. WHILE s # e DO
  2091. WITH [s:0 T]^ DO
  2092. size := Used;
  2093. IF size < max THEN
  2094. INC(poss,size);
  2095. IF size > min THEN
  2096. res := s;
  2097. IF size >= aim THEN
  2098. min := aim;
  2099. max := size;
  2100. ELSE
  2101. min := size;
  2102. END; (*IF*)
  2103. END; (*IF*)
  2104. END; (*IF*)
  2105. INC(s,Size);
  2106. END; (*WITH*)
  2107. END; (*WHILE*)
  2108. IF poss < aim THEN
  2109. res := 0;
  2110. END; (*IF*)
  2111. RETURN res;
  2112. END Choose;
  2113. (* In decreasing size, evacuate segs in area s satisfying Used < lim, *)
  2114. (* until free space for s..e >= need *)
  2115. PROCEDURE Evac(s,e:CARDINAL;lim:CARDINAL;need:CARDINAL):BOOLEAN;
  2116. VAR
  2117. got,old,new,poss : CARDINAL;
  2118. res : BOOLEAN;
  2119. BEGIN
  2120. got := Got(s,e);
  2121. [s:0 T]^.Active := TRUE;
  2122. LOOP
  2123. IF got >= need THEN
  2124. res := TRUE;
  2125. EXIT;
  2126. ELSE
  2127. old := Choose(s,e,need-got,lim);
  2128. IF old = 0 THEN
  2129. res := FALSE;
  2130. EXIT;
  2131. END; (*IF*)
  2132. WITH [old:0 T]^ DO
  2133. lim := Used;
  2134. new := Get(lim);
  2135. IF new # 0 THEN
  2136. new := SplitLow(lim,new);
  2137. SimpleMove(old,new);
  2138. INC(got,lim);
  2139. INC(lim); (* others of same size are acceptable *)
  2140. END; (*IF*)
  2141. END; (*WITH*)
  2142. END; (*IF*)
  2143. END; (*LOOP*)
  2144. [s:0 T]^.Active := FALSE;
  2145. RETURN res;
  2146. END Evac;
  2147. PROCEDURE Get(req:CARDINAL):CARDINAL;
  2148. VAR
  2149. max,s,e,res : CARDINAL;
  2150. BEGIN
  2151. max := MaxPoss(req,s,e);
  2152. IF (max >= req) & Evac(s,e,req,req) THEN
  2153. Shuffle(s, e);
  2154. res := Try(req,s,e);
  2155. (*%T CHECK*)
  2156. IF res = 0 THEN
  2157. abort(ErrInternal);
  2158. END; (*IF*)
  2159. (*%E*)
  2160. ELSE
  2161. res := 0;
  2162. END; (*IF*)
  2163. RETURN res;
  2164. END Get;
  2165. (* Moves relocatable segments in range (s..e) up, thus increasing *)
  2166. (* s^.Size. *)
  2167. PROCEDURE ShuffleUp(s,e:CARDINAL);
  2168. VAR
  2169. w,p,new,diff : CARDINAL;
  2170. BEGIN
  2171. w := [e:0 T]^.Prev;
  2172. LOOP
  2173. IF w = s THEN
  2174. EXIT;
  2175. END; (*IF*)
  2176. WITH [w:0 T]^ DO
  2177. p := Prev;
  2178. diff := Size - Used;
  2179. new := w + diff;
  2180. IF (diff > 0) THEN
  2181. Relocate(w,new);
  2182. DEC(Size,diff);
  2183. [e:0 T]^.Prev := new;
  2184. INC([p:0 T]^.Size,diff);
  2185. (*%T MoveTrace *)
  2186. INC(g.move_total,LONGCARD(Used*16));
  2187. (*%E*)
  2188. MoveUp([w:0],[new:0],Used*16);
  2189. (*%T VidSupport*)
  2190. TellVidMove;
  2191. (*%E*)
  2192. END; (*IF*)
  2193. END; (*WITH*)
  2194. e := new;
  2195. w := p;
  2196. END; (*LOOP*)
  2197. (*%T CHECK*)
  2198. CheckMem;
  2199. (*%E*)
  2200. END ShuffleUp;
  2201. PROCEDURE IAlloc(size:CARDINAL;id1,id2:CARDINAL;kind:SegKind;high:BOOLEAN):CARDINAL;
  2202. VAR
  2203. s,e,sm,em,
  2204. use,res : CARDINAL;
  2205. BEGIN
  2206. (*%T CHECK*)
  2207. CheckMem;
  2208. (*%E*)
  2209. g.allockind := kind;
  2210. INC(size,H);
  2211. IF high THEN
  2212. LOOP (* decide area: last such that Poss(a) >= size *)
  2213. sm := 0;
  2214. s := g.start;
  2215. REPEAT
  2216. e := NextArea(s);
  2217. IF Poss(s,e,MAX(CARDINAL)) >= size THEN
  2218. sm := s;
  2219. em := e;
  2220. END; (*IF*)
  2221. s := e;
  2222. UNTIL s = g.start;
  2223. IF sm # 0 THEN
  2224. IF (TotalAvail() >= size) & Evac(sm,em,MAX(CARDINAL),size) THEN
  2225. Shuffle(sm,em);
  2226. use := Try(size,sm,em);
  2227. (*%T CHECK*)
  2228. IF use = 0 THEN
  2229. abort(ErrInternal);
  2230. END; (*IF*)
  2231. (*%E*)
  2232. EXIT;
  2233. END; (*IF*)
  2234. END; (*IF*)
  2235. FlushLRU(size);
  2236. END; (*LOOP*)
  2237. WITH [use:0 T]^ DO
  2238. DEC(Size,size);
  2239. res := use + Size;
  2240. END; (*WITH*)
  2241. WITH [res:0 T]^ DO
  2242. Size := size;
  2243. Used := size;
  2244. IF res # use THEN
  2245. Prev := use;
  2246. END; (*IF*)
  2247. [res+size:0 T]^.Prev := res;
  2248. END; (*WITH*)
  2249. DEC(g.freemem,size);
  2250. ELSE
  2251. LOOP
  2252. (*%T DEBUG*)
  2253. use := 0;
  2254. (*%E*)
  2255. (*%F DEBUG*)
  2256. use := Try(size,g.start,g.start);
  2257. (*%E*)
  2258. IF (use = 0) & (TotalAvail() >= size) THEN
  2259. use := Get(size);
  2260. END; (*IF*)
  2261. IF use # 0 THEN
  2262. EXIT;
  2263. END; (*IF*)
  2264. FlushLRU(size);
  2265. END; (*IF*)
  2266. res := SplitLow(size,use);
  2267. END; (*IF*)
  2268. WITH [res:0 T]^ DO
  2269. Id1 := id1;
  2270. Id2 := id2;
  2271. Kind := kind;
  2272. Active := FALSE;
  2273. Lock := 1;
  2274. Tick := IncTick();
  2275. END; (*WITH*)
  2276. INC(res,H);
  2277. DEC(size,H);
  2278. (*%T MemoryTrace*)
  2279. IF (kind IN MemTraceSet) THEN
  2280. TraceSeg('IAlloc',res);
  2281. END; (*IF*)
  2282. (*%E*)
  2283. (*%T Debuging*)
  2284. IF res = g.trap_alloc THEN
  2285. P;
  2286. END; (*IF*)
  2287. (*%E*)
  2288. (*%T CHECK*)
  2289. CheckAlloc(res,0);
  2290. CheckMem;
  2291. (*%E*)
  2292. RETURN res;
  2293. END IAlloc;
  2294. PROCEDURE AllocFixed(size:CARDINAL):CARDINAL;
  2295. BEGIN
  2296. RETURN IAlloc(size, 0, 0, FixedSeg, TRUE);
  2297. END AllocFixed;
  2298. PROCEDURE AllocMove(VAR seg:CARDINAL;size:CARDINAL);
  2299. VAR
  2300. a:ADDRESS;
  2301. res:CARDINAL;
  2302. BEGIN
  2303. a := ADR(seg);
  2304. res := IAlloc(size, Ofs(a^), Seg(a^), MoveSeg, FALSE);
  2305. UnLock(res);
  2306. seg := res;
  2307. END AllocMove;
  2308. PROCEDURE ReSize(VAR seg:CARDINAL;newsize:CARDINAL);
  2309. VAR
  2310. old,use,s,e:CARDINAL;
  2311. (*%T MemoryTrace*) easy:BOOLEAN; (*%E*)
  2312. BEGIN
  2313. (*%T MemoryTrace*) easy := TRUE; (*%E*)
  2314. g.allockind := MoveSeg;
  2315. INC(newsize,H);
  2316. LOOP
  2317. old := seg-H;
  2318. WITH [old:0 T]^ DO
  2319. IF Size >= newsize THEN
  2320. INC(g.freemem, Used);
  2321. DEC(g.freemem, newsize);
  2322. Used := newsize;
  2323. EXIT;
  2324. END;
  2325. (*%T MemoryTrace*) easy := FALSE; (*%E*)
  2326. use := Try(newsize, g.start, g.start);
  2327. IF use = 0 THEN
  2328. s := Find(old);
  2329. e := NextArea(s);
  2330. IF (newsize>1000H) &
  2331. (TotalAvail()>newsize-Used) &
  2332. Evac(s, e, Used, newsize-Used)
  2333. THEN
  2334. ShuffleUp(old, e);
  2335. Shuffle(s, old+Size);
  2336. (*%T CHECK*) IF [seg-H:0 T]^.Size < newsize THEN abort(ErrInternal); END; (*%E*)
  2337. ELSE
  2338. IF TotalAvail() >= newsize THEN
  2339. use := Get(newsize);
  2340. END;
  2341. IF use = 0 THEN
  2342. FlushLRU(newsize);
  2343. END;
  2344. END;
  2345. END;
  2346. IF use # 0 THEN
  2347. use := SplitLow(newsize, use);
  2348. SimpleMove(seg-H, use);
  2349. EXIT;
  2350. END;
  2351. END;
  2352. END;
  2353. (*%T MemoryTrace*)
  2354. IF (MoveSeg IN MemTraceSet) & (~easy) THEN
  2355. TraceSeg('ReSize',seg);
  2356. END;
  2357. (*%E*)
  2358. END ReSize;
  2359. PROCEDURE LoadMove(VAR seg:CARDINAL;size:CARDINAL);
  2360. VAR
  2361. tmp:CARDINAL;
  2362. BEGIN
  2363. tmp := seg;
  2364. IF ~ is_mem(tmp) THEN
  2365. AllocMove(seg, size);
  2366. TempXfer(Load, tmp, seg, 0, size*16);
  2367. ELSE
  2368. (*%T CHECK*) CheckAlloc(tmp,ErrInvalidVFix); (*%E*)
  2369. WITH [tmp-H:0 T]^ DO
  2370. (*%T CHECK*) IF (Kind # MoveSeg)
  2371. & (Kind # SwapSeg)
  2372. THEN abort(ErrInvalidVFix);
  2373. END;
  2374. (*%E*)
  2375. Kind := MoveSeg;
  2376. END;
  2377. END;
  2378. END LoadMove;
  2379. PROCEDURE LoadCode(seghdr:SegPtr):CARDINAL;
  2380. VAR
  2381. segment:CARDINAL;
  2382. modnum:ModNum;
  2383. module:Module;
  2384. segnum:SegNum;
  2385. BEGIN
  2386. segment := seghdr^.seg_val;
  2387. IF ~ is_mem(segment) THEN
  2388. modnum := 0;
  2389. LOOP
  2390. INC(modnum);
  2391. (*%T CHECK*) IF modnum > g.module_count THEN abort(ErrInternal); END; (*%E*)
  2392. module := g.module_list[modnum];
  2393. segnum := 1+(CARDINAL(seghdr)-CARDINAL(module^.seg_info)) DIV SIZE(SegRec);
  2394. IF segnum-1 < module^.seg_count THEN
  2395. EXIT;
  2396. END;
  2397. END;
  2398. segment := DoSeg(modnum, segnum, Load);
  2399. UnLock(segment);
  2400. ELSE
  2401. [segment-H:0 T]^.Tick := IncTick();
  2402. END;
  2403. RETURN segment;
  2404. END LoadCode;
  2405. PROCEDURE CallTrap(sd:CARDINAL;gd:CARDINAL):CARDINAL;
  2406. VAR
  2407. seghdr:SegPtr;
  2408. gate:GatePtr;
  2409. segment:CARDINAL;
  2410. BEGIN
  2411. gate := GatePtr(gd);
  2412. seghdr := SegPtr(sd);
  2413. segment := LoadCode(seghdr);
  2414. gate^.next_direct := seghdr^.direct_list;
  2415. seghdr^.direct_list := gate;
  2416. gate^.state := DirectGate;
  2417. gate^.w1 := gate^.w2;
  2418. gate^.w2 := segment;
  2419. RETURN CARDINAL(gate);
  2420. END CallTrap;
  2421. PROCEDURE ReturnTrap(sd:CARDINAL):CARDINAL;
  2422. VAR
  2423. seghdr : SegPtr;
  2424. BEGIN
  2425. seghdr := SegPtr(sd);
  2426. RETURN LoadCode(seghdr);
  2427. END ReturnTrap;
  2428. PROCEDURE DoSeg(modnum:ModNum;segnum:SegNum;op:DoSegOp):CARDINAL;
  2429. CONST
  2430. (* values for Fixup.lockind *)
  2431. FixOfs = 5;
  2432. FixBase = 2;
  2433. FixPtr = 3;
  2434. VAR
  2435. segment : CARDINAL;
  2436. TYPE
  2437. LocPtr = POINTER segment TO RECORD
  2438. lo,hi : CARDINAL;
  2439. END; (*LocPtr*)
  2440. set = SET OF [0..7];
  2441. Fixup = RECORD
  2442. lockind : SHORTCARD;
  2443. flags : SHORTCARD;
  2444. off : CARDINAL;
  2445. CASE :SHORTCARD OF
  2446. 0 : target_mod : CARDINAL;
  2447. target_ent : CARDINAL; |
  2448. 1 : target_seg : SegNum;
  2449. target_off : CARDINAL; |
  2450. END; (*CASE*)
  2451. END; (*Fixup*)
  2452. VAR
  2453. loc,next : LocPtr;
  2454. fixbuf : POINTER TO ARRAY [1..999] OF Fixup;
  2455. fix : Fixup;
  2456. fi : CARDINAL;
  2457. segsize : CARDINAL;
  2458. target_modnum : ModNum;
  2459. target_module : Module;
  2460. target_segment : CARDINAL;
  2461. target_attr : SegSet;
  2462. chain : BOOLEAN;
  2463. pos : LONGCARD;
  2464. fillcount : CARDINAL;
  2465. tempsize : CARDINAL;
  2466. gate : GatePtr;
  2467. target_seghdr : SegPtr;
  2468. module : Module;
  2469. seghdr : SegPtr;
  2470. (*%T VidSupport*)
  2471. vid_op : VidAction;
  2472. (*%E*)
  2473. LABEL
  2474. ordinal;
  2475. BEGIN
  2476. module := g.module_list[modnum];
  2477. (*%T VidSupport*)
  2478. IF op # Load THEN
  2479. TellVid(modnum,segnum,VID_UNLOAD_SEG);
  2480. END; (*IF*)
  2481. (*%E*)
  2482. seghdr := SegPtr(HeapAdr(module^.seg_info^[segnum]));
  2483. (*%T CHECK*)
  2484. IF (modnum > g.module_count)OR
  2485. (segnum > module^.seg_count) THEN
  2486. abort(ErrInternal);
  2487. END; (*IF*)
  2488. (*%E*)
  2489. (*%T LoadTrace *)
  2490. (*%F MemoryTrace*)
  2491. hex(g.freemem);
  2492. (*%E*)
  2493. (*%T MemoryTrace*)
  2494. string(' ');
  2495. (*%E*)
  2496. string(' ');
  2497. CASE op OF
  2498. |Load: string('Load: ');
  2499. |Swap: string('Swap: ');
  2500. |Discard: string('Discard: ');
  2501. END;
  2502. string(g.module_list[modnum]^.name^);
  2503. char('.');
  2504. hex(segnum);
  2505. string(' mem=');hex(seghdr^.membyte);
  2506. string(' dsk=');hex(seghdr^.filebyte);
  2507. string(' flags= ');
  2508. IF IsData IN seghdr^.flags THEN string('Data ') END;
  2509. IF IsIter IN seghdr^.flags THEN string('Iter ') END;
  2510. IF IsMove IN seghdr^.flags THEN string('Move ') END;
  2511. IF IsPure IN seghdr^.flags THEN string('Pure ') END;
  2512. IF IsPreLoad IN seghdr^.flags THEN string('PreLoad ') END;
  2513. IF IsExRd IN seghdr^.flags THEN string('ExRd ') END;
  2514. IF HasReloc IN seghdr^.flags THEN string('HasReloc ') END;
  2515. IF IsDiscard IN seghdr^.flags THEN string('Discard ') END;
  2516. IF DataActive IN seghdr^.flags THEN string('DataActive ') END;
  2517. eol;
  2518. (*%E*)
  2519. IF seghdr^.membyte=1 THEN (* zero length segment *)
  2520. IF op = Load THEN
  2521. [Seg(DoSeg)-1:0 T]^.Lock := 7FFFH;
  2522. RETURN Seg(DoSeg);
  2523. END;
  2524. RETURN 0;
  2525. END;
  2526. pos := LONGCARD(seghdr^.sector) << LONGCARD(module^.log_sector_size);
  2527. segsize := Para(seghdr^.membyte);
  2528. IF op = Load THEN
  2529. seghdr^.fix_count := 0;
  2530. IF (HasReloc IN seghdr^.flags) THEN
  2531. IF ModuleRead(module,pos+LONGCARD(seghdr^.filebyte),
  2532. ADR(seghdr^.fix_count),2) THEN
  2533. (*%T CHECK*)
  2534. abort(ErrOpenFail);
  2535. (*%E*)
  2536. END; (*IF*)
  2537. END;
  2538. segment := IAlloc(segsize+Para(seghdr^.fix_count*SIZE(fix)),modnum,segnum,StaticSeg,
  2539. seghdr^.flags * SegSet{IsData,IsPreLoad} # SegSet{});
  2540. IF ModuleRead(module,pos,[segment:0],seghdr^.filebyte) THEN
  2541. (*%T CHECK*)
  2542. abort(ErrOpenFail);
  2543. (*%E*)
  2544. END; (*IF*)
  2545. fixbuf := [segment+segsize:0];
  2546. IF seghdr^.fix_count>0 THEN (* read fixups *)
  2547. IF ModuleRead(module,pos+LONGCARD(seghdr^.filebyte)+2,
  2548. fixbuf,seghdr^.fix_count*SIZE(fix)) THEN
  2549. (*%T CHECK*)
  2550. abort(ErrOpenFail);
  2551. (*%E*)
  2552. END; (*IF*)
  2553. END;
  2554. (*%T GraphUseTrace*)
  2555. IF seghdr^.flags*SegSet{IsData,IsPreLoad}=SegSet{} THEN
  2556. GraphTrace(segnum+modnum*256,segment,GTadd);
  2557. END;
  2558. (*%E*)
  2559. ELSE
  2560. segment := seghdr^.seg_val;
  2561. fixbuf := [segment+segsize:0];
  2562. (*%T GraphUseTrace*)
  2563. IF seghdr^.flags*SegSet{IsData,IsPreLoad}=SegSet{} THEN
  2564. GraphTrace(segnum+modnum*256,segment,GTdel);
  2565. END;
  2566. (*%E*)
  2567. IF op = Swap THEN
  2568. IF (~(IsData IN seghdr^.flags)) & IsActive(seghdr) THEN
  2569. INCL(seghdr^.flags,DataActive);
  2570. END; (*IF*)
  2571. IF (SegSet{IsDiscard,IsExRd} * seghdr^.flags # SegSet{}) OR (modnum=g.delay) THEN
  2572. op := Discard;
  2573. END; (*IF*)
  2574. END; (*IF*)
  2575. END; (*IF*)
  2576. fillcount := seghdr^.membyte-seghdr^.filebyte;
  2577. IF ODD(fillcount) THEN
  2578. DEC(fillcount)
  2579. END; (*IF*) (* OK as always an extra byte! *)
  2580. TempXfer(op,seghdr^.seg_val,segment,seghdr^.filebyte,fillcount);
  2581. IF is_mem(segment) & (op # Load) THEN
  2582. SetIndirect(seghdr);
  2583. END; (*IF*)
  2584. IF (op = Swap) & (DataActive IN seghdr^.flags) THEN
  2585. (* do nothing *)
  2586. ELSIF seghdr^.fix_count=0 THEN
  2587. (* do nothing *)
  2588. ELSIF is_mem(segment) OR ((DataActive IN seghdr^.flags) & (op = Discard)) THEN
  2589. fi := 0;
  2590. WHILE fi<seghdr^.fix_count DO
  2591. INC(fi);
  2592. fix := fixbuf^[fi];
  2593. chain := ~(2 IN set(fix.flags));
  2594. fix.flags := fix.flags MOD 4;
  2595. IF fix.flags = 0 THEN (* internal fixup *)
  2596. target_modnum := modnum;
  2597. target_module := module;
  2598. IF fix.target_seg = 0FFH THEN
  2599. GOTO ordinal;
  2600. END; (*IF*)
  2601. ELSIF fix.flags = 1 THEN (* ordinal import *)
  2602. target_modnum := ModNum(module^.module_table^[fix.target_mod]);
  2603. target_module := g.module_list[target_modnum];
  2604. ordinal:
  2605. fix.target_seg := CARDINAL(target_module^.entry_table^[fix.target_ent].seg);
  2606. fix.target_off := target_module^.entry_table^[fix.target_ent].ofs;
  2607. ELSE
  2608. (*%T CHECK*)
  2609. abort(ErrNamedImport); (* named import not supported *)
  2610. (*%E*)
  2611. END; (*IF*)
  2612. target_seghdr := GetSeg(target_module, fix.target_seg);
  2613. target_attr := target_seghdr^.flags;
  2614. IF op = Load THEN
  2615. loc := LocPtr(fix.off);
  2616. IF ~chain THEN
  2617. INC(fix.target_off,loc^.lo);
  2618. END; (*IF*)
  2619. IF (fix.lockind = FixPtr) & (target_attr * SegSet{IsData,IsPreLoad} = SegSet{}) THEN
  2620. fix.target_off := Gate(fix.target_off,target_seghdr,TRUE);
  2621. target_segment := Seg(g);
  2622. ELSE
  2623. target_segment := target_seghdr^.seg_val;
  2624. IF ~is_mem(target_segment) THEN
  2625. target_segment := DoSeg(target_modnum,fix.target_seg,Load);
  2626. ELSIF (~(IsPreLoad IN target_seghdr^.flags)) & ~(DataActive IN seghdr^.flags) THEN
  2627. Lock(target_segment);
  2628. END; (*IF*)
  2629. END; (*IF*)
  2630. IF fix.lockind = FixOfs THEN
  2631. IF chain THEN
  2632. REPEAT
  2633. next := LocPtr(loc^.lo);
  2634. loc^.lo := fix.target_off;
  2635. loc := next;
  2636. UNTIL loc = LocPtr(0FFFFH);
  2637. ELSE
  2638. loc^.lo := fix.target_off;
  2639. END; (*IF*)
  2640. ELSIF fix.lockind = FixBase THEN
  2641. IF chain THEN
  2642. REPEAT
  2643. next := LocPtr(loc^.lo);
  2644. loc^.lo := target_segment;
  2645. loc := next;
  2646. UNTIL loc = LocPtr(0FFFFH);
  2647. ELSE
  2648. loc^.lo := target_segment;
  2649. END; (*IF*)
  2650. ELSE
  2651. IF chain THEN
  2652. REPEAT
  2653. next := LocPtr(loc^.lo);
  2654. loc^.lo := fix.target_off;
  2655. loc^.hi := target_segment;
  2656. loc := next;
  2657. UNTIL loc = LocPtr(0FFFFH);
  2658. ELSE
  2659. loc^.lo := fix.target_off;
  2660. loc^.hi := target_segment;
  2661. END; (*IF*)
  2662. END; (*IF*)
  2663. ELSE (* unloading *)
  2664. IF (fix.lockind = FixPtr) & (target_attr * SegSet{IsData,IsPreLoad} = SegSet{}) THEN
  2665. (* do nothing *)
  2666. ELSIF IsPreLoad IN target_attr THEN
  2667. (* do nothing *)
  2668. ELSE
  2669. target_segment := target_seghdr^.seg_val;
  2670. IF is_mem(target_segment) THEN
  2671. UnLock(target_segment);
  2672. END; (*IF*)
  2673. END; (*IF*)
  2674. END; (*IF*)
  2675. END; (*WHILE*)
  2676. EXCL(seghdr^.flags,DataActive);
  2677. END; (*IF*)
  2678. (*%T VidSupport*)
  2679. IF op = Load THEN
  2680. TellVid(modnum,segnum,VID_LOAD_SEG);
  2681. END; (*IF*)
  2682. (*%E*)
  2683. IF op = Load THEN
  2684. RETURN segment;
  2685. ELSE
  2686. Free(segment);
  2687. RETURN 0;
  2688. END; (*IF*)
  2689. END DoSeg;
  2690. (* Virtual Segments - dynamically allocated segments that can be unlocked *)
  2691. PROCEDURE VAlloc(VAR addr : FarADDRESS; size : CARDINAL);
  2692. (* Allocates Virtual memory block of specified size (in bytes).
  2693. returns result in addr.
  2694. Block is initially fixed so VUnfix must be called before
  2695. it can be swapped out.
  2696. Address of addr is used as handle so only one variable must be used
  2697. to hold pointer.
  2698. *)
  2699. VAR ptr : POINTER TO ARRAY[0..1] OF CARDINAL;
  2700. BEGIN
  2701. ptr := ADR(addr);
  2702. AllocMove(ptr^[1],Para(size));
  2703. Lock(ptr^[1]);
  2704. ptr^[0] := 0;
  2705. END VAlloc;
  2706. PROCEDURE VUnfix(VAR addr : FarADDRESS);
  2707. (*
  2708. Unfixes memory allowing it to be moved or swapped to EMS or disk if
  2709. memory runs low. The address should not be used to reference memory
  2710. when unfixed.
  2711. *)
  2712. VAR ptr : POINTER TO ARRAY[0..1] OF CARDINAL;
  2713. BEGIN
  2714. ptr := ADR(addr);
  2715. (*%T CHECK*)
  2716. IF (ptr^[0]<>0)OR(~is_mem(ptr^[1]))OR([ptr^[1]-H:0 T]^.Kind<>MoveSeg) OR
  2717. (NOT Locked(ptr^[1])) THEN
  2718. abort(ErrInvalidVUnfix);
  2719. END;
  2720. (*%E*)
  2721. [ptr^[1]-H:0 T]^.Tick := IncTick(); (* LRU now, otherwise could get old while fixed *)
  2722. UnLock(ptr^[1]);
  2723. IF NOT Locked(ptr^[1]) THEN
  2724. ptr^[0] := [ptr^[1]-H:0 T]^.Size-H;
  2725. SwapMove(ptr^[1]);
  2726. END;
  2727. END VUnfix;
  2728. PROCEDURE VFix(VAR addr : FarADDRESS);
  2729. (*
  2730. Swaps block back into memory if necessary and
  2731. fixes the address so it can be used.
  2732. Calls to FixVSeg and UnfixVSeg may be nested.
  2733. *)
  2734. VAR ptr : POINTER TO ARRAY[0..1] OF CARDINAL;
  2735. BEGIN
  2736. ptr := ADR(addr);
  2737. IF ptr^[0]=0 THEN
  2738. (*%T CHECK*)
  2739. IF (([ptr^[1]-H:0 T]^.Kind<>MoveSeg) AND ([ptr^[1]-H:0 T]^.Kind<>SwapSeg))OR
  2740. ([ptr^[1]-H:0 T]^.Lock=0) THEN
  2741. abort(ErrInvalidVFix);
  2742. END;
  2743. (*%E*)
  2744. ELSE
  2745. (*%T CHECK*)
  2746. IF is_mem(ptr^[1]) AND ([ptr^[1]-H:0 T]^.Kind<>MoveSeg)
  2747. AND ([ptr^[1]-H:0 T]^.Kind<>SwapSeg) THEN
  2748. abort(ErrInvalidVFix);
  2749. END;
  2750. (*%E*)
  2751. LoadMove(ptr^[1],ptr^[0]);
  2752. ptr^[0] := 0;
  2753. END;
  2754. Lock(ptr^[1]);
  2755. END VFix;
  2756. PROCEDURE VFree(VAR addr : FarADDRESS);
  2757. (* frees virtual memory block
  2758. can be called only when segment fixed
  2759. addr is reset to NIL on exit
  2760. *)
  2761. VAR ptr : POINTER TO ARRAY[0..1] OF CARDINAL;
  2762. BEGIN
  2763. VFix(addr);
  2764. ptr := ADR(addr);
  2765. WHILE Locked(ptr^[1]) DO
  2766. UnLock(ptr^[1]);
  2767. END;
  2768. Free(ptr^[1]);
  2769. addr := FarNIL;
  2770. END VFree;
  2771. PROCEDURE VUnfixAll();
  2772. (* Equivalent to calling VUnfix for all Virtual addresses allocated *)
  2773. VAR s : CARDINAL;
  2774. TYPE ap = POINTER TO ADDRESS;
  2775. BEGIN
  2776. s := g.start;
  2777. REPEAT
  2778. IF [s:0 T]^.Kind=MoveSeg THEN
  2779. WHILE Locked(s+H) DO
  2780. VUnfix([[s:0 T]^.Id1:[s:0 T]^.Id2 ap]^); (* cannot upset loop *)
  2781. END;
  2782. END;
  2783. INC(s,[s:0 T]^.Size);
  2784. UNTIL s = g.start;
  2785. END VUnfixAll;
  2786. (* Tiny Allocation - (smaller overhead for upto 127 bytes) *)
  2787. CONST
  2788. TinyMax = 16;
  2789. TinyGranularity = 8;
  2790. TinyMaxSize = TinyMax*TinyGranularity-1;
  2791. TinyGranularityLog2 = 3;
  2792. VAR
  2793. TinyFreeList : ARRAY[1..TinyMax] OF CARDINAL;
  2794. PROCEDURE TinyAlloc(size : CARDINAL):FarADDRESS;
  2795. (* only called for allocations of 1 to TinyMaxSize *)
  2796. VAR
  2797. csize,i,seg : CARDINAL;
  2798. BEGIN
  2799. csize := (size+(TinyGranularity-1))DIV TinyGranularity;
  2800. seg := TinyFreeList[csize];
  2801. IF seg=MAX(CARDINAL) THEN
  2802. seg := AllocFixed(csize*TinyGranularity);
  2803. IF seg=0 THEN RETURN FarNIL END;
  2804. DEC(seg);
  2805. [seg:0 T]^.Id1 := MAX(CARDINAL);
  2806. [seg:0 T]^.Id2 := TinyFreeList[csize];
  2807. TinyFreeList[csize] := seg;
  2808. END;
  2809. (*%T CHECK*)
  2810. IF ([seg:0 T]^.Id1=0) THEN
  2811. END;
  2812. (*%E*)
  2813. i := 0;
  2814. WHILE NOT (i IN BITSET([seg:0 T]^.Id1)) DO INC(i) END;
  2815. EXCL(BITSET([seg:0 T]^.Id1),i);
  2816. IF [seg:0 T]^.Id1=0 THEN
  2817. TinyFreeList[csize] := [seg:0 T]^.Id2;
  2818. END;
  2819. RETURN [seg+1:i*csize*TinyGranularity];
  2820. END TinyAlloc;
  2821. PROCEDURE TinyFree(p:FarADDRESS): BOOLEAN;
  2822. VAR
  2823. seg,csize,i : CARDINAL;
  2824. BEGIN
  2825. seg := Seg(p^)-1;
  2826. WITH [seg:0 T]^ DO
  2827. IF (Kind<>FixedSeg)OR(Id2=0) THEN RETURN FALSE END;
  2828. csize := (Used-1)DIV TinyGranularity;
  2829. i := CARDINAL(p)DIV(csize*TinyGranularity);
  2830. (*%T CHECK*)
  2831. IF (csize=0)OR(csize>TinyMax)OR(i IN BITSET(Id1))OR
  2832. (i*csize*TinyGranularity<>CARDINAL(p)) THEN
  2833. abort(ErrInvalidFree);
  2834. END;
  2835. CheckAlloc(seg+1,ErrInvalidFree);
  2836. (*%E*)
  2837. IF Id1=0 THEN
  2838. Id2 := TinyFreeList[csize];
  2839. TinyFreeList[csize] := seg;
  2840. END;
  2841. INCL(BITSET(Id1),i);
  2842. END;
  2843. RETURN TRUE;
  2844. END TinyFree;
  2845. PROCEDURE TinyFlush;
  2846. (* called occasionally to clean up tiny chains *)
  2847. VAR
  2848. prev,ptr,next,i : CARDINAL;
  2849. BEGIN
  2850. FOR i := 1 TO TinyMax DO
  2851. prev := MAX(CARDINAL);
  2852. ptr := TinyFreeList[i];
  2853. WHILE ptr<>MAX(CARDINAL) DO
  2854. WITH [ptr:0 T]^ DO
  2855. next := Id2;
  2856. IF Id1=MAX(CARDINAL) THEN
  2857. IF prev=MAX(CARDINAL) THEN
  2858. TinyFreeList[i] := next;
  2859. ELSE
  2860. [prev:0 T]^.Id2 := next;
  2861. END;
  2862. Id1 := 0;
  2863. Id2 := 0;
  2864. Free(ptr+1);
  2865. ELSE
  2866. prev := ptr;
  2867. END;
  2868. END;
  2869. ptr := next;
  2870. END;
  2871. END;
  2872. END TinyFlush;
  2873. PROCEDURE TinyInit;
  2874. VAR i : CARDINAL;
  2875. BEGIN
  2876. FOR i := 1 TO TinyMax DO
  2877. TinyFreeList[i] := MAX(CARDINAL);
  2878. END;
  2879. END TinyInit;
  2880. TYPE
  2881. ExeHeader = RECORD
  2882. magic1,magic2 : CHAR;
  2883. link_version : SHORTCARD;
  2884. link_revision : SHORTCARD;
  2885. entry_table_off : CARDINAL;
  2886. entry_table_size : CARDINAL;
  2887. crc : LONGCARD;
  2888. flag : CARDINAL;
  2889. dgroup : CARDINAL;
  2890. small_heap_size : CARDINAL;
  2891. small_stack_size : CARDINAL;
  2892. ip,cs,sp,ss : CARDINAL;
  2893. seg_count : CARDINAL;
  2894. lib_count : CARDINAL;
  2895. non_res_name_size : CARDINAL;
  2896. seg_off : CARDINAL;
  2897. resource_off : CARDINAL;
  2898. res_name_off : CARDINAL;
  2899. module_ref_off : CARDINAL;
  2900. imp_name_off : CARDINAL;
  2901. non_res_name_off : LONGCARD;
  2902. mov_entry_count : CARDINAL;
  2903. log_sector_size : CARDINAL;
  2904. reserved : ARRAY [0..11] OF SHORTCARD;
  2905. END; (*ExeHeader*)
  2906. TYPE InitProc = PROCEDURE():CARDINAL;
  2907. PROCEDURE InternalLoadModule(name:ARRAY OF CHAR;is_exe:BOOLEAN;stage:ModStage):CARDINAL;
  2908. VAR
  2909. modnum : ModNum;
  2910. module : Module;
  2911. len : CARDINAL;
  2912. hpos : LONGCARD;
  2913. hdr : ExeHeader;
  2914. i : CARDINAL;
  2915. libname : ARRAY [0..255] OF CHAR;
  2916. bundle : RECORD
  2917. ne : SHORTCARD;
  2918. si : SHORTCARD;
  2919. END; (*bundle*)
  2920. fs : RECORD
  2921. flags : SHORTCARD;
  2922. off : CARDINAL;
  2923. END; (*fs*)
  2924. fs6 : RECORD
  2925. flags : SHORTCARD;
  2926. int3 : CARDINAL;
  2927. seg : SHORTCARD;
  2928. off : CARDINAL;
  2929. END; (*fs6*)
  2930. eseg : SHORTCARD;
  2931. eoff : CARDINAL;
  2932. SecondPass : BOOLEAN;
  2933. epass : SHORTCARD[0..1];
  2934. done : CARDINAL;
  2935. ord : CARDINAL;
  2936. cs : CARDINAL;
  2937. p : InitProc;
  2938. impnameoff : CARDINAL;
  2939. dummy : CARDINAL;
  2940. submod : CARDINAL;
  2941. substage : ModStage;
  2942. pss : CARDINAL;
  2943. buf_index : CARDINAL;
  2944. buffer : ARRAY [0..511] OF SHORTCARD;
  2945. PROCEDURE Read2(a:ADDRESS;count:CARDINAL);
  2946. VAR
  2947. avail : CARDINAL;
  2948. BEGIN
  2949. LOOP
  2950. avail := SIZE(buffer) - buf_index;
  2951. IF avail > count THEN
  2952. avail := count;
  2953. END; (*IF*)
  2954. Move(ADR(buffer[buf_index]),a,avail);
  2955. INC(buf_index,avail);
  2956. DEC(count,avail);
  2957. IF count = 0 THEN
  2958. EXIT;
  2959. END; (*IF*)
  2960. INC(CARDINAL(a),avail);
  2961. FileRead(ADR(buffer),SIZE(buffer),module^.file);
  2962. buf_index := 0;
  2963. END; (*LOOP*)
  2964. END Read2;
  2965. PROCEDURE Seek2(pos:LONGCARD);
  2966. BEGIN
  2967. buf_index := SIZE(buffer);
  2968. FileSeek(module^.file,pos);
  2969. END Seek2;
  2970. PROCEDURE Read(pos:LONGCARD;a:ADDRESS;count:CARDINAL):BOOLEAN;
  2971. BEGIN
  2972. buf_index := SIZE(buffer);
  2973. RETURN ModuleRead(module,pos,a,count);
  2974. END Read;
  2975. BEGIN
  2976. modnum := 1;
  2977. LOOP
  2978. IF modnum > g.module_count THEN
  2979. module := New(SIZE(module^));
  2980. len := Length(name) + 1;
  2981. module^.name := New(len);
  2982. Append(module^.name^,name);
  2983. IF modnum > MaxModule THEN
  2984. abort(ErrModuleLimit);
  2985. END; (*IF*)
  2986. g.module_count := modnum; (* should be check for > MaxModule *)
  2987. g.module_list[modnum] := module;
  2988. module^.file := MAX(CARDINAL);
  2989. module^.is_exe := is_exe;
  2990. (*%T GraphUseTrace*)
  2991. string('Module ');hex(modnum);string(' = ');string(name);eol;
  2992. (*%E*)
  2993. EXIT;
  2994. END; (*IF*)
  2995. module := g.module_list[modnum];
  2996. IF Compare(module^.name^,name) & (module^.is_exe = is_exe) THEN
  2997. EXIT;
  2998. END; (*IF*)
  2999. INC(modnum);
  3000. END; (*LOOP*)
  3001. IF module^.stage < stage THEN
  3002. (* read header *)
  3003. IF Read(3CH,ADR(hpos),SIZE(hpos)) OR Read(hpos,ADR(hdr),SIZE(hdr)) OR (hdr.magic1 # 'N') THEN
  3004. RETURN 0;
  3005. END; (*IF*)
  3006. REPEAT
  3007. INC(module^.stage);
  3008. CASE module^.stage OF
  3009. internal_stage (* verify header, build basic tables, allocate module table *)
  3010. :(* allocate module table *)
  3011. module^.module_table := New(hdr.lib_count * 2);
  3012. (* build segment table *)
  3013. module^.seg_count := hdr.seg_count;
  3014. module^.log_sector_size := hdr.log_sector_size;
  3015. module^.seg_info := New(hdr.seg_count * SIZE(SegRec));
  3016. Seek2(hpos + LONGCARD(hdr.seg_off));
  3017. buf_index := SIZE(buffer);
  3018. FOR i := 1 TO hdr.seg_count DO
  3019. WITH module^.seg_info^[i] DO
  3020. Read2(ADR(sector),8);
  3021. no_op := 90H;
  3022. jump_op := 0E9H;
  3023. jump_disp := CARDINAL(HeapAdr(LoaderA.GateHandler)) - CARDINAL(HeapAdr(jump_disp)) - 2;
  3024. END; (*WITH*)
  3025. END; (*FOR*)
  3026. (* build entry table *)
  3027. IF EntryTableTrace THEN
  3028. string('entry table for ');
  3029. string(module^.name^);
  3030. eol;
  3031. END; (*IF*)
  3032. FOR SecondPass := FALSE TO TRUE DO
  3033. Seek2(hpos + LONGCARD(hdr.entry_table_off));
  3034. ord := 0;
  3035. done := 0;
  3036. WHILE done < hdr.entry_table_size DO
  3037. Read2(ADR(bundle),2);
  3038. INC(done,2);
  3039. FOR i := 1 TO CARDINAL(bundle.ne) DO
  3040. INC(ord);
  3041. IF bundle.si = 255 THEN
  3042. Read2(ADR(fs6),SIZE(fs6));
  3043. INC(done,SIZE(fs6));
  3044. eseg := fs6.seg;
  3045. eoff := fs6.off;
  3046. ELSE
  3047. Read2(ADR(fs), SIZE(fs));
  3048. INC(done, SIZE(fs));
  3049. eseg := bundle.si;
  3050. eoff := fs.off;
  3051. END; (*IF*)
  3052. IF SecondPass THEN
  3053. module^.entry_table^[ord].seg := eseg;
  3054. module^.entry_table^[ord].ofs := eoff;
  3055. IF EntryTableTrace THEN
  3056. dec(ord);
  3057. char('=');
  3058. dec(CARDINAL(module^.entry_table^[ord].seg));
  3059. char(':');
  3060. hex(CARDINAL(module^.entry_table^[ord].ofs));
  3061. eol;
  3062. END; (*IF*)
  3063. END; (*IF*)
  3064. END; (*FOR*)
  3065. END; (*WHILE*)
  3066. IF ~SecondPass THEN
  3067. module^.entry_table := New(ord * SIZE(EntryRec));
  3068. END; (*IF*)
  3069. END; (*FOR*) |
  3070. sub_module_stage (* fill in module table, initialise sub-modules up to stage 2 *)
  3071. : FOR i := 1 TO hdr.lib_count DO
  3072. len := 0;
  3073. IF Read(hpos+LONGCARD(hdr.module_ref_off+(i-1)*2),ADR(impnameoff),SIZE(impnameoff)) OR Read(hpos+LONGCARD(hdr.imp_name_off+impnameoff),ADR(len),1) THEN
  3074. RETURN 0;
  3075. END; (*IF*)
  3076. Read2(ADR(libname),len);
  3077. libname[len] := 0C;
  3078. submod := InternalLoadModule(libname,FALSE,sub_module_stage);
  3079. IF submod = 0 THEN
  3080. RETURN 0;
  3081. END;(*IF*)
  3082. module^.module_table^[i] := SHORTCARD(submod);
  3083. END; (*FOR*) |
  3084. execute_stage (* execute sub-module entry points *)
  3085. :
  3086. FOR i := 1 TO hdr.lib_count DO
  3087. submod := CARDINAL(module^.module_table^[i]);
  3088. IF InternalLoadModule(g.module_list[submod]^.name^,FALSE,execute_stage) = 0 THEN
  3089. RETURN 0;
  3090. END; (*IF*)
  3091. END; (*FOR*)
  3092. (*%T VidSupport*)
  3093. TellVid(modnum,0,VID_LOAD_MODULE);
  3094. (*%E*)
  3095. (* execute entry-point *)
  3096. cs := DoSeg(modnum,hdr.cs,Load);
  3097. (* UnLock(cs); -- only if not packed *)
  3098. IF is_exe THEN
  3099. pss := DoSeg(modnum,hdr.ss,Load);
  3100. WITH [g.stk-1:0 T]^ DO
  3101. INC([Prev:0 T]^.Size,800H);
  3102. [g.stk-1+Size:0 T]^.Prev := Prev;
  3103. INC(g.freemem,800H);
  3104. END; (*WITH*)
  3105. Exec(g.psp,pss,hdr.sp,cs,hdr.ip);
  3106. ELSE
  3107. p := InitProc([cs:hdr.ip]);
  3108. dummy := p();
  3109. END; (*IF*)
  3110. END; (*CASE*)
  3111. UNTIL module^.stage = stage;
  3112. END; (*IF*)
  3113. RETURN modnum;
  3114. END InternalLoadModule;
  3115. PROCEDURE LoadModule (name:ARRAY OF CHAR):CARDINAL;
  3116. VAR
  3117. modnum:CARDINAL;
  3118. BEGIN
  3119. IF (g.delay=0) OR Compare(g.module_list[g.delay]^.name^, name) THEN
  3120. g.delay := 0;
  3121. ELSE
  3122. DoDelay;
  3123. END;
  3124. modnum := InternalLoadModule(name,FALSE,execute_stage);
  3125. IF modnum = 0 THEN
  3126. modnum := MAX(CARDINAL); (* external convention *)
  3127. END;
  3128. RETURN modnum;
  3129. END LoadModule;
  3130. PROCEDURE GetProcAddr (modnum:CARDINAL;entry: ARRAY OF CHAR):ADDRESS;
  3131. VAR s : SHORTCARD;
  3132. str : ARRAY [0..255] OF CHAR;
  3133. ord : CARDINAL;
  3134. a :FarADDRESS;
  3135. Nonres : BOOLEAN;
  3136. module : Module;
  3137. hpos : LONGCARD;
  3138. hdr : ExeHeader;
  3139. i : CARDINAL;
  3140. BEGIN
  3141. module := g.module_list[modnum];
  3142. IF ModuleRead(module,3CH,ADR(hpos),SIZE(hpos))OR
  3143. ModuleRead(module,hpos,ADR(hdr),SIZE(hdr)) THEN
  3144. RETURN FarNIL;
  3145. END;
  3146. FileSeek(module^.file,hpos+LONGCARD(hdr.res_name_off));
  3147. ord := 0;
  3148. Nonres := FALSE;
  3149. LOOP
  3150. FileRead(ADR(s),1,module^.file);
  3151. IF s=0 THEN
  3152. IF Nonres THEN
  3153. EXIT;
  3154. ELSE
  3155. Nonres := TRUE;
  3156. FileSeek(module^.file,hdr.non_res_name_off);
  3157. END;
  3158. ELSE
  3159. FileRead(ADR(str),CARDINAL(s),module^.file);
  3160. str[CARDINAL(s)]:= 0C;
  3161. FileRead(ADR(ord),2,module^.file);
  3162. i := 0;
  3163. WHILE (str[i]=entry[i]) DO
  3164. INC(i);
  3165. IF (i=CARDINAL(s)) THEN
  3166. IF (entry[i]=0C) THEN EXIT END;
  3167. str[i] := 0C;
  3168. END;
  3169. END;
  3170. END;
  3171. END;
  3172. IF ord=0 THEN RETURN FarNIL END;
  3173. RETURN GetOrdProcAddr(modnum,ord);
  3174. END GetProcAddr;
  3175. PROCEDURE FlushAll;
  3176. BEGIN
  3177. DoDelay;
  3178. DoFlushAll;
  3179. END FlushAll;
  3180. PROCEDURE Terminate;
  3181. BEGIN
  3182. (*%T ExitTrace*)
  3183. eol;
  3184. IF TraceToFile THEN
  3185. FlushAll;
  3186. DumpMemory;
  3187. eol;
  3188. END; (*IF*)
  3189. MemStat;
  3190. string('Gate count = ');
  3191. dec(g.gate_count);
  3192. eol;
  3193. string('Module count = ');
  3194. dec(g.module_count);
  3195. eol;
  3196. (*%T EMS*)
  3197. string('Ems pages = ');
  3198. dec(g.ems_count);
  3199. eol;
  3200. (*%E*)
  3201. string('Heap used = ');
  3202. hex(g.near_alloc-CARDINAL(Ofs(g.heap)));
  3203. char('H');
  3204. eol;
  3205. string('Temp file = ');
  3206. hex(g.temp_max*(TempPageSize DIV 256));
  3207. string('00H');
  3208. eol;
  3209. (*%E*)
  3210. FileClose(g.temp_file);
  3211. FileDelete(FullTempFileName);
  3212. (*%T EMS*)
  3213. IF g.ems_data_handle # 0 THEN
  3214. EmsMap(4500H,0,g.ems_data_handle); (* free pages *)
  3215. END; (*IF*)
  3216. IF g.ems_temp_handle # 0 THEN
  3217. EmsMap(4500H,0,g.ems_temp_handle); (* free temp pages *)
  3218. END; (*IF*)
  3219. (*%E*)
  3220. END Terminate;
  3221. PROCEDURE AllocMem(size:CARDINAL):FarADDRESS;
  3222. BEGIN
  3223. IF size = 0 THEN
  3224. RETURN FarNIL;
  3225. END; (*IF*)
  3226. IF size<=TinyMaxSize THEN
  3227. RETURN TinyAlloc(size);
  3228. END;
  3229. RETURN [AllocFixed(Para(size)):0];
  3230. END AllocMem;
  3231. PROCEDURE FreeMem(ofs,seg:CARDINAL);
  3232. BEGIN
  3233. IF NOT TinyFree([seg:ofs]) THEN
  3234. Free(seg);
  3235. END;
  3236. END FreeMem;
  3237. PROCEDURE ClearAllocMem(num,size:CARDINAL):FarADDRESS;
  3238. VAR
  3239. res : FarADDRESS;
  3240. BEGIN
  3241. size := num * size;
  3242. IF size = 0 THEN
  3243. RETURN FarNIL;
  3244. END; (*IF*)
  3245. IF size<=TinyMaxSize THEN
  3246. res := TinyAlloc(size);
  3247. ELSE
  3248. res := [AllocFixed(Para(size)):0];
  3249. END;
  3250. IF res<>FarNIL THEN
  3251. Fill(res,size,0);
  3252. END;
  3253. RETURN res;
  3254. END ClearAllocMem;
  3255. PROCEDURE HugeAllocMem(size:LONGCARD):FarADDRESS;
  3256. BEGIN
  3257. RETURN [AllocFixed(CARDINAL((size+15) DIV 16)):0];
  3258. END HugeAllocMem;
  3259. PROCEDURE ExpandMem(Buffer:FarADDRESS;newsize:CARDINAL):FarADDRESS;
  3260. VAR
  3261. seg,next : CARDINAL;
  3262. BEGIN
  3263. seg := Seg(Buffer^) - H;
  3264. newsize := Para(newsize) + H;
  3265. LOOP
  3266. WITH [seg:0 T]^ DO
  3267. IF Size >= newsize THEN
  3268. INC(g.freemem,Used);
  3269. DEC(g.freemem,newsize);
  3270. Used := newsize;
  3271. RETURN Buffer;
  3272. ELSE
  3273. next := seg + Size;
  3274. IF [next:0 T]^.Used = 0 THEN
  3275. INC(Size,[next:0 T]^.Size);
  3276. next := seg + Size;
  3277. [next:0 T]^.Prev := seg;
  3278. ELSE
  3279. RETURN FarNIL;
  3280. END; (*IF*)
  3281. END; (*IF*)
  3282. END; (*WITH*)
  3283. END; (*LOOP*)
  3284. END ExpandMem;
  3285. PROCEDURE HugeExpandMem(Buffer:FarADDRESS;newsize:LONGCARD):FarADDRESS;
  3286. VAR
  3287. seg,next,NewCard : CARDINAL;
  3288. BEGIN
  3289. seg := Seg(Buffer^) - H;
  3290. NewCard := CARDINAL((newsize + 15) DIV 16) + H;
  3291. LOOP
  3292. WITH [seg:0 T]^ DO
  3293. IF Size >= NewCard THEN
  3294. INC(g.freemem,Used);
  3295. DEC(g.freemem,NewCard);
  3296. Used := NewCard;
  3297. RETURN Buffer;
  3298. ELSE
  3299. next := seg + Size;
  3300. IF [next:0 T]^.Used = 0 THEN
  3301. INC(Size,[next:0 T]^.Size);
  3302. next := seg + Size;
  3303. [next:0 T]^.Prev := seg;
  3304. ELSE
  3305. RETURN FarNIL;
  3306. END; (*IF*)
  3307. END; (*IF*)
  3308. END; (*WITH*)
  3309. END; (*LOOP*)
  3310. END HugeExpandMem;
  3311. PROCEDURE InvalidProc;
  3312. BEGIN
  3313. abort(ErrInvalidProcedure);
  3314. END InvalidProc;
  3315. CONST
  3316. HEAPOK = 0;
  3317. HEAPEMPTY = -1;
  3318. HEAPBADBEGIN = -2;
  3319. HEAPBADNODE = -3;
  3320. HEAPOVERFLOW = -4;
  3321. HEAPEND = -5;
  3322. HEAPBADPTR = -6;
  3323. PROCEDURE HeapCheck(Val:CARDINAL;DoFill:BOOLEAN):INTEGER;
  3324. VAR
  3325. TSeg : CARDINAL;
  3326. BEGIN
  3327. TSeg := g.start;
  3328. REPEAT
  3329. WITH [TSeg:0 T]^ DO
  3330. IF Size = 0 THEN
  3331. RETURN HEAPBADNODE;
  3332. END; (*IF*)
  3333. IF DoFill & (Used < Size) THEN
  3334. Fill([TSeg+Used:0],(Size-Used)*16,Val);
  3335. END; (*IF*)
  3336. INC(TSeg,Size);
  3337. END; (*WITH*)
  3338. UNTIL TSeg = g.start;
  3339. RETURN HEAPOK;
  3340. END HeapCheck;
  3341. PROCEDURE HeapWalk(VAR Entry:HeapInfo):INTEGER;
  3342. BEGIN
  3343. WITH Entry DO
  3344. IF pentry = FarNIL THEN
  3345. pentry := [g.start:0];
  3346. ELSE
  3347. pentry := [Seg(pentry^) + T(pentry)^.Size:0];
  3348. END; (*IF*)
  3349. WITH T(pentry)^ DO
  3350. IF Seg(pentry^) = g.start THEN
  3351. RETURN HEAPEND;
  3352. END; (*IF*)
  3353. IF Size = 0 THEN
  3354. RETURN HEAPBADNODE;
  3355. ELSE
  3356. size := Size * 16;
  3357. END; (*IF*)
  3358. useflag := Used > 0;
  3359. END; (*WITH*)
  3360. END; (*WITH*)
  3361. RETURN HEAPOK;
  3362. END HeapWalk;
  3363. (*# save,call(reg_param=>(bx,ax),reg_saved=>(cx,dx,di,si,ds,st1,st2),inline=>on)*)
  3364. PROCEDURE DOSAllocMem(Para:CARDINAL):CARDINAL = A4(0B4H,048H,0CDH,021H);
  3365. PROCEDURE DOSResizeMem(Para,Seg:CARDINAL) = A6(08EH,0C0H,0B4H,04AH,0CDH,021H);
  3366. PROCEDURE DOSFreeMem(Para:CARDINAL) = A6(08EH,0C3H,0B4H,049H,0CDH,021H);
  3367. (*# call(reg_return=>(bx))*)
  3368. PROCEDURE DOSMemAvail():CARDINAL = A7(0B4H,048H,0BBH,0FFH,0FFH,0CDH,021H);
  3369. (*# restore *)
  3370. VAR
  3371. AvailMem,AvailSeg : CARDINAL;
  3372. HighMem,HighSeg : CARDINAL;
  3373. PROCEDURE ShrinkHeap():CARDINAL;
  3374. BEGIN
  3375. FlushAll;
  3376. AvailMem := Avail();
  3377. IF AvailMem>800H THEN DEC(AvailMem,800H); END; (* needed to reload caller *)
  3378. AvailSeg := AllocFixed(AvailMem);
  3379. DOSResizeMem((AvailSeg + AvailMem) - g.psp - 1,g.psp);
  3380. HighMem := DOSMemAvail();
  3381. HighSeg := DOSAllocMem(HighMem);
  3382. DOSResizeMem(AvailSeg - g.psp,g.psp);
  3383. RETURN 0;
  3384. END ShrinkHeap;
  3385. PROCEDURE GrowHeap;
  3386. BEGIN
  3387. DOSFreeMem(HighSeg);
  3388. DOSResizeMem((AvailSeg + AvailMem + HighMem) - g.psp,g.psp);
  3389. Free(AvailSeg);
  3390. END GrowHeap;
  3391. PROCEDURE UserFlush;
  3392. BEGIN
  3393. FlushAll;
  3394. END UserFlush;
  3395. PROCEDURE SetExitHandler(p:ExitHandler);
  3396. BEGIN
  3397. g.abort := p;
  3398. reserve_panic;
  3399. END SetExitHandler;
  3400. PROCEDURE SetMemHandler(p:MemHandler);
  3401. BEGIN
  3402. g.OutOfMem := p;
  3403. END SetMemHandler;
  3404. PROCEDURE LoadSeg(segno:CARDINAL;ModName:ARRAY OF CHAR):SegReturn;
  3405. VAR
  3406. modno : CARDINAL;
  3407. BEGIN
  3408. modno := 1;
  3409. IF ModName[0] # 0C THEN
  3410. LOOP
  3411. IF Compare(g.module_list[modno]^.name^,ModName) THEN
  3412. EXIT;
  3413. END; (*IF*)
  3414. INC(modno);
  3415. IF modno > g.module_count THEN
  3416. RETURN INVALID_MOD;
  3417. END; (*IF*)
  3418. END; (*LOOP*)
  3419. END; (*IF*)
  3420. WITH g.module_list[modno]^ DO
  3421. IF segno > seg_count THEN
  3422. RETURN INVALID_SEG;
  3423. ELSIF seg_info^[segno].direct_list # GatePtr(0) THEN
  3424. RETURN RESIDENT;
  3425. ELSIF DoSeg(modno,segno,Load) # 0 THEN
  3426. RETURN SUCCESS;
  3427. ELSE
  3428. RETURN FAIL;
  3429. END; (*IF*)
  3430. END; (*WITH*)
  3431. END LoadSeg;
  3432. PROCEDURE UnloadSeg(segno:CARDINAL;ModName:ARRAY OF CHAR):SegReturn;
  3433. VAR
  3434. modno : CARDINAL;
  3435. BEGIN
  3436. modno := 1;
  3437. IF ModName[0] # 0C THEN
  3438. LOOP
  3439. IF Compare(g.module_list[modno]^.name^,ModName) THEN
  3440. EXIT;
  3441. END; (*IF*)
  3442. INC(modno);
  3443. IF modno > g.module_count THEN
  3444. RETURN INVALID_MOD;
  3445. END; (*IF*)
  3446. END; (*LOOP*)
  3447. END; (*IF*)
  3448. WITH g.module_list[modno]^ DO
  3449. IF segno > seg_count THEN
  3450. RETURN INVALID_SEG;
  3451. ELSIF seg_info^[segno].direct_list = GatePtr(0) THEN
  3452. RETURN UNLOADED;
  3453. ELSIF DoSeg(modno,segno,Swap) = 0 THEN
  3454. RETURN SUCCESS;
  3455. ELSE
  3456. RETURN FAIL;
  3457. END; (*IF*)
  3458. END; (*WITH*)
  3459. END UnloadSeg;
  3460. PROCEDURE Getseg(seg:CARDINAL):CARDINAL;
  3461. VAR
  3462. i,j : CARDINAL;
  3463. BEGIN
  3464. FOR i := 1 TO g.module_count DO
  3465. WITH g.module_list[i]^ DO
  3466. FOR j := 1 TO seg_count DO
  3467. WITH seg_info^[j] DO
  3468. IF seg_val = seg THEN
  3469. RETURN j;
  3470. END; (*IF*)
  3471. END; (*WITH*)
  3472. END; (*FOR*)
  3473. END; (*WITH*)
  3474. END; (*FOR*)
  3475. RETURN 0;
  3476. END Getseg;
  3477. (*# save, call(same_ds=>off) *)
  3478. PROCEDURE default_abort(name:ARRAY OF CHAR;errno:CARDINAL);
  3479. (*# restore *)
  3480. BEGIN
  3481. eol;
  3482. (*%T CHECK*)
  3483. string('Loader fatal error : ');
  3484. dec(errno);
  3485. string(', ');
  3486. (*%E*)
  3487. CASE errno-ErrBase OF (* only startup errors should be possible *)
  3488. ErrTempCreate : string('Failed to create ');
  3489. string(FullTempFileName); |
  3490. ErrLoad : string('DLL load failed. Is your PATH set correctly?');|
  3491. (* happens when ts.exe in local directory but path not set up *)
  3492. ErrOutOfMem: string('Out of memory');|
  3493. ErrTempDiskFull: string('Disk full on swap file');|
  3494. (*%T CHECK*)
  3495. ErrTempFileLimit : string('ErrTempFileLimit'); |
  3496. ErrPoolLimit : string('ErrPoolLimit'); |
  3497. ErrGateLimit : string('ErrGateLimit'); |
  3498. ErrDiskFull : string('ErrDiskFull'); |
  3499. ErrInternal : string('ErrInternal'); |
  3500. ErrNearHeap : string('ErrNearHeap'); |
  3501. ErrModuleLimit : string('ErrModuleLimit'); |
  3502. ErrInvalidProcedure : string('ErrInvalidProcedure'); |
  3503. ErrMemoryCorruption : string('ErrMemoryCorruption'); |
  3504. ErrTooManyUnlocks : string('ErrTooManyUnlocks'); |
  3505. ErrCallChainInvalid : string('ErrCallChainInvalid'); |
  3506. ErrOpenFail : string('ErrOpenFail'); |
  3507. ErrNamedImport : string('ErrNamedImport'); |
  3508. ErrInvalidVUnfix : string('ErrInvalidVUnfix'); |
  3509. ErrInvalidVFix : string('ErrInvalidVFix'); |
  3510. ErrInvalidFree : string('ErrInvalidFree'); |
  3511. END;
  3512. (*%E*)
  3513. (*%F CHECK*)
  3514. ELSE
  3515. string('Overlay loader fatal error : ');
  3516. dec(errno);
  3517. END; (*CASE*)
  3518. (*%E*)
  3519. eol;
  3520. END default_abort;
  3521. (*# save, call(same_ds=>off) *)
  3522. PROCEDURE default_MemHandler(Size:CARDINAL):BOOLEAN;
  3523. (*# restore *)
  3524. BEGIN
  3525. RETURN FALSE;
  3526. END default_MemHandler;
  3527. PROCEDURE Init(psp:CARDINAL); FORWARD;
  3528. (* Note this proc is overwritten by memory initialisation !! *)
  3529. PROCEDURE GetFullTempFileName(s:ARRAY OF CHAR);
  3530. VAR
  3531. drive : SHORTCARD;
  3532. p : ARRAY SHORTCARD OF CHAR;
  3533. BEGIN
  3534. drive := GetCurDrive();
  3535. GetCurDir(0,p);
  3536. s[0] := CHR(drive + ORD('A'));
  3537. IF p[0] = 0C THEN
  3538. s[2] := 0C;
  3539. ELSE
  3540. s[3] := 0C;
  3541. Append(s,p);
  3542. END; (*IF*)
  3543. Append(s,TempFileName);
  3544. END GetFullTempFileName;
  3545. PROCEDURE MakeSys(seg:CARDINAL);
  3546. VAR next,prev:CARDINAL;
  3547. BEGIN
  3548. (* links seg into memory list, initialises it to be a free seg *)
  3549. next := g.start;
  3550. LOOP
  3551. prev := [next:0 T]^.Prev;
  3552. IF seg <= g.start THEN
  3553. g.start := seg;
  3554. EXIT;
  3555. END;
  3556. IF prev <= seg THEN
  3557. EXIT;
  3558. END;
  3559. next := prev;
  3560. END;
  3561. WITH [next:0 T]^ DO
  3562. Prev := seg;
  3563. END;
  3564. WITH [prev:0 T]^ DO
  3565. Size := seg-prev;
  3566. Used := seg-prev;
  3567. END;
  3568. WITH [seg:0 T]^ DO
  3569. Size := next - seg;
  3570. Used := next - seg;
  3571. Prev := prev;
  3572. Active := FALSE;
  3573. Kind := SystemSeg;
  3574. Id1 := 0;
  3575. Id2 := 0;
  3576. Lock := 1;
  3577. END;
  3578. END MakeSys;
  3579. PROCEDURE Init(psp:CARDINAL);
  3580. VAR
  3581. m : CARDINAL;
  3582. code : CARDINAL;
  3583. cp : POINTER TO ARRAY [0..255] OF CHAR;
  3584. i : CARDINAL;
  3585. drive : SHORTCARD;
  3586. LABEL
  3587. NoEms;
  3588. BEGIN
  3589. Fill(ADR(g),SIZE(g),0);
  3590. TinyInit;
  3591. (*%T TraceToFile*)
  3592. output_file := FileCreate('otrace.txt');
  3593. (*%E*)
  3594. (*%T VidSupport*)
  3595. FindVid;
  3596. (*%E*)
  3597. (*%T GraphUseTrace*)
  3598. Fill(ADR(graphsegs),SIZE(graphsegs),0);
  3599. (*%E*)
  3600. g.abort := default_abort;
  3601. g.OutOfMem := default_MemHandler;
  3602. g.near_alloc := CARDINAL(Ofs(g.heap));
  3603. GetFullTempFileName(FullTempFileName);
  3604. (*#save,data(const_assign=>on)*)
  3605. g.temp_file := FileCreateNew(FullTempFileName);
  3606. (*#restore*)
  3607. IF g.temp_file = MAX(CARDINAL) THEN
  3608. abort(ErrTempCreate);
  3609. RETURN;
  3610. END; (*IF*)
  3611. g.psp := psp;
  3612. code := Seg(Main) - H;
  3613. g.stk := Seg(psp) + 2;
  3614. g.end := CARDINAL([g.psp:2]^) - H;
  3615. g.start := code - 1;
  3616. [g.start:0 T]^.Prev := g.start;
  3617. MakeSys(code-1);
  3618. MakeSys(code);
  3619. MakeSys(g.stk-1);
  3620. MakeSys(g.end);
  3621. WITH [g.stk-1:0 T]^ DO
  3622. Used := 0800H;
  3623. INC(g.freemem,Size-Used);
  3624. END; (*WITH*)
  3625. [g.stk:0]^ := 0;
  3626. WITH loader_module.seg_info^[1] DO
  3627. membyte := Ofs(Init);
  3628. jump_disp := CARDINAL(HeapAdr(LoaderA.GateHandler)) - CARDINAL(HeapAdr(jump_disp)) - 2;
  3629. seg_val := code + H;
  3630. END; (*WITH*)
  3631. WITH [code:0 T]^ DO (* will overwrite program entry ! *)
  3632. Kind := StaticSeg;
  3633. Id1 := 1;
  3634. Id2 := 1;
  3635. END; (*WITH*)
  3636. g.module_count := 1;
  3637. g.module_list[1] := Module(HeapAdr(loader_module));
  3638. (*%T CHECK*)
  3639. CheckMem;
  3640. (*%E*)
  3641. reserve_panic;
  3642. (* get ems frame *)
  3643. g.ems_frame := 0E000H; (* dummy value when no ems *)
  3644. (*%T EMS*)
  3645. cp := [[0:19CH+2]^:0AH];
  3646. FOR i := 0 TO 7 DO
  3647. IF cp^[i] # EmsName[i] THEN
  3648. GOTO NoEms;
  3649. END; (*IF*)
  3650. END; (*FOR*)
  3651. IF EmsTest(4000H) = 0 THEN
  3652. g.ems_frame := EmsGet(4100H); (* get frame *)
  3653. g.ems_present := TRUE;
  3654. END; (*IF*)
  3655. (*%E*)
  3656. NoEms:
  3657. m := InternalLoadModule(MainName,TRUE,execute_stage);
  3658. (* returns only if error *)
  3659. abort(ErrLoad);
  3660. END Init;
  3661. PROCEDURE Main(psp:CARDINAL);
  3662. BEGIN
  3663. Init(psp);
  3664. END Main;
  3665. END Loader.
  3666.