system.pas 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227
  1. {
  2. ****************************************************************************
  3. This file is part of the Free Pascal run time library.
  4. Copyright (c) 1999-2005 by Free Pascal development team
  5. Free Pascal - OS/2 runtime library
  6. See the file COPYING.FPC, included in this distribution,
  7. for details about the copyright.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  11. ****************************************************************************}
  12. unit system;
  13. interface
  14. {$ifdef SYSTEMDEBUG}
  15. {$define SYSTEMEXCEPTIONDEBUG}
  16. {.$define IODEBUG}
  17. {.$define DEBUGENVIRONMENT}
  18. {.$define DEBUGARGUMENTS}
  19. {$endif SYSTEMDEBUG}
  20. {$DEFINE OS2EXCEPTIONS}
  21. {$define DISABLE_NO_THREAD_MANAGER}
  22. {$DEFINE HAS_GETCPUCOUNT}
  23. {$I systemh.inc}
  24. const
  25. LineEnding = #13#10;
  26. { LFNSupport is defined separately below!!! }
  27. DirectorySeparator = '\';
  28. DriveSeparator = ':';
  29. ExtensionSeparator = '.';
  30. PathSeparator = ';';
  31. AllowDirectorySeparators : set of char = ['\','/'];
  32. AllowDriveSeparators : set of char = [':'];
  33. { FileNameCaseSensitive and FileNameCasePreserving are defined separately below!!! }
  34. MaxExitCode = 65535;
  35. MaxPathLen = 260;
  36. (* MaxPathLen is referenced as constant from unit SysUtils *)
  37. (* - changing to variable or typed constant is not possible. *)
  38. AllFilesMask = '*';
  39. RealMaxPathLen: word = MaxPathLen;
  40. (* Default value only - real value queried from the system on startup. *)
  41. type Tos=(osDOS,osOS2,osDPMI);
  42. const OS_Mode: Tos = osOS2;
  43. First_Meg: pointer = nil;
  44. const UnusedHandle=-1;
  45. StdInputHandle=0;
  46. StdOutputHandle=1;
  47. StdErrorHandle=2;
  48. LFNSupport: boolean = true;
  49. FileNameCaseSensitive: boolean = false;
  50. FileNameCasePreserving: boolean = true;
  51. CtrlZMarksEOF: boolean = true; (* #26 is considered as end of file *)
  52. sLineBreak = LineEnding;
  53. DefaultTextLineBreakStyle : TTextLineBreakStyle = tlbsCRLF;
  54. var
  55. { C-compatible arguments and environment }
  56. argc : longint;
  57. argv : ppchar;
  58. envp : ppchar;
  59. EnvC: cardinal;
  60. (* Pointer to the block of environment variables - used e.g. in unit Dos. *)
  61. Environment: PChar;
  62. var
  63. (* Type / run mode of the current process: *)
  64. (* 0 .. full screen OS/2 session *)
  65. (* 1 .. DOS session *)
  66. (* 2 .. VIO windowable OS/2 session *)
  67. (* 3 .. Presentation Manager OS/2 session *)
  68. (* 4 .. detached (background) OS/2 process *)
  69. ApplicationType: cardinal;
  70. const
  71. HeapAllocFlags: cardinal = $53; (* Compatible to VP/2 *)
  72. (* mfPag_Commit or mfObj_Tile or mfPag_Write or mfPag_Read *)
  73. function ReadUseHighMem: boolean;
  74. procedure WriteUseHighMem (B: boolean);
  75. (* Is allocation of memory above 512 MB address limit allowed? Initialized *)
  76. (* during initialization of system unit according to capabilities of the *)
  77. (* underlying OS/2 version, can be overridden by user - heap is allocated *)
  78. (* for all threads, so the setting isn't declared as a threadvar and *)
  79. (* should be only changed at the beginning of the main thread if needed. *)
  80. property
  81. UseHighMem: boolean read ReadUseHighMem write WriteUseHighMem;
  82. (* UseHighMem is provided for compatibility with 2.0.x. *)
  83. const
  84. (* Are file sizes > 2 GB (64-bit) supported on the current system? *)
  85. FSApi64: boolean = false;
  86. procedure SetDefaultOS2FileType (FType: ShortString);
  87. procedure SetDefaultOS2Creator (Creator: ShortString);
  88. type
  89. TDosOpenL = function (FileName: PChar; var Handle: THandle;
  90. var Action: cardinal; InitSize: int64;
  91. Attrib, OpenFlags, FileMode: cardinal;
  92. EA: pointer): cardinal; cdecl;
  93. TDosSetFilePtrL = function (Handle: THandle; Pos: int64; Method: cardinal;
  94. var PosActual: int64): cardinal; cdecl;
  95. TDosSetFileSizeL = function (Handle: THandle; Size: int64): cardinal; cdecl;
  96. function DummyDosOpenL (FileName: PChar; var Handle: THandle;
  97. var Action: cardinal; InitSize: int64;
  98. Attrib, OpenFlags, FileMode: cardinal;
  99. EA: pointer): cardinal; cdecl;
  100. function DummyDosSetFilePtrL (Handle: THandle; Pos: int64; Method: cardinal;
  101. var PosActual: int64): cardinal; cdecl;
  102. function DummyDosSetFileSizeL (Handle: THandle; Size: int64): cardinal; cdecl;
  103. const
  104. Sys_DosOpenL: TDosOpenL = @DummyDosOpenL;
  105. Sys_DosSetFilePtrL: TDosSetFilePtrL = @DummyDosSetFilePtrL;
  106. Sys_DosSetFileSizeL: TDosSetFileSizeL = @DummyDosSetFileSizeL;
  107. implementation
  108. {*****************************************************************************
  109. System unit initialization.
  110. ****************************************************************************}
  111. {$I system.inc}
  112. {*****************************************************************************
  113. Exception handling.
  114. ****************************************************************************}
  115. {$IFDEF OS2EXCEPTIONS}
  116. var
  117. { value of the stack segment
  118. to check if the call stack can be written on exceptions }
  119. _SS : Cardinal;
  120. function Is_Prefetch (P: pointer): boolean;
  121. var
  122. A: array [0..15] of byte;
  123. DoAgain: boolean;
  124. InstrLo, InstrHi, OpCode: byte;
  125. I: longint;
  126. MemSize, MemAttrs: cardinal;
  127. begin
  128. Is_Prefetch := false;
  129. MemSize := SizeOf (A);
  130. if (DosQueryMem (P, MemSize, MemAttrs) = 0) and
  131. (MemAttrs and (mfPag_Free or mfPag_Commit) <> 0)
  132. and (MemSize >= SizeOf (A)) then
  133. Move (P^, A [0], SizeOf (A))
  134. else
  135. Exit;
  136. I := 0;
  137. DoAgain := true;
  138. while DoAgain and (I < 15) do
  139. begin
  140. OpCode := A [I];
  141. InstrLo := OpCode and $f;
  142. InstrHi := OpCode and $f0;
  143. case InstrHi of
  144. { prefix? }
  145. $20, $30:
  146. DoAgain := (InstrLo and 7) = 6;
  147. $60:
  148. DoAgain := (InstrLo and $c) = 4;
  149. $f0:
  150. DoAgain := InstrLo in [0, 2, 3];
  151. $0:
  152. begin
  153. Is_Prefetch := (InstrLo = $f) and (A [I + 1] in [$D, $18]);
  154. Exit;
  155. end;
  156. else
  157. DoAgain := false;
  158. end;
  159. Inc (I);
  160. end;
  161. end;
  162. const
  163. MaxExceptionLevel = 16;
  164. ExceptLevel: byte = 0;
  165. var
  166. ExceptEIP: array [0..MaxExceptionLevel - 1] of longint;
  167. ExceptError: array [0..MaxExceptionLevel - 1] of byte;
  168. ResetFPU: array [0..MaxExceptionLevel - 1] of boolean;
  169. {$ifdef SYSTEMEXCEPTIONDEBUG}
  170. procedure DebugHandleErrorAddrFrame (Error: longint; Addr, Frame: pointer);
  171. begin
  172. if IsConsole then
  173. begin
  174. Write (StdErr, ' HandleErrorAddrFrame (error = ', Error);
  175. Write (StdErr, ', addr = ', hexstr (PtrUInt (Addr), 8));
  176. WriteLn (StdErr, ', frame = ', hexstr (PtrUInt (Frame), 8), ')');
  177. end;
  178. HandleErrorAddrFrame (Error, Addr, Frame);
  179. end;
  180. {$endif SYSTEMEXCEPTIONDEBUG}
  181. procedure JumpToHandleErrorFrame;
  182. var
  183. EIP, EBP, Error: longint;
  184. begin
  185. (* save ebp *)
  186. asm
  187. movl (%ebp),%eax
  188. movl %eax,ebp
  189. end;
  190. if (ExceptLevel > 0) then
  191. Dec (ExceptLevel);
  192. EIP := ExceptEIP [ExceptLevel];
  193. Error := ExceptError [ExceptLevel];
  194. {$ifdef SYSTEMEXCEPTIONDEBUG}
  195. if IsConsole then
  196. WriteLn (StdErr, 'In JumpToHandleErrorFrame error = ', Error);
  197. {$endif SYSTEMEXCEPTIONDEBUG}
  198. if ResetFPU [ExceptLevel] then
  199. SysResetFPU;
  200. { build a fake stack }
  201. asm
  202. {$ifdef REGCALL}
  203. movl ebp,%ecx
  204. movl eip,%edx
  205. movl error,%eax
  206. pushl eip
  207. movl ebp,%ebp // Change frame pointer
  208. {$else}
  209. movl ebp,%eax
  210. pushl %eax
  211. movl eip,%eax
  212. pushl %eax
  213. movl error,%eax
  214. pushl %eax
  215. movl eip,%eax
  216. pushl %eax
  217. movl ebp,%ebp // Change frame pointer
  218. {$endif}
  219. {$ifdef SYSTEMEXCEPTIONDEBUG}
  220. jmpl DebugHandleErrorAddrFrame
  221. {$else not SYSTEMEXCEPTIONDEBUG}
  222. jmpl HandleErrorAddrFrame
  223. {$endif SYSTEMEXCEPTIONDEBUG}
  224. end;
  225. end;
  226. function System_Exception_Handler (Report: PExceptionReportRecord;
  227. RegRec: PExceptionRegistrationRecord;
  228. Context: PContextRecord;
  229. DispContext: pointer): cardinal; cdecl;
  230. var
  231. Res: cardinal;
  232. Err: byte;
  233. Must_Reset_FPU: boolean;
  234. {$IFDEF SYSTEMEXCEPTIONDEBUG}
  235. CurSS: cardinal;
  236. B: byte;
  237. {$ENDIF SYSTEMEXCEPTIONDEBUG}
  238. begin
  239. {$ifdef SYSTEMEXCEPTIONDEBUG}
  240. if IsConsole then
  241. begin
  242. asm
  243. xorl %eax,%eax
  244. movw %ss,%ax
  245. movl %eax,CurSS
  246. end;
  247. WriteLn (StdErr, 'In System_Exception_Handler, error = ',
  248. HexStr (Report^.Exception_Num, 8));
  249. WriteLn (StdErr, 'Context SS = ', HexStr (Context^.Reg_SS, 8),
  250. ', current SS = ', HexStr (CurSS, 8));
  251. end;
  252. {$endif SYSTEMEXCEPTIONDEBUG}
  253. Res := Xcpt_Continue_Search;
  254. if Context^.Reg_SS = _SS then
  255. begin
  256. Err := 0;
  257. Must_Reset_FPU := true;
  258. {$ifdef SYSTEMEXCEPTIONDEBUG}
  259. if IsConsole then
  260. Writeln (StdErr, 'Exception ', HexStr (Report^.Exception_Num, 8));
  261. {$endif SYSTEMEXCEPTIONDEBUG}
  262. case Report^.Exception_Num of
  263. Xcpt_Integer_Divide_By_Zero,
  264. Xcpt_Float_Divide_By_Zero:
  265. Err := 200;
  266. Xcpt_Array_Bounds_Exceeded:
  267. begin
  268. Err := 201;
  269. Must_Reset_FPU := false;
  270. end;
  271. Xcpt_Unable_To_Grow_Stack:
  272. begin
  273. Err := 202;
  274. Must_Reset_FPU := false;
  275. end;
  276. Xcpt_Float_Overflow:
  277. Err := 205;
  278. Xcpt_Float_Denormal_Operand,
  279. Xcpt_Float_Underflow:
  280. Err := 206;
  281. {Context^.FloatSave.StatusWord := Context^.FloatSave.StatusWord and $ffffff00;}
  282. Xcpt_Float_Inexact_Result,
  283. Xcpt_Float_Invalid_Operation,
  284. Xcpt_Float_Stack_Check:
  285. Err := 207;
  286. Xcpt_Integer_Overflow:
  287. begin
  288. Err := 215;
  289. Must_Reset_FPU := false;
  290. end;
  291. Xcpt_Illegal_Instruction:
  292. { if we're testing sse support, simply set the flag and continue }
  293. if SSE_Check then
  294. begin
  295. OS_Supports_SSE := false;
  296. { skip the offending movaps %xmm7, %xmm6 instruction }
  297. Inc (Context^.Reg_EIP, 3);
  298. Report^.Exception_Num := 0;
  299. Res := Xcpt_Continue_Execution;
  300. end
  301. else
  302. Err := 216;
  303. Xcpt_Access_Violation:
  304. { Athlon prefetch bug? }
  305. if Is_Prefetch (pointer (Context^.Reg_EIP)) then
  306. begin
  307. { if yes, then retry }
  308. Report^.Exception_Num := 0;
  309. Res := Xcpt_Continue_Execution;
  310. end
  311. else
  312. Err := 216;
  313. Xcpt_Signal:
  314. case Report^.Parameters [0] of
  315. Xcpt_Signal_KillProc:
  316. Err := 217;
  317. Xcpt_Signal_Break,
  318. Xcpt_Signal_Intr:
  319. if Assigned (CtrlBreakHandler) then
  320. if CtrlBreakHandler (Report^.Parameters [0] = Xcpt_Signal_Break) then
  321. begin
  322. {$IFDEF SYSTEMEXCEPTIONDEBUG}
  323. WriteLn (StdErr, 'CtrlBreakHandler returned true');
  324. {$ENDIF SYSTEMEXCEPTIONDEBUG}
  325. Report^.Exception_Num := 0;
  326. Res := Xcpt_Continue_Execution;
  327. DosAcknowledgeSignalException (Report^.Parameters [0]);
  328. end
  329. else
  330. Err := 217;
  331. end;
  332. Xcpt_Privileged_Instruction:
  333. begin
  334. Err := 218;
  335. Must_Reset_FPU := false;
  336. end;
  337. else
  338. begin
  339. if ((Report^.Exception_Num and Xcpt_Severity_Code)
  340. = Xcpt_Fatal_Exception) then
  341. Err := 217
  342. else
  343. Err := 255;
  344. end;
  345. end;
  346. if (Err <> 0) and (ExceptLevel < MaxExceptionLevel)
  347. (* TH: The following line is necessary to avoid an endless loop *)
  348. and (Report^.Exception_Num < Xcpt_Process_Terminate)
  349. then
  350. begin
  351. ExceptEIP [ExceptLevel] := Context^.Reg_EIP;
  352. ExceptError [ExceptLevel] := Err;
  353. ResetFPU [ExceptLevel] := Must_Reset_FPU;
  354. Inc (ExceptLevel);
  355. Context^.Reg_EIP := cardinal (@JumpToHandleErrorFrame);
  356. Report^.Exception_Num := 0;
  357. Res := Xcpt_Continue_Execution;
  358. {$ifdef SYSTEMEXCEPTIONDEBUG}
  359. if IsConsole then
  360. begin
  361. WriteLn (StdErr, 'Exception Continue Exception set at ',
  362. HexStr (ExceptEIP [ExceptLevel], 8));
  363. WriteLn (StdErr, 'EIP changed to ',
  364. HexStr (longint (@JumpToHandleErrorFrame), 8), ', error = ', Err);
  365. end;
  366. {$endif SYSTEMEXCEPTIONDEBUG}
  367. end;
  368. end
  369. else
  370. if (Report^.Exception_Num = Xcpt_Signal) and
  371. (Report^.Parameters [0] and (Xcpt_Signal_Intr or Xcpt_Signal_Break) <> 0)
  372. and Assigned (CtrlBreakHandler) then
  373. {$IFDEF SYSTEMEXCEPTIONDEBUG}
  374. begin
  375. WriteLn (StdErr, 'XCPT_SIGNAL caught, CtrlBreakHandler assigned, Param = ',
  376. Report^.Parameters [0]);
  377. {$ENDIF SYSTEMEXCEPTIONDEBUG}
  378. if CtrlBreakHandler (Report^.Parameters [0] = Xcpt_Signal_Break) then
  379. begin
  380. {$IFDEF SYSTEMEXCEPTIONDEBUG}
  381. WriteLn (StdErr, 'CtrlBreakHandler returned true');
  382. {$ENDIF SYSTEMEXCEPTIONDEBUG}
  383. Report^.Exception_Num := 0;
  384. Res := Xcpt_Continue_Execution;
  385. DosAcknowledgeSignalException (Report^.Parameters [0]);
  386. end
  387. else
  388. Err := 217;
  389. {$IFDEF SYSTEMEXCEPTIONDEBUG}
  390. end
  391. else
  392. if IsConsole then
  393. begin
  394. WriteLn (StdErr, 'Ctx flags = ', HexStr (Context^.ContextFlags, 8));
  395. if Context^.ContextFlags and Context_Floating_Point <> 0 then
  396. begin
  397. for B := 1 to 6 do
  398. Write (StdErr, 'Ctx Env [', B, '] = ', HexStr (Context^.Env [B], 8),
  399. ', ');
  400. WriteLn (StdErr, 'Ctx Env [7] = ', HexStr (Context^.Env [7], 8));
  401. for B := 0 to 6 do
  402. Write (StdErr, 'FPU stack [', B, '] = ', Context^.FPUStack [B], ', ');
  403. WriteLn (StdErr, 'FPU stack [7] = ', Context^.FPUStack [7]);
  404. end;
  405. if Context^.ContextFlags and Context_Segments <> 0 then
  406. WriteLn (StdErr, 'GS = ', HexStr (Context^.Reg_GS, 8),
  407. ', FS = ', HexStr (Context^.Reg_FS, 8),
  408. ', ES = ', HexStr (Context^.Reg_ES, 8),
  409. ', DS = ', HexStr (Context^.Reg_DS, 8));
  410. if Context^.ContextFlags and Context_Integer <> 0 then
  411. begin
  412. WriteLn (StdErr, 'EDI = ', HexStr (Context^.Reg_EDI, 8),
  413. ', ESI = ', HexStr (Context^.Reg_ESI, 8));
  414. WriteLn (StdErr, 'EAX = ', HexStr (Context^.Reg_EAX, 8),
  415. ', EBX = ', HexStr (Context^.Reg_EBX, 8),
  416. ', ECX = ', HexStr (Context^.Reg_ECX, 8),
  417. ', EDX = ', HexStr (Context^.Reg_EDX, 8));
  418. end;
  419. if Context^.ContextFlags and Context_Control <> 0 then
  420. begin
  421. WriteLn (StdErr, 'EBP = ', HexStr (Context^.Reg_EBP, 8),
  422. ', SS = ', HexStr (Context^.Reg_SS, 8),
  423. ', ESP = ', HexStr (Context^.Reg_ESP, 8));
  424. WriteLn (StdErr, 'CS = ', HexStr (Context^.Reg_CS, 8),
  425. ', EIP = ', HexStr (Context^.Reg_EIP, 8),
  426. ', EFlags = ', HexStr (Context^.Flags, 8));
  427. end;
  428. end;
  429. {$endif SYSTEMEXCEPTIONDEBUG}
  430. System_Exception_Handler := Res;
  431. end;
  432. var
  433. ExcptReg: PExceptionRegistrationRecord; public name '_excptregptr';
  434. {$ifdef SYSTEMEXCEPTIONDEBUG}
  435. var
  436. OldExceptAddr,
  437. NewExceptAddr: PtrUInt;
  438. {$endif SYSTEMEXCEPTIONDEBUG}
  439. procedure Install_Exception_Handler;
  440. var
  441. T: cardinal;
  442. begin
  443. {$ifdef SYSTEMEXCEPTIONDEBUG}
  444. (* ThreadInfoBlock is located at FS:[0], the first *)
  445. (* entry is pointer to head of exception handler chain. *)
  446. asm
  447. movl $0,%eax
  448. movl %fs:(%eax),%eax
  449. movl %eax, OldExceptAddr
  450. end;
  451. {$endif SYSTEMEXCEPTIONDEBUG}
  452. with ExcptReg^ do
  453. begin
  454. Prev_Structure := nil;
  455. ExceptionHandler := TExceptionHandler (@System_Exception_Handler);
  456. end;
  457. (* Disable pop-up windows for errors and exceptions *)
  458. DosError (deDisableExceptions);
  459. DosSetExceptionHandler (ExcptReg^);
  460. if IsConsole then
  461. begin
  462. DosSetSignalExceptionFocus (1, T);
  463. DosAcknowledgeSignalException (Xcpt_Signal_Intr);
  464. DosAcknowledgeSignalException (Xcpt_Signal_Break);
  465. end;
  466. {$ifdef SYSTEMEXCEPTIONDEBUG}
  467. asm
  468. movl $0,%eax
  469. movl %fs:(%eax),%eax
  470. movl %eax, NewExceptAddr
  471. end;
  472. {$endif SYSTEMEXCEPTIONDEBUG}
  473. end;
  474. procedure Remove_Exception_Handlers;
  475. begin
  476. DosUnsetExceptionHandler (ExcptReg^);
  477. end;
  478. {$ENDIF OS2EXCEPTIONS}
  479. procedure system_exit;
  480. begin
  481. (* if IsLibrary then
  482. ExitDLL(ExitCode);
  483. *)
  484. (*
  485. if not IsConsole then
  486. begin
  487. Close(stderr);
  488. Close(stdout);
  489. Close(erroutput);
  490. Close(Input);
  491. Close(Output);
  492. end;
  493. *)
  494. {$IFDEF OS2EXCEPTIONS}
  495. Remove_Exception_Handlers;
  496. {$ENDIF OS2EXCEPTIONS}
  497. DosExit (1{process}, exitcode);
  498. end;
  499. {$ASMMODE ATT}
  500. {****************************************************************************
  501. Miscellaneous related routines.
  502. ****************************************************************************}
  503. function paramcount:longint;assembler;
  504. asm
  505. movl argc,%eax
  506. decl %eax
  507. end {['EAX']};
  508. function paramstr(l:longint):string;
  509. var p:^Pchar;
  510. begin
  511. if (l>=0) and (l<=paramcount) then
  512. begin
  513. p:=argv;
  514. paramstr:=strpas(p[l]);
  515. end
  516. else paramstr:='';
  517. end;
  518. procedure randomize;
  519. var
  520. dt: TSysDateTime;
  521. begin
  522. // Hmm... Lets use timer
  523. DosGetDateTime(dt);
  524. randseed:=dt.hour+(dt.minute shl 8)+(dt.second shl 16)+(dt.sec100 shl 32);
  525. end;
  526. {****************************************************************************
  527. Error Message writing using messageboxes
  528. ****************************************************************************}
  529. const
  530. WinInitialize: TWinInitialize = nil;
  531. WinCreateMsgQueue: TWinCreateMsgQueue = nil;
  532. WinMessageBox: TWinMessageBox = nil;
  533. EnvSize: cardinal = 0;
  534. var
  535. ErrorBuf: array [0..ErrorBufferLength] of char;
  536. ErrorLen: longint;
  537. PMWinHandle: cardinal;
  538. function ErrorWrite (var F: TextRec): integer;
  539. {
  540. An error message should always end with #13#10#13#10
  541. }
  542. var
  543. P: PChar;
  544. I: longint;
  545. begin
  546. if F.BufPos > 0 then
  547. begin
  548. if F.BufPos + ErrorLen > ErrorBufferLength then
  549. I := ErrorBufferLength - ErrorLen
  550. else
  551. I := F.BufPos;
  552. Move (F.BufPtr^, ErrorBuf [ErrorLen], I);
  553. Inc (ErrorLen, I);
  554. ErrorBuf [ErrorLen] := #0;
  555. end;
  556. if ErrorLen > 3 then
  557. begin
  558. P := @ErrorBuf [ErrorLen];
  559. for I := 1 to 4 do
  560. begin
  561. Dec (P);
  562. if not (P^ in [#10, #13]) then
  563. break;
  564. end;
  565. end;
  566. if ErrorLen = ErrorBufferLength then
  567. I := 4;
  568. if (I = 4) then
  569. begin
  570. WinMessageBox (0, 0, @ErrorBuf, PChar ('Error'), 0, MBStyle);
  571. ErrorLen := 0;
  572. end;
  573. F.BufPos := 0;
  574. ErrorWrite := 0;
  575. end;
  576. function ErrorClose (var F: TextRec): integer;
  577. begin
  578. if ErrorLen > 0 then
  579. begin
  580. WinMessageBox (0, 0, @ErrorBuf, PChar ('Error'), 0, MBStyle);
  581. ErrorLen := 0;
  582. end;
  583. ErrorLen := 0;
  584. ErrorClose := 0;
  585. end;
  586. function ErrorOpen (var F: TextRec): integer;
  587. begin
  588. TextRec(F).InOutFunc := @ErrorWrite;
  589. TextRec(F).FlushFunc := @ErrorWrite;
  590. TextRec(F).CloseFunc := @ErrorClose;
  591. ErrorOpen := 0;
  592. end;
  593. procedure AssignError (var T: Text);
  594. begin
  595. Assign (T, '');
  596. TextRec (T).OpenFunc := @ErrorOpen;
  597. Rewrite (T);
  598. end;
  599. procedure SysInitStdIO;
  600. begin
  601. { Setup stdin, stdout and stderr, for GUI apps redirect stderr,stdout to be
  602. displayed in a messagebox }
  603. (*
  604. StdInputHandle := longint(GetStdHandle(cardinal(STD_INPUT_HANDLE)));
  605. StdOutputHandle := longint(GetStdHandle(cardinal(STD_OUTPUT_HANDLE)));
  606. StdErrorHandle := longint(GetStdHandle(cardinal(STD_ERROR_HANDLE)));
  607. if not IsConsole then
  608. begin
  609. if (DosLoadModule (nil, 0, 'PMWIN', PMWinHandle) = 0) and
  610. (DosQueryProcAddr (PMWinHandle, 789, nil, pointer (WinMessageBox)) = 0)
  611. and
  612. (DosQueryProcAddr (PMWinHandle, 763, nil, pointer (WinInitialize)) = 0)
  613. and
  614. (DosQueryProcAddr (PMWinHandle, 716, nil, pointer (WinCreateMsgQueue))
  615. = 0)
  616. then
  617. begin
  618. WinInitialize (0);
  619. WinCreateMsgQueue (0, 0);
  620. end
  621. else
  622. HandleError (2);
  623. AssignError (StdErr);
  624. AssignError (StdOut);
  625. Assign (Output, '');
  626. Assign (Input, '');
  627. end
  628. else
  629. begin
  630. *)
  631. OpenStdIO (Input, fmInput, StdInputHandle);
  632. OpenStdIO (Output, fmOutput, StdOutputHandle);
  633. OpenStdIO (ErrOutput, fmOutput, StdErrorHandle);
  634. OpenStdIO (StdOut, fmOutput, StdOutputHandle);
  635. OpenStdIO (StdErr, fmOutput, StdErrorHandle);
  636. (*
  637. end;
  638. *)
  639. end;
  640. function strcopy(dest,source : pchar) : pchar;assembler;
  641. var
  642. saveeax,saveesi,saveedi : longint;
  643. asm
  644. movl %edi,saveedi
  645. movl %esi,saveesi
  646. {$ifdef REGCALL}
  647. movl %eax,saveeax
  648. movl %edx,%edi
  649. {$else}
  650. movl source,%edi
  651. {$endif}
  652. testl %edi,%edi
  653. jz .LStrCopyDone
  654. leal 3(%edi),%ecx
  655. andl $-4,%ecx
  656. movl %edi,%esi
  657. subl %edi,%ecx
  658. {$ifdef REGCALL}
  659. movl %eax,%edi
  660. {$else}
  661. movl dest,%edi
  662. {$endif}
  663. jz .LStrCopyAligned
  664. .LStrCopyAlignLoop:
  665. movb (%esi),%al
  666. incl %edi
  667. incl %esi
  668. testb %al,%al
  669. movb %al,-1(%edi)
  670. jz .LStrCopyDone
  671. decl %ecx
  672. jnz .LStrCopyAlignLoop
  673. .balign 16
  674. .LStrCopyAligned:
  675. movl (%esi),%eax
  676. movl %eax,%edx
  677. leal 0x0fefefeff(%eax),%ecx
  678. notl %edx
  679. addl $4,%esi
  680. andl %edx,%ecx
  681. andl $0x080808080,%ecx
  682. jnz .LStrCopyEndFound
  683. movl %eax,(%edi)
  684. addl $4,%edi
  685. jmp .LStrCopyAligned
  686. .LStrCopyEndFound:
  687. testl $0x0ff,%eax
  688. jz .LStrCopyByte
  689. testl $0x0ff00,%eax
  690. jz .LStrCopyWord
  691. testl $0x0ff0000,%eax
  692. jz .LStrCopy3Bytes
  693. movl %eax,(%edi)
  694. jmp .LStrCopyDone
  695. .LStrCopy3Bytes:
  696. xorb %dl,%dl
  697. movw %ax,(%edi)
  698. movb %dl,2(%edi)
  699. jmp .LStrCopyDone
  700. .LStrCopyWord:
  701. movw %ax,(%edi)
  702. jmp .LStrCopyDone
  703. .LStrCopyByte:
  704. movb %al,(%edi)
  705. .LStrCopyDone:
  706. {$ifdef REGCALL}
  707. movl saveeax,%eax
  708. {$else}
  709. movl dest,%eax
  710. {$endif}
  711. movl saveedi,%edi
  712. movl saveesi,%esi
  713. end;
  714. threadvar
  715. DefaultCreator: ShortString;
  716. DefaultFileType: ShortString;
  717. procedure SetDefaultOS2FileType (FType: ShortString);
  718. begin
  719. {$WARNING Not implemented yet!}
  720. DefaultFileType := FType;
  721. end;
  722. procedure SetDefaultOS2Creator (Creator: ShortString);
  723. begin
  724. {$WARNING Not implemented yet!}
  725. DefaultCreator := Creator;
  726. end;
  727. procedure InitEnvironment;
  728. var env_count : longint;
  729. dos_env,cp : pchar;
  730. begin
  731. env_count:=0;
  732. cp:=environment;
  733. while cp ^ <> #0 do
  734. begin
  735. inc(env_count);
  736. while (cp^ <> #0) do inc(longint(cp)); { skip to NUL }
  737. inc(longint(cp)); { skip to next character }
  738. end;
  739. envp := sysgetmem((env_count+1) * sizeof(pchar));
  740. envc := env_count;
  741. if (envp = nil) then exit;
  742. cp:=environment;
  743. env_count:=0;
  744. while cp^ <> #0 do
  745. begin
  746. envp[env_count] := sysgetmem(strlen(cp)+1);
  747. strcopy(envp[env_count], cp);
  748. {$IfDef DEBUGENVIRONMENT}
  749. Writeln(stderr,'env ',env_count,' = "',envp[env_count],'"');
  750. {$EndIf}
  751. inc(env_count);
  752. while (cp^ <> #0) do
  753. inc(longint(cp)); { skip to NUL }
  754. inc(longint(cp)); { skip to next character }
  755. end;
  756. envp[env_count]:=nil;
  757. end;
  758. var
  759. (* Initialized by system unit initialization *)
  760. PIB: PProcessInfoBlock;
  761. procedure InitArguments;
  762. var
  763. arglen,
  764. count : PtrInt;
  765. argstart,
  766. pc,arg : pchar;
  767. quote : char;
  768. argvlen : PtrInt;
  769. procedure allocarg(idx,len: PtrInt);
  770. var
  771. oldargvlen : PtrInt;
  772. begin
  773. if idx>=argvlen then
  774. begin
  775. oldargvlen:=argvlen;
  776. argvlen:=(idx+8) and (not 7);
  777. sysreallocmem(argv,argvlen*sizeof(pointer));
  778. { fillchar(argv[oldargvlen],(argvlen-oldargvlen)*sizeof(pointer),0);}
  779. end;
  780. { use realloc to reuse already existing memory }
  781. { always allocate, even if length is zero, since }
  782. { the arg. is still present! }
  783. ArgV [Idx] := SysAllocMem (Succ (Len));
  784. end;
  785. begin
  786. CmdLine := SysAllocMem (MaxPathLen);
  787. ArgV := SysAllocMem (8 * SizeOf (pointer));
  788. ArgLen := StrLen (PChar (PIB^.Cmd));
  789. Inc (ArgLen);
  790. if DosQueryModuleName (PIB^.Handle, MaxPathLen, CmdLine) = 0 then
  791. ArgVLen := Succ (StrLen (CmdLine))
  792. else
  793. (* Error occurred - use program name from command line as fallback. *)
  794. begin
  795. Move (PIB^.Cmd^, CmdLine, ArgLen);
  796. ArgVLen := ArgLen;
  797. end;
  798. { Get ArgV [0] }
  799. ArgV [0] := SysAllocMem (ArgVLen);
  800. Move (CmdLine^, ArgV [0]^, ArgVLen);
  801. Count := 1;
  802. (* PC points to leading space after program name on command line *)
  803. PC := PChar (PIB^.Cmd) + ArgLen;
  804. (* ArgLen contains size of command line arguments including leading space. *)
  805. ArgLen := Succ (StrLen (PC));
  806. SysReallocMem (CmdLine, ArgVLen + ArgLen);
  807. Move (PC^, CmdLine [ArgVLen], Succ (ArgLen));
  808. (* ArgV has space for 8 parameters from the first allocation. *)
  809. ArgVLen := 8;
  810. { process arguments }
  811. while pc^<>#0 do
  812. begin
  813. { skip leading spaces }
  814. while pc^ in [#1..#32] do
  815. inc(pc);
  816. if pc^=#0 then
  817. break;
  818. { calc argument length }
  819. quote:=' ';
  820. argstart:=pc;
  821. arglen:=0;
  822. while (pc^<>#0) do
  823. begin
  824. case pc^ of
  825. #1..#32 :
  826. begin
  827. if quote<>' ' then
  828. inc(arglen)
  829. else
  830. break;
  831. end;
  832. '"' :
  833. begin
  834. if quote<>'''' then
  835. begin
  836. if pchar(pc+1)^<>'"' then
  837. begin
  838. if quote='"' then
  839. quote:=' '
  840. else
  841. quote:='"';
  842. end
  843. else
  844. inc(pc);
  845. end
  846. else
  847. inc(arglen);
  848. end;
  849. '''' :
  850. begin
  851. if quote<>'"' then
  852. begin
  853. if pchar(pc+1)^<>'''' then
  854. begin
  855. if quote='''' then
  856. quote:=' '
  857. else
  858. quote:='''';
  859. end
  860. else
  861. inc(pc);
  862. end
  863. else
  864. inc(arglen);
  865. end;
  866. else
  867. inc(arglen);
  868. end;
  869. inc(pc);
  870. end;
  871. { copy argument }
  872. { Don't copy the first one, it is already there.}
  873. If Count<>0 then
  874. begin
  875. allocarg(count,arglen);
  876. quote:=' ';
  877. pc:=argstart;
  878. arg:=argv[count];
  879. while (pc^<>#0) do
  880. begin
  881. case pc^ of
  882. #1..#32 :
  883. begin
  884. if quote<>' ' then
  885. begin
  886. arg^:=pc^;
  887. inc(arg);
  888. end
  889. else
  890. break;
  891. end;
  892. '"' :
  893. begin
  894. if quote<>'''' then
  895. begin
  896. if pchar(pc+1)^<>'"' then
  897. begin
  898. if quote='"' then
  899. quote:=' '
  900. else
  901. quote:='"';
  902. end
  903. else
  904. inc(pc);
  905. end
  906. else
  907. begin
  908. arg^:=pc^;
  909. inc(arg);
  910. end;
  911. end;
  912. '''' :
  913. begin
  914. if quote<>'"' then
  915. begin
  916. if pchar(pc+1)^<>'''' then
  917. begin
  918. if quote='''' then
  919. quote:=' '
  920. else
  921. quote:='''';
  922. end
  923. else
  924. inc(pc);
  925. end
  926. else
  927. begin
  928. arg^:=pc^;
  929. inc(arg);
  930. end;
  931. end;
  932. else
  933. begin
  934. arg^:=pc^;
  935. inc(arg);
  936. end;
  937. end;
  938. inc(pc);
  939. end;
  940. arg^:=#0;
  941. end;
  942. {$IfDef DEBUGARGUMENTS}
  943. Writeln(stderr,'dos arg ',count,' #',arglen,'#',argv[count],'#');
  944. {$EndIf}
  945. inc(count);
  946. end;
  947. { get argc and create an nil entry }
  948. argc:=count;
  949. allocarg(argc,0);
  950. { free unused memory }
  951. sysreallocmem(argv,(argc+1)*sizeof(pointer));
  952. end;
  953. function GetFileHandleCount: longint;
  954. var L1: longint;
  955. L2: cardinal;
  956. begin
  957. L1 := 0; (* Don't change the amount, just check. *)
  958. if DosSetRelMaxFH (L1, L2) <> 0 then GetFileHandleCount := 50
  959. else GetFileHandleCount := L2;
  960. end;
  961. function CheckInitialStkLen (StkLen: SizeUInt): SizeUInt;
  962. begin
  963. CheckInitialStkLen := StkLen;
  964. end;
  965. var TIB: PThreadInfoBlock;
  966. RC: cardinal;
  967. ErrStr: string;
  968. P: pointer;
  969. DosCallsHandle: THandle;
  970. DW: cardinal;
  971. const
  972. DosCallsName: array [0..8] of char = 'DOSCALLS'#0;
  973. {$IFDEF OS2UNICODE}
  974. {$I sysucode.inc}
  975. {$ENDIF OS2UNICODE}
  976. {*var}
  977. {* ST: pointer;}
  978. {*}
  979. begin
  980. {$IFDEF OS2EXCEPTIONS}
  981. (* asm
  982. { allocate space for exception registration record }
  983. pushl $0
  984. pushl $0}
  985. {* pushl %fs:(0)}
  986. { movl %esp,%fs:(0)
  987. but don't insert it as it doesn't
  988. point to anything yet
  989. this will be used in signals unit }
  990. movl %esp,%eax
  991. movl %eax,ExcptReg
  992. pushl %ebp
  993. movl %esp,%eax
  994. {* movl %eax,st*}
  995. movl %eax,StackTop
  996. end;
  997. {* StackTop:=st;}
  998. *) asm
  999. xorl %eax,%eax
  1000. movw %ss,%ax
  1001. movl %eax,_SS
  1002. call SysResetFPU
  1003. end;
  1004. {$ENDIF OS2EXCEPTIONS}
  1005. DosGetInfoBlocks (@TIB, @PIB);
  1006. StackBottom := TIB^.Stack;
  1007. { $IFNDEF OS2EXCEPTIONS}
  1008. StackTop := TIB^.StackLimit;
  1009. { $ENDIF OS2EXCEPTIONS}
  1010. StackLength := CheckInitialStkLen (InitialStkLen);
  1011. {Set type of application}
  1012. ApplicationType := PIB^.ProcType;
  1013. ProcessID := PIB^.PID;
  1014. ThreadID := TIB^.TIB2^.TID;
  1015. IsConsole := ApplicationType <> 3;
  1016. {Query maximum path length (QSV_MAX_PATH_LEN = 1)}
  1017. if DosQuerySysInfo (1, 1, DW, SizeOf (DW)) = 0 then
  1018. RealMaxPathLen := DW;
  1019. ExitProc := nil;
  1020. {$IFDEF OS2EXCEPTIONS}
  1021. Install_Exception_Handler;
  1022. {$ENDIF OS2EXCEPTIONS}
  1023. (* Initialize the amount of file handles *)
  1024. FileHandleCount := GetFileHandleCount;
  1025. {Initialize the heap.}
  1026. (* Logic is following:
  1027. The heap is initially restricted to low address space (< 512 MB).
  1028. If underlying OS/2 version allows using more than 512 MB per process
  1029. (OS/2 WarpServer for e-Business, eComStation, possibly OS/2 Warp 4.0
  1030. with FP13 and above as well), use of this high memory is allowed for
  1031. future memory allocations at the end of System unit initialization.
  1032. The consequences are that the compiled application can allocate more
  1033. memory, but it must make sure to use direct DosAllocMem calls if it
  1034. needs a memory block for some system API not supporting high memory.
  1035. This is probably no problem for direct calls to these APIs, but
  1036. there might be situations when a memory block needs to be passed
  1037. to a 3rd party DLL which in turn calls such an API call. In case
  1038. of problems usage of high memory can be turned off by setting
  1039. UseHighMem to false - the program should change the setting at its
  1040. very beginning (e.g. in initialization section of the first unit
  1041. listed in the "uses" section) to avoid having preallocated memory
  1042. from the high memory region before changing value of this variable. *)
  1043. InitHeap;
  1044. if DosQueryModuleHandle (@DosCallsName [0], DosCallsHandle) = 0 then
  1045. begin
  1046. if DosQueryProcAddr (DosCallsHandle, OrdDosOpenL, nil, P) = 0 then
  1047. begin
  1048. Sys_DosOpenL := TDosOpenL (P);
  1049. if DosQueryProcAddr (DosCallsHandle, OrdDosSetFilePtrL, nil, P) = 0
  1050. then
  1051. begin
  1052. Sys_DosSetFilePtrL := TDosSetFilePtrL (P);
  1053. if DosQueryProcAddr (DosCallsHandle, OrdDosSetFileSizeL, nil,
  1054. P) = 0 then
  1055. begin
  1056. Sys_DosSetFileSizeL := TDosSetFileSizeL (P);
  1057. FSApi64 := true;
  1058. end;
  1059. end;
  1060. end;
  1061. end;
  1062. { ... and exceptions }
  1063. SysInitExceptions;
  1064. fpc_cpucodeinit;
  1065. InitUnicodeStringManager;
  1066. {$ifdef OS2UCODE}
  1067. InitOS2WideStrings;
  1068. {$endif OS2UCODE}
  1069. { ... and I/O }
  1070. SysInitStdIO;
  1071. { no I/O-Error }
  1072. inoutres:=0;
  1073. {Initialize environment (must be after InitHeap because allocates memory)}
  1074. Environment := pointer (PIB^.Env);
  1075. InitEnvironment;
  1076. InitArguments;
  1077. DefaultCreator := '';
  1078. DefaultFileType := '';
  1079. InitSystemThreads;
  1080. InitVariantManager;
  1081. {$IFDEF EXTDUMPGROW}
  1082. { Int_HeapSize := high (cardinal);}
  1083. {$ENDIF EXTDUMPGROW}
  1084. {$ifdef SYSTEMEXCEPTIONDEBUG}
  1085. if IsConsole then
  1086. WriteLn (StdErr, 'Old exception ', HexStr (OldExceptAddr, 8),
  1087. ', new exception ', HexStr (NewExceptAddr, 8), ', _SS = ', HexStr (_SS, 8));
  1088. {$endif SYSTEMEXCEPTIONDEBUG}
  1089. end.